From f8f5d7ca517217e5fbaef8de0d2a1eb8356959d0 Mon Sep 17 00:00:00 2001 From: Igor Rudenko Date: Sun, 13 Oct 2024 22:14:26 +0300 Subject: [PATCH] Add jdk.internal.* to std libs --- .../std/jdk/internal/ValueBased.class | Bin 0 -> 384 bytes .../std/jdk/internal/ValueBased.java | 49 + .../jdk/internal/access/JavaAWTAccess.class | Bin 0 -> 177 bytes .../jdk/internal/access/JavaAWTAccess.java | 36 + .../internal/access/JavaAWTFontAccess.class | Bin 0 -> 255 bytes .../internal/access/JavaAWTFontAccess.java | 39 + .../jdk/internal/access/JavaBeansAccess.class | Bin 0 -> 519 bytes .../jdk/internal/access/JavaBeansAccess.java | 50 + .../jdk/internal/access/JavaIOAccess.class | Bin 0 -> 165 bytes .../std/jdk/internal/access/JavaIOAccess.java | 32 + .../access/JavaIOFileDescriptorAccess.class | Bin 0 -> 776 bytes .../access/JavaIOFileDescriptorAccess.java | 49 + .../access/JavaIOFilePermissionAccess.class | Bin 0 -> 265 bytes .../access/JavaIOFilePermissionAccess.java | 48 + .../access/JavaIOPrintStreamAccess.class | Bin 0 -> 206 bytes .../access/JavaIOPrintStreamAccess.java | 31 + .../access/JavaIOPrintWriterAccess.class | Bin 0 -> 206 bytes .../access/JavaIOPrintWriterAccess.java | 31 + .../access/JavaIORandomAccessFileAccess.class | Bin 0 -> 292 bytes .../access/JavaIORandomAccessFileAccess.java | 35 + .../jdk/internal/access/JavaLangAccess.class | Bin 0 -> 8769 bytes .../jdk/internal/access/JavaLangAccess.java | 618 +++ .../access/JavaLangInvokeAccess.class | Bin 0 -> 2941 bytes .../internal/access/JavaLangInvokeAccess.java | 173 + .../access/JavaLangModuleAccess.class | Bin 0 -> 4439 bytes .../internal/access/JavaLangModuleAccess.java | 140 + .../internal/access/JavaLangRefAccess.class | Bin 0 -> 443 bytes .../internal/access/JavaLangRefAccess.java | 60 + .../access/JavaLangReflectAccess.class | Bin 0 -> 2753 bytes .../access/JavaLangReflectAccess.java | 108 + .../access/JavaNetHttpCookieAccess.class | Bin 0 -> 345 bytes .../access/JavaNetHttpCookieAccess.java | 44 + .../access/JavaNetInetAddressAccess.class | Bin 0 -> 329 bytes .../access/JavaNetInetAddressAccess.java | 48 + .../internal/access/JavaNetURLAccess.class | Bin 0 -> 200 bytes .../jdk/internal/access/JavaNetURLAccess.java | 32 + .../internal/access/JavaNetUriAccess.class | Bin 0 -> 205 bytes .../jdk/internal/access/JavaNetUriAccess.java | 35 + .../jdk/internal/access/JavaNioAccess.class | Bin 0 -> 1277 bytes .../jdk/internal/access/JavaNioAccess.java | 144 + .../access/JavaObjectInputFilterAccess.class | Bin 0 -> 229 bytes .../access/JavaObjectInputFilterAccess.java | 38 + .../access/JavaObjectInputStreamAccess.class | Bin 0 -> 433 bytes .../access/JavaObjectInputStreamAccess.java | 38 + .../JavaObjectInputStreamReadString.class | Bin 0 -> 356 bytes .../JavaObjectInputStreamReadString.java | 38 + ...SecurityAccess$ProtectionDomainCache.class | Bin 0 -> 452 bytes .../internal/access/JavaSecurityAccess.class | Bin 0 -> 1016 bytes .../internal/access/JavaSecurityAccess.java | 53 + .../access/JavaSecurityPropertiesAccess.class | Bin 0 -> 215 bytes .../access/JavaSecurityPropertiesAccess.java | 32 + .../access/JavaSecuritySignatureAccess.class | Bin 0 -> 678 bytes .../access/JavaSecuritySignatureAccess.java | 43 + .../access/JavaSecuritySpecAccess.class | Bin 0 -> 216 bytes .../access/JavaSecuritySpecAccess.java | 32 + .../access/JavaUtilCollectionAccess.class | Bin 0 -> 358 bytes .../access/JavaUtilCollectionAccess.java | 33 + .../access/JavaUtilConcurrentFJPAccess.class | Bin 0 -> 300 bytes .../access/JavaUtilConcurrentFJPAccess.java | 32 + .../access/JavaUtilConcurrentTLRAccess.class | Bin 0 -> 206 bytes .../access/JavaUtilConcurrentTLRAccess.java | 30 + .../internal/access/JavaUtilJarAccess.class | Bin 0 -> 535 bytes .../internal/access/JavaUtilJarAccess.java | 40 + .../access/JavaUtilResourceBundleAccess.class | Bin 0 -> 728 bytes .../access/JavaUtilResourceBundleAccess.java | 66 + .../access/JavaUtilZipFileAccess.class | Bin 0 -> 1099 bytes .../access/JavaUtilZipFileAccess.java | 48 + .../JavaxCryptoSealedObjectAccess.class | Bin 0 -> 407 bytes .../access/JavaxCryptoSealedObjectAccess.java | 38 + .../access/JavaxCryptoSpecAccess.class | Bin 0 -> 211 bytes .../access/JavaxCryptoSpecAccess.java | 32 + .../internal/access/JavaxSecurityAccess.class | Bin 0 -> 332 bytes .../internal/access/JavaxSecurityAccess.java | 34 + .../jdk/internal/access/SharedSecrets.class | Bin 0 -> 17671 bytes .../jdk/internal/access/SharedSecrets.java | 539 ++ .../access/foreign/UnmapperProxy.class | Bin 0 -> 258 bytes .../access/foreign/UnmapperProxy.java | 40 + ...ributeMapper$AnnotationDefaultMapper.class | Bin 0 -> 2792 bytes ...tributeMapper$BootstrapMethodsMapper.class | Bin 0 -> 2755 bytes ...buteMapper$CharacterRangeTableMapper.class | Bin 0 -> 3542 bytes .../AbstractAttributeMapper$CodeMapper.class | Bin 0 -> 2547 bytes ...tAttributeMapper$CompilationIDMapper.class | Bin 0 -> 2776 bytes ...tAttributeMapper$ConstantValueMapper.class | Bin 0 -> 2780 bytes ...ractAttributeMapper$DeprecatedMapper.class | Bin 0 -> 2548 bytes ...ttributeMapper$EnclosingMethodMapper.class | Bin 0 -> 3037 bytes ...ractAttributeMapper$ExceptionsMapper.class | Bin 0 -> 2690 bytes ...ctAttributeMapper$InnerClassesMapper.class | Bin 0 -> 3671 bytes ...ttributeMapper$LineNumberTableMapper.class | Bin 0 -> 3312 bytes ...ibuteMapper$LocalVariableTableMapper.class | Bin 0 -> 3614 bytes ...eMapper$LocalVariableTypeTableMapper.class | Bin 0 -> 3675 bytes ...tributeMapper$MethodParametersMapper.class | Bin 0 -> 3586 bytes ...ctAttributeMapper$ModuleHashesMapper.class | Bin 0 -> 3540 bytes ...ttributeMapper$ModuleMainClassMapper.class | Bin 0 -> 2795 bytes ...AbstractAttributeMapper$ModuleMapper.class | Bin 0 -> 4723 bytes ...AttributeMapper$ModulePackagesMapper.class | Bin 0 -> 2732 bytes ...tributeMapper$ModuleResolutionMapper.class | Bin 0 -> 2724 bytes ...ctAttributeMapper$ModuleTargetMapper.class | Bin 0 -> 2766 bytes ...stractAttributeMapper$NestHostMapper.class | Bin 0 -> 2706 bytes ...actAttributeMapper$NestMembersMapper.class | Bin 0 -> 2702 bytes ...buteMapper$PermittedSubclassesMapper.class | Bin 0 -> 2798 bytes ...AbstractAttributeMapper$RecordMapper.class | Bin 0 -> 3439 bytes ...er$RuntimeInvisibleAnnotationsMapper.class | Bin 0 -> 2843 bytes ...eInvisibleParameterAnnotationsMapper.class | Bin 0 -> 3512 bytes ...untimeInvisibleTypeAnnotationsMapper.class | Bin 0 -> 2956 bytes ...pper$RuntimeVisibleAnnotationsMapper.class | Bin 0 -> 2821 bytes ...imeVisibleParameterAnnotationsMapper.class | Bin 0 -> 3490 bytes ...$RuntimeVisibleTypeAnnotationsMapper.class | Bin 0 -> 2934 bytes ...tractAttributeMapper$SignatureMapper.class | Bin 0 -> 2716 bytes ...uteMapper$SourceDebugExtensionMapper.class | Bin 0 -> 2766 bytes ...ractAttributeMapper$SourceFileMapper.class | Bin 0 -> 2727 bytes ...stractAttributeMapper$SourceIDMapper.class | Bin 0 -> 2716 bytes ...tAttributeMapper$StackMapTableMapper.class | Bin 0 -> 2839 bytes ...tractAttributeMapper$SyntheticMapper.class | Bin 0 -> 2537 bytes .../impl/AbstractAttributeMapper.class | Bin 0 -> 7321 bytes .../impl/AbstractAttributeMapper.java | 824 +++ .../impl/AbstractBoundLocalVariable.class | Bin 0 -> 3109 bytes .../impl/AbstractBoundLocalVariable.java | 104 + .../impl/AbstractDirectBuilder.class | Bin 0 -> 2364 bytes .../classfile/impl/AbstractDirectBuilder.java | 59 + .../classfile/impl/AbstractElement.class | Bin 0 -> 1112 bytes .../classfile/impl/AbstractElement.java | 45 + ...ion$BoundArgumentConstantInstruction.class | Bin 0 -> 2140 bytes ...ctInstruction$BoundBranchInstruction.class | Bin 0 -> 2214 bytes ...actInstruction$BoundFieldInstruction.class | Bin 0 -> 2816 bytes ...nstruction$BoundIncrementInstruction.class | Bin 0 -> 1965 bytes ...AbstractInstruction$BoundInstruction.class | Bin 0 -> 3836 bytes ...uction$BoundInvokeDynamicInstruction.class | Bin 0 -> 2640 bytes ...ctInstruction$BoundInvokeInstruction.class | Bin 0 -> 3053 bytes ...tion$BoundInvokeInterfaceInstruction.class | Bin 0 -> 3092 bytes ...tractInstruction$BoundJsrInstruction.class | Bin 0 -> 2317 bytes ...ruction$BoundLoadConstantInstruction.class | Bin 0 -> 2821 bytes ...ractInstruction$BoundLoadInstruction.class | Bin 0 -> 2318 bytes ...ruction$BoundLookupSwitchInstruction.class | Bin 0 -> 3465 bytes ...dNewMultidimensionalArrayInstruction.class | Bin 0 -> 2631 bytes ...nstruction$BoundNewObjectInstruction.class | Bin 0 -> 2439 bytes ...on$BoundNewPrimitiveArrayInstruction.class | Bin 0 -> 1794 bytes ...on$BoundNewReferenceArrayInstruction.class | Bin 0 -> 2400 bytes ...tractInstruction$BoundRetInstruction.class | Bin 0 -> 2197 bytes ...actInstruction$BoundStoreInstruction.class | Bin 0 -> 2320 bytes ...truction$BoundTableSwitchInstruction.class | Bin 0 -> 4062 bytes ...nstruction$BoundTypeCheckInstruction.class | Bin 0 -> 2501 bytes .../AbstractInstruction$SwitchCaseImpl.class | Bin 0 -> 1902 bytes ...n$UnboundArgumentConstantInstruction.class | Bin 0 -> 1879 bytes ...truction$UnboundArrayLoadInstruction.class | Bin 0 -> 925 bytes ...ruction$UnboundArrayStoreInstruction.class | Bin 0 -> 929 bytes ...Instruction$UnboundBranchInstruction.class | Bin 0 -> 1554 bytes ...nstruction$UnboundConvertInstruction.class | Bin 0 -> 1020 bytes ...tInstruction$UnboundFieldInstruction.class | Bin 0 -> 1980 bytes ...truction$UnboundIncrementInstruction.class | Bin 0 -> 1822 bytes ...stractInstruction$UnboundInstruction.class | Bin 0 -> 4721 bytes ...$UnboundIntrinsicConstantInstruction.class | Bin 0 -> 1335 bytes ...tion$UnboundInvokeDynamicInstruction.class | Bin 0 -> 1854 bytes ...Instruction$UnboundInvokeInstruction.class | Bin 0 -> 2918 bytes ...actInstruction$UnboundJsrInstruction.class | Bin 0 -> 1658 bytes ...ction$UnboundLoadConstantInstruction.class | Bin 0 -> 2016 bytes ...ctInstruction$UnboundLoadInstruction.class | Bin 0 -> 1733 bytes ...ction$UnboundLookupSwitchInstruction.class | Bin 0 -> 2156 bytes ...nstruction$UnboundMonitorInstruction.class | Bin 0 -> 737 bytes ...dNewMultidimensionalArrayInstruction.class | Bin 0 -> 2095 bytes ...truction$UnboundNewObjectInstruction.class | Bin 0 -> 1739 bytes ...$UnboundNewPrimitiveArrayInstruction.class | Bin 0 -> 1730 bytes ...$UnboundNewReferenceArrayInstruction.class | Bin 0 -> 1802 bytes ...actInstruction$UnboundNopInstruction.class | Bin 0 -> 762 bytes ...struction$UnboundOperatorInstruction.class | Bin 0 -> 921 bytes ...actInstruction$UnboundRetInstruction.class | Bin 0 -> 1580 bytes ...Instruction$UnboundReturnInstruction.class | Bin 0 -> 1214 bytes ...tInstruction$UnboundStackInstruction.class | Bin 0 -> 729 bytes ...tInstruction$UnboundStoreInstruction.class | Bin 0 -> 1738 bytes ...uction$UnboundTableSwitchInstruction.class | Bin 0 -> 2391 bytes ...tInstruction$UnboundThrowInstruction.class | Bin 0 -> 1073 bytes ...truction$UnboundTypeCheckInstruction.class | Bin 0 -> 1743 bytes .../classfile/impl/AbstractInstruction.class | Bin 0 -> 8205 bytes .../classfile/impl/AbstractInstruction.java | 1453 +++++ ...try$AbstractDynamicConstantPoolEntry.class | Bin 0 -> 3598 bytes ...ractPoolEntry$AbstractMemberRefEntry.class | Bin 0 -> 3844 bytes ...AbstractPoolEntry$AbstractNamedEntry.class | Bin 0 -> 2237 bytes .../AbstractPoolEntry$AbstractRefEntry.class | Bin 0 -> 2417 bytes .../AbstractPoolEntry$AbstractRefsEntry.class | Bin 0 -> 2633 bytes .../AbstractPoolEntry$ClassEntryImpl.class | Bin 0 -> 3347 bytes ...ctPoolEntry$ConstantDynamicEntryImpl.class | Bin 0 -> 3160 bytes .../impl/AbstractPoolEntry$CpException.class | Bin 0 -> 603 bytes .../AbstractPoolEntry$DoubleEntryImpl.class | Bin 0 -> 2838 bytes .../AbstractPoolEntry$FieldRefEntryImpl.class | Bin 0 -> 2535 bytes .../AbstractPoolEntry$FloatEntryImpl.class | Bin 0 -> 2824 bytes .../AbstractPoolEntry$IntegerEntryImpl.class | Bin 0 -> 2826 bytes ...oolEntry$InterfaceMethodRefEntryImpl.class | Bin 0 -> 2605 bytes ...ractPoolEntry$InvokeDynamicEntryImpl.class | Bin 0 -> 3146 bytes .../AbstractPoolEntry$LongEntryImpl.class | Bin 0 -> 2811 bytes ...tractPoolEntry$MethodHandleEntryImpl.class | Bin 0 -> 4758 bytes ...AbstractPoolEntry$MethodRefEntryImpl.class | Bin 0 -> 2542 bytes ...bstractPoolEntry$MethodTypeEntryImpl.class | Bin 0 -> 3363 bytes .../AbstractPoolEntry$ModuleEntryImpl.class | Bin 0 -> 3032 bytes ...stractPoolEntry$NameAndTypeEntryImpl.class | Bin 0 -> 4176 bytes .../AbstractPoolEntry$PackageEntryImpl.class | Bin 0 -> 3111 bytes .../AbstractPoolEntry$PrimitiveEntry.class | Bin 0 -> 2241 bytes .../AbstractPoolEntry$StringEntryImpl.class | Bin 0 -> 3453 bytes ...bstractPoolEntry$Utf8EntryImpl$State.class | Bin 0 -> 1602 bytes .../AbstractPoolEntry$Utf8EntryImpl.class | Bin 0 -> 8511 bytes .../classfile/impl/AbstractPoolEntry.class | Bin 0 -> 5219 bytes .../classfile/impl/AbstractPoolEntry.java | 1201 +++++ ...seudoInstruction$AbstractLocalPseudo.class | Bin 0 -> 2576 bytes ...PseudoInstruction$ExceptionCatchImpl.class | Bin 0 -> 3091 bytes ...udoInstruction$UnboundCharacterRange.class | Bin 0 -> 1603 bytes ...eudoInstruction$UnboundLocalVariable.class | Bin 0 -> 2489 bytes ...Instruction$UnboundLocalVariableType.class | Bin 0 -> 2521 bytes .../impl/AbstractPseudoInstruction.class | Bin 0 -> 1149 bytes .../impl/AbstractPseudoInstruction.java | 260 + .../classfile/impl/AbstractUnboundModel.class | Bin 0 -> 3542 bytes .../classfile/impl/AbstractUnboundModel.java | 71 + .../classfile/impl/AccessFlagsImpl.class | Bin 0 -> 3067 bytes .../classfile/impl/AccessFlagsImpl.java | 90 + ...AnnotationImpl$AnnotationElementImpl.class | Bin 0 -> 2418 bytes .../AnnotationImpl$OfAnnotationImpl.class | Bin 0 -> 2228 bytes .../impl/AnnotationImpl$OfArrayImpl.class | Bin 0 -> 2471 bytes .../impl/AnnotationImpl$OfBooleanImpl.class | Bin 0 -> 2371 bytes .../impl/AnnotationImpl$OfByteImpl.class | Bin 0 -> 2309 bytes .../impl/AnnotationImpl$OfCharacterImpl.class | Bin 0 -> 2343 bytes .../impl/AnnotationImpl$OfClassImpl.class | Bin 0 -> 2250 bytes .../impl/AnnotationImpl$OfConstantImpl.class | Bin 0 -> 1931 bytes .../impl/AnnotationImpl$OfDoubleImpl.class | Bin 0 -> 2311 bytes .../impl/AnnotationImpl$OfEnumImpl.class | Bin 0 -> 2450 bytes .../impl/AnnotationImpl$OfFloatImpl.class | Bin 0 -> 2298 bytes .../impl/AnnotationImpl$OfIntegerImpl.class | Bin 0 -> 2314 bytes .../impl/AnnotationImpl$OfLongImpl.class | Bin 0 -> 2285 bytes .../impl/AnnotationImpl$OfShortImpl.class | Bin 0 -> 2318 bytes .../impl/AnnotationImpl$OfStringImpl.class | Bin 0 -> 2297 bytes .../classfile/impl/AnnotationImpl.class | Bin 0 -> 4042 bytes .../classfile/impl/AnnotationImpl.java | 304 ++ .../classfile/impl/AnnotationReader.class | Bin 0 -> 15123 bytes .../classfile/impl/AnnotationReader.java | 282 + .../classfile/impl/AttributeHolder.class | Bin 0 -> 3213 bytes .../classfile/impl/AttributeHolder.java | 69 + .../classfile/impl/BlockCodeBuilderImpl.class | Bin 0 -> 4018 bytes .../classfile/impl/BlockCodeBuilderImpl.java | 118 + .../impl/BootstrapMethodEntryImpl.class | Bin 0 -> 3300 bytes .../impl/BootstrapMethodEntryImpl.java | 95 + .../classfile/impl/BoundAttribute$1.class | Bin 0 -> 2788 bytes ...Attribute$BoundAnnotationDefaultAttr.class | Bin 0 -> 1728 bytes ...ibute$BoundBootstrapMethodsAttribute.class | Bin 0 -> 3109 bytes ...te$BoundCharacterRangeTableAttribute.class | Bin 0 -> 2468 bytes .../BoundAttribute$BoundCodeAttribute.class | Bin 0 -> 2410 bytes ...ttribute$BoundCompilationIDAttribute.class | Bin 0 -> 1565 bytes ...ttribute$BoundConstantValueAttribute.class | Bin 0 -> 1644 bytes ...ndAttribute$BoundDeprecatedAttribute.class | Bin 0 -> 1186 bytes ...ribute$BoundEnclosingMethodAttribute.class | Bin 0 -> 2032 bytes ...ndAttribute$BoundExceptionsAttribute.class | Bin 0 -> 1602 bytes ...Attribute$BoundInnerClassesAttribute.class | Bin 0 -> 2819 bytes ...ribute$BoundLineNumberTableAttribute.class | Bin 0 -> 2253 bytes ...ute$BoundLocalVariableTableAttribute.class | Bin 0 -> 2576 bytes ...BoundLocalVariableTypeTableAttribute.class | Bin 0 -> 2628 bytes ...ibute$BoundMethodParametersAttribute.class | Bin 0 -> 2543 bytes .../BoundAttribute$BoundModuleAttribute.class | Bin 0 -> 6219 bytes ...Attribute$BoundModuleHashesAttribute.class | Bin 0 -> 2621 bytes ...ribute$BoundModuleMainClassAttribute.class | Bin 0 -> 1580 bytes ...tribute$BoundModulePackagesAttribute.class | Bin 0 -> 1636 bytes ...ibute$BoundModuleResolutionAttribute.class | Bin 0 -> 1498 bytes ...Attribute$BoundModuleTargetAttribute.class | Bin 0 -> 1558 bytes ...oundAttribute$BoundNestHostAttribute.class | Bin 0 -> 1523 bytes ...dAttribute$BoundNestMembersAttribute.class | Bin 0 -> 1621 bytes ...te$BoundPermittedSubclassesAttribute.class | Bin 0 -> 1683 bytes .../BoundAttribute$BoundRecordAttribute.class | Bin 0 -> 2185 bytes ...RuntimeInvisibleAnnotationsAttribute.class | Bin 0 -> 1662 bytes ...visibleParameterAnnotationsAttribute.class | Bin 0 -> 1826 bytes ...imeInvisibleTypeAnnotationsAttribute.class | Bin 0 -> 2384 bytes ...ndRuntimeVisibleAnnotationsAttribute.class | Bin 0 -> 1648 bytes ...VisibleParameterAnnotationsAttribute.class | Bin 0 -> 1810 bytes ...ntimeVisibleTypeAnnotationsAttribute.class | Bin 0 -> 2368 bytes ...undAttribute$BoundSignatureAttribute.class | Bin 0 -> 1529 bytes ...e$BoundSourceDebugExtensionAttribute.class | Bin 0 -> 1266 bytes ...ndAttribute$BoundSourceFileAttribute.class | Bin 0 -> 1538 bytes ...oundAttribute$BoundSourceIDAttribute.class | Bin 0 -> 1520 bytes ...ttribute$BoundStackMapTableAttribute.class | Bin 0 -> 2490 bytes ...undAttribute$BoundSyntheticAttribute.class | Bin 0 -> 1178 bytes ...BoundAttribute$BoundUnknownAttribute.class | Bin 0 -> 1162 bytes .../classfile/impl/BoundAttribute.class | Bin 0 -> 15612 bytes .../classfile/impl/BoundAttribute.java | 1066 ++++ .../classfile/impl/BoundCharacterRange.class | Bin 0 -> 2350 bytes .../classfile/impl/BoundCharacterRange.java | 86 + .../classfile/impl/BoundLocalVariable.class | Bin 0 -> 1804 bytes .../classfile/impl/BoundLocalVariable.java | 61 + .../impl/BoundLocalVariableType.class | Bin 0 -> 1617 bytes .../impl/BoundLocalVariableType.java | 54 + .../impl/BoundRecordComponentInfo.class | Bin 0 -> 1555 bytes .../impl/BoundRecordComponentInfo.java | 64 + .../classfile/impl/BufWriterImpl.class | Bin 0 -> 6886 bytes .../classfile/impl/BufWriterImpl.java | 217 + .../impl/BufferedCodeBuilder$Model$1.class | Bin 0 -> 1338 bytes .../impl/BufferedCodeBuilder$Model.class | Bin 0 -> 5918 bytes .../classfile/impl/BufferedCodeBuilder.class | Bin 0 -> 5627 bytes .../classfile/impl/BufferedCodeBuilder.java | 218 + .../impl/BufferedFieldBuilder$Model$1.class | Bin 0 -> 1491 bytes .../impl/BufferedFieldBuilder$Model.class | Bin 0 -> 3679 bytes .../classfile/impl/BufferedFieldBuilder.class | Bin 0 -> 3265 bytes .../classfile/impl/BufferedFieldBuilder.java | 135 + .../impl/BufferedMethodBuilder$Model$1.class | Bin 0 -> 1359 bytes .../impl/BufferedMethodBuilder$Model.class | Bin 0 -> 4853 bytes .../impl/BufferedMethodBuilder.class | Bin 0 -> 5968 bytes .../classfile/impl/BufferedMethodBuilder.java | 221 + .../classfile/impl/BytecodeHelpers$1.class | Bin 0 -> 2412 bytes .../classfile/impl/BytecodeHelpers.class | Bin 0 -> 15510 bytes .../classfile/impl/BytecodeHelpers.java | 350 ++ .../classfile/impl/CatchBuilderImpl.class | Bin 0 -> 4893 bytes .../classfile/impl/CatchBuilderImpl.java | 111 + .../classfile/impl/ChainedClassBuilder.class | Bin 0 -> 6243 bytes .../classfile/impl/ChainedClassBuilder.java | 102 + .../classfile/impl/ChainedCodeBuilder.class | Bin 0 -> 1935 bytes .../classfile/impl/ChainedCodeBuilder.java | 65 + .../classfile/impl/ChainedFieldBuilder.class | Bin 0 -> 2603 bytes .../classfile/impl/ChainedFieldBuilder.java | 65 + .../classfile/impl/ChainedMethodBuilder.class | Bin 0 -> 3842 bytes .../classfile/impl/ChainedMethodBuilder.java | 83 + .../classfile/impl/ClassFileImpl$1.class | Bin 0 -> 1144 bytes .../classfile/impl/ClassFileImpl$2.class | Bin 0 -> 1751 bytes ...ssFileImpl$AttributeMapperOptionImpl.class | Bin 0 -> 2317 bytes ...mpl$ClassHierarchyResolverOptionImpl.class | Bin 0 -> 1979 bytes .../classfile/impl/ClassFileImpl.class | Bin 0 -> 11519 bytes .../classfile/impl/ClassFileImpl.java | 154 + .../classfile/impl/ClassFileVersionImpl.class | Bin 0 -> 1310 bytes .../classfile/impl/ClassFileVersionImpl.java | 58 + ...yImpl$CachedClassHierarchyResolver$1.class | Bin 0 -> 1969 bytes ...chyImpl$CachedClassHierarchyResolver.class | Bin 0 -> 2407 bytes ...HierarchyImpl$ClassHierarchyInfoImpl.class | Bin 0 -> 2236 bytes ...ClassLoadingClassHierarchyResolver$1.class | Bin 0 -> 1693 bytes ...l$ClassLoadingClassHierarchyResolver.class | Bin 0 -> 2309 bytes ...ourceParsingClassHierarchyResolver$1.class | Bin 0 -> 1657 bytes ...esourceParsingClassHierarchyResolver.class | Bin 0 -> 3692 bytes ...chyImpl$StaticClassHierarchyResolver.class | Bin 0 -> 2889 bytes .../classfile/impl/ClassHierarchyImpl.class | Bin 0 -> 3875 bytes .../classfile/impl/ClassHierarchyImpl.java | 251 + .../internal/classfile/impl/ClassImpl$1.class | Bin 0 -> 1391 bytes .../internal/classfile/impl/ClassImpl.class | Bin 0 -> 9049 bytes .../internal/classfile/impl/ClassImpl.java | 224 + .../classfile/impl/ClassPrinterImpl$1.class | Bin 0 -> 1304 bytes .../ClassPrinterImpl$ExceptionHandler.class | Bin 0 -> 2042 bytes .../impl/ClassPrinterImpl$LeafNodeImpl.class | Bin 0 -> 2342 bytes .../impl/ClassPrinterImpl$ListNodeImpl.class | Bin 0 -> 4066 bytes ...Impl$MapNodeImpl$PrivateListNodeImpl.class | Bin 0 -> 1445 bytes .../impl/ClassPrinterImpl$MapNodeImpl.class | Bin 0 -> 6224 bytes .../impl/ClassPrinterImpl$Style.class | Bin 0 -> 1327 bytes .../classfile/impl/ClassPrinterImpl.class | Bin 0 -> 68936 bytes .../classfile/impl/ClassPrinterImpl.java | 1084 ++++ .../classfile/impl/ClassReaderImpl.class | Bin 0 -> 18596 bytes .../classfile/impl/ClassReaderImpl.java | 516 ++ .../classfile/impl/ClassRemapperImpl$1.class | Bin 0 -> 998 bytes .../classfile/impl/ClassRemapperImpl.class | Bin 0 -> 40081 bytes .../classfile/impl/ClassRemapperImpl.java | 418 ++ .../internal/classfile/impl/CodeImpl$1.class | Bin 0 -> 1155 bytes .../internal/classfile/impl/CodeImpl$2.class | Bin 0 -> 1801 bytes .../internal/classfile/impl/CodeImpl$3.class | Bin 0 -> 1884 bytes .../internal/classfile/impl/CodeImpl$4.class | Bin 0 -> 1282 bytes .../CodeImpl$ExceptionHandlerAction.class | Bin 0 -> 292 bytes .../internal/classfile/impl/CodeImpl.class | Bin 0 -> 25867 bytes .../jdk/internal/classfile/impl/CodeImpl.java | 495 ++ .../impl/CodeLocalsShifterImpl.class | Bin 0 -> 4774 bytes .../classfile/impl/CodeLocalsShifterImpl.java | 99 + .../classfile/impl/CodeRelabelerImpl.class | Bin 0 -> 8317 bytes .../classfile/impl/CodeRelabelerImpl.java | 108 + .../impl/CodeStackTrackerImpl$1.class | Bin 0 -> 1622 bytes .../impl/CodeStackTrackerImpl$Item.class | Bin 0 -> 1904 bytes .../impl/CodeStackTrackerImpl$Stack$1.class | Bin 0 -> 1589 bytes .../impl/CodeStackTrackerImpl$Stack.class | Bin 0 -> 2219 bytes .../classfile/impl/CodeStackTrackerImpl.class | Bin 0 -> 13401 bytes .../classfile/impl/CodeStackTrackerImpl.java | 346 ++ .../classfile/impl/DirectClassBuilder.class | Bin 0 -> 10213 bytes .../classfile/impl/DirectClassBuilder.java | 208 + .../classfile/impl/DirectCodeBuilder$1.class | Bin 0 -> 2960 bytes .../classfile/impl/DirectCodeBuilder$2.class | Bin 0 -> 2626 bytes .../classfile/impl/DirectCodeBuilder$3.class | Bin 0 -> 2658 bytes .../classfile/impl/DirectCodeBuilder$4.class | Bin 0 -> 5466 bytes .../classfile/impl/DirectCodeBuilder$5.class | Bin 0 -> 1334 bytes .../classfile/impl/DirectCodeBuilder$6.class | Bin 0 -> 1312 bytes .../classfile/impl/DirectCodeBuilder$7.class | Bin 0 -> 1317 bytes .../classfile/impl/DirectCodeBuilder$8.class | Bin 0 -> 972 bytes ...uilder$DedupLineNumberTableAttribute.class | Bin 0 -> 2583 bytes .../DirectCodeBuilder$DeferredLabel.class | Bin 0 -> 2091 bytes ...ctCodeBuilder$LabelOverflowException.class | Bin 0 -> 650 bytes .../classfile/impl/DirectCodeBuilder.class | Bin 0 -> 23400 bytes .../classfile/impl/DirectCodeBuilder.java | 786 +++ .../classfile/impl/DirectFieldBuilder.class | Bin 0 -> 3453 bytes .../classfile/impl/DirectFieldBuilder.java | 83 + .../impl/DirectMethodBuilder$1.class | Bin 0 -> 1546 bytes .../classfile/impl/DirectMethodBuilder.class | Bin 0 -> 7273 bytes .../classfile/impl/DirectMethodBuilder.java | 158 + .../internal/classfile/impl/EntryMap.class | Bin 0 -> 3525 bytes .../jdk/internal/classfile/impl/EntryMap.java | 187 + .../internal/classfile/impl/FieldImpl$1.class | Bin 0 -> 1182 bytes .../internal/classfile/impl/FieldImpl.class | Bin 0 -> 5059 bytes .../internal/classfile/impl/FieldImpl.java | 124 + .../classfile/impl/InterfacesImpl.class | Bin 0 -> 2797 bytes .../classfile/impl/InterfacesImpl.java | 58 + .../classfile/impl/LabelContext.class | Bin 0 -> 478 bytes .../internal/classfile/impl/LabelContext.java | 35 + .../internal/classfile/impl/LabelImpl.class | Bin 0 -> 1782 bytes .../internal/classfile/impl/LabelImpl.java | 85 + .../classfile/impl/LineNumberImpl.class | Bin 0 -> 1588 bytes .../classfile/impl/LineNumberImpl.java | 66 + .../classfile/impl/MethodImpl$1.class | Bin 0 -> 1192 bytes .../internal/classfile/impl/MethodImpl.class | Bin 0 -> 7041 bytes .../internal/classfile/impl/MethodImpl.java | 154 + .../internal/classfile/impl/MethodInfo.class | Bin 0 -> 723 bytes .../internal/classfile/impl/MethodInfo.java | 45 + .../impl/ModuleAttributeBuilderImpl.class | Bin 0 -> 8025 bytes .../impl/ModuleAttributeBuilderImpl.java | 159 + .../impl/NonterminalCodeBuilder.class | Bin 0 -> 2243 bytes .../impl/NonterminalCodeBuilder.java | 71 + .../classfile/impl/RawBytecodeHelper.class | Bin 0 -> 4398 bytes .../classfile/impl/RawBytecodeHelper.java | 171 + .../classfile/impl/SignaturesImpl$1.class | Bin 0 -> 1080 bytes .../SignaturesImpl$ArrayTypeSigImpl.class | Bin 0 -> 2406 bytes .../impl/SignaturesImpl$BaseTypeSigImpl.class | Bin 0 -> 1962 bytes .../SignaturesImpl$ClassSignatureImpl.class | Bin 0 -> 3531 bytes .../SignaturesImpl$ClassTypeSigImpl.class | Bin 0 -> 5345 bytes .../SignaturesImpl$MethodSignatureImpl.class | Bin 0 -> 4004 bytes .../impl/SignaturesImpl$TypeArgImpl.class | Bin 0 -> 2395 bytes .../impl/SignaturesImpl$TypeParamImpl.class | Bin 0 -> 2736 bytes .../impl/SignaturesImpl$TypeVarSigImpl.class | Bin 0 -> 1990 bytes .../SignaturesImpl$UnboundedTypeArgImpl.class | Bin 0 -> 1596 bytes .../classfile/impl/SignaturesImpl.class | Bin 0 -> 10296 bytes .../classfile/impl/SignaturesImpl.java | 374 ++ .../classfile/impl/SplitConstantPool$1.class | Bin 0 -> 1837 bytes .../classfile/impl/SplitConstantPool$2.class | Bin 0 -> 1163 bytes .../classfile/impl/SplitConstantPool$3.class | Bin 0 -> 1194 bytes .../classfile/impl/SplitConstantPool.class | Bin 0 -> 28208 bytes .../classfile/impl/SplitConstantPool.java | 606 +++ .../classfile/impl/StackCounter$Target.class | Bin 0 -> 1653 bytes .../classfile/impl/StackCounter.class | Bin 0 -> 13079 bytes .../internal/classfile/impl/StackCounter.java | 386 ++ ...coder$ObjectVerificationTypeInfoImpl.class | Bin 0 -> 1715 bytes .../StackMapDecoder$StackMapFrameImpl.class | Bin 0 -> 2840 bytes ...ninitializedVerificationTypeInfoImpl.class | Bin 0 -> 2199 bytes .../classfile/impl/StackMapDecoder.class | Bin 0 -> 13944 bytes .../classfile/impl/StackMapDecoder.java | 289 + .../classfile/impl/StackMapGenerator$1.class | Bin 0 -> 2913 bytes .../classfile/impl/StackMapGenerator$2.class | Bin 0 -> 994 bytes .../impl/StackMapGenerator$Frame.class | Bin 0 -> 11943 bytes .../StackMapGenerator$RawExceptionCatch.class | Bin 0 -> 2251 bytes .../impl/StackMapGenerator$Type.class | Bin 0 -> 7795 bytes .../classfile/impl/StackMapGenerator.class | Bin 0 -> 28550 bytes .../classfile/impl/StackMapGenerator.java | 1402 +++++ .../classfile/impl/SuperclassImpl.class | Bin 0 -> 1502 bytes .../classfile/impl/SuperclassImpl.java | 56 + .../impl/TargetInfoImpl$CatchTargetImpl.class | Bin 0 -> 2001 bytes .../impl/TargetInfoImpl$EmptyTargetImpl.class | Bin 0 -> 2103 bytes ...etInfoImpl$FormalParameterTargetImpl.class | Bin 0 -> 2086 bytes .../TargetInfoImpl$LocalVarTargetImpl.class | Bin 0 -> 2952 bytes ...argetInfoImpl$LocalVarTargetInfoImpl.class | Bin 0 -> 2269 bytes .../TargetInfoImpl$OffsetTargetImpl.class | Bin 0 -> 2471 bytes .../TargetInfoImpl$SupertypeTargetImpl.class | Bin 0 -> 2022 bytes .../TargetInfoImpl$ThrowsTargetImpl.class | Bin 0 -> 1994 bytes ...argetInfoImpl$TypeArgumentTargetImpl.class | Bin 0 -> 2676 bytes ...nfoImpl$TypeParameterBoundTargetImpl.class | Bin 0 -> 2518 bytes ...rgetInfoImpl$TypeParameterTargetImpl.class | Bin 0 -> 2337 bytes .../classfile/impl/TargetInfoImpl.class | Bin 0 -> 2407 bytes .../classfile/impl/TargetInfoImpl.java | 139 + .../impl/TemporaryConstantPool.class | Bin 0 -> 8679 bytes .../classfile/impl/TemporaryConstantPool.java | 202 + .../classfile/impl/TerminalCodeBuilder.class | Bin 0 -> 400 bytes .../classfile/impl/TerminalCodeBuilder.java | 32 + .../classfile/impl/TerminalFieldBuilder.class | Bin 0 -> 329 bytes .../classfile/impl/TerminalFieldBuilder.java | 32 + .../impl/TerminalMethodBuilder.class | Bin 0 -> 449 bytes .../classfile/impl/TerminalMethodBuilder.java | 34 + .../TransformImpl$ChainedClassTransform.class | Bin 0 -> 3893 bytes .../TransformImpl$ChainedCodeTransform.class | Bin 0 -> 3683 bytes .../TransformImpl$ChainedFieldTransform.class | Bin 0 -> 3704 bytes ...TransformImpl$ChainedMethodTransform.class | Bin 0 -> 3725 bytes .../TransformImpl$ClassFieldTransform.class | Bin 0 -> 5579 bytes .../TransformImpl$ClassMethodTransform.class | Bin 0 -> 5601 bytes .../TransformImpl$MethodCodeTransform.class | Bin 0 -> 4573 bytes .../TransformImpl$ResolvedTransformImpl.class | Bin 0 -> 3013 bytes ...TransformImpl$SupplierClassTransform.class | Bin 0 -> 2987 bytes .../TransformImpl$SupplierCodeTransform.class | Bin 0 -> 2970 bytes ...TransformImpl$SupplierFieldTransform.class | Bin 0 -> 2987 bytes ...ransformImpl$SupplierMethodTransform.class | Bin 0 -> 3004 bytes ...ansformImpl$UnresolvedClassTransform.class | Bin 0 -> 1552 bytes ...ransformImpl$UnresolvedCodeTransform.class | Bin 0 -> 1541 bytes ...ansformImpl$UnresolvedFieldTransform.class | Bin 0 -> 1552 bytes ...nsformImpl$UnresolvedMethodTransform.class | Bin 0 -> 1563 bytes .../classfile/impl/TransformImpl.class | Bin 0 -> 3052 bytes .../classfile/impl/TransformImpl.java | 299 ++ .../UnboundAttribute$AdHocAttribute.class | Bin 0 -> 1735 bytes ...undAttribute$EmptyBootstrapAttribute.class | Bin 0 -> 1162 bytes ...boundAttribute$TypePathComponentImpl.class | Bin 0 -> 2203 bytes ...te$UnboundAnnotationDefaultAttribute.class | Bin 0 -> 1152 bytes ...dAttribute$UnboundCharacterRangeInfo.class | Bin 0 -> 2288 bytes ...$UnboundCharacterRangeTableAttribute.class | Bin 0 -> 1467 bytes ...ribute$UnboundCompilationIDAttribute.class | Bin 0 -> 1140 bytes ...ribute$UnboundConstantValueAttribute.class | Bin 0 -> 1176 bytes ...Attribute$UnboundDeprecatedAttribute.class | Bin 0 -> 871 bytes ...bute$UnboundEnclosingMethodAttribute.class | Bin 0 -> 1593 bytes ...Attribute$UnboundExceptionsAttribute.class | Bin 0 -> 1380 bytes ...boundAttribute$UnboundInnerClassInfo.class | Bin 0 -> 2930 bytes ...tribute$UnboundInnerClassesAttribute.class | Bin 0 -> 1407 bytes ...boundAttribute$UnboundLineNumberInfo.class | Bin 0 -> 1841 bytes ...bute$UnboundLineNumberTableAttribute.class | Bin 0 -> 1440 bytes ...ndAttribute$UnboundLocalVariableInfo.class | Bin 0 -> 2407 bytes ...e$UnboundLocalVariableTableAttribute.class | Bin 0 -> 1474 bytes ...tribute$UnboundLocalVariableTypeInfo.class | Bin 0 -> 2445 bytes ...boundLocalVariableTypeTableAttribute.class | Bin 0 -> 1518 bytes ...Attribute$UnboundMethodParameterInfo.class | Bin 0 -> 2235 bytes ...ute$UnboundMethodParametersAttribute.class | Bin 0 -> 1453 bytes ...oundAttribute$UnboundModuleAttribute.class | Bin 0 -> 4148 bytes ...undAttribute$UnboundModuleExportInfo.class | Bin 0 -> 2661 bytes ...boundAttribute$UnboundModuleHashInfo.class | Bin 0 -> 1989 bytes ...tribute$UnboundModuleHashesAttribute.class | Bin 0 -> 1700 bytes ...bute$UnboundModuleMainClassAttribute.class | Bin 0 -> 1159 bytes ...boundAttribute$UnboundModuleOpenInfo.class | Bin 0 -> 2635 bytes ...ibute$UnboundModulePackagesAttribute.class | Bin 0 -> 1452 bytes ...ndAttribute$UnboundModuleProvideInfo.class | Bin 0 -> 2493 bytes ...dAttribute$UnboundModuleRequiresInfo.class | Bin 0 -> 2587 bytes ...ute$UnboundModuleResolutionAttribute.class | Bin 0 -> 1048 bytes ...tribute$UnboundModuleTargetAttribute.class | Bin 0 -> 1140 bytes ...ndAttribute$UnboundNestHostAttribute.class | Bin 0 -> 1110 bytes ...ttribute$UnboundNestMembersAttribute.class | Bin 0 -> 1403 bytes ...$UnboundPermittedSubclassesAttribute.class | Bin 0 -> 1443 bytes ...oundAttribute$UnboundRecordAttribute.class | Bin 0 -> 1383 bytes ...Attribute$UnboundRecordComponentInfo.class | Bin 0 -> 2684 bytes ...RuntimeInvisibleAnnotationsAttribute.class | Bin 0 -> 1485 bytes ...visibleParameterAnnotationsAttribute.class | Bin 0 -> 1611 bytes ...imeInvisibleTypeAnnotationsAttribute.class | Bin 0 -> 1525 bytes ...ndRuntimeVisibleAnnotationsAttribute.class | Bin 0 -> 1471 bytes ...VisibleParameterAnnotationsAttribute.class | Bin 0 -> 1597 bytes ...ntimeVisibleTypeAnnotationsAttribute.class | Bin 0 -> 1511 bytes ...dAttribute$UnboundSignatureAttribute.class | Bin 0 -> 1102 bytes ...UnboundSourceDebugExtensionAttribute.class | Bin 0 -> 1064 bytes ...Attribute$UnboundSourceFileAttribute.class | Bin 0 -> 1109 bytes ...ndAttribute$UnboundSourceIDAttribute.class | Bin 0 -> 1105 bytes ...ribute$UnboundStackMapTableAttribute.class | Bin 0 -> 1423 bytes ...dAttribute$UnboundSyntheticAttribute.class | Bin 0 -> 864 bytes ...boundAttribute$UnboundTypeAnnotation.class | Bin 0 -> 8710 bytes .../classfile/impl/UnboundAttribute.class | Bin 0 -> 9124 bytes .../classfile/impl/UnboundAttribute.java | 937 ++++ .../jdk/internal/classfile/impl/Util$1.class | Bin 0 -> 1083 bytes .../jdk/internal/classfile/impl/Util$2.class | Bin 0 -> 1650 bytes .../jdk/internal/classfile/impl/Util.class | Bin 0 -> 13297 bytes .../std/jdk/internal/classfile/impl/Util.java | 240 + .../impl/verifier/ParserVerifier$1.class | Bin 0 -> 1177 bytes .../impl/verifier/ParserVerifier$1F.class | Bin 0 -> 1944 bytes .../impl/verifier/ParserVerifier$1M.class | Bin 0 -> 1945 bytes .../impl/verifier/ParserVerifier.class | Bin 0 -> 37876 bytes .../impl/verifier/ParserVerifier.java | 494 ++ .../impl/verifier/VerificationBytecodes.class | Bin 0 -> 12824 bytes .../impl/verifier/VerificationBytecodes.java | 384 ++ .../impl/verifier/VerificationFrame$1.class | Bin 0 -> 1456 bytes .../impl/verifier/VerificationFrame.class | Bin 0 -> 12210 bytes .../impl/verifier/VerificationFrame.java | 400 ++ .../VerificationSignature$BasicType.class | Bin 0 -> 3215 bytes .../impl/verifier/VerificationSignature.class | Bin 0 -> 6442 bytes .../impl/verifier/VerificationSignature.java | 319 ++ .../VerificationTable$StackMapReader.class | Bin 0 -> 7982 bytes .../VerificationTable$StackMapStream.class | Bin 0 -> 1292 bytes .../impl/verifier/VerificationTable.class | Bin 0 -> 4631 bytes .../impl/verifier/VerificationTable.java | 411 ++ .../impl/verifier/VerificationType$1.class | Bin 0 -> 1405 bytes .../impl/verifier/VerificationType.class | Bin 0 -> 13089 bytes .../impl/verifier/VerificationType.java | 438 ++ ...ificationWrapper$ConstantPoolWrapper.class | Bin 0 -> 2688 bytes .../VerificationWrapper$MethodWrapper.class | Bin 0 -> 6635 bytes .../impl/verifier/VerificationWrapper.class | Bin 0 -> 4228 bytes .../impl/verifier/VerificationWrapper.java | 204 + .../impl/verifier/VerifierImpl$1.class | Bin 0 -> 1393 bytes ...rifierImpl$sig_as_verification_types.class | Bin 0 -> 1282 bytes .../impl/verifier/VerifierImpl.class | Bin 0 -> 47281 bytes .../classfile/impl/verifier/VerifierImpl.java | 1843 +++++++ .../jdk/internal/constant/ConstantUtils.class | Bin 0 -> 6839 bytes .../jdk/internal/constant/ConstantUtils.java | 322 ++ .../DirectMethodHandleDescImpl$1.class | Bin 0 -> 1387 bytes .../constant/DirectMethodHandleDescImpl.class | Bin 0 -> 7349 bytes .../constant/DirectMethodHandleDescImpl.java | 205 + .../constant/MethodTypeDescImpl$1.class | Bin 0 -> 1615 bytes .../constant/MethodTypeDescImpl.class | Bin 0 -> 8414 bytes .../internal/constant/MethodTypeDescImpl.java | 266 + .../internal/constant/ModuleDescImpl.class | Bin 0 -> 1551 bytes .../jdk/internal/constant/ModuleDescImpl.java | 39 + .../internal/constant/PackageDescImpl.class | Bin 0 -> 1573 bytes .../internal/constant/PackageDescImpl.java | 39 + .../constant/PrimitiveClassDescImpl.class | Bin 0 -> 2471 bytes .../constant/PrimitiveClassDescImpl.java | 77 + .../constant/ReferenceClassDescImpl.class | Bin 0 -> 3454 bytes .../constant/ReferenceClassDescImpl.java | 144 + .../internal/event/DeserializationEvent.class | Bin 0 -> 636 bytes .../internal/event/DeserializationEvent.java | 42 + .../jdk/internal/event/ErrorThrownEvent.class | Bin 0 -> 793 bytes .../jdk/internal/event/ErrorThrownEvent.java | 47 + .../std/jdk/internal/event/Event.class | Bin 0 -> 774 bytes .../std/jdk/internal/event/Event.java | 96 + .../event/EventHelper$ThreadTrackHolder.class | Bin 0 -> 604 bytes .../std/jdk/internal/event/EventHelper.class | Bin 0 -> 6427 bytes .../std/jdk/internal/event/EventHelper.java | 173 + .../event/ExceptionStatisticsEvent.class | Bin 0 -> 566 bytes .../event/ExceptionStatisticsEvent.java | 47 + .../internal/event/ExceptionThrownEvent.class | Bin 0 -> 805 bytes .../internal/event/ExceptionThrownEvent.java | 47 + .../jdk/internal/event/FileForceEvent.class | Bin 0 -> 926 bytes .../jdk/internal/event/FileForceEvent.java | 110 + .../jdk/internal/event/FileReadEvent.class | Bin 0 -> 741 bytes .../std/jdk/internal/event/FileReadEvent.java | 56 + .../jdk/internal/event/FileWriteEvent.class | Bin 0 -> 712 bytes .../jdk/internal/event/FileWriteEvent.java | 55 + .../std/jdk/internal/event/JFRTracing.class | Bin 0 -> 1173 bytes .../std/jdk/internal/event/JFRTracing.java | 52 + .../internal/event/ProcessStartEvent.class | Bin 0 -> 399 bytes .../jdk/internal/event/ProcessStartEvent.java | 36 + .../SecurityPropertyModificationEvent.class | Bin 0 -> 421 bytes .../SecurityPropertyModificationEvent.java | 35 + .../event/SecurityProviderServiceEvent.class | Bin 0 -> 607 bytes .../event/SecurityProviderServiceEvent.java | 45 + .../SerializationMisdeclarationEvent.class | Bin 0 -> 937 bytes .../SerializationMisdeclarationEvent.java | 91 + .../jdk/internal/event/SocketReadEvent.class | Bin 0 -> 2096 bytes .../jdk/internal/event/SocketReadEvent.java | 149 + .../jdk/internal/event/SocketWriteEvent.class | Bin 0 -> 1966 bytes .../jdk/internal/event/SocketWriteEvent.java | 140 + .../internal/event/TLSHandshakeEvent.class | Bin 0 -> 461 bytes .../jdk/internal/event/TLSHandshakeEvent.java | 38 + .../jdk/internal/event/ThreadSleepEvent.class | Bin 0 -> 515 bytes .../jdk/internal/event/ThreadSleepEvent.java | 43 + .../jdk/internal/event/ThrowableTracer.class | Bin 0 -> 1641 bytes .../jdk/internal/event/ThrowableTracer.java | 64 + .../event/VirtualThreadEndEvent.class | Bin 0 -> 538 bytes .../internal/event/VirtualThreadEndEvent.java | 41 + .../event/VirtualThreadPinnedEvent.class | Bin 0 -> 343 bytes .../event/VirtualThreadPinnedEvent.java | 31 + .../event/VirtualThreadStartEvent.class | Bin 0 -> 544 bytes .../event/VirtualThreadStartEvent.java | 41 + .../VirtualThreadSubmitFailedEvent.class | Bin 0 -> 436 bytes .../event/VirtualThreadSubmitFailedEvent.java | 33 + .../internal/event/X509CertificateEvent.class | Bin 0 -> 718 bytes .../internal/event/X509CertificateEvent.java | 52 + .../internal/event/X509ValidationEvent.class | Bin 0 -> 418 bytes .../internal/event/X509ValidationEvent.java | 37 + ...actMemorySegmentImpl$SegmentSplitter.class | Bin 0 -> 2871 bytes .../foreign/AbstractMemorySegmentImpl.class | Bin 0 -> 35691 bytes .../foreign/AbstractMemorySegmentImpl.java | 985 ++++ .../std/jdk/internal/foreign/ArenaImpl.class | Bin 0 -> 1574 bytes .../std/jdk/internal/foreign/ArenaImpl.java | 63 + .../std/jdk/internal/foreign/CABI.class | Bin 0 -> 3118 bytes .../std/jdk/internal/foreign/CABI.java | 108 + ...ConfinedSession$ConfinedResourceList.class | Bin 0 -> 1244 bytes .../internal/foreign/ConfinedSession.class | Bin 0 -> 2401 bytes .../jdk/internal/foreign/ConfinedSession.java | 117 + .../foreign/FunctionDescriptorImpl.class | Bin 0 -> 7867 bytes .../foreign/FunctionDescriptorImpl.java | 196 + .../foreign/GlobalSession$HeapSession.class | Bin 0 -> 935 bytes .../jdk/internal/foreign/GlobalSession.class | Bin 0 -> 1402 bytes .../jdk/internal/foreign/GlobalSession.java | 101 + .../HeapMemorySegmentImpl$OfByte.class | Bin 0 -> 2180 bytes .../HeapMemorySegmentImpl$OfChar.class | Bin 0 -> 2181 bytes .../HeapMemorySegmentImpl$OfDouble.class | Bin 0 -> 2190 bytes .../HeapMemorySegmentImpl$OfFloat.class | Bin 0 -> 2184 bytes .../foreign/HeapMemorySegmentImpl$OfInt.class | Bin 0 -> 2174 bytes .../HeapMemorySegmentImpl$OfLong.class | Bin 0 -> 2180 bytes .../HeapMemorySegmentImpl$OfShort.class | Bin 0 -> 2186 bytes .../foreign/HeapMemorySegmentImpl.class | Bin 0 -> 4060 bytes .../foreign/HeapMemorySegmentImpl.java | 290 + .../internal/foreign/ImplicitSession.class | Bin 0 -> 1280 bytes .../jdk/internal/foreign/ImplicitSession.java | 67 + .../LayoutPath$DereferenceElement.class | Bin 0 -> 2159 bytes .../LayoutPath$GroupElementByIndex.class | Bin 0 -> 2517 bytes .../LayoutPath$GroupElementByName.class | Bin 0 -> 2428 bytes .../foreign/LayoutPath$SequenceElement.class | Bin 0 -> 2216 bytes .../LayoutPath$SequenceElementByIndex.class | Bin 0 -> 2538 bytes .../LayoutPath$SequenceElementByRange.class | Bin 0 -> 2800 bytes .../std/jdk/internal/foreign/LayoutPath.class | Bin 0 -> 15059 bytes .../std/jdk/internal/foreign/LayoutPath.java | 502 ++ .../foreign/MappedMemorySegmentImpl.class | Bin 0 -> 3437 bytes .../foreign/MappedMemorySegmentImpl.java | 95 + ...nImpl$ResourceList$ResourceCleanup$1.class | Bin 0 -> 855 bytes ...nImpl$ResourceList$ResourceCleanup$2.class | Bin 0 -> 983 bytes ...ionImpl$ResourceList$ResourceCleanup.class | Bin 0 -> 1111 bytes .../MemorySessionImpl$ResourceList.class | Bin 0 -> 1276 bytes .../internal/foreign/MemorySessionImpl.class | Bin 0 -> 7916 bytes .../internal/foreign/MemorySessionImpl.java | 321 ++ .../foreign/NativeMemorySegmentImpl.class | Bin 0 -> 2654 bytes .../foreign/NativeMemorySegmentImpl.java | 99 + .../internal/foreign/SegmentFactories$1.class | Bin 0 -> 1353 bytes .../internal/foreign/SegmentFactories$2.class | Bin 0 -> 1060 bytes .../internal/foreign/SegmentFactories.class | Bin 0 -> 6872 bytes .../internal/foreign/SegmentFactories.java | 215 + .../SharedSession$SharedResourceList.class | Bin 0 -> 2363 bytes .../jdk/internal/foreign/SharedSession.class | Bin 0 -> 2309 bytes .../jdk/internal/foreign/SharedSession.java | 141 + .../internal/foreign/SlicingAllocator.class | Bin 0 -> 1139 bytes .../internal/foreign/SlicingAllocator.java | 55 + .../foreign/StringSupport$CharsetKind.class | Bin 0 -> 2527 bytes .../jdk/internal/foreign/StringSupport.class | Bin 0 -> 7201 bytes .../jdk/internal/foreign/StringSupport.java | 332 ++ .../jdk/internal/foreign/SystemLookup$1.class | Bin 0 -> 900 bytes .../jdk/internal/foreign/SystemLookup$2.class | Bin 0 -> 1095 bytes .../SystemLookup$WindowsFallbackSymbols.class | Bin 0 -> 4782 bytes .../jdk/internal/foreign/SystemLookup.class | Bin 0 -> 8339 bytes .../jdk/internal/foreign/SystemLookup.java | 228 + .../foreign/Utils$1VarHandleCache.class | Bin 0 -> 797 bytes .../internal/foreign/Utils$BaseAndScale.class | Bin 0 -> 3610 bytes .../std/jdk/internal/foreign/Utils.class | Bin 0 -> 11419 bytes .../std/jdk/internal/foreign/Utils.java | 325 ++ .../internal/foreign/abi/ABIDescriptor.class | Bin 0 -> 1596 bytes .../internal/foreign/abi/ABIDescriptor.java | 79 + .../abi/AbstractLinker$LinkRequest.class | Bin 0 -> 1941 bytes .../AbstractLinker$UpcallStubFactory.class | Bin 0 -> 380 bytes .../internal/foreign/abi/AbstractLinker.class | Bin 0 -> 16908 bytes .../internal/foreign/abi/AbstractLinker.java | 282 + .../internal/foreign/abi/Architecture.class | Bin 0 -> 185 bytes .../internal/foreign/abi/Architecture.java | 30 + .../foreign/abi/Binding$Allocate.class | Bin 0 -> 3256 bytes .../foreign/abi/Binding$BoxAddress.class | Bin 0 -> 3818 bytes .../foreign/abi/Binding$BufferLoad.class | Bin 0 -> 5684 bytes .../foreign/abi/Binding$BufferStore.class | Bin 0 -> 5548 bytes .../foreign/abi/Binding$Builder.class | Bin 0 -> 6528 bytes .../internal/foreign/abi/Binding$Cast$1.class | Bin 0 -> 2035 bytes .../internal/foreign/abi/Binding$Cast.class | Bin 0 -> 5373 bytes .../internal/foreign/abi/Binding$Copy.class | Bin 0 -> 3766 bytes .../foreign/abi/Binding$Dereference.class | Bin 0 -> 517 bytes .../internal/foreign/abi/Binding$Dup.class | Bin 0 -> 2761 bytes .../internal/foreign/abi/Binding$Move.class | Bin 0 -> 523 bytes .../foreign/abi/Binding$SegmentBase.class | Bin 0 -> 3144 bytes .../foreign/abi/Binding$SegmentOffset.class | Bin 0 -> 3642 bytes .../foreign/abi/Binding$ShiftLeft.class | Bin 0 -> 3227 bytes .../foreign/abi/Binding$ShiftRight.class | Bin 0 -> 3233 bytes .../internal/foreign/abi/Binding$VMLoad.class | Bin 0 -> 3410 bytes .../foreign/abi/Binding$VMStore.class | Bin 0 -> 3606 bytes .../jdk/internal/foreign/abi/Binding.class | Bin 0 -> 8794 bytes .../std/jdk/internal/foreign/abi/Binding.java | 902 ++++ .../abi/BindingInterpreter$LoadFunc.class | Bin 0 -> 525 bytes .../abi/BindingInterpreter$StoreFunc.class | Bin 0 -> 413 bytes .../foreign/abi/BindingInterpreter.class | Bin 0 -> 2599 bytes .../foreign/abi/BindingInterpreter.java | 61 + .../foreign/abi/BindingSpecializer$1.class | Bin 0 -> 2254 bytes .../foreign/abi/BindingSpecializer.class | Bin 0 -> 37068 bytes .../foreign/abi/BindingSpecializer.java | 996 ++++ .../foreign/abi/CallingSequence.class | Bin 0 -> 5693 bytes .../internal/foreign/abi/CallingSequence.java | 220 + .../foreign/abi/CallingSequenceBuilder.class | Bin 0 -> 14989 bytes .../foreign/abi/CallingSequenceBuilder.java | 273 + .../foreign/abi/CapturableState.class | Bin 0 -> 5565 bytes .../internal/foreign/abi/CapturableState.java | 88 + .../foreign/abi/DowncallLinker$1.class | Bin 0 -> 1351 bytes .../foreign/abi/DowncallLinker$2.class | Bin 0 -> 2079 bytes .../abi/DowncallLinker$InvocationData.class | Bin 0 -> 1948 bytes .../internal/foreign/abi/DowncallLinker.class | Bin 0 -> 13694 bytes .../internal/foreign/abi/DowncallLinker.java | 223 + .../abi/LinkerOptions$CaptureCallState.class | Bin 0 -> 2176 bytes .../foreign/abi/LinkerOptions$Critical.class | Bin 0 -> 1971 bytes .../abi/LinkerOptions$FirstVariadicArg.class | Bin 0 -> 2411 bytes .../abi/LinkerOptions$LinkerOptionImpl.class | Bin 0 -> 1434 bytes .../internal/foreign/abi/LinkerOptions.class | Bin 0 -> 6498 bytes .../internal/foreign/abi/LinkerOptions.java | 162 + .../abi/NativeEntryPoint$CacheKey.class | Bin 0 -> 3118 bytes .../foreign/abi/NativeEntryPoint.class | Bin 0 -> 5313 bytes .../foreign/abi/NativeEntryPoint.java | 112 + .../internal/foreign/abi/SharedUtils$1.class | Bin 0 -> 956 bytes .../internal/foreign/abi/SharedUtils$2.class | Bin 0 -> 1465 bytes .../internal/foreign/abi/SharedUtils$3.class | Bin 0 -> 1130 bytes .../internal/foreign/abi/SharedUtils$4.class | Bin 0 -> 1257 bytes .../internal/foreign/abi/SharedUtils.class | Bin 0 -> 24194 bytes .../jdk/internal/foreign/abi/SharedUtils.java | 526 ++ .../foreign/abi/SoftReferenceCache$Node.class | Bin 0 -> 1636 bytes .../foreign/abi/SoftReferenceCache.class | Bin 0 -> 2096 bytes .../foreign/abi/SoftReferenceCache.java | 57 + .../internal/foreign/abi/StubLocations.class | Bin 0 -> 1467 bytes .../internal/foreign/abi/StubLocations.java | 36 + .../foreign/abi/UpcallLinker$CallRegs.class | Bin 0 -> 1809 bytes .../abi/UpcallLinker$InvocationData.class | Bin 0 -> 3218 bytes .../internal/foreign/abi/UpcallLinker.class | Bin 0 -> 16386 bytes .../internal/foreign/abi/UpcallLinker.java | 219 + .../internal/foreign/abi/UpcallStubs$1.class | Bin 0 -> 866 bytes .../internal/foreign/abi/UpcallStubs.class | Bin 0 -> 1907 bytes .../jdk/internal/foreign/abi/UpcallStubs.java | 64 + .../jdk/internal/foreign/abi/VMStorage.class | Bin 0 -> 2162 bytes .../jdk/internal/foreign/abi/VMStorage.java | 46 + .../aarch64/AArch64Architecture$Regs.class | Bin 0 -> 2927 bytes .../AArch64Architecture$StorageType.class | Bin 0 -> 431 bytes .../abi/aarch64/AArch64Architecture.class | Bin 0 -> 3497 bytes .../abi/aarch64/AArch64Architecture.java | 177 + .../foreign/abi/aarch64/CallArranger$1.class | Bin 0 -> 1020 bytes .../CallArranger$BindingCalculator.class | Bin 0 -> 1279 bytes .../abi/aarch64/CallArranger$Bindings.class | Bin 0 -> 1880 bytes .../CallArranger$BoxBindingCalculator.class | Bin 0 -> 5289 bytes ...nger$StorageCalculator$StructStorage.class | Bin 0 -> 2568 bytes .../CallArranger$StorageCalculator.class | Bin 0 -> 6086 bytes .../CallArranger$UnboxBindingCalculator.class | Bin 0 -> 5611 bytes .../foreign/abi/aarch64/CallArranger.class | Bin 0 -> 10034 bytes .../foreign/abi/aarch64/CallArranger.java | 523 ++ .../foreign/abi/aarch64/TypeClass.class | Bin 0 -> 5416 bytes .../foreign/abi/aarch64/TypeClass.java | 137 + .../linux/LinuxAArch64CallArranger.class | Bin 0 -> 941 bytes .../linux/LinuxAArch64CallArranger.java | 62 + .../linux/LinuxAArch64Linker$1Holder.class | Bin 0 -> 762 bytes .../aarch64/linux/LinuxAArch64Linker.class | Bin 0 -> 2439 bytes .../abi/aarch64/linux/LinuxAArch64Linker.java | 76 + .../macos/MacOsAArch64CallArranger.class | Bin 0 -> 941 bytes .../macos/MacOsAArch64CallArranger.java | 62 + .../macos/MacOsAArch64Linker$1Holder.class | Bin 0 -> 762 bytes .../aarch64/macos/MacOsAArch64Linker.class | Bin 0 -> 2439 bytes .../abi/aarch64/macos/MacOsAArch64Linker.java | 76 + .../windows/WindowsAArch64CallArranger.class | Bin 0 -> 3409 bytes .../windows/WindowsAArch64CallArranger.java | 115 + .../WindowsAArch64Linker$1Holder.class | Bin 0 -> 784 bytes .../windows/WindowsAArch64Linker.class | Bin 0 -> 2577 bytes .../aarch64/windows/WindowsAArch64Linker.java | 72 + .../foreign/abi/fallback/FFIABI.class | Bin 0 -> 1353 bytes .../internal/foreign/abi/fallback/FFIABI.java | 42 + .../foreign/abi/fallback/FFIStatus.class | Bin 0 -> 1866 bytes .../foreign/abi/fallback/FFIStatus.java | 52 + .../foreign/abi/fallback/FFIType.class | Bin 0 -> 9969 bytes .../foreign/abi/fallback/FFIType.java | 162 + .../abi/fallback/FallbackLinker$1Holder.class | Bin 0 -> 713 bytes .../abi/fallback/FallbackLinker$2Holder.class | Bin 0 -> 3445 bytes .../FallbackLinker$DowncallData.class | Bin 0 -> 2778 bytes .../fallback/FallbackLinker$UpcallData.class | Bin 0 -> 2452 bytes .../foreign/abi/fallback/FallbackLinker.class | Bin 0 -> 17622 bytes .../foreign/abi/fallback/FallbackLinker.java | 329 ++ .../foreign/abi/fallback/LibFallback$1.class | Bin 0 -> 1254 bytes .../LibFallback$NativeConstants.class | Bin 0 -> 2043 bytes .../foreign/abi/fallback/LibFallback.class | Bin 0 -> 8249 bytes .../foreign/abi/fallback/LibFallback.java | 278 + .../foreign/abi/ppc64/CallArranger$1.class | Bin 0 -> 950 bytes .../CallArranger$BindingCalculator.class | Bin 0 -> 1111 bytes .../abi/ppc64/CallArranger$Bindings.class | Bin 0 -> 1868 bytes .../CallArranger$BoxBindingCalculator.class | Bin 0 -> 6236 bytes .../abi/ppc64/CallArranger$HfaRegs.class | Bin 0 -> 1833 bytes .../CallArranger$StorageCalculator.class | Bin 0 -> 5268 bytes .../CallArranger$UnboxBindingCalculator.class | Bin 0 -> 6212 bytes .../foreign/abi/ppc64/CallArranger.class | Bin 0 -> 9351 bytes .../foreign/abi/ppc64/CallArranger.java | 521 ++ .../abi/ppc64/PPC64Architecture$Regs.class | Bin 0 -> 2912 bytes .../ppc64/PPC64Architecture$StorageType.class | Bin 0 -> 420 bytes .../foreign/abi/ppc64/PPC64Architecture.class | Bin 0 -> 3513 bytes .../foreign/abi/ppc64/PPC64Architecture.java | 180 + .../foreign/abi/ppc64/TypeClass.class | Bin 0 -> 5575 bytes .../internal/foreign/abi/ppc64/TypeClass.java | 136 + .../abi/ppc64/aix/AixCallArranger.class | Bin 0 -> 508 bytes .../abi/ppc64/aix/AixCallArranger.java | 44 + .../ppc64/aix/AixPPC64Linker$1Holder.class | Bin 0 -> 718 bytes .../abi/ppc64/aix/AixPPC64Linker.class | Bin 0 -> 3552 bytes .../foreign/abi/ppc64/aix/AixPPC64Linker.java | 90 + .../abi/ppc64/linux/ABIv1CallArranger.class | Bin 0 -> 518 bytes .../abi/ppc64/linux/ABIv1CallArranger.java | 44 + .../abi/ppc64/linux/ABIv2CallArranger.class | Bin 0 -> 518 bytes .../abi/ppc64/linux/ABIv2CallArranger.java | 44 + .../linux/LinuxPPC64Linker$1Holder.class | Bin 0 -> 740 bytes .../abi/ppc64/linux/LinuxPPC64Linker.class | Bin 0 -> 2417 bytes .../abi/ppc64/linux/LinuxPPC64Linker.java | 72 + .../linux/LinuxPPC64leLinker$1Holder.class | Bin 0 -> 752 bytes .../abi/ppc64/linux/LinuxPPC64leLinker.class | Bin 0 -> 2427 bytes .../abi/ppc64/linux/LinuxPPC64leLinker.java | 72 + .../riscv64/RISCV64Architecture$Regs.class | Bin 0 -> 3641 bytes .../RISCV64Architecture$StorageType.class | Bin 0 -> 430 bytes .../abi/riscv64/RISCV64Architecture.class | Bin 0 -> 3506 bytes .../abi/riscv64/RISCV64Architecture.java | 180 + .../linux/LinuxRISCV64CallArranger$1.class | Bin 0 -> 1161 bytes ...ISCV64CallArranger$BindingCalculator.class | Bin 0 -> 1931 bytes .../LinuxRISCV64CallArranger$Bindings.class | Bin 0 -> 2000 bytes ...V64CallArranger$BoxBindingCalculator.class | Bin 0 -> 7015 bytes ...ISCV64CallArranger$StorageCalculator.class | Bin 0 -> 4435 bytes ...4CallArranger$UnboxBindingCalculator.class | Bin 0 -> 6967 bytes .../linux/LinuxRISCV64CallArranger.class | Bin 0 -> 8838 bytes .../linux/LinuxRISCV64CallArranger.java | 481 ++ .../linux/LinuxRISCV64Linker$1Holder.class | Bin 0 -> 762 bytes .../riscv64/linux/LinuxRISCV64Linker.class | Bin 0 -> 2383 bytes .../abi/riscv64/linux/LinuxRISCV64Linker.java | 74 + .../linux/TypeClass$FieldCounter.class | Bin 0 -> 4758 bytes .../linux/TypeClass$FlattenedFieldDesc.class | Bin 0 -> 2175 bytes .../foreign/abi/riscv64/linux/TypeClass.class | Bin 0 -> 6844 bytes .../foreign/abi/riscv64/linux/TypeClass.java | 221 + .../abi/s390/S390Architecture$Regs.class | Bin 0 -> 1753 bytes .../s390/S390Architecture$StorageType.class | Bin 0 -> 415 bytes .../foreign/abi/s390/S390Architecture.class | Bin 0 -> 3504 bytes .../foreign/abi/s390/S390Architecture.java | 148 + .../s390/linux/LinuxS390CallArranger$1.class | Bin 0 -> 1065 bytes ...uxS390CallArranger$BindingCalculator.class | Bin 0 -> 1043 bytes .../LinuxS390CallArranger$Bindings.class | Bin 0 -> 1961 bytes ...390CallArranger$BoxBindingCalculator.class | Bin 0 -> 4498 bytes ...uxS390CallArranger$StorageCalculator.class | Bin 0 -> 2649 bytes ...0CallArranger$UnboxBindingCalculator.class | Bin 0 -> 4410 bytes .../s390/linux/LinuxS390CallArranger.class | Bin 0 -> 7812 bytes .../abi/s390/linux/LinuxS390CallArranger.java | 318 ++ .../s390/linux/LinuxS390Linker$1Holder.class | Bin 0 -> 729 bytes .../abi/s390/linux/LinuxS390Linker.class | Bin 0 -> 2350 bytes .../abi/s390/linux/LinuxS390Linker.java | 71 + .../foreign/abi/s390/linux/TypeClass.class | Bin 0 -> 5176 bytes .../foreign/abi/s390/linux/TypeClass.java | 123 + .../abi/x64/X86_64Architecture$Regs.class | Bin 0 -> 2665 bytes .../x64/X86_64Architecture$StorageType.class | Bin 0 -> 447 bytes .../foreign/abi/x64/X86_64Architecture.class | Bin 0 -> 4931 bytes .../foreign/abi/x64/X86_64Architecture.java | 176 + .../abi/x64/sysv/ArgumentClassImpl.class | Bin 0 -> 2303 bytes .../abi/x64/sysv/ArgumentClassImpl.java | 75 + .../foreign/abi/x64/sysv/CallArranger$1.class | Bin 0 -> 992 bytes .../sysv/CallArranger$BindingCalculator.class | Bin 0 -> 979 bytes .../abi/x64/sysv/CallArranger$Bindings.class | Bin 0 -> 2027 bytes .../CallArranger$BoxBindingCalculator.class | Bin 0 -> 4651 bytes .../sysv/CallArranger$StorageCalculator.class | Bin 0 -> 5274 bytes .../CallArranger$UnboxBindingCalculator.class | Bin 0 -> 4485 bytes .../foreign/abi/x64/sysv/CallArranger.class | Bin 0 -> 9745 bytes .../foreign/abi/x64/sysv/CallArranger.java | 354 ++ .../abi/x64/sysv/SysVx64Linker$1Holder.class | Bin 0 -> 707 bytes .../foreign/abi/x64/sysv/SysVx64Linker.class | Bin 0 -> 2321 bytes .../foreign/abi/x64/sysv/SysVx64Linker.java | 74 + .../foreign/abi/x64/sysv/TypeClass$1.class | Bin 0 -> 882 bytes .../foreign/abi/x64/sysv/TypeClass$Kind.class | Bin 0 -> 1424 bytes .../foreign/abi/x64/sysv/TypeClass.class | Bin 0 -> 11328 bytes .../foreign/abi/x64/sysv/TypeClass.java | 247 + .../abi/x64/windows/CallArranger$1.class | Bin 0 -> 1046 bytes ...ranger$1CallingSequenceBuilderHelper.class | Bin 0 -> 2965 bytes .../CallArranger$BindingCalculator.class | Bin 0 -> 508 bytes .../x64/windows/CallArranger$Bindings.class | Bin 0 -> 1904 bytes .../CallArranger$BoxBindingCalculator.class | Bin 0 -> 4204 bytes .../CallArranger$StorageCalculator.class | Bin 0 -> 1947 bytes .../CallArranger$UnboxBindingCalculator.class | Bin 0 -> 4519 bytes .../abi/x64/windows/CallArranger.class | Bin 0 -> 8095 bytes .../foreign/abi/x64/windows/CallArranger.java | 297 + .../foreign/abi/x64/windows/TypeClass.class | Bin 0 -> 3546 bytes .../foreign/abi/x64/windows/TypeClass.java | 91 + .../windows/Windowsx64Linker$1Holder.class | Bin 0 -> 740 bytes .../abi/x64/windows/Windowsx64Linker.class | Bin 0 -> 2473 bytes .../abi/x64/windows/Windowsx64Linker.java | 73 + .../layout/AbstractGroupLayout$Kind.class | Bin 0 -> 1499 bytes .../foreign/layout/AbstractGroupLayout.class | Bin 0 -> 4446 bytes .../foreign/layout/AbstractGroupLayout.java | 133 + .../layout/AbstractLayout$1Holder.class | Bin 0 -> 1676 bytes .../foreign/layout/AbstractLayout.class | Bin 0 -> 9696 bytes .../foreign/layout/AbstractLayout.java | 229 + .../foreign/layout/MemoryLayoutUtil.class | Bin 0 -> 826 bytes .../foreign/layout/MemoryLayoutUtil.java | 40 + .../foreign/layout/PaddingLayoutImpl.class | Bin 0 -> 3516 bytes .../foreign/layout/PaddingLayoutImpl.java | 74 + .../foreign/layout/SequenceLayoutImpl.class | Bin 0 -> 6923 bytes .../foreign/layout/SequenceLayoutImpl.java | 223 + .../foreign/layout/StructLayoutImpl.class | Bin 0 -> 4420 bytes .../foreign/layout/StructLayoutImpl.java | 57 + .../foreign/layout/UnionLayoutImpl.class | Bin 0 -> 3987 bytes .../foreign/layout/UnionLayoutImpl.java | 54 + ...$AbstractValueLayout$1VarHandleCache.class | Bin 0 -> 1158 bytes .../ValueLayouts$AbstractValueLayout.class | Bin 0 -> 7744 bytes .../layout/ValueLayouts$OfAddressImpl.class | Bin 0 -> 6127 bytes .../layout/ValueLayouts$OfBooleanImpl.class | Bin 0 -> 4044 bytes .../layout/ValueLayouts$OfByteImpl.class | Bin 0 -> 3982 bytes .../layout/ValueLayouts$OfCharImpl.class | Bin 0 -> 4000 bytes .../layout/ValueLayouts$OfDoubleImpl.class | Bin 0 -> 4023 bytes .../layout/ValueLayouts$OfFloatImpl.class | Bin 0 -> 4009 bytes .../layout/ValueLayouts$OfIntImpl.class | Bin 0 -> 3985 bytes .../layout/ValueLayouts$OfLongImpl.class | Bin 0 -> 3995 bytes .../layout/ValueLayouts$OfShortImpl.class | Bin 0 -> 4009 bytes .../foreign/layout/ValueLayouts.class | Bin 0 -> 3767 bytes .../internal/foreign/layout/ValueLayouts.java | 412 ++ .../std/jdk/internal/icu/impl/BMPSet.class | Bin 0 -> 6132 bytes .../std/jdk/internal/icu/impl/BMPSet.java | 527 ++ .../std/jdk/internal/icu/impl/CharTrie.class | Bin 0 -> 2255 bytes .../std/jdk/internal/icu/impl/CharTrie.java | 177 + .../icu/impl/CharacterIteratorWrapper.class | Bin 0 -> 2194 bytes .../icu/impl/CharacterIteratorWrapper.java | 147 + .../jdk/internal/icu/impl/ICUBinary$1.class | Bin 0 -> 1069 bytes .../icu/impl/ICUBinary$Authenticate.class | Bin 0 -> 278 bytes .../icu/impl/ICUBinary$IsAcceptable.class | Bin 0 -> 654 bytes .../std/jdk/internal/icu/impl/ICUBinary.class | Bin 0 -> 7632 bytes .../std/jdk/internal/icu/impl/ICUBinary.java | 324 ++ .../Norm2AllModes$ComposeNormalizer2.class | Bin 0 -> 2308 bytes .../Norm2AllModes$DecomposeNormalizer2.class | Bin 0 -> 1774 bytes .../icu/impl/Norm2AllModes$NFCSingleton.class | Bin 0 -> 734 bytes .../impl/Norm2AllModes$NFKCSingleton.class | Bin 0 -> 738 bytes .../impl/Norm2AllModes$NoopNormalizer2.class | Bin 0 -> 2316 bytes ...Norm2AllModes$Norm2AllModesSingleton.class | Bin 0 -> 1366 bytes .../Norm2AllModes$Normalizer2WithImpl.class | Bin 0 -> 2933 bytes .../jdk/internal/icu/impl/Norm2AllModes.class | Bin 0 -> 2129 bytes .../jdk/internal/icu/impl/Norm2AllModes.java | 292 + .../icu/impl/NormalizerImpl$Hangul.class | Bin 0 -> 1555 bytes .../impl/NormalizerImpl$IsAcceptable.class | Bin 0 -> 711 bytes .../icu/impl/NormalizerImpl$NextCCArgs.class | Bin 0 -> 525 bytes .../icu/impl/NormalizerImpl$PrevArgs.class | Bin 0 -> 519 bytes .../NormalizerImpl$ReorderingBuffer.class | Bin 0 -> 6071 bytes .../icu/impl/NormalizerImpl$UTF16Plus.class | Bin 0 -> 1068 bytes .../internal/icu/impl/NormalizerImpl.class | Bin 0 -> 29273 bytes .../jdk/internal/icu/impl/NormalizerImpl.java | 2193 ++++++++ .../std/jdk/internal/icu/impl/Punycode.class | Bin 0 -> 7330 bytes .../std/jdk/internal/icu/impl/Punycode.java | 513 ++ .../impl/ReplaceableUCharacterIterator.class | Bin 0 -> 2305 bytes .../impl/ReplaceableUCharacterIterator.java | 190 + .../icu/impl/StringPrepDataReader.class | Bin 0 -> 1886 bytes .../icu/impl/StringPrepDataReader.java | 128 + .../icu/impl/Trie$DataManipulate.class | Bin 0 -> 259 bytes .../impl/Trie$DefaultGetFoldingOffset.class | Bin 0 -> 617 bytes .../std/jdk/internal/icu/impl/Trie.class | Bin 0 -> 3338 bytes .../std/jdk/internal/icu/impl/Trie.java | 367 ++ .../std/jdk/internal/icu/impl/Trie2$1.class | Bin 0 -> 558 bytes .../jdk/internal/icu/impl/Trie2$Range.class | Bin 0 -> 1128 bytes .../icu/impl/Trie2$Trie2Iterator.class | Bin 0 -> 2584 bytes .../icu/impl/Trie2$UTrie2Header.class | Bin 0 -> 579 bytes .../internal/icu/impl/Trie2$ValueMapper.class | Bin 0 -> 243 bytes .../std/jdk/internal/icu/impl/Trie2.class | Bin 0 -> 5212 bytes .../std/jdk/internal/icu/impl/Trie2.java | 655 +++ .../std/jdk/internal/icu/impl/Trie2_16.class | Bin 0 -> 1995 bytes .../std/jdk/internal/icu/impl/Trie2_16.java | 167 + .../icu/impl/UBiDiProps$IsAcceptable.class | Bin 0 -> 695 bytes .../jdk/internal/icu/impl/UBiDiProps.class | Bin 0 -> 4985 bytes .../std/jdk/internal/icu/impl/UBiDiProps.java | 274 + .../icu/impl/UCharacterProperty$1.class | Bin 0 -> 883 bytes .../UCharacterProperty$BiDiIntProperty.class | Bin 0 -> 654 bytes ...erProperty$CombiningClassIntProperty.class | Bin 0 -> 663 bytes .../impl/UCharacterProperty$IntProperty.class | Bin 0 -> 1087 bytes .../UCharacterProperty$IsAcceptable.class | Bin 0 -> 728 bytes ...erProperty$NormQuickCheckIntProperty.class | Bin 0 -> 811 bytes .../icu/impl/UCharacterProperty.class | Bin 0 -> 9352 bytes .../internal/icu/impl/UCharacterProperty.java | 629 +++ .../UnicodeSetStringSpan$OffsetList.class | Bin 0 -> 2739 bytes .../icu/impl/UnicodeSetStringSpan.class | Bin 0 -> 11894 bytes .../icu/impl/UnicodeSetStringSpan.java | 1175 ++++ .../std/jdk/internal/icu/impl/Utility.class | Bin 0 -> 4694 bytes .../std/jdk/internal/icu/impl/Utility.java | 276 + .../internal/icu/impl/data/icudt74b/nfc.nrm | Bin 0 -> 35392 bytes .../internal/icu/impl/data/icudt74b/nfkc.nrm | Bin 0 -> 55120 bytes .../internal/icu/impl/data/icudt74b/ubidi.icu | Bin 0 -> 27584 bytes .../icu/impl/data/icudt74b/uprops.icu | Bin 0 -> 141616 bytes .../lang/UCharacter$HangulSyllableType.class | Bin 0 -> 516 bytes .../icu/lang/UCharacter$JoiningGroup.class | Bin 0 -> 299 bytes .../icu/lang/UCharacter$NumericType.class | Bin 0 -> 405 bytes .../jdk/internal/icu/lang/UCharacter.class | Bin 0 -> 2897 bytes .../std/jdk/internal/icu/lang/UCharacter.java | 545 ++ .../icu/lang/UCharacterDirection.class | Bin 0 -> 1352 bytes .../icu/lang/UCharacterDirection.java | 113 + .../UCharacterEnums$ECharacterCategory.class | Bin 0 -> 1731 bytes .../UCharacterEnums$ECharacterDirection.class | Bin 0 -> 2642 bytes .../internal/icu/lang/UCharacterEnums.class | Bin 0 -> 631 bytes .../internal/icu/lang/UCharacterEnums.java | 588 ++ .../text/BidiBase$BidiPairedBracketType.class | Bin 0 -> 385 bytes .../icu/text/BidiBase$BracketData.class | Bin 0 -> 765 bytes .../icu/text/BidiBase$ImpTabPair.class | Bin 0 -> 631 bytes .../icu/text/BidiBase$InsertPoints.class | Bin 0 -> 598 bytes .../internal/icu/text/BidiBase$IsoRun.class | Bin 0 -> 544 bytes .../internal/icu/text/BidiBase$Isolate.class | Bin 0 -> 483 bytes .../internal/icu/text/BidiBase$LevState.class | Bin 0 -> 581 bytes .../icu/text/BidiBase$NumericShapings.class | Bin 0 -> 1182 bytes .../internal/icu/text/BidiBase$Opening.class | Bin 0 -> 510 bytes .../internal/icu/text/BidiBase$Point.class | Bin 0 -> 432 bytes .../BidiBase$TextAttributeConstants$1.class | Bin 0 -> 796 bytes .../BidiBase$TextAttributeConstants.class | Bin 0 -> 1863 bytes .../std/jdk/internal/icu/text/BidiBase.class | Bin 0 -> 49751 bytes .../std/jdk/internal/icu/text/BidiBase.java | 4783 +++++++++++++++++ .../std/jdk/internal/icu/text/BidiLine.class | Bin 0 -> 9731 bytes .../std/jdk/internal/icu/text/BidiLine.java | 836 +++ .../std/jdk/internal/icu/text/BidiRun.class | Bin 0 -> 946 bytes .../std/jdk/internal/icu/text/BidiRun.java | 124 + .../jdk/internal/icu/text/BidiWriter.class | Bin 0 -> 5478 bytes .../std/jdk/internal/icu/text/BidiWriter.java | 451 ++ .../icu/text/FilteredNormalizer2.class | Bin 0 -> 4898 bytes .../icu/text/FilteredNormalizer2.java | 266 + .../jdk/internal/icu/text/Normalizer2.class | Bin 0 -> 2354 bytes .../jdk/internal/icu/text/Normalizer2.java | 276 + .../internal/icu/text/NormalizerBase$1.class | Bin 0 -> 848 bytes .../icu/text/NormalizerBase$Mode.class | Bin 0 -> 592 bytes .../icu/text/NormalizerBase$ModeImpl.class | Bin 0 -> 571 bytes .../text/NormalizerBase$NFC32ModeImpl.class | Bin 0 -> 1085 bytes .../icu/text/NormalizerBase$NFCMode.class | Bin 0 -> 1074 bytes .../icu/text/NormalizerBase$NFCModeImpl.class | Bin 0 -> 810 bytes .../text/NormalizerBase$NFD32ModeImpl.class | Bin 0 -> 1085 bytes .../icu/text/NormalizerBase$NFDMode.class | Bin 0 -> 1074 bytes .../icu/text/NormalizerBase$NFDModeImpl.class | Bin 0 -> 810 bytes .../text/NormalizerBase$NFKC32ModeImpl.class | Bin 0 -> 1089 bytes .../icu/text/NormalizerBase$NFKCMode.class | Bin 0 -> 1081 bytes .../text/NormalizerBase$NFKCModeImpl.class | Bin 0 -> 814 bytes .../text/NormalizerBase$NFKD32ModeImpl.class | Bin 0 -> 1089 bytes .../icu/text/NormalizerBase$NFKDMode.class | Bin 0 -> 1081 bytes .../text/NormalizerBase$NFKDModeImpl.class | Bin 0 -> 814 bytes .../icu/text/NormalizerBase$NONEMode.class | Bin 0 -> 823 bytes .../icu/text/NormalizerBase$Unicode32.class | Bin 0 -> 713 bytes .../internal/icu/text/NormalizerBase.class | Bin 0 -> 9245 bytes .../jdk/internal/icu/text/NormalizerBase.java | 784 +++ .../jdk/internal/icu/text/Replaceable.class | Bin 0 -> 202 bytes .../jdk/internal/icu/text/Replaceable.java | 121 + .../internal/icu/text/ReplaceableString.class | Bin 0 -> 1071 bytes .../internal/icu/text/ReplaceableString.java | 118 + .../text/StringPrep$StringPrepTrieImpl.class | Bin 0 -> 732 bytes .../internal/icu/text/StringPrep$Values.class | Bin 0 -> 589 bytes .../jdk/internal/icu/text/StringPrep.class | Bin 0 -> 7637 bytes .../std/jdk/internal/icu/text/StringPrep.java | 485 ++ .../icu/text/UCharacterIterator.class | Bin 0 -> 2681 bytes .../internal/icu/text/UCharacterIterator.java | 317 ++ .../std/jdk/internal/icu/text/UTF16.class | Bin 0 -> 5220 bytes .../std/jdk/internal/icu/text/UTF16.java | 621 +++ .../internal/icu/text/UnicodeSet$Filter.class | Bin 0 -> 253 bytes .../icu/text/UnicodeSet$SpanCondition.class | Bin 0 -> 1367 bytes .../icu/text/UnicodeSet$VersionFilter.class | Bin 0 -> 1020 bytes .../jdk/internal/icu/text/UnicodeSet.class | Bin 0 -> 14311 bytes .../std/jdk/internal/icu/text/UnicodeSet.java | 1412 +++++ .../icu/util/CodePointMap$Range.class | Bin 0 -> 871 bytes .../icu/util/CodePointMap$RangeIterator.class | Bin 0 -> 1639 bytes .../icu/util/CodePointMap$RangeOption.class | Bin 0 -> 1388 bytes .../util/CodePointMap$StringIterator.class | Bin 0 -> 1883 bytes .../icu/util/CodePointMap$ValueFilter.class | Bin 0 -> 266 bytes .../jdk/internal/icu/util/CodePointMap.class | Bin 0 -> 2682 bytes .../jdk/internal/icu/util/CodePointMap.java | 475 ++ .../icu/util/CodePointTrie$Data.class | Bin 0 -> 722 bytes .../icu/util/CodePointTrie$Data16.class | Bin 0 -> 1334 bytes .../icu/util/CodePointTrie$Data32.class | Bin 0 -> 1329 bytes .../icu/util/CodePointTrie$Data8.class | Bin 0 -> 1332 bytes ...odePointTrie$Fast$FastStringIterator.class | Bin 0 -> 2528 bytes .../icu/util/CodePointTrie$Fast.class | Bin 0 -> 2398 bytes .../icu/util/CodePointTrie$Fast16.class | Bin 0 -> 2184 bytes .../icu/util/CodePointTrie$Fast32.class | Bin 0 -> 2189 bytes .../icu/util/CodePointTrie$Fast8.class | Bin 0 -> 2193 bytes ...ePointTrie$Small$SmallStringIterator.class | Bin 0 -> 2536 bytes .../icu/util/CodePointTrie$Small.class | Bin 0 -> 2368 bytes .../icu/util/CodePointTrie$Small16.class | Bin 0 -> 1429 bytes .../icu/util/CodePointTrie$Small32.class | Bin 0 -> 1434 bytes .../icu/util/CodePointTrie$Small8.class | Bin 0 -> 1426 bytes .../icu/util/CodePointTrie$Type.class | Bin 0 -> 1262 bytes .../icu/util/CodePointTrie$ValueWidth.class | Bin 0 -> 1362 bytes .../jdk/internal/icu/util/CodePointTrie.class | Bin 0 -> 11830 bytes .../jdk/internal/icu/util/CodePointTrie.java | 1266 +++++ .../std/jdk/internal/icu/util/OutputInt.class | Bin 0 -> 316 bytes .../std/jdk/internal/icu/util/OutputInt.java | 50 + .../jdk/internal/icu/util/VersionInfo.class | Bin 0 -> 2813 bytes .../jdk/internal/icu/util/VersionInfo.java | 203 + .../std/jdk/internal/io/JdkConsole.class | Bin 0 -> 745 bytes .../std/jdk/internal/io/JdkConsole.java | 51 + .../jdk/internal/io/JdkConsoleImpl$1.class | Bin 0 -> 954 bytes .../jdk/internal/io/JdkConsoleImpl$2.class | Bin 0 -> 755 bytes .../io/JdkConsoleImpl$LineReader.class | Bin 0 -> 2453 bytes .../std/jdk/internal/io/JdkConsoleImpl.class | Bin 0 -> 7822 bytes .../std/jdk/internal/io/JdkConsoleImpl.java | 407 ++ .../jdk/internal/io/JdkConsoleProvider.class | Bin 0 -> 316 bytes .../jdk/internal/io/JdkConsoleProvider.java | 44 + .../std/jdk/internal/javac/NoPreview.class | Bin 0 -> 461 bytes .../std/jdk/internal/javac/NoPreview.java | 49 + .../javac/ParticipatesInPreview.class | Bin 0 -> 412 bytes .../internal/javac/ParticipatesInPreview.java | 39 + .../javac/PreviewFeature$Feature.class | Bin 0 -> 2489 bytes .../internal/javac/PreviewFeature$JEP.class | Bin 0 -> 628 bytes .../jdk/internal/javac/PreviewFeature.class | Bin 0 -> 769 bytes .../jdk/internal/javac/PreviewFeature.java | 106 + .../std/jdk/internal/javac/Restricted.class | Bin 0 -> 392 bytes .../std/jdk/internal/javac/Restricted.java | 39 + .../internal/jimage/BasicImageReader$1.class | Bin 0 -> 1283 bytes .../internal/jimage/BasicImageReader$2.class | Bin 0 -> 1894 bytes .../internal/jimage/BasicImageReader.class | Bin 0 -> 14703 bytes .../jdk/internal/jimage/BasicImageReader.java | 467 ++ .../internal/jimage/ImageBufferCache$1.class | Bin 0 -> 950 bytes .../internal/jimage/ImageBufferCache$2.class | Bin 0 -> 1465 bytes .../internal/jimage/ImageBufferCache.class | Bin 0 -> 3915 bytes .../jdk/internal/jimage/ImageBufferCache.java | 158 + .../std/jdk/internal/jimage/ImageHeader.class | Bin 0 -> 3953 bytes .../std/jdk/internal/jimage/ImageHeader.java | 183 + .../jdk/internal/jimage/ImageLocation.class | Bin 0 -> 7599 bytes .../jdk/internal/jimage/ImageLocation.java | 369 ++ .../jimage/ImageReader$Directory.class | Bin 0 -> 2983 bytes .../jimage/ImageReader$LinkNode.class | Bin 0 -> 1611 bytes .../internal/jimage/ImageReader$Node.class | Bin 0 -> 4056 bytes .../jimage/ImageReader$Resource.class | Bin 0 -> 2055 bytes ...er$SharedImageReader$LocationVisitor.class | Bin 0 -> 402 bytes .../ImageReader$SharedImageReader.class | Bin 0 -> 14138 bytes .../std/jdk/internal/jimage/ImageReader.class | Bin 0 -> 6964 bytes .../std/jdk/internal/jimage/ImageReader.java | 858 +++ .../jimage/ImageReaderFactory$1.class | Bin 0 -> 1185 bytes .../internal/jimage/ImageReaderFactory.class | Bin 0 -> 2100 bytes .../internal/jimage/ImageReaderFactory.java | 90 + .../std/jdk/internal/jimage/ImageStream.class | Bin 0 -> 5042 bytes .../std/jdk/internal/jimage/ImageStream.java | 207 + .../jdk/internal/jimage/ImageStrings.class | Bin 0 -> 547 bytes .../std/jdk/internal/jimage/ImageStrings.java | 49 + .../internal/jimage/ImageStringsReader.class | Bin 0 -> 7256 bytes .../internal/jimage/ImageStringsReader.java | 387 ++ .../internal/jimage/NativeImageBuffer$1.class | Bin 0 -> 840 bytes .../internal/jimage/NativeImageBuffer.class | Bin 0 -> 669 bytes .../internal/jimage/NativeImageBuffer.java | 49 + .../jimage/decompressor/CompressIndexes.class | Bin 0 -> 2550 bytes .../jimage/decompressor/CompressIndexes.java | 136 + .../CompressedResourceHeader.class | Bin 0 -> 2656 bytes .../CompressedResourceHeader.java | 124 + .../jimage/decompressor/Decompressor.class | Bin 0 -> 2886 bytes .../jimage/decompressor/Decompressor.java | 93 + ...ResourceDecompressor$StringsProvider.class | Bin 0 -> 341 bytes .../decompressor/ResourceDecompressor.class | Bin 0 -> 494 bytes .../decompressor/ResourceDecompressor.java | 59 + .../ResourceDecompressorFactory.class | Bin 0 -> 693 bytes .../ResourceDecompressorFactory.java | 62 + .../ResourceDecompressorRepository.class | Bin 0 -> 1735 bytes .../ResourceDecompressorRepository.java | 74 + .../SignatureParser$ParseResult.class | Bin 0 -> 672 bytes .../jimage/decompressor/SignatureParser.class | Bin 0 -> 2638 bytes .../jimage/decompressor/SignatureParser.java | 129 + .../StringSharingDecompressor.class | Bin 0 -> 6780 bytes .../StringSharingDecompressor.java | 237 + .../StringSharingDecompressorFactory.class | Bin 0 -> 801 bytes .../StringSharingDecompressorFactory.java | 51 + .../jimage/decompressor/ZipDecompressor.class | Bin 0 -> 1829 bytes .../jimage/decompressor/ZipDecompressor.java | 76 + .../decompressor/ZipDecompressorFactory.class | Bin 0 -> 754 bytes .../decompressor/ZipDecompressorFactory.java | 50 + .../jdk/internal/jmod/JmodFile$Entry.class | Bin 0 -> 3403 bytes .../jdk/internal/jmod/JmodFile$Section.class | Bin 0 -> 1812 bytes .../std/jdk/internal/jmod/JmodFile.class | Bin 0 -> 4612 bytes .../std/jdk/internal/jmod/JmodFile.java | 240 + .../jrtfs/ExplodedImage$PathNode.class | Bin 0 -> 4932 bytes .../jdk/internal/jrtfs/ExplodedImage.class | Bin 0 -> 9393 bytes .../std/jdk/internal/jrtfs/ExplodedImage.java | 308 ++ .../internal/jrtfs/JrtDirectoryStream$1.class | Bin 0 -> 1394 bytes .../internal/jrtfs/JrtDirectoryStream.class | Bin 0 -> 2361 bytes .../internal/jrtfs/JrtDirectoryStream.java | 100 + .../jrtfs/JrtFileAttributeView$AttrID.class | Bin 0 -> 1857 bytes .../internal/jrtfs/JrtFileAttributeView.class | Bin 0 -> 6140 bytes .../internal/jrtfs/JrtFileAttributeView.java | 198 + .../internal/jrtfs/JrtFileAttributes.class | Bin 0 -> 3347 bytes .../jdk/internal/jrtfs/JrtFileAttributes.java | 141 + .../std/jdk/internal/jrtfs/JrtFileStore.class | Bin 0 -> 2816 bytes .../std/jdk/internal/jrtfs/JrtFileStore.java | 104 + .../jdk/internal/jrtfs/JrtFileSystem$1.class | Bin 0 -> 2060 bytes .../jdk/internal/jrtfs/JrtFileSystem.class | Bin 0 -> 16620 bytes .../std/jdk/internal/jrtfs/JrtFileSystem.java | 491 ++ .../jrtfs/JrtFileSystemProvider$1.class | Bin 0 -> 1033 bytes .../JrtFileSystemProvider$JrtFsLoader.class | Bin 0 -> 1574 bytes .../jrtfs/JrtFileSystemProvider.class | Bin 0 -> 13539 bytes .../internal/jrtfs/JrtFileSystemProvider.java | 358 ++ .../std/jdk/internal/jrtfs/JrtPath$1.class | Bin 0 -> 1391 bytes .../std/jdk/internal/jrtfs/JrtPath$2.class | Bin 0 -> 737 bytes .../std/jdk/internal/jrtfs/JrtPath.class | Bin 0 -> 26375 bytes .../std/jdk/internal/jrtfs/JrtPath.java | 949 ++++ .../std/jdk/internal/jrtfs/JrtUtils.class | Bin 0 -> 2803 bytes .../std/jdk/internal/jrtfs/JrtUtils.java | 194 + .../jdk/internal/jrtfs/SystemImage$1.class | Bin 0 -> 1176 bytes .../jdk/internal/jrtfs/SystemImage$2.class | Bin 0 -> 993 bytes .../std/jdk/internal/jrtfs/SystemImage.class | Bin 0 -> 4561 bytes .../std/jdk/internal/jrtfs/SystemImage.java | 131 + ...emoizer$RecursiveInvocationException.class | Bin 0 -> 751 bytes .../AbstractClassLoaderValue$Memoizer.class | Bin 0 -> 2558 bytes .../loader/AbstractClassLoaderValue$Sub.class | Bin 0 -> 2421 bytes .../loader/AbstractClassLoaderValue.class | Bin 0 -> 5623 bytes .../loader/AbstractClassLoaderValue.java | 434 ++ .../loader/ArchivedClassLoaders.class | Bin 0 -> 2011 bytes .../internal/loader/ArchivedClassLoaders.java | 96 + .../jdk/internal/loader/BootLoader$1.class | Bin 0 -> 1018 bytes .../loader/BootLoader$PackageHelper$1.class | Bin 0 -> 1461 bytes .../loader/BootLoader$PackageHelper$2.class | Bin 0 -> 2028 bytes .../loader/BootLoader$PackageHelper.class | Bin 0 -> 4163 bytes .../std/jdk/internal/loader/BootLoader.class | Bin 0 -> 6355 bytes .../std/jdk/internal/loader/BootLoader.java | 348 ++ .../loader/BuiltinClassLoader$1.class | Bin 0 -> 1876 bytes .../loader/BuiltinClassLoader$2.class | Bin 0 -> 2474 bytes .../loader/BuiltinClassLoader$3.class | Bin 0 -> 1609 bytes .../loader/BuiltinClassLoader$4.class | Bin 0 -> 1627 bytes .../loader/BuiltinClassLoader$5.class | Bin 0 -> 1484 bytes .../BuiltinClassLoader$LoadedModule.class | Bin 0 -> 2191 bytes .../BuiltinClassLoader$NullModuleReader.class | Bin 0 -> 1153 bytes .../internal/loader/BuiltinClassLoader.class | Bin 0 -> 22077 bytes .../internal/loader/BuiltinClassLoader.java | 1088 ++++ .../internal/loader/ClassLoaderHelper.class | Bin 0 -> 2162 bytes .../internal/loader/ClassLoaderHelper.java | 90 + .../internal/loader/ClassLoaderValue.class | Bin 0 -> 1373 bytes .../jdk/internal/loader/ClassLoaderValue.java | 102 + .../loader/ClassLoaders$AppClassLoader.class | Bin 0 -> 2680 bytes .../loader/ClassLoaders$BootClassLoader.class | Bin 0 -> 1074 bytes .../ClassLoaders$PlatformClassLoader.class | Bin 0 -> 1008 bytes .../jdk/internal/loader/ClassLoaders.class | Bin 0 -> 3947 bytes .../std/jdk/internal/loader/ClassLoaders.java | 239 + .../jdk/internal/loader/FileURLMapper.class | Bin 0 -> 1161 bytes .../jdk/internal/loader/FileURLMapper.java | 81 + .../std/jdk/internal/loader/Loader$1.class | Bin 0 -> 1816 bytes .../std/jdk/internal/loader/Loader$2.class | Bin 0 -> 1172 bytes .../std/jdk/internal/loader/Loader$3.class | Bin 0 -> 1493 bytes .../internal/loader/Loader$LoadedModule.class | Bin 0 -> 1713 bytes .../loader/Loader$NullModuleReader.class | Bin 0 -> 1105 bytes .../std/jdk/internal/loader/Loader.class | Bin 0 -> 20237 bytes .../std/jdk/internal/loader/Loader.java | 736 +++ .../std/jdk/internal/loader/LoaderPool.class | Bin 0 -> 3506 bytes .../std/jdk/internal/loader/LoaderPool.java | 85 + .../internal/loader/NativeLibraries$1.class | Bin 0 -> 1300 bytes .../internal/loader/NativeLibraries$2.class | Bin 0 -> 1366 bytes .../internal/loader/NativeLibraries$3.class | Bin 0 -> 1415 bytes .../loader/NativeLibraries$CountedLock.class | Bin 0 -> 918 bytes .../loader/NativeLibraries$LibraryPaths.class | Bin 0 -> 824 bytes ...tiveLibraries$NativeLibraryContext$1.class | Bin 0 -> 1356 bytes ...NativeLibraries$NativeLibraryContext.class | Bin 0 -> 2271 bytes .../NativeLibraries$NativeLibraryImpl$1.class | Bin 0 -> 1331 bytes .../NativeLibraries$NativeLibraryImpl.class | Bin 0 -> 2444 bytes .../loader/NativeLibraries$Unloader.class | Bin 0 -> 2088 bytes .../jdk/internal/loader/NativeLibraries.class | Bin 0 -> 8861 bytes .../jdk/internal/loader/NativeLibraries.java | 551 ++ .../jdk/internal/loader/NativeLibrary.class | Bin 0 -> 916 bytes .../jdk/internal/loader/NativeLibrary.java | 61 + .../loader/RawNativeLibraries$1.class | Bin 0 -> 1325 bytes ...NativeLibraries$RawNativeLibraryImpl.class | Bin 0 -> 1444 bytes .../internal/loader/RawNativeLibraries.class | Bin 0 -> 3516 bytes .../internal/loader/RawNativeLibraries.java | 194 + .../std/jdk/internal/loader/Resource.class | Bin 0 -> 2849 bytes .../std/jdk/internal/loader/Resource.java | 198 + .../jdk/internal/loader/URLClassPath$1.class | Bin 0 -> 1782 bytes .../jdk/internal/loader/URLClassPath$2.class | Bin 0 -> 1844 bytes .../jdk/internal/loader/URLClassPath$3.class | Bin 0 -> 2308 bytes .../loader/URLClassPath$FileLoader$1.class | Bin 0 -> 1634 bytes .../loader/URLClassPath$FileLoader.class | Bin 0 -> 2524 bytes .../loader/URLClassPath$JarLoader$1.class | Bin 0 -> 1763 bytes .../loader/URLClassPath$JarLoader$2.class | Bin 0 -> 2977 bytes .../loader/URLClassPath$JarLoader.class | Bin 0 -> 9451 bytes .../loader/URLClassPath$Loader$1.class | Bin 0 -> 1563 bytes .../internal/loader/URLClassPath$Loader.class | Bin 0 -> 3196 bytes .../jdk/internal/loader/URLClassPath.class | Bin 0 -> 12099 bytes .../std/jdk/internal/loader/URLClassPath.java | 1092 ++++ .../logger/AbstractLoggerWrapper.class | Bin 0 -> 12162 bytes .../logger/AbstractLoggerWrapper.java | 380 ++ ...BootstrapLogger$BootstrapExecutors$1.class | Bin 0 -> 1900 bytes ...Executors$BootstrapMessageLoggerTask.class | Bin 0 -> 1035 bytes .../BootstrapLogger$BootstrapExecutors.class | Bin 0 -> 5054 bytes .../BootstrapLogger$DetectBackend$1.class | Bin 0 -> 2274 bytes .../BootstrapLogger$DetectBackend.class | Bin 0 -> 873 bytes .../logger/BootstrapLogger$LogEvent.class | Bin 0 -> 14099 bytes .../BootstrapLogger$LoggingBackend.class | Bin 0 -> 1564 bytes .../BootstrapLogger$RedirectedLoggers.class | Bin 0 -> 3795 bytes .../jdk/internal/logger/BootstrapLogger.class | Bin 0 -> 16664 bytes .../jdk/internal/logger/BootstrapLogger.java | 1105 ++++ .../logger/DefaultLoggerFinder$1.class | Bin 0 -> 1124 bytes .../DefaultLoggerFinder$SharedLoggers.class | Bin 0 -> 2532 bytes .../internal/logger/DefaultLoggerFinder.class | Bin 0 -> 3312 bytes .../internal/logger/DefaultLoggerFinder.java | 191 + .../jdk/internal/logger/LazyLoggers$1.class | Bin 0 -> 1119 bytes .../logger/LazyLoggers$JdkLazyLogger.class | Bin 0 -> 1381 bytes .../LazyLoggers$LazyLoggerAccessor.class | Bin 0 -> 7062 bytes .../LazyLoggers$LazyLoggerFactories.class | Bin 0 -> 1461 bytes .../LazyLoggers$LazyLoggerWrapper.class | Bin 0 -> 1713 bytes .../logger/LazyLoggers$LoggerAccessor.class | Bin 0 -> 567 bytes .../std/jdk/internal/logger/LazyLoggers.class | Bin 0 -> 4666 bytes .../std/jdk/internal/logger/LazyLoggers.java | 469 ++ .../logger/LocalizedLoggerWrapper.class | Bin 0 -> 5445 bytes .../logger/LocalizedLoggerWrapper.java | 155 + .../LoggerFinderLoader$ErrorPolicy.class | Bin 0 -> 1428 bytes ...FinderLoader$TemporaryLoggerFinder$1.class | Bin 0 -> 738 bytes ...erFinderLoader$TemporaryLoggerFinder.class | Bin 0 -> 1740 bytes .../internal/logger/LoggerFinderLoader.class | Bin 0 -> 7519 bytes .../internal/logger/LoggerFinderLoader.java | 267 + .../jdk/internal/logger/LoggerWrapper.class | Bin 0 -> 7179 bytes .../jdk/internal/logger/LoggerWrapper.java | 65 + .../SimpleConsoleLogger$CallerFinder$1.class | Bin 0 -> 1111 bytes .../SimpleConsoleLogger$CallerFinder.class | Bin 0 -> 3257 bytes .../SimpleConsoleLogger$Formatting.class | Bin 0 -> 4203 bytes .../internal/logger/SimpleConsoleLogger.class | Bin 0 -> 12835 bytes .../internal/logger/SimpleConsoleLogger.java | 557 ++ .../jdk/internal/logger/SurrogateLogger.class | Bin 0 -> 2056 bytes .../jdk/internal/logger/SurrogateLogger.java | 72 + .../std/jdk/internal/logger/package-info.java | 68 + .../std/jdk/internal/math/DoubleConsts.class | Bin 0 -> 670 bytes .../std/jdk/internal/math/DoubleConsts.java | 95 + .../jdk/internal/math/DoubleToDecimal.class | Bin 0 -> 7933 bytes .../jdk/internal/math/DoubleToDecimal.java | 559 ++ .../std/jdk/internal/math/FDBigInteger.class | Bin 0 -> 16884 bytes .../std/jdk/internal/math/FDBigInteger.java | 1521 ++++++ .../std/jdk/internal/math/FloatConsts.class | Bin 0 -> 646 bytes .../std/jdk/internal/math/FloatConsts.java | 95 + .../jdk/internal/math/FloatToDecimal.class | Bin 0 -> 6828 bytes .../std/jdk/internal/math/FloatToDecimal.java | 502 ++ .../jdk/internal/math/FloatingDecimal$1.class | Bin 0 -> 862 bytes .../FloatingDecimal$ASCIIToBinaryBuffer.class | Bin 0 -> 8383 bytes ...oatingDecimal$ASCIIToBinaryConverter.class | Bin 0 -> 321 bytes .../FloatingDecimal$BinaryToASCIIBuffer.class | Bin 0 -> 10748 bytes ...oatingDecimal$BinaryToASCIIConverter.class | Bin 0 -> 534 bytes ...cimal$ExceptionalBinaryToASCIIBuffer.class | Bin 0 -> 2228 bytes .../FloatingDecimal$HexFloatPattern.class | Bin 0 -> 753 bytes ...gDecimal$PreparedASCIIToBinaryBuffer.class | Bin 0 -> 856 bytes .../jdk/internal/math/FloatingDecimal.class | Bin 0 -> 13417 bytes .../jdk/internal/math/FloatingDecimal.java | 2551 +++++++++ .../internal/math/FormattedFPDecimal.class | Bin 0 -> 4605 bytes .../jdk/internal/math/FormattedFPDecimal.java | 320 ++ .../std/jdk/internal/math/MathUtils.class | Bin 0 -> 22080 bytes .../std/jdk/internal/math/MathUtils.java | 813 +++ .../std/jdk/internal/misc/Blocker.class | Bin 0 -> 1422 bytes .../std/jdk/internal/misc/Blocker.java | 94 + .../test_data/std/jdk/internal/misc/CDS.class | Bin 0 -> 11828 bytes .../test_data/std/jdk/internal/misc/CDS.java | 339 ++ .../jdk/internal/misc/CarrierThread$1.class | Bin 0 -> 1267 bytes .../misc/CarrierThread$ForkJoinPools.class | Bin 0 -> 1115 bytes .../std/jdk/internal/misc/CarrierThread.class | Bin 0 -> 4253 bytes .../std/jdk/internal/misc/CarrierThread.java | 169 + .../internal/misc/CarrierThreadLocal.class | Bin 0 -> 1626 bytes .../jdk/internal/misc/CarrierThreadLocal.java | 57 + .../jdk/internal/misc/ExtendedMapMode.class | Bin 0 -> 2777 bytes .../jdk/internal/misc/ExtendedMapMode.java | 68 + .../jdk/internal/misc/FileSystemOption.class | Bin 0 -> 2567 bytes .../jdk/internal/misc/FileSystemOption.java | 90 + .../jdk/internal/misc/InnocuousThread$1.class | Bin 0 -> 1252 bytes .../jdk/internal/misc/InnocuousThread$2.class | Bin 0 -> 1160 bytes .../jdk/internal/misc/InnocuousThread$3.class | Bin 0 -> 1161 bytes .../jdk/internal/misc/InnocuousThread$4.class | Bin 0 -> 968 bytes .../jdk/internal/misc/InnocuousThread.class | Bin 0 -> 5881 bytes .../jdk/internal/misc/InnocuousThread.java | 235 + .../std/jdk/internal/misc/InternalLock.class | Bin 0 -> 1516 bytes .../std/jdk/internal/misc/InternalLock.java | 84 + .../std/jdk/internal/misc/MethodFinder.class | Bin 0 -> 1766 bytes .../std/jdk/internal/misc/MethodFinder.java | 108 + .../std/jdk/internal/misc/OSEnvironment.class | Bin 0 -> 352 bytes .../std/jdk/internal/misc/OSEnvironment.java | 38 + .../jdk/internal/misc/PreviewFeatures.class | Bin 0 -> 757 bytes .../jdk/internal/misc/PreviewFeatures.java | 55 + .../misc/ScopedMemoryAccess$Scoped.class | Bin 0 -> 534 bytes ...ScopedMemoryAccess$ScopedAccessError.class | Bin 0 -> 1160 bytes .../internal/misc/ScopedMemoryAccess.class | Bin 0 -> 98363 bytes .../jdk/internal/misc/ScopedMemoryAccess.java | 4138 ++++++++++++++ .../std/jdk/internal/misc/Signal$1.class | Bin 0 -> 849 bytes .../jdk/internal/misc/Signal$Handler.class | Bin 0 -> 552 bytes .../internal/misc/Signal$NativeHandler.class | Bin 0 -> 1155 bytes .../std/jdk/internal/misc/Signal.class | Bin 0 -> 3919 bytes .../std/jdk/internal/misc/Signal.java | 287 + .../misc/TerminatingThreadLocal$1.class | Bin 0 -> 1029 bytes .../misc/TerminatingThreadLocal.class | Bin 0 -> 2247 bytes .../internal/misc/TerminatingThreadLocal.java | 106 + .../ThreadFlock$ThreadContainerImpl.class | Bin 0 -> 3924 bytes .../std/jdk/internal/misc/ThreadFlock.class | Bin 0 -> 8302 bytes .../std/jdk/internal/misc/ThreadFlock.java | 591 ++ .../misc/ThreadTracker$ThreadRef.class | Bin 0 -> 1573 bytes .../std/jdk/internal/misc/ThreadTracker.class | Bin 0 -> 1971 bytes .../std/jdk/internal/misc/ThreadTracker.java | 93 + .../std/jdk/internal/misc/Unsafe.class | Bin 0 -> 59478 bytes .../std/jdk/internal/misc/Unsafe.java | 3865 +++++++++++++ .../jdk/internal/misc/UnsafeConstants.class | Bin 0 -> 583 bytes .../jdk/internal/misc/UnsafeConstants.java | 122 + .../std/jdk/internal/misc/VM$BufferPool.class | Bin 0 -> 320 bytes .../internal/misc/VM$BufferPoolsHolder.class | Bin 0 -> 1348 bytes .../test_data/std/jdk/internal/misc/VM.class | Bin 0 -> 7547 bytes tests/test_data/std/jdk/internal/misc/VM.java | 507 ++ .../jdk/internal/misc/VirtualThreads.class | Bin 0 -> 1458 bytes .../std/jdk/internal/misc/VirtualThreads.java | 95 + .../internal/module/ArchivedBootLayer.class | Bin 0 -> 886 bytes .../internal/module/ArchivedBootLayer.java | 56 + .../internal/module/ArchivedModuleGraph.class | Bin 0 -> 2357 bytes .../internal/module/ArchivedModuleGraph.java | 113 + .../std/jdk/internal/module/Builder.class | Bin 0 -> 8392 bytes .../std/jdk/internal/module/Builder.java | 282 + .../std/jdk/internal/module/Checks.class | Bin 0 -> 4401 bytes .../std/jdk/internal/module/Checks.java | 247 + .../internal/module/ClassFileConstants.class | Bin 0 -> 1132 bytes .../internal/module/ClassFileConstants.java | 60 + .../jdk/internal/module/DefaultRoots.class | Bin 0 -> 3677 bytes .../std/jdk/internal/module/DefaultRoots.java | 81 + .../module/ExplodedSystemModules.class | Bin 0 -> 1251 bytes .../module/ExplodedSystemModules.java | 71 + .../internal/module/ModuleBootstrap$1.class | Bin 0 -> 1353 bytes .../module/ModuleBootstrap$Counters.class | Bin 0 -> 2847 bytes .../ModuleBootstrap$SafeModuleFinder.class | Bin 0 -> 2917 bytes .../jdk/internal/module/ModuleBootstrap.class | Bin 0 -> 27634 bytes .../jdk/internal/module/ModuleBootstrap.java | 1088 ++++ .../module/ModuleHashes$Builder.class | Bin 0 -> 1359 bytes .../module/ModuleHashes$HashSupplier.class | Bin 0 -> 285 bytes .../jdk/internal/module/ModuleHashes.class | Bin 0 -> 8192 bytes .../std/jdk/internal/module/ModuleHashes.java | 254 + .../ModuleHashesBuilder$Graph$Builder.class | Bin 0 -> 2536 bytes .../module/ModuleHashesBuilder$Graph.class | Bin 0 -> 7303 bytes .../ModuleHashesBuilder$TopoSorter.class | Bin 0 -> 4148 bytes .../internal/module/ModuleHashesBuilder.class | Bin 0 -> 6602 bytes .../internal/module/ModuleHashesBuilder.java | 287 + .../module/ModuleInfo$Attributes.class | Bin 0 -> 1332 bytes .../ModuleInfo$ConstantPool$Entry.class | Bin 0 -> 557 bytes .../ModuleInfo$ConstantPool$Index2Entry.class | Bin 0 -> 693 bytes .../ModuleInfo$ConstantPool$IndexEntry.class | Bin 0 -> 642 bytes .../ModuleInfo$ConstantPool$ValueEntry.class | Bin 0 -> 680 bytes .../module/ModuleInfo$ConstantPool.class | Bin 0 -> 6614 bytes .../module/ModuleInfo$CountingDataInput.class | Bin 0 -> 2930 bytes .../module/ModuleInfo$DataInputWrapper.class | Bin 0 -> 3381 bytes .../std/jdk/internal/module/ModuleInfo.class | Bin 0 -> 19332 bytes .../std/jdk/internal/module/ModuleInfo.java | 1227 +++++ .../internal/module/ModuleInfoExtender.class | Bin 0 -> 8193 bytes .../internal/module/ModuleInfoExtender.java | 212 + .../module/ModuleLoaderMap$Mapper.class | Bin 0 -> 2695 bytes .../module/ModuleLoaderMap$Modules.class | Bin 0 -> 2329 bytes .../jdk/internal/module/ModuleLoaderMap.class | Bin 0 -> 1525 bytes .../jdk/internal/module/ModuleLoaderMap.java | 239 + ...dulePatcher$ExplodedResourceFinder$1.class | Bin 0 -> 2420 bytes ...ModulePatcher$ExplodedResourceFinder.class | Bin 0 -> 3239 bytes .../ModulePatcher$JarResourceFinder$1.class | Bin 0 -> 2699 bytes .../ModulePatcher$JarResourceFinder.class | Bin 0 -> 2569 bytes .../ModulePatcher$PatchedModuleReader$1.class | Bin 0 -> 2139 bytes .../ModulePatcher$PatchedModuleReader.class | Bin 0 -> 6688 bytes .../module/ModulePatcher$ResourceFinder.class | Bin 0 -> 514 bytes .../jdk/internal/module/ModulePatcher.class | Bin 0 -> 13680 bytes .../jdk/internal/module/ModulePatcher.java | 604 +++ .../internal/module/ModulePath$Patterns.class | Bin 0 -> 878 bytes .../std/jdk/internal/module/ModulePath.class | Bin 0 -> 25430 bytes .../std/jdk/internal/module/ModulePath.java | 789 +++ .../internal/module/ModulePathValidator.class | Bin 0 -> 9040 bytes .../internal/module/ModulePathValidator.java | 254 + .../ModuleReferenceImpl$CachedHash.class | Bin 0 -> 1735 bytes .../internal/module/ModuleReferenceImpl.class | Bin 0 -> 4727 bytes .../internal/module/ModuleReferenceImpl.java | 200 + ...oduleReferences$ExplodedModuleReader.class | Bin 0 -> 4407 bytes .../ModuleReferences$JModModuleReader.class | Bin 0 -> 4639 bytes .../ModuleReferences$JarModuleReader.class | Bin 0 -> 4377 bytes ...duleReferences$SafeCloseModuleReader.class | Bin 0 -> 2375 bytes .../internal/module/ModuleReferences.class | Bin 0 -> 5303 bytes .../jdk/internal/module/ModuleReferences.java | 430 ++ .../internal/module/ModuleResolution.class | Bin 0 -> 2476 bytes .../jdk/internal/module/ModuleResolution.java | 113 + .../jdk/internal/module/ModuleTarget.class | Bin 0 -> 488 bytes .../std/jdk/internal/module/ModuleTarget.java | 45 + .../std/jdk/internal/module/Modules.class | Bin 0 -> 12016 bytes .../std/jdk/internal/module/Modules.java | 301 ++ .../std/jdk/internal/module/Resources.class | Bin 0 -> 3762 bytes .../std/jdk/internal/module/Resources.java | 177 + .../ServicesCatalog$ServiceProvider.class | Bin 0 -> 1260 bytes .../jdk/internal/module/ServicesCatalog.class | Bin 0 -> 4747 bytes .../jdk/internal/module/ServicesCatalog.java | 186 + .../module/SystemModuleFinders$1.class | Bin 0 -> 2504 bytes .../module/SystemModuleFinders$2.class | Bin 0 -> 1403 bytes .../module/SystemModuleFinders$3.class | Bin 0 -> 875 bytes ...duleFinders$ModuleContentSpliterator.class | Bin 0 -> 3758 bytes .../SystemModuleFinders$SystemImage.class | Bin 0 -> 734 bytes ...stemModuleFinders$SystemModuleFinder.class | Bin 0 -> 2454 bytes ...stemModuleFinders$SystemModuleReader.class | Bin 0 -> 5803 bytes .../internal/module/SystemModuleFinders.class | Bin 0 -> 11983 bytes .../internal/module/SystemModuleFinders.java | 595 ++ .../jdk/internal/module/SystemModules$0.class | Bin 0 -> 69880 bytes .../jdk/internal/module/SystemModules$1.class | Bin 0 -> 69454 bytes .../jdk/internal/module/SystemModules$2.class | Bin 0 -> 69454 bytes .../jdk/internal/module/SystemModules$3.class | Bin 0 -> 69454 bytes .../jdk/internal/module/SystemModules$4.class | Bin 0 -> 69454 bytes .../jdk/internal/module/SystemModules$5.class | Bin 0 -> 69454 bytes .../internal/module/SystemModules$all.class | Bin 0 -> 80512 bytes .../module/SystemModules$default.class | Bin 0 -> 73990 bytes .../jdk/internal/module/SystemModules.class | Bin 0 -> 595 bytes .../jdk/internal/module/SystemModules.java | 86 + .../internal/module/SystemModulesMap.class | Bin 0 -> 944 bytes .../jdk/internal/module/SystemModulesMap.java | 68 + .../org/objectweb/asm/AnnotationVisitor.class | Bin 0 -> 2177 bytes .../org/objectweb/asm/AnnotationVisitor.java | 196 + .../org/objectweb/asm/AnnotationWriter.class | Bin 0 -> 9750 bytes .../org/objectweb/asm/AnnotationWriter.java | 585 ++ .../org/objectweb/asm/Attribute$Set.class | Bin 0 -> 1679 bytes .../org/objectweb/asm/Attribute.class | Bin 0 -> 4607 bytes .../internal/org/objectweb/asm/Attribute.java | 424 ++ .../org/objectweb/asm/ByteVector.class | Bin 0 -> 5036 bytes .../org/objectweb/asm/ByteVector.java | 405 ++ .../org/objectweb/asm/ClassReader.class | Bin 0 -> 50442 bytes .../org/objectweb/asm/ClassReader.java | 3900 ++++++++++++++ .../asm/ClassTooLargeException.class | Bin 0 -> 978 bytes .../objectweb/asm/ClassTooLargeException.java | 104 + .../org/objectweb/asm/ClassVisitor.class | Bin 0 -> 5148 bytes .../org/objectweb/asm/ClassVisitor.java | 426 ++ .../org/objectweb/asm/ClassWriter.class | Bin 0 -> 19225 bytes .../org/objectweb/asm/ClassWriter.java | 1113 ++++ .../org/objectweb/asm/ConstantDynamic.class | Bin 0 -> 2672 bytes .../org/objectweb/asm/ConstantDynamic.java | 210 + .../org/objectweb/asm/Constants.class | Bin 0 -> 6912 bytes .../internal/org/objectweb/asm/Constants.java | 253 + .../internal/org/objectweb/asm/Context.class | Bin 0 -> 1161 bytes .../internal/org/objectweb/asm/Context.java | 168 + .../org/objectweb/asm/CurrentFrame.class | Bin 0 -> 1073 bytes .../org/objectweb/asm/CurrentFrame.java | 87 + .../jdk/internal/org/objectweb/asm/Edge.class | Bin 0 -> 648 bytes .../jdk/internal/org/objectweb/asm/Edge.java | 123 + .../org/objectweb/asm/FieldVisitor.class | Bin 0 -> 2227 bytes .../org/objectweb/asm/FieldVisitor.java | 179 + .../org/objectweb/asm/FieldWriter.class | Bin 0 -> 5574 bytes .../org/objectweb/asm/FieldWriter.java | 316 ++ .../internal/org/objectweb/asm/Frame.class | Bin 0 -> 19293 bytes .../jdk/internal/org/objectweb/asm/Frame.java | 1522 ++++++ .../internal/org/objectweb/asm/Handle.class | Bin 0 -> 2280 bytes .../internal/org/objectweb/asm/Handle.java | 221 + .../internal/org/objectweb/asm/Handler.class | Bin 0 -> 2598 bytes .../internal/org/objectweb/asm/Handler.java | 230 + .../internal/org/objectweb/asm/Label.class | Bin 0 -> 6620 bytes .../jdk/internal/org/objectweb/asm/Label.java | 686 +++ .../asm/MethodTooLargeException.class | Bin 0 -> 1287 bytes .../asm/MethodTooLargeException.java | 131 + .../org/objectweb/asm/MethodVisitor.class | Bin 0 -> 9035 bytes .../org/objectweb/asm/MethodVisitor.java | 827 +++ .../org/objectweb/asm/MethodWriter.class | Bin 0 -> 35956 bytes .../org/objectweb/asm/MethodWriter.java | 2426 +++++++++ .../org/objectweb/asm/ModuleVisitor.class | Bin 0 -> 2476 bytes .../org/objectweb/asm/ModuleVisitor.java | 224 + .../org/objectweb/asm/ModuleWriter.class | Bin 0 -> 4666 bytes .../org/objectweb/asm/ModuleWriter.java | 285 + .../internal/org/objectweb/asm/Opcodes.class | Bin 0 -> 7638 bytes .../internal/org/objectweb/asm/Opcodes.java | 590 ++ .../asm/RecordComponentVisitor.class | Bin 0 -> 2183 bytes .../objectweb/asm/RecordComponentVisitor.java | 181 + .../objectweb/asm/RecordComponentWriter.class | Bin 0 -> 4877 bytes .../objectweb/asm/RecordComponentWriter.java | 257 + .../internal/org/objectweb/asm/Symbol.class | Bin 0 -> 1921 bytes .../internal/org/objectweb/asm/Symbol.java | 291 + .../org/objectweb/asm/SymbolTable$Entry.class | Bin 0 -> 1406 bytes .../asm/SymbolTable$LabelEntry.class | Bin 0 -> 652 bytes .../org/objectweb/asm/SymbolTable.class | Bin 0 -> 22245 bytes .../org/objectweb/asm/SymbolTable.java | 1495 ++++++ .../jdk/internal/org/objectweb/asm/Type.class | Bin 0 -> 12281 bytes .../jdk/internal/org/objectweb/asm/Type.java | 952 ++++ .../internal/org/objectweb/asm/TypePath.class | Bin 0 -> 2853 bytes .../internal/org/objectweb/asm/TypePath.java | 232 + .../org/objectweb/asm/TypeReference.class | Bin 0 -> 4178 bytes .../org/objectweb/asm/TypeReference.java | 467 ++ .../objectweb/asm/commons/AdviceAdapter.class | Bin 0 -> 10675 bytes .../objectweb/asm/commons/AdviceAdapter.java | 702 +++ .../asm/commons/AnalyzerAdapter.class | Bin 0 -> 14861 bytes .../asm/commons/AnalyzerAdapter.java | 942 ++++ .../asm/commons/AnnotationRemapper.class | Bin 0 -> 3794 bytes .../asm/commons/AnnotationRemapper.java | 241 + .../objectweb/asm/commons/ClassRemapper.class | Bin 0 -> 9320 bytes .../objectweb/asm/commons/ClassRemapper.java | 331 ++ .../asm/commons/CodeSizeEvaluator.class | Bin 0 -> 4473 bytes .../asm/commons/CodeSizeEvaluator.java | 239 + .../objectweb/asm/commons/FieldRemapper.class | Bin 0 -> 2705 bytes .../objectweb/asm/commons/FieldRemapper.java | 146 + .../asm/commons/GeneratorAdapter.class | Bin 0 -> 21796 bytes .../asm/commons/GeneratorAdapter.java | 1401 +++++ .../asm/commons/InstructionAdapter.class | Bin 0 -> 21187 bytes .../asm/commons/InstructionAdapter.java | 1334 +++++ .../JSRInlinerAdapter$Instantiation.class | Bin 0 -> 4275 bytes .../asm/commons/JSRInlinerAdapter.class | Bin 0 -> 10976 bytes .../asm/commons/JSRInlinerAdapter.java | 604 +++ .../asm/commons/LocalVariablesSorter.class | Bin 0 -> 7033 bytes .../asm/commons/LocalVariablesSorter.java | 383 ++ .../org/objectweb/asm/commons/Method.class | Bin 0 -> 5343 bytes .../org/objectweb/asm/commons/Method.java | 294 + .../asm/commons/MethodRemapper.class | Bin 0 -> 7791 bytes .../objectweb/asm/commons/MethodRemapper.java | 321 ++ .../asm/commons/ModuleHashesAttribute.class | Bin 0 -> 3453 bytes .../asm/commons/ModuleHashesAttribute.java | 170 + .../asm/commons/ModuleRemapper.class | Bin 0 -> 2637 bytes .../objectweb/asm/commons/ModuleRemapper.java | 152 + .../commons/ModuleResolutionAttribute.class | Bin 0 -> 1892 bytes .../commons/ModuleResolutionAttribute.java | 144 + .../asm/commons/ModuleTargetAttribute.class | Bin 0 -> 1842 bytes .../asm/commons/ModuleTargetAttribute.java | 118 + .../asm/commons/RecordComponentRemapper.class | Bin 0 -> 2795 bytes .../asm/commons/RecordComponentRemapper.java | 149 + .../org/objectweb/asm/commons/Remapper.class | Bin 0 -> 7473 bytes .../org/objectweb/asm/commons/Remapper.java | 416 ++ .../commons/RemappingAnnotationAdapter.class | Bin 0 -> 2305 bytes .../commons/RemappingAnnotationAdapter.java | 116 + .../asm/commons/RemappingMethodAdapter.class | Bin 0 -> 7877 bytes .../asm/commons/RemappingMethodAdapter.java | 310 ++ .../commons/SerialVersionUIDAdder$Item.class | Bin 0 -> 1576 bytes .../asm/commons/SerialVersionUIDAdder.class | Bin 0 -> 7110 bytes .../asm/commons/SerialVersionUIDAdder.java | 524 ++ .../asm/commons/SignatureRemapper.class | Bin 0 -> 3963 bytes .../asm/commons/SignatureRemapper.java | 204 + .../asm/commons/SimpleRemapper.class | Bin 0 -> 2266 bytes .../objectweb/asm/commons/SimpleRemapper.java | 135 + .../asm/commons/StaticInitMerger.class | Bin 0 -> 2549 bytes .../asm/commons/StaticInitMerger.java | 156 + .../asm/commons/TableSwitchGenerator.class | Bin 0 -> 260 bytes .../asm/commons/TableSwitchGenerator.java | 83 + .../asm/commons/TryCatchBlockSorter$1.class | Bin 0 -> 1929 bytes .../asm/commons/TryCatchBlockSorter.class | Bin 0 -> 2226 bytes .../asm/commons/TryCatchBlockSorter.java | 157 + .../asm/signature/SignatureReader.class | Bin 0 -> 3151 bytes .../asm/signature/SignatureReader.java | 284 + .../asm/signature/SignatureVisitor.class | Bin 0 -> 2443 bytes .../asm/signature/SignatureVisitor.java | 241 + .../asm/signature/SignatureWriter.class | Bin 0 -> 3339 bytes .../asm/signature/SignatureWriter.java | 279 + .../objectweb/asm/tree/AbstractInsnNode.class | Bin 0 -> 5178 bytes .../objectweb/asm/tree/AbstractInsnNode.java | 301 ++ .../objectweb/asm/tree/AnnotationNode.class | Bin 0 -> 4544 bytes .../objectweb/asm/tree/AnnotationNode.java | 262 + .../org/objectweb/asm/tree/ClassNode.class | Bin 0 -> 9965 bytes .../org/objectweb/asm/tree/ClassNode.java | 504 ++ .../objectweb/asm/tree/FieldInsnNode.class | Bin 0 -> 1843 bytes .../org/objectweb/asm/tree/FieldInsnNode.java | 128 + .../org/objectweb/asm/tree/FieldNode.class | Bin 0 -> 4793 bytes .../org/objectweb/asm/tree/FieldNode.java | 276 + .../org/objectweb/asm/tree/FrameNode.class | Bin 0 -> 3420 bytes .../org/objectweb/asm/tree/FrameNode.java | 224 + .../org/objectweb/asm/tree/IincInsnNode.class | Bin 0 -> 1630 bytes .../org/objectweb/asm/tree/IincInsnNode.java | 106 + .../objectweb/asm/tree/InnerClassNode.class | Bin 0 -> 909 bytes .../objectweb/asm/tree/InnerClassNode.java | 123 + .../asm/tree/InsnList$InsnListIterator.class | Bin 0 -> 3168 bytes .../org/objectweb/asm/tree/InsnList.class | Bin 0 -> 6361 bytes .../org/objectweb/asm/tree/InsnList.java | 636 +++ .../org/objectweb/asm/tree/InsnNode.class | Bin 0 -> 1477 bytes .../org/objectweb/asm/tree/InsnNode.java | 105 + .../org/objectweb/asm/tree/IntInsnNode.class | Bin 0 -> 1645 bytes .../org/objectweb/asm/tree/IntInsnNode.java | 111 + .../asm/tree/InvokeDynamicInsnNode.class | Bin 0 -> 2000 bytes .../asm/tree/InvokeDynamicInsnNode.java | 124 + .../org/objectweb/asm/tree/JumpInsnNode.class | Bin 0 -> 2035 bytes .../org/objectweb/asm/tree/JumpInsnNode.java | 119 + .../org/objectweb/asm/tree/LabelNode.class | Bin 0 -> 1851 bytes .../org/objectweb/asm/tree/LabelNode.java | 111 + .../org/objectweb/asm/tree/LdcInsnNode.class | Bin 0 -> 1603 bytes .../org/objectweb/asm/tree/LdcInsnNode.java | 115 + .../objectweb/asm/tree/LineNumberNode.class | Bin 0 -> 1785 bytes .../objectweb/asm/tree/LineNumberNode.java | 106 + .../tree/LocalVariableAnnotationNode.class | Bin 0 -> 2947 bytes .../asm/tree/LocalVariableAnnotationNode.java | 171 + .../asm/tree/LocalVariableNode.class | Bin 0 -> 1440 bytes .../objectweb/asm/tree/LocalVariableNode.java | 124 + .../asm/tree/LookupSwitchInsnNode.class | Bin 0 -> 3190 bytes .../asm/tree/LookupSwitchInsnNode.java | 125 + .../objectweb/asm/tree/MethodInsnNode.class | Bin 0 -> 2250 bytes .../objectweb/asm/tree/MethodInsnNode.java | 155 + .../org/objectweb/asm/tree/MethodNode$1.class | Bin 0 -> 1008 bytes .../org/objectweb/asm/tree/MethodNode.class | Bin 0 -> 19166 bytes .../org/objectweb/asm/tree/MethodNode.java | 804 +++ .../objectweb/asm/tree/ModuleExportNode.class | Bin 0 -> 1304 bytes .../objectweb/asm/tree/ModuleExportNode.java | 115 + .../org/objectweb/asm/tree/ModuleNode.class | Bin 0 -> 5290 bytes .../org/objectweb/asm/tree/ModuleNode.java | 277 + .../objectweb/asm/tree/ModuleOpenNode.class | Bin 0 -> 1296 bytes .../objectweb/asm/tree/ModuleOpenNode.java | 114 + .../asm/tree/ModuleProvideNode.class | Bin 0 -> 1167 bytes .../objectweb/asm/tree/ModuleProvideNode.java | 101 + .../asm/tree/ModuleRequireNode.class | Bin 0 -> 847 bytes .../objectweb/asm/tree/ModuleRequireNode.java | 105 + .../asm/tree/MultiANewArrayInsnNode.class | Bin 0 -> 1727 bytes .../asm/tree/MultiANewArrayInsnNode.java | 106 + .../objectweb/asm/tree/ParameterNode.class | Bin 0 -> 766 bytes .../org/objectweb/asm/tree/ParameterNode.java | 100 + .../asm/tree/RecordComponentNode.class | Bin 0 -> 4590 bytes .../asm/tree/RecordComponentNode.java | 236 + .../asm/tree/TableSwitchInsnNode.class | Bin 0 -> 2908 bytes .../asm/tree/TableSwitchInsnNode.java | 125 + .../asm/tree/TryCatchBlockNode.class | Bin 0 -> 2826 bytes .../objectweb/asm/tree/TryCatchBlockNode.java | 159 + .../asm/tree/TypeAnnotationNode.class | Bin 0 -> 1157 bytes .../asm/tree/TypeAnnotationNode.java | 117 + .../org/objectweb/asm/tree/TypeInsnNode.class | Bin 0 -> 1691 bytes .../org/objectweb/asm/tree/TypeInsnNode.java | 117 + .../UnsupportedClassVersionException.class | Bin 0 -> 467 bytes .../UnsupportedClassVersionException.java | 72 + .../org/objectweb/asm/tree/Util.class | Bin 0 -> 5218 bytes .../internal/org/objectweb/asm/tree/Util.java | 195 + .../org/objectweb/asm/tree/VarInsnNode.class | Bin 0 -> 1652 bytes .../org/objectweb/asm/tree/VarInsnNode.java | 114 + .../asm/tree/analysis/Analyzer.class | Bin 0 -> 18120 bytes .../objectweb/asm/tree/analysis/Analyzer.java | 729 +++ .../asm/tree/analysis/AnalyzerException.class | Bin 0 -> 1893 bytes .../asm/tree/analysis/AnalyzerException.java | 121 + .../asm/tree/analysis/BasicInterpreter.class | Bin 0 -> 10383 bytes .../asm/tree/analysis/BasicInterpreter.java | 407 ++ .../asm/tree/analysis/BasicValue.class | Bin 0 -> 2128 bytes .../asm/tree/analysis/BasicValue.java | 161 + .../asm/tree/analysis/BasicVerifier.class | Bin 0 -> 11498 bytes .../asm/tree/analysis/BasicVerifier.java | 482 ++ .../objectweb/asm/tree/analysis/Frame.class | Bin 0 -> 14475 bytes .../objectweb/asm/tree/analysis/Frame.java | 784 +++ .../asm/tree/analysis/Interpreter.class | Bin 0 -> 4222 bytes .../asm/tree/analysis/Interpreter.java | 299 ++ .../asm/tree/analysis/SimpleVerifier.class | Bin 0 -> 8278 bytes .../asm/tree/analysis/SimpleVerifier.java | 413 ++ .../tree/analysis/SmallSet$IteratorImpl.class | Bin 0 -> 1484 bytes .../asm/tree/analysis/SmallSet.class | Bin 0 -> 2245 bytes .../objectweb/asm/tree/analysis/SmallSet.java | 230 + .../asm/tree/analysis/SourceInterpreter.class | Bin 0 -> 8930 bytes .../asm/tree/analysis/SourceInterpreter.java | 252 + .../asm/tree/analysis/SourceValue.class | Bin 0 -> 1650 bytes .../asm/tree/analysis/SourceValue.java | 151 + .../asm/tree/analysis/Subroutine.class | Bin 0 -> 1782 bytes .../asm/tree/analysis/Subroutine.java | 138 + .../objectweb/asm/tree/analysis/Value.class | Bin 0 -> 160 bytes .../objectweb/asm/tree/analysis/Value.java | 76 + .../org/objectweb/asm/util/ASMifier.class | Bin 0 -> 38720 bytes .../org/objectweb/asm/util/ASMifier.java | 1647 ++++++ .../objectweb/asm/util/ASMifierSupport.class | Bin 0 -> 370 bytes .../objectweb/asm/util/ASMifierSupport.java | 83 + .../asm/util/CheckAnnotationAdapter.class | Bin 0 -> 3097 bytes .../asm/util/CheckAnnotationAdapter.java | 167 + .../asm/util/CheckClassAdapter$1.class | Bin 0 -> 749 bytes .../asm/util/CheckClassAdapter.class | Bin 0 -> 23238 bytes .../objectweb/asm/util/CheckClassAdapter.java | 1169 ++++ .../asm/util/CheckFieldAdapter.class | Bin 0 -> 2967 bytes .../objectweb/asm/util/CheckFieldAdapter.java | 148 + .../asm/util/CheckFrameAnalyzer.class | Bin 0 -> 14050 bytes .../asm/util/CheckFrameAnalyzer.java | 513 ++ .../asm/util/CheckMethodAdapter$1.class | Bin 0 -> 4104 bytes .../asm/util/CheckMethodAdapter$Method.class | Bin 0 -> 1744 bytes ...eckMethodAdapter$MethodWriterWrapper.class | Bin 0 -> 1378 bytes .../asm/util/CheckMethodAdapter.class | Bin 0 -> 27615 bytes .../asm/util/CheckMethodAdapter.java | 1519 ++++++ .../asm/util/CheckModuleAdapter$NameSet.class | Bin 0 -> 1187 bytes .../asm/util/CheckModuleAdapter.class | Bin 0 -> 4611 bytes .../asm/util/CheckModuleAdapter.java | 244 + .../util/CheckRecordComponentAdapter.class | Bin 0 -> 3047 bytes .../asm/util/CheckRecordComponentAdapter.java | 153 + .../util/CheckSignatureAdapter$State.class | Bin 0 -> 1814 bytes .../asm/util/CheckSignatureAdapter.class | Bin 0 -> 7381 bytes .../asm/util/CheckSignatureAdapter.java | 391 ++ .../org/objectweb/asm/util/Printer.class | Bin 0 -> 15827 bytes .../org/objectweb/asm/util/Printer.java | 1342 +++++ .../org/objectweb/asm/util/Textifier.class | Bin 0 -> 35476 bytes .../org/objectweb/asm/util/Textifier.java | 1636 ++++++ .../objectweb/asm/util/TextifierSupport.class | Bin 0 -> 337 bytes .../objectweb/asm/util/TextifierSupport.java | 79 + .../asm/util/TraceAnnotationVisitor.class | Bin 0 -> 2178 bytes .../asm/util/TraceAnnotationVisitor.java | 125 + .../asm/util/TraceClassVisitor.class | Bin 0 -> 6687 bytes .../objectweb/asm/util/TraceClassVisitor.java | 276 + .../asm/util/TraceFieldVisitor.class | Bin 0 -> 2399 bytes .../objectweb/asm/util/TraceFieldVisitor.java | 125 + .../asm/util/TraceMethodVisitor.class | Bin 0 -> 8932 bytes .../asm/util/TraceMethodVisitor.java | 344 ++ .../asm/util/TraceModuleVisitor.class | Bin 0 -> 2263 bytes .../asm/util/TraceModuleVisitor.java | 143 + .../util/TraceRecordComponentVisitor.class | Bin 0 -> 2519 bytes .../asm/util/TraceRecordComponentVisitor.java | 128 + .../asm/util/TraceSignatureVisitor.class | Bin 0 -> 6072 bytes .../asm/util/TraceSignatureVisitor.java | 376 ++ .../jdk/internal/org/xml/sax/Attributes.class | Bin 0 -> 497 bytes .../jdk/internal/org/xml/sax/Attributes.java | 281 + .../internal/org/xml/sax/ContentHandler.class | Bin 0 -> 851 bytes .../internal/org/xml/sax/ContentHandler.java | 443 ++ .../jdk/internal/org/xml/sax/DTDHandler.class | Bin 0 -> 735 bytes .../jdk/internal/org/xml/sax/DTDHandler.java | 173 + .../internal/org/xml/sax/EntityResolver.class | Bin 0 -> 330 bytes .../internal/org/xml/sax/EntityResolver.java | 143 + .../internal/org/xml/sax/ErrorHandler.class | Bin 0 -> 321 bytes .../internal/org/xml/sax/ErrorHandler.java | 163 + .../internal/org/xml/sax/InputSource.class | Bin 0 -> 1798 bytes .../jdk/internal/org/xml/sax/InputSource.java | 363 ++ .../jdk/internal/org/xml/sax/Locator.class | Bin 0 -> 243 bytes .../std/jdk/internal/org/xml/sax/Locator.java | 160 + .../internal/org/xml/sax/SAXException.class | Bin 0 -> 3443 bytes .../internal/org/xml/sax/SAXException.java | 243 + .../xml/sax/SAXNotRecognizedException.class | Bin 0 -> 580 bytes .../xml/sax/SAXNotRecognizedException.java | 80 + .../xml/sax/SAXNotSupportedException.class | Bin 0 -> 577 bytes .../org/xml/sax/SAXNotSupportedException.java | 80 + .../org/xml/sax/SAXParseException.class | Bin 0 -> 2912 bytes .../org/xml/sax/SAXParseException.java | 314 ++ .../jdk/internal/org/xml/sax/XMLReader.class | Bin 0 -> 1270 bytes .../jdk/internal/org/xml/sax/XMLReader.java | 428 ++ .../org/xml/sax/helpers/DefaultHandler.class | Bin 0 -> 3104 bytes .../org/xml/sax/helpers/DefaultHandler.java | 491 ++ .../internal/perf/Perf$CleanerAction.class | Bin 0 -> 1163 bytes .../internal/perf/Perf$GetPerfAction.class | Bin 0 -> 741 bytes .../std/jdk/internal/perf/Perf.class | Bin 0 -> 2974 bytes .../test_data/std/jdk/internal/perf/Perf.java | 438 ++ .../perf/PerfCounter$CoreCounters.class | Bin 0 -> 1003 bytes .../std/jdk/internal/perf/PerfCounter.class | Bin 0 -> 3214 bytes .../std/jdk/internal/perf/PerfCounter.java | 182 + .../std/jdk/internal/platform/Container.class | Bin 0 -> 445 bytes .../std/jdk/internal/platform/Container.java | 45 + .../std/jdk/internal/platform/Metrics.class | Bin 0 -> 1067 bytes .../std/jdk/internal/platform/Metrics.java | 399 ++ .../jdk/internal/platform/SystemMetrics.class | Bin 0 -> 395 bytes .../jdk/internal/platform/SystemMetrics.java | 31 + .../internal/random/L128X1024MixRandom.class | Bin 0 -> 3732 bytes .../internal/random/L128X1024MixRandom.java | 331 ++ .../internal/random/L128X128MixRandom.class | Bin 0 -> 2762 bytes .../internal/random/L128X128MixRandom.java | 261 + .../internal/random/L128X256MixRandom.class | Bin 0 -> 3135 bytes .../internal/random/L128X256MixRandom.java | 285 + .../jdk/internal/random/L32X64MixRandom.class | Bin 0 -> 2458 bytes .../jdk/internal/random/L32X64MixRandom.java | 251 + .../internal/random/L64X1024MixRandom.class | Bin 0 -> 3347 bytes .../internal/random/L64X1024MixRandom.java | 314 ++ .../internal/random/L64X128MixRandom.class | Bin 0 -> 2384 bytes .../jdk/internal/random/L64X128MixRandom.java | 247 + .../random/L64X128StarStarRandom.class | Bin 0 -> 2406 bytes .../random/L64X128StarStarRandom.java | 247 + .../internal/random/L64X256MixRandom.class | Bin 0 -> 2710 bytes .../jdk/internal/random/L64X256MixRandom.java | 262 + .../random/Xoroshiro128PlusPlus.class | Bin 0 -> 2972 bytes .../internal/random/Xoroshiro128PlusPlus.java | 269 + .../internal/random/Xoshiro256PlusPlus.class | Bin 0 -> 3399 bytes .../internal/random/Xoshiro256PlusPlus.java | 300 ++ .../std/jdk/internal/ref/Cleaner$1.class | Bin 0 -> 1197 bytes .../std/jdk/internal/ref/Cleaner.class | Bin 0 -> 2079 bytes .../std/jdk/internal/ref/Cleaner.java | 156 + .../jdk/internal/ref/CleanerFactory$1.class | Bin 0 -> 790 bytes .../std/jdk/internal/ref/CleanerFactory.class | Bin 0 -> 713 bytes .../std/jdk/internal/ref/CleanerFactory.java | 60 + .../ref/CleanerImpl$CleanerCleanable.class | Bin 0 -> 731 bytes .../CleanerImpl$InnocuousThreadFactory.class | Bin 0 -> 1404 bytes .../ref/CleanerImpl$PhantomCleanableRef.class | Bin 0 -> 1270 bytes .../std/jdk/internal/ref/CleanerImpl.class | Bin 0 -> 3261 bytes .../std/jdk/internal/ref/CleanerImpl.java | 234 + .../jdk/internal/ref/PhantomCleanable.class | Bin 0 -> 2795 bytes .../jdk/internal/ref/PhantomCleanable.java | 180 + .../internal/reflect/AccessorGenerator.class | Bin 0 -> 12695 bytes .../internal/reflect/AccessorGenerator.java | 722 +++ .../jdk/internal/reflect/AccessorUtils.class | Bin 0 -> 2633 bytes .../jdk/internal/reflect/AccessorUtils.java | 109 + .../std/jdk/internal/reflect/ByteVector.class | Bin 0 -> 258 bytes .../std/jdk/internal/reflect/ByteVector.java | 37 + .../internal/reflect/ByteVectorFactory.class | Bin 0 -> 587 bytes .../internal/reflect/ByteVectorFactory.java | 36 + .../jdk/internal/reflect/ByteVectorImpl.class | Bin 0 -> 1550 bytes .../jdk/internal/reflect/ByteVectorImpl.java | 88 + .../internal/reflect/CallerSensitive.class | Bin 0 -> 404 bytes .../jdk/internal/reflect/CallerSensitive.java | 41 + .../reflect/CallerSensitiveAdapter.class | Bin 0 -> 416 bytes .../reflect/CallerSensitiveAdapter.java | 112 + .../jdk/internal/reflect/ClassDefiner$1.class | Bin 0 -> 1010 bytes .../jdk/internal/reflect/ClassDefiner.class | Bin 0 -> 1426 bytes .../jdk/internal/reflect/ClassDefiner.java | 80 + .../internal/reflect/ClassFileAssembler.class | Bin 0 -> 11869 bytes .../internal/reflect/ClassFileAssembler.java | 671 +++ .../internal/reflect/ClassFileConstants.class | Bin 0 -> 2924 bytes .../internal/reflect/ClassFileConstants.java | 140 + .../internal/reflect/ConstantPool$Tag.class | Bin 0 -> 2661 bytes .../jdk/internal/reflect/ConstantPool.class | Bin 0 -> 3786 bytes .../jdk/internal/reflect/ConstantPool.java | 132 + .../reflect/ConstructorAccessor.class | Bin 0 -> 358 bytes .../internal/reflect/ConstructorAccessor.java | 41 + .../reflect/ConstructorAccessorImpl.class | Bin 0 -> 624 bytes .../reflect/ConstructorAccessorImpl.java | 41 + .../reflect/CsMethodAccessorAdapter.class | Bin 0 -> 2503 bytes .../reflect/CsMethodAccessorAdapter.java | 72 + .../reflect/DelegatingClassLoader.class | Bin 0 -> 399 bytes ...tructorHandleAccessor$NativeAccessor.class | Bin 0 -> 1284 bytes .../DirectConstructorHandleAccessor.class | Bin 0 -> 3953 bytes .../DirectConstructorHandleAccessor.java | 110 + ...sor$NativeAccessor$ReflectiveInvoker.class | Bin 0 -> 3150 bytes ...tMethodHandleAccessor$NativeAccessor.class | Bin 0 -> 3557 bytes .../reflect/DirectMethodHandleAccessor.class | Bin 0 -> 8093 bytes .../reflect/DirectMethodHandleAccessor.java | 354 ++ .../jdk/internal/reflect/FieldAccessor.class | Bin 0 -> 1220 bytes .../jdk/internal/reflect/FieldAccessor.java | 96 + .../internal/reflect/FieldAccessorImpl.class | Bin 0 -> 6897 bytes .../internal/reflect/FieldAccessorImpl.java | 267 + ...tionExceptionConstructorAccessorImpl.class | Bin 0 -> 906 bytes ...ationExceptionConstructorAccessorImpl.java | 52 + .../internal/reflect/Label$PatchInfo.class | Bin 0 -> 692 bytes .../std/jdk/internal/reflect/Label.class | Bin 0 -> 1500 bytes .../std/jdk/internal/reflect/Label.java | 76 + .../internal/reflect/MagicAccessorImpl.class | Bin 0 -> 318 bytes .../internal/reflect/MagicAccessorImpl.java | 47 + .../jdk/internal/reflect/MethodAccessor.class | Bin 0 -> 518 bytes .../jdk/internal/reflect/MethodAccessor.java | 43 + .../internal/reflect/MethodAccessorImpl.class | Bin 0 -> 1020 bytes .../internal/reflect/MethodAccessorImpl.java | 53 + ...ndleAccessorFactory$LazyStaticHolder.class | Bin 0 -> 753 bytes .../reflect/MethodHandleAccessorFactory.class | Bin 0 -> 11117 bytes .../reflect/MethodHandleAccessorFactory.java | 417 ++ ...MethodHandleBooleanFieldAccessorImpl.class | Bin 0 -> 5957 bytes .../MethodHandleBooleanFieldAccessorImpl.java | 185 + .../MethodHandleByteFieldAccessorImpl.class | Bin 0 -> 5716 bytes .../MethodHandleByteFieldAccessorImpl.java | 185 + ...thodHandleCharacterFieldAccessorImpl.class | Bin 0 -> 5792 bytes ...ethodHandleCharacterFieldAccessorImpl.java | 185 + .../MethodHandleDoubleFieldAccessorImpl.class | Bin 0 -> 6565 bytes .../MethodHandleDoubleFieldAccessorImpl.java | 204 + .../MethodHandleFieldAccessorImpl.class | Bin 0 -> 3207 bytes .../MethodHandleFieldAccessorImpl.java | 96 + .../MethodHandleFloatFieldAccessorImpl.class | Bin 0 -> 6406 bytes .../MethodHandleFloatFieldAccessorImpl.java | 201 + ...MethodHandleIntegerFieldAccessorImpl.class | Bin 0 -> 6120 bytes .../MethodHandleIntegerFieldAccessorImpl.java | 195 + .../MethodHandleLongFieldAccessorImpl.class | Bin 0 -> 6261 bytes .../MethodHandleLongFieldAccessorImpl.java | 198 + .../MethodHandleObjectFieldAccessorImpl.class | Bin 0 -> 5706 bytes .../MethodHandleObjectFieldAccessorImpl.java | 168 + .../MethodHandleShortFieldAccessorImpl.class | Bin 0 -> 5866 bytes .../MethodHandleShortFieldAccessorImpl.java | 189 + .../internal/reflect/Reflection$1Holder.class | Bin 0 -> 750 bytes .../std/jdk/internal/reflect/Reflection.class | Bin 0 -> 11388 bytes .../std/jdk/internal/reflect/Reflection.java | 445 ++ .../reflect/ReflectionFactory$Config.class | Bin 0 -> 1911 bytes ...onFactory$GetReflectionFactoryAction.class | Bin 0 -> 886 bytes .../internal/reflect/ReflectionFactory.class | Bin 0 -> 16299 bytes .../internal/reflect/ReflectionFactory.java | 636 +++ ...zationConstructorAccessorGenerator$1.class | Bin 0 -> 2083 bytes ...lizationConstructorAccessorGenerator.class | Bin 0 -> 10908 bytes ...alizationConstructorAccessorGenerator.java | 725 +++ ...SerializationConstructorAccessorImpl.class | Bin 0 -> 403 bytes .../SerializationConstructorAccessorImpl.java | 45 + .../std/jdk/internal/util/Architecture.class | Bin 0 -> 4384 bytes .../std/jdk/internal/util/Architecture.java | 245 + .../std/jdk/internal/util/ArraysSupport.class | Bin 0 -> 13180 bytes .../std/jdk/internal/util/ArraysSupport.java | 971 ++++ .../std/jdk/internal/util/ByteArray.class | Bin 0 -> 3747 bytes .../std/jdk/internal/util/ByteArray.java | 424 ++ .../internal/util/ByteArrayLittleEndian.class | Bin 0 -> 3798 bytes .../internal/util/ByteArrayLittleEndian.java | 424 ++ .../jdk/internal/util/ClassFileDumper$1.class | Bin 0 -> 2307 bytes .../jdk/internal/util/ClassFileDumper$2.class | Bin 0 -> 2115 bytes .../jdk/internal/util/ClassFileDumper.class | Bin 0 -> 5174 bytes .../jdk/internal/util/ClassFileDumper.java | 196 + .../std/jdk/internal/util/DecimalDigits.class | Bin 0 -> 785 bytes .../std/jdk/internal/util/DecimalDigits.java | 87 + .../std/jdk/internal/util/HexDigits.class | Bin 0 -> 2244 bytes .../std/jdk/internal/util/HexDigits.java | 202 + ...dicate$SmallImmutableBitSetPredicate.class | Bin 0 -> 2112 bytes .../util/ImmutableBitSetPredicate.class | Bin 0 -> 1383 bytes .../util/ImmutableBitSetPredicate.java | 114 + .../util/NullableKeyValueHolder.class | Bin 0 -> 2675 bytes .../internal/util/NullableKeyValueHolder.java | 166 + .../std/jdk/internal/util/OSVersion.class | Bin 0 -> 4079 bytes .../std/jdk/internal/util/OSVersion.java | 137 + .../std/jdk/internal/util/OctalDigits.class | Bin 0 -> 1754 bytes .../std/jdk/internal/util/OctalDigits.java | 130 + .../jdk/internal/util/OperatingSystem.class | Bin 0 -> 1961 bytes .../jdk/internal/util/OperatingSystem.java | 136 + .../std/jdk/internal/util/PlatformProps.class | Bin 0 -> 1201 bytes .../std/jdk/internal/util/PlatformProps.java | 69 + .../jdk/internal/util/Preconditions$1.class | Bin 0 -> 1010 bytes .../jdk/internal/util/Preconditions$2.class | Bin 0 -> 1007 bytes .../jdk/internal/util/Preconditions$3.class | Bin 0 -> 992 bytes .../jdk/internal/util/Preconditions$4.class | Bin 0 -> 1593 bytes .../std/jdk/internal/util/Preconditions.class | Bin 0 -> 8151 bytes .../std/jdk/internal/util/Preconditions.java | 546 ++ .../std/jdk/internal/util/ReferenceKey.class | Bin 0 -> 420 bytes .../std/jdk/internal/util/ReferenceKey.java | 51 + .../internal/util/ReferencedKeyMap$1.class | Bin 0 -> 965 bytes .../jdk/internal/util/ReferencedKeyMap.class | Bin 0 -> 11672 bytes .../jdk/internal/util/ReferencedKeyMap.java | 483 ++ .../jdk/internal/util/ReferencedKeySet.class | Bin 0 -> 4451 bytes .../jdk/internal/util/ReferencedKeySet.java | 214 + .../jdk/internal/util/SoftReferenceKey.class | Bin 0 -> 1993 bytes .../jdk/internal/util/SoftReferenceKey.java | 91 + .../jdk/internal/util/StaticProperty.class | Bin 0 -> 4717 bytes .../std/jdk/internal/util/StaticProperty.java | 311 ++ .../internal/util/StrongReferenceKey.class | Bin 0 -> 1836 bytes .../jdk/internal/util/StrongReferenceKey.java | 82 + .../jdk/internal/util/SystemProps$Raw.class | Bin 0 -> 3168 bytes .../std/jdk/internal/util/SystemProps.class | Bin 0 -> 4594 bytes .../std/jdk/internal/util/SystemProps.java | 322 ++ .../jdk/internal/util/WeakReferenceKey.class | Bin 0 -> 1993 bytes .../jdk/internal/util/WeakReferenceKey.java | 91 + ...ator$RandomArbitraryJumpsSpliterator.class | Bin 0 -> 3021 bytes ...leGenerator$RandomDoublesSpliterator.class | Bin 0 -> 3114 bytes ...pableGenerator$RandomIntsSpliterator.class | Bin 0 -> 3081 bytes ...ableGenerator$RandomJumpsSpliterator.class | Bin 0 -> 2867 bytes ...ableGenerator$RandomLeapsSpliterator.class | Bin 0 -> 3023 bytes ...ableGenerator$RandomLongsSpliterator.class | Bin 0 -> 3088 bytes ...AbstractArbitrarilyJumpableGenerator.class | Bin 0 -> 4926 bytes ...Support$AbstractSpliteratorGenerator.class | Bin 0 -> 5822 bytes ...leGenerator$RandomDoublesSpliterator.class | Bin 0 -> 2960 bytes ...tableGenerator$RandomIntsSpliterator.class | Bin 0 -> 2927 bytes ...ableGenerator$RandomLongsSpliterator.class | Bin 0 -> 2934 bytes ...bleGenerator$RandomSplitsSpliterator.class | Bin 0 -> 2998 bytes ...mSupport$AbstractSplittableGenerator.class | Bin 0 -> 3454 bytes ...ator$RandomSplitsSpliteratorWithSalt.class | Bin 0 -> 3491 bytes ...AbstractSplittableWithBrineGenerator.class | Bin 0 -> 2324 bytes .../RandomSupport$DoubleZigguratTables.class | Bin 0 -> 29872 bytes ...ndomSupport$RandomDoublesSpliterator.class | Bin 0 -> 2547 bytes .../RandomSupport$RandomIntsSpliterator.class | Bin 0 -> 2514 bytes ...RandomSupport$RandomLongsSpliterator.class | Bin 0 -> 2521 bytes .../RandomSupport$RandomSpliterator.class | Bin 0 -> 764 bytes .../internal/util/random/RandomSupport.class | Bin 0 -> 12224 bytes .../internal/util/random/RandomSupport.java | 3027 +++++++++++ .../jdk/internal/util/regex/Grapheme.class | Bin 0 -> 4314 bytes .../std/jdk/internal/util/regex/Grapheme.java | 332 ++ .../util/regex/IndicConjunctBreak.class | Bin 0 -> 3444 bytes .../util/regex/IndicConjunctBreak.java | 286 + .../util/xml/PropertiesDefaultHandler.class | Bin 0 -> 7816 bytes .../util/xml/PropertiesDefaultHandler.java | 262 + .../std/jdk/internal/util/xml/SAXParser.class | Bin 0 -> 3144 bytes .../std/jdk/internal/util/xml/SAXParser.java | 246 + .../util/xml/XMLStreamException.class | Bin 0 -> 968 bytes .../internal/util/xml/XMLStreamException.java | 91 + .../internal/util/xml/XMLStreamWriter.class | Bin 0 -> 1032 bytes .../internal/util/xml/XMLStreamWriter.java | 158 + .../jdk/internal/util/xml/impl/Attrs.class | Bin 0 -> 4061 bytes .../std/jdk/internal/util/xml/impl/Attrs.java | 426 ++ .../jdk/internal/util/xml/impl/Input.class | Bin 0 -> 743 bytes .../std/jdk/internal/util/xml/impl/Input.java | 83 + .../std/jdk/internal/util/xml/impl/Pair.class | Bin 0 -> 1267 bytes .../std/jdk/internal/util/xml/impl/Pair.java | 122 + .../jdk/internal/util/xml/impl/Parser.class | Bin 0 -> 33209 bytes .../jdk/internal/util/xml/impl/Parser.java | 3454 ++++++++++++ .../internal/util/xml/impl/ParserSAX.class | Bin 0 -> 9473 bytes .../jdk/internal/util/xml/impl/ParserSAX.java | 696 +++ .../internal/util/xml/impl/ReaderUTF16.class | Bin 0 -> 1384 bytes .../internal/util/xml/impl/ReaderUTF16.java | 122 + .../internal/util/xml/impl/ReaderUTF8.class | Bin 0 -> 1415 bytes .../internal/util/xml/impl/ReaderUTF8.java | 138 + .../util/xml/impl/SAXParserImpl.class | Bin 0 -> 1403 bytes .../internal/util/xml/impl/SAXParserImpl.java | 118 + .../impl/XMLStreamWriterImpl$Element.class | Bin 0 -> 1351 bytes .../util/xml/impl/XMLStreamWriterImpl.class | Bin 0 -> 9680 bytes .../util/xml/impl/XMLStreamWriterImpl.java | 658 +++ .../internal/util/xml/impl/XMLWriter.class | Bin 0 -> 3297 bytes .../jdk/internal/util/xml/impl/XMLWriter.java | 152 + .../jdk/internal/vm/Continuation$Pinned.class | Bin 0 -> 1293 bytes .../vm/Continuation$PreemptStatus.class | Bin 0 -> 2113 bytes .../std/jdk/internal/vm/Continuation.class | Bin 0 -> 13937 bytes .../std/jdk/internal/vm/Continuation.java | 503 ++ .../jdk/internal/vm/ContinuationScope.class | Bin 0 -> 1070 bytes .../jdk/internal/vm/ContinuationScope.java | 73 + .../jdk/internal/vm/ContinuationSupport.class | Bin 0 -> 737 bytes .../jdk/internal/vm/ContinuationSupport.java | 54 + .../std/jdk/internal/vm/FillerObject.class | Bin 0 -> 293 bytes .../std/jdk/internal/vm/FillerObject.java | 31 + .../internal/vm/ForeignLinkerSupport.class | Bin 0 -> 506 bytes .../jdk/internal/vm/ForeignLinkerSupport.java | 44 + ...copedValueContainer$BindingsSnapshot.class | Bin 0 -> 1894 bytes .../internal/vm/ScopedValueContainer.class | Bin 0 -> 5291 bytes .../jdk/internal/vm/ScopedValueContainer.java | 213 + .../internal/vm/SharedThreadContainer.class | Bin 0 -> 5342 bytes .../internal/vm/SharedThreadContainer.java | 166 + .../std/jdk/internal/vm/StackChunk.class | Bin 0 -> 639 bytes .../std/jdk/internal/vm/StackChunk.java | 40 + .../std/jdk/internal/vm/StackableScope.class | Bin 0 -> 3932 bytes .../std/jdk/internal/vm/StackableScope.java | 261 + .../std/jdk/internal/vm/ThreadContainer.class | Bin 0 -> 2901 bytes .../std/jdk/internal/vm/ThreadContainer.java | 116 + ...$RootContainer$CountingRootContainer.class | Bin 0 -> 1645 bytes ...$RootContainer$TrackingRootContainer.class | Bin 0 -> 2608 bytes .../vm/ThreadContainers$RootContainer.class | Bin 0 -> 2356 bytes .../jdk/internal/vm/ThreadContainers.class | Bin 0 -> 7216 bytes .../std/jdk/internal/vm/ThreadContainers.java | 293 + ...dDumper$BoundedByteArrayOutputStream.class | Bin 0 -> 1003 bytes .../std/jdk/internal/vm/ThreadDumper.class | Bin 0 -> 11537 bytes .../std/jdk/internal/vm/ThreadDumper.java | 370 ++ .../jdk/internal/vm/TranslatedException.class | Bin 0 -> 8855 bytes .../jdk/internal/vm/TranslatedException.java | 318 ++ .../vm/VMSupport$AnnotationDecoder.class | Bin 0 -> 857 bytes .../jdk/internal/vm/VMSupport$IOReader.class | Bin 0 -> 376 bytes .../std/jdk/internal/vm/VMSupport.class | Bin 0 -> 20827 bytes .../std/jdk/internal/vm/VMSupport.java | 581 ++ .../vm/annotation/ChangesCurrentThread.class | Bin 0 -> 439 bytes .../vm/annotation/ChangesCurrentThread.java | 44 + .../internal/vm/annotation/Contended.class | Bin 0 -> 472 bytes .../jdk/internal/vm/annotation/Contended.java | 83 + .../internal/vm/annotation/DontInline.class | Bin 0 -> 419 bytes .../internal/vm/annotation/DontInline.java | 50 + .../internal/vm/annotation/ForceInline.class | Bin 0 -> 421 bytes .../internal/vm/annotation/ForceInline.java | 51 + .../jdk/internal/vm/annotation/Hidden.class | Bin 0 -> 411 bytes .../jdk/internal/vm/annotation/Hidden.java | 45 + .../vm/annotation/IntrinsicCandidate.class | Bin 0 -> 435 bytes .../vm/annotation/IntrinsicCandidate.java | 125 + .../vm/annotation/JvmtiMountTransition.class | Bin 0 -> 420 bytes .../vm/annotation/JvmtiMountTransition.java | 40 + .../vm/annotation/ReservedStackAccess.class | Bin 0 -> 437 bytes .../vm/annotation/ReservedStackAccess.java | 52 + .../jdk/internal/vm/annotation/Stable.class | Bin 0 -> 391 bytes .../jdk/internal/vm/annotation/Stable.java | 90 + .../VectorSupport$BinaryOperation.class | Bin 0 -> 816 bytes ...ectorSupport$CompressExpandOperation.class | Bin 0 -> 877 bytes ...ctorSupport$FromBitsCoercedOperation.class | Bin 0 -> 739 bytes .../vector/VectorSupport$IndexOperation.class | Bin 0 -> 737 bytes ...$IndexPartiallyInUpperRangeOperation.class | Bin 0 -> 579 bytes .../vector/VectorSupport$LoadOperation.class | Bin 0 -> 754 bytes ...torSupport$LoadVectorMaskedOperation.class | Bin 0 -> 931 bytes ...orSupport$LoadVectorOperationWithMap.class | Bin 0 -> 946 bytes .../VectorSupport$ReductionOperation.class | Bin 0 -> 685 bytes .../VectorSupport$ShuffleIotaOperation.class | Bin 0 -> 735 bytes ...ctorSupport$ShuffleToVectorOperation.class | Bin 0 -> 709 bytes ...orSupport$StoreVectorMaskedOperation.class | Bin 0 -> 744 bytes .../VectorSupport$StoreVectorOperation.class | Bin 0 -> 577 bytes ...rSupport$StoreVectorOperationWithMap.class | Bin 0 -> 759 bytes .../VectorSupport$TernaryOperation.class | Bin 0 -> 823 bytes .../vector/VectorSupport$UnaryOperation.class | Bin 0 -> 723 bytes .../vector/VectorSupport$VecExtractOp.class | Bin 0 -> 522 bytes .../vm/vector/VectorSupport$VecInsertOp.class | Bin 0 -> 541 bytes .../vm/vector/VectorSupport$Vector.class | Bin 0 -> 740 bytes .../vector/VectorSupport$VectorBlendOp.class | Bin 0 -> 769 bytes .../VectorSupport$VectorBroadcastIntOp.class | Bin 0 -> 737 bytes .../VectorSupport$VectorCompareOp.class | Bin 0 -> 779 bytes .../VectorSupport$VectorConvertOp.class | Bin 0 -> 833 bytes .../vm/vector/VectorSupport$VectorMask.class | Bin 0 -> 756 bytes .../vector/VectorSupport$VectorMaskOp.class | Bin 0 -> 509 bytes .../vector/VectorSupport$VectorPayload.class | Bin 0 -> 774 bytes .../VectorSupport$VectorRearrangeOp.class | Bin 0 -> 923 bytes .../vector/VectorSupport$VectorShuffle.class | Bin 0 -> 768 bytes .../vector/VectorSupport$VectorSpecies.class | Bin 0 -> 612 bytes .../internal/vm/vector/VectorSupport.class | Bin 0 -> 35765 bytes .../jdk/internal/vm/vector/VectorSupport.java | 738 +++ 2145 files changed, 196864 insertions(+) create mode 100644 tests/test_data/std/jdk/internal/ValueBased.class create mode 100644 tests/test_data/std/jdk/internal/ValueBased.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaAWTAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaAWTAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaBeansAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaBeansAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangRefAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangRefAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaNetURLAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaNetURLAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaNetUriAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaNetUriAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaNioAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaNioAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaSecurityAccess$ProtectionDomainCache.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaSecurityAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaSecurityAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaSecuritySignatureAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaSecuritySignatureAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaSecuritySpecAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaSecuritySpecAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.class create mode 100644 tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.java create mode 100644 tests/test_data/std/jdk/internal/access/SharedSecrets.class create mode 100644 tests/test_data/std/jdk/internal/access/SharedSecrets.java create mode 100644 tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.class create mode 100644 tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$AnnotationDefaultMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$BootstrapMethodsMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CharacterRangeTableMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CodeMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CompilationIDMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ConstantValueMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$DeprecatedMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$EnclosingMethodMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ExceptionsMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$InnerClassesMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LineNumberTableMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTableMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTypeTableMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$MethodParametersMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleHashesMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMainClassMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModulePackagesMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleResolutionMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleTargetMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestHostMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestMembersMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$PermittedSubclassesMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RecordMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleAnnotationsMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleParameterAnnotationsMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleTypeAnnotationsMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleAnnotationsMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleParameterAnnotationsMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleTypeAnnotationsMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SignatureMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceDebugExtensionMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceFileMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceIDMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$StackMapTableMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SyntheticMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundArgumentConstantInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundBranchInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundFieldInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundIncrementInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeDynamicInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInterfaceInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundJsrInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadConstantInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLookupSwitchInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewMultidimensionalArrayInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewObjectInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewPrimitiveArrayInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewReferenceArrayInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundRetInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundStoreInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTableSwitchInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTypeCheckInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$SwitchCaseImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArgumentConstantInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayLoadInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayStoreInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundBranchInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundConvertInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundFieldInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIncrementInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIntrinsicConstantInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeDynamicInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundJsrInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadConstantInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLookupSwitchInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundMonitorInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewMultidimensionalArrayInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewObjectInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewPrimitiveArrayInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewReferenceArrayInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNopInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundOperatorInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundRetInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundReturnInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStackInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStoreInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTableSwitchInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundThrowInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTypeCheckInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractDynamicConstantPoolEntry.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractMemberRefEntry.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractNamedEntry.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefEntry.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefsEntry.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ClassEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ConstantDynamicEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$CpException.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$DoubleEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FieldRefEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FloatEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$IntegerEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InterfaceMethodRefEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InvokeDynamicEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$LongEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodHandleEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodRefEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodTypeEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ModuleEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$NameAndTypeEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$PackageEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$PrimitiveEntry.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$StringEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl$State.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$AbstractLocalPseudo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundCharacterRange.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariable.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariableType.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$AnnotationElementImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfAnnotationImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfArrayImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfBooleanImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfByteImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfCharacterImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfClassImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfConstantImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfDoubleImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfEnumImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfFloatImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfIntegerImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfLongImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfShortImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfStringImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundAnnotationDefaultAttr.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundBootstrapMethodsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCharacterRangeTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCodeAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCompilationIDAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundConstantValueAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundDeprecatedAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundEnclosingMethodAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundExceptionsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundInnerClassesAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLineNumberTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLocalVariableTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLocalVariableTypeTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundMethodParametersAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleHashesAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleMainClassAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModulePackagesAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleResolutionAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleTargetAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundNestHostAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundNestMembersAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundPermittedSubclassesAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRecordAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleParameterAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleTypeAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleParameterAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleTypeAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSignatureAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceDebugExtensionAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceFileAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceIDAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundStackMapTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSyntheticAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundUnknownAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundCharacterRange.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundCharacterRange.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariable.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariable.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariableType.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariableType.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundRecordComponentInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BoundRecordComponentInfo.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufWriterImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufWriterImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder$Model$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder$Model.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedFieldBuilder$Model$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedFieldBuilder$Model.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedFieldBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedFieldBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder$Model$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder$Model.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BytecodeHelpers$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BytecodeHelpers.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/BytecodeHelpers.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CatchBuilderImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CatchBuilderImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ChainedClassBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ChainedClassBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ChainedCodeBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ChainedCodeBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ChainedFieldBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ChainedFieldBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ChainedMethodBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ChainedMethodBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$2.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$AttributeMapperOptionImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$ClassHierarchyResolverOptionImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassFileVersionImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassFileVersionImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$CachedClassHierarchyResolver$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$CachedClassHierarchyResolver.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ClassHierarchyInfoImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ClassLoadingClassHierarchyResolver$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ClassLoadingClassHierarchyResolver.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ResourceParsingClassHierarchyResolver$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ResourceParsingClassHierarchyResolver.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$StaticClassHierarchyResolver.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$ExceptionHandler.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$LeafNodeImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$ListNodeImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$MapNodeImpl$PrivateListNodeImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$MapNodeImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$Style.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassReaderImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassReaderImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$2.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$3.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$4.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$ExceptionHandlerAction.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeLocalsShifterImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeLocalsShifterImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeRelabelerImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeRelabelerImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$Item.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$Stack$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$Stack.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectClassBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectClassBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$2.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$3.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$4.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$5.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$6.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$7.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$8.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$DedupLineNumberTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$DeferredLabel.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$LabelOverflowException.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectFieldBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectFieldBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/EntryMap.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/EntryMap.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/FieldImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/FieldImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/FieldImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/InterfacesImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/InterfacesImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/LabelContext.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/LabelContext.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/LabelImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/LabelImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/LineNumberImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/LineNumberImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/MethodImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/MethodImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/MethodImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/MethodInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/MethodInfo.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/NonterminalCodeBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/NonterminalCodeBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/RawBytecodeHelper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/RawBytecodeHelper.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$ArrayTypeSigImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$BaseTypeSigImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$ClassSignatureImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$ClassTypeSigImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$MethodSignatureImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$TypeArgImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$TypeParamImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$TypeVarSigImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$UnboundedTypeArgImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool$2.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool$3.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackCounter$Target.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackCounter.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackCounter.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder$ObjectVerificationTypeInfoImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder$StackMapFrameImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder$UninitializedVerificationTypeInfoImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator$2.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator$Frame.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator$RawExceptionCatch.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator$Type.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SuperclassImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/SuperclassImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$CatchTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$EmptyTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$FormalParameterTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$LocalVarTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$LocalVarTargetInfoImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$OffsetTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$SupertypeTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$ThrowsTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$TypeArgumentTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$TypeParameterBoundTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$TypeParameterTargetImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TemporaryConstantPool.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TemporaryConstantPool.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TerminalCodeBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TerminalCodeBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TerminalFieldBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TerminalFieldBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TerminalMethodBuilder.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TerminalMethodBuilder.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedClassTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedCodeTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedFieldTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedMethodTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ClassFieldTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ClassMethodTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$MethodCodeTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ResolvedTransformImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierClassTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierCodeTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierFieldTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierMethodTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$UnresolvedClassTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$UnresolvedCodeTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$UnresolvedFieldTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$UnresolvedMethodTransform.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/TransformImpl.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$AdHocAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$EmptyBootstrapAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$TypePathComponentImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundAnnotationDefaultAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundCharacterRangeInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundCharacterRangeTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundCompilationIDAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundConstantValueAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundDeprecatedAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundEnclosingMethodAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundExceptionsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundInnerClassInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundInnerClassesAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundLineNumberInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundLineNumberTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTypeInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTypeTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundMethodParameterInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundMethodParametersAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleExportInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleHashInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleHashesAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleMainClassAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleOpenInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModulePackagesAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleProvideInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleRequiresInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleResolutionAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleTargetAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundNestHostAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundNestMembersAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundPermittedSubclassesAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRecordAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRecordComponentInfo.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleParameterAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleTypeAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleParameterAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleTypeAnnotationsAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundSignatureAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceDebugExtensionAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceFileAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceIDAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundStackMapTableAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundSyntheticAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundTypeAnnotation.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/Util$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/Util$2.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/Util.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/Util.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier$1F.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier$1M.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationBytecodes.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationFrame$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationFrame.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationFrame.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationSignature$BasicType.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationSignature.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationSignature.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable$StackMapReader.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable$StackMapStream.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationType$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationType.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationType.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationWrapper$ConstantPoolWrapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationWrapper$MethodWrapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationWrapper.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationWrapper.java create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl$sig_as_verification_types.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl.class create mode 100644 tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl.java create mode 100644 tests/test_data/std/jdk/internal/constant/ConstantUtils.class create mode 100644 tests/test_data/std/jdk/internal/constant/ConstantUtils.java create mode 100644 tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl.class create mode 100644 tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl.java create mode 100644 tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl.class create mode 100644 tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl.java create mode 100644 tests/test_data/std/jdk/internal/constant/ModuleDescImpl.class create mode 100644 tests/test_data/std/jdk/internal/constant/ModuleDescImpl.java create mode 100644 tests/test_data/std/jdk/internal/constant/PackageDescImpl.class create mode 100644 tests/test_data/std/jdk/internal/constant/PackageDescImpl.java create mode 100644 tests/test_data/std/jdk/internal/constant/PrimitiveClassDescImpl.class create mode 100644 tests/test_data/std/jdk/internal/constant/PrimitiveClassDescImpl.java create mode 100644 tests/test_data/std/jdk/internal/constant/ReferenceClassDescImpl.class create mode 100644 tests/test_data/std/jdk/internal/constant/ReferenceClassDescImpl.java create mode 100644 tests/test_data/std/jdk/internal/event/DeserializationEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/DeserializationEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/ErrorThrownEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/ErrorThrownEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/Event.class create mode 100644 tests/test_data/std/jdk/internal/event/Event.java create mode 100644 tests/test_data/std/jdk/internal/event/EventHelper$ThreadTrackHolder.class create mode 100644 tests/test_data/std/jdk/internal/event/EventHelper.class create mode 100644 tests/test_data/std/jdk/internal/event/EventHelper.java create mode 100644 tests/test_data/std/jdk/internal/event/ExceptionStatisticsEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/ExceptionStatisticsEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/ExceptionThrownEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/ExceptionThrownEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/FileForceEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/FileForceEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/FileReadEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/FileReadEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/FileWriteEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/FileWriteEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/JFRTracing.class create mode 100644 tests/test_data/std/jdk/internal/event/JFRTracing.java create mode 100644 tests/test_data/std/jdk/internal/event/ProcessStartEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/ProcessStartEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/SecurityPropertyModificationEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/SecurityPropertyModificationEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/SecurityProviderServiceEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/SecurityProviderServiceEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/SerializationMisdeclarationEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/SerializationMisdeclarationEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/SocketReadEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/SocketReadEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/SocketWriteEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/SocketWriteEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/TLSHandshakeEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/TLSHandshakeEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/ThreadSleepEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/ThreadSleepEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/ThrowableTracer.class create mode 100644 tests/test_data/std/jdk/internal/event/ThrowableTracer.java create mode 100644 tests/test_data/std/jdk/internal/event/VirtualThreadEndEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/VirtualThreadEndEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/VirtualThreadPinnedEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/VirtualThreadPinnedEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/VirtualThreadStartEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/VirtualThreadStartEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/VirtualThreadSubmitFailedEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/VirtualThreadSubmitFailedEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/X509CertificateEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/X509CertificateEvent.java create mode 100644 tests/test_data/std/jdk/internal/event/X509ValidationEvent.class create mode 100644 tests/test_data/std/jdk/internal/event/X509ValidationEvent.java create mode 100644 tests/test_data/std/jdk/internal/foreign/AbstractMemorySegmentImpl$SegmentSplitter.class create mode 100644 tests/test_data/std/jdk/internal/foreign/AbstractMemorySegmentImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/AbstractMemorySegmentImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/ArenaImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/ArenaImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/CABI.class create mode 100644 tests/test_data/std/jdk/internal/foreign/CABI.java create mode 100644 tests/test_data/std/jdk/internal/foreign/ConfinedSession$ConfinedResourceList.class create mode 100644 tests/test_data/std/jdk/internal/foreign/ConfinedSession.class create mode 100644 tests/test_data/std/jdk/internal/foreign/ConfinedSession.java create mode 100644 tests/test_data/std/jdk/internal/foreign/FunctionDescriptorImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/FunctionDescriptorImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/GlobalSession$HeapSession.class create mode 100644 tests/test_data/std/jdk/internal/foreign/GlobalSession.class create mode 100644 tests/test_data/std/jdk/internal/foreign/GlobalSession.java create mode 100644 tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfByte.class create mode 100644 tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfChar.class create mode 100644 tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfDouble.class create mode 100644 tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfFloat.class create mode 100644 tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfInt.class create mode 100644 tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfLong.class create mode 100644 tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfShort.class create mode 100644 tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/ImplicitSession.class create mode 100644 tests/test_data/std/jdk/internal/foreign/ImplicitSession.java create mode 100644 tests/test_data/std/jdk/internal/foreign/LayoutPath$DereferenceElement.class create mode 100644 tests/test_data/std/jdk/internal/foreign/LayoutPath$GroupElementByIndex.class create mode 100644 tests/test_data/std/jdk/internal/foreign/LayoutPath$GroupElementByName.class create mode 100644 tests/test_data/std/jdk/internal/foreign/LayoutPath$SequenceElement.class create mode 100644 tests/test_data/std/jdk/internal/foreign/LayoutPath$SequenceElementByIndex.class create mode 100644 tests/test_data/std/jdk/internal/foreign/LayoutPath$SequenceElementByRange.class create mode 100644 tests/test_data/std/jdk/internal/foreign/LayoutPath.class create mode 100644 tests/test_data/std/jdk/internal/foreign/LayoutPath.java create mode 100644 tests/test_data/std/jdk/internal/foreign/MappedMemorySegmentImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/MappedMemorySegmentImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList$ResourceCleanup$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList$ResourceCleanup$2.class create mode 100644 tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList$ResourceCleanup.class create mode 100644 tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList.class create mode 100644 tests/test_data/std/jdk/internal/foreign/MemorySessionImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/MemorySessionImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/NativeMemorySegmentImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/NativeMemorySegmentImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/SegmentFactories$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SegmentFactories$2.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SegmentFactories.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SegmentFactories.java create mode 100644 tests/test_data/std/jdk/internal/foreign/SharedSession$SharedResourceList.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SharedSession.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SharedSession.java create mode 100644 tests/test_data/std/jdk/internal/foreign/SlicingAllocator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SlicingAllocator.java create mode 100644 tests/test_data/std/jdk/internal/foreign/StringSupport$CharsetKind.class create mode 100644 tests/test_data/std/jdk/internal/foreign/StringSupport.class create mode 100644 tests/test_data/std/jdk/internal/foreign/StringSupport.java create mode 100644 tests/test_data/std/jdk/internal/foreign/SystemLookup$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SystemLookup$2.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SystemLookup$WindowsFallbackSymbols.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SystemLookup.class create mode 100644 tests/test_data/std/jdk/internal/foreign/SystemLookup.java create mode 100644 tests/test_data/std/jdk/internal/foreign/Utils$1VarHandleCache.class create mode 100644 tests/test_data/std/jdk/internal/foreign/Utils$BaseAndScale.class create mode 100644 tests/test_data/std/jdk/internal/foreign/Utils.class create mode 100644 tests/test_data/std/jdk/internal/foreign/Utils.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ABIDescriptor.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ABIDescriptor.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker$LinkRequest.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker$UpcallStubFactory.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Architecture.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Architecture.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$Allocate.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$BoxAddress.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$BufferLoad.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$BufferStore.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$Builder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$Cast$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$Cast.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$Copy.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$Dereference.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$Dup.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$Move.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$SegmentBase.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$SegmentOffset.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$ShiftLeft.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$ShiftRight.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$VMLoad.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding$VMStore.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/Binding.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter$LoadFunc.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter$StoreFunc.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/CallingSequence.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/CallingSequence.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/CallingSequenceBuilder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/CallingSequenceBuilder.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/CapturableState.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/CapturableState.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/DowncallLinker$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/DowncallLinker$2.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/DowncallLinker$InvocationData.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/DowncallLinker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/DowncallLinker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$CaptureCallState.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$Critical.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$FirstVariadicArg.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$LinkerOptionImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/NativeEntryPoint$CacheKey.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/NativeEntryPoint.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/NativeEntryPoint.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/SharedUtils$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/SharedUtils$2.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/SharedUtils$3.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/SharedUtils$4.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/SharedUtils.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/SharedUtils.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache$Node.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/StubLocations.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/StubLocations.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/UpcallLinker$CallRegs.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/UpcallLinker$InvocationData.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/UpcallLinker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/UpcallLinker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/UpcallStubs$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/UpcallStubs.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/UpcallStubs.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/VMStorage.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/VMStorage.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/AArch64Architecture$Regs.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/AArch64Architecture$StorageType.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/AArch64Architecture.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/AArch64Architecture.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$BindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$Bindings.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$BoxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$StorageCalculator$StructStorage.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$StorageCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$UnboxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/TypeClass.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/TypeClass.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64Linker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64Linker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64Linker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64Linker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64Linker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64Linker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIABI.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIABI.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIStatus.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIStatus.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIType.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIType.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker$2Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker$DowncallData.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker$UpcallData.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback$NativeConstants.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$BindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$Bindings.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$BoxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$HfaRegs.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$StorageCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$UnboxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/PPC64Architecture$Regs.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/PPC64Architecture$StorageType.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/PPC64Architecture.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/PPC64Architecture.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/TypeClass.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/TypeClass.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixCallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixCallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv1CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv1CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv2CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv2CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64leLinker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64leLinker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64leLinker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture$Regs.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture$StorageType.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$BindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$Bindings.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$BoxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$StorageCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$UnboxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64Linker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64Linker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64Linker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/TypeClass$FieldCounter.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/TypeClass$FlattenedFieldDesc.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/TypeClass.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/TypeClass.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/S390Architecture$Regs.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/S390Architecture$StorageType.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/S390Architecture.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/S390Architecture.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$BindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$Bindings.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$BoxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$StorageCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$UnboxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/TypeClass.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/s390/linux/TypeClass.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/X86_64Architecture$Regs.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/X86_64Architecture$StorageType.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/X86_64Architecture.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/X86_64Architecture.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/ArgumentClassImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/ArgumentClassImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$BindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$Bindings.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$BoxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$StorageCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$UnboxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/TypeClass$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/TypeClass$Kind.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/TypeClass.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/TypeClass.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$1.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$1CallingSequenceBuilderHelper.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$BindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$Bindings.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$BoxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$StorageCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$UnboxBindingCalculator.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/TypeClass.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/TypeClass.java create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker.class create mode 100644 tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker.java create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/AbstractGroupLayout$Kind.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/AbstractGroupLayout.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/AbstractGroupLayout.java create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/AbstractLayout$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/AbstractLayout.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/AbstractLayout.java create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/MemoryLayoutUtil.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/MemoryLayoutUtil.java create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/PaddingLayoutImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/PaddingLayoutImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/SequenceLayoutImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/SequenceLayoutImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/StructLayoutImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/StructLayoutImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/UnionLayoutImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/UnionLayoutImpl.java create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$AbstractValueLayout$1VarHandleCache.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$AbstractValueLayout.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfAddressImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfBooleanImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfByteImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfCharImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfDoubleImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfFloatImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfIntImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfLongImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfShortImpl.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts.class create mode 100644 tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/BMPSet.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/BMPSet.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/CharTrie.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/CharTrie.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/CharacterIteratorWrapper.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/CharacterIteratorWrapper.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/ICUBinary$1.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/ICUBinary$Authenticate.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/ICUBinary$IsAcceptable.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/ICUBinary.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/ICUBinary.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$ComposeNormalizer2.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$DecomposeNormalizer2.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$NFCSingleton.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$NFKCSingleton.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$NoopNormalizer2.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$Norm2AllModesSingleton.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$Normalizer2WithImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$Hangul.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$IsAcceptable.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$NextCCArgs.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$PrevArgs.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$ReorderingBuffer.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$UTF16Plus.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Punycode.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Punycode.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/ReplaceableUCharacterIterator.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/ReplaceableUCharacterIterator.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/StringPrepDataReader.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/StringPrepDataReader.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie$DataManipulate.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie$DefaultGetFoldingOffset.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie2$1.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie2$Range.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie2$Trie2Iterator.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie2$UTrie2Header.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie2$ValueMapper.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie2.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie2.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie2_16.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Trie2_16.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UBiDiProps$IsAcceptable.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UBiDiProps.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UBiDiProps.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$1.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$BiDiIntProperty.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$CombiningClassIntProperty.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$IntProperty.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$IsAcceptable.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$NormQuickCheckIntProperty.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UnicodeSetStringSpan$OffsetList.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UnicodeSetStringSpan.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/UnicodeSetStringSpan.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Utility.class create mode 100644 tests/test_data/std/jdk/internal/icu/impl/Utility.java create mode 100644 tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/nfc.nrm create mode 100644 tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/nfkc.nrm create mode 100644 tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/ubidi.icu create mode 100644 tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/uprops.icu create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacter$HangulSyllableType.class create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacter$JoiningGroup.class create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacter$NumericType.class create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacter.class create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacter.java create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacterDirection.class create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacterDirection.java create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacterEnums$ECharacterCategory.class create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacterEnums$ECharacterDirection.class create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacterEnums.class create mode 100644 tests/test_data/std/jdk/internal/icu/lang/UCharacterEnums.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$BidiPairedBracketType.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$BracketData.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$ImpTabPair.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$InsertPoints.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$IsoRun.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$Isolate.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$LevState.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$NumericShapings.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$Opening.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$Point.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$TextAttributeConstants$1.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase$TextAttributeConstants.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiBase.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiLine.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiLine.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiRun.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiRun.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiWriter.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/BidiWriter.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/FilteredNormalizer2.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/FilteredNormalizer2.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/Normalizer2.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/Normalizer2.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$1.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$Mode.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$ModeImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFC32ModeImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFCMode.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFCModeImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFD32ModeImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFDMode.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFDModeImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKC32ModeImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKCMode.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKCModeImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKD32ModeImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKDMode.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKDModeImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NONEMode.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase$Unicode32.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/NormalizerBase.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/Replaceable.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/Replaceable.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/ReplaceableString.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/ReplaceableString.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/StringPrep$StringPrepTrieImpl.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/StringPrep$Values.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/StringPrep.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/StringPrep.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/UCharacterIterator.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/UCharacterIterator.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/UTF16.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/UTF16.java create mode 100644 tests/test_data/std/jdk/internal/icu/text/UnicodeSet$Filter.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/UnicodeSet$SpanCondition.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/UnicodeSet$VersionFilter.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/UnicodeSet.class create mode 100644 tests/test_data/std/jdk/internal/icu/text/UnicodeSet.java create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointMap$Range.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointMap$RangeIterator.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointMap$RangeOption.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointMap$StringIterator.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointMap$ValueFilter.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointMap.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointMap.java create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data16.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data32.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data8.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast$FastStringIterator.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast16.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast32.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast8.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Small$SmallStringIterator.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Small.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Small16.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Small32.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Small8.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Type.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie$ValueWidth.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/CodePointTrie.java create mode 100644 tests/test_data/std/jdk/internal/icu/util/OutputInt.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/OutputInt.java create mode 100644 tests/test_data/std/jdk/internal/icu/util/VersionInfo.class create mode 100644 tests/test_data/std/jdk/internal/icu/util/VersionInfo.java create mode 100644 tests/test_data/std/jdk/internal/io/JdkConsole.class create mode 100644 tests/test_data/std/jdk/internal/io/JdkConsole.java create mode 100644 tests/test_data/std/jdk/internal/io/JdkConsoleImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/io/JdkConsoleImpl$2.class create mode 100644 tests/test_data/std/jdk/internal/io/JdkConsoleImpl$LineReader.class create mode 100644 tests/test_data/std/jdk/internal/io/JdkConsoleImpl.class create mode 100644 tests/test_data/std/jdk/internal/io/JdkConsoleImpl.java create mode 100644 tests/test_data/std/jdk/internal/io/JdkConsoleProvider.class create mode 100644 tests/test_data/std/jdk/internal/io/JdkConsoleProvider.java create mode 100644 tests/test_data/std/jdk/internal/javac/NoPreview.class create mode 100644 tests/test_data/std/jdk/internal/javac/NoPreview.java create mode 100644 tests/test_data/std/jdk/internal/javac/ParticipatesInPreview.class create mode 100644 tests/test_data/std/jdk/internal/javac/ParticipatesInPreview.java create mode 100644 tests/test_data/std/jdk/internal/javac/PreviewFeature$Feature.class create mode 100644 tests/test_data/std/jdk/internal/javac/PreviewFeature$JEP.class create mode 100644 tests/test_data/std/jdk/internal/javac/PreviewFeature.class create mode 100644 tests/test_data/std/jdk/internal/javac/PreviewFeature.java create mode 100644 tests/test_data/std/jdk/internal/javac/Restricted.class create mode 100644 tests/test_data/std/jdk/internal/javac/Restricted.java create mode 100644 tests/test_data/std/jdk/internal/jimage/BasicImageReader$1.class create mode 100644 tests/test_data/std/jdk/internal/jimage/BasicImageReader$2.class create mode 100644 tests/test_data/std/jdk/internal/jimage/BasicImageReader.class create mode 100644 tests/test_data/std/jdk/internal/jimage/BasicImageReader.java create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageBufferCache$1.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageBufferCache$2.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageBufferCache.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageBufferCache.java create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageHeader.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageHeader.java create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageLocation.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageLocation.java create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReader$Directory.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReader$LinkNode.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReader$Node.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReader$Resource.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReader$SharedImageReader$LocationVisitor.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReader$SharedImageReader.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReader.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReader.java create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReaderFactory$1.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReaderFactory.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageReaderFactory.java create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageStream.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageStream.java create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageStrings.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageStrings.java create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageStringsReader.class create mode 100644 tests/test_data/std/jdk/internal/jimage/ImageStringsReader.java create mode 100644 tests/test_data/std/jdk/internal/jimage/NativeImageBuffer$1.class create mode 100644 tests/test_data/std/jdk/internal/jimage/NativeImageBuffer.class create mode 100644 tests/test_data/std/jdk/internal/jimage/NativeImageBuffer.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/CompressIndexes.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/CompressIndexes.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/CompressedResourceHeader.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/CompressedResourceHeader.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/Decompressor.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/Decompressor.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressor$StringsProvider.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressor.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressor.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser$ParseResult.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressor.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressor.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressor.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressor.java create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressorFactory.class create mode 100644 tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java create mode 100644 tests/test_data/std/jdk/internal/jmod/JmodFile$Entry.class create mode 100644 tests/test_data/std/jdk/internal/jmod/JmodFile$Section.class create mode 100644 tests/test_data/std/jdk/internal/jmod/JmodFile.class create mode 100644 tests/test_data/std/jdk/internal/jmod/JmodFile.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/ExplodedImage$PathNode.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/ExplodedImage.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/ExplodedImage.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtDirectoryStream$1.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtDirectoryStream.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtDirectoryStream.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributeView$AttrID.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributeView.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributeView.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributes.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributes.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileStore.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileStore.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem$1.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileSystemProvider$1.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileSystemProvider$JrtFsLoader.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileSystemProvider.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtFileSystemProvider.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtPath$1.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtPath$2.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtPath.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtPath.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtUtils.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/JrtUtils.java create mode 100644 tests/test_data/std/jdk/internal/jrtfs/SystemImage$1.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/SystemImage$2.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/SystemImage.class create mode 100644 tests/test_data/std/jdk/internal/jrtfs/SystemImage.java create mode 100644 tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue$Memoizer$RecursiveInvocationException.class create mode 100644 tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue$Memoizer.class create mode 100644 tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue$Sub.class create mode 100644 tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue.class create mode 100644 tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue.java create mode 100644 tests/test_data/std/jdk/internal/loader/ArchivedClassLoaders.class create mode 100644 tests/test_data/std/jdk/internal/loader/ArchivedClassLoaders.java create mode 100644 tests/test_data/std/jdk/internal/loader/BootLoader$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/BootLoader$PackageHelper$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/BootLoader$PackageHelper$2.class create mode 100644 tests/test_data/std/jdk/internal/loader/BootLoader$PackageHelper.class create mode 100644 tests/test_data/std/jdk/internal/loader/BootLoader.class create mode 100644 tests/test_data/std/jdk/internal/loader/BootLoader.java create mode 100644 tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$2.class create mode 100644 tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$3.class create mode 100644 tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$4.class create mode 100644 tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$5.class create mode 100644 tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$LoadedModule.class create mode 100644 tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$NullModuleReader.class create mode 100644 tests/test_data/std/jdk/internal/loader/BuiltinClassLoader.class create mode 100644 tests/test_data/std/jdk/internal/loader/BuiltinClassLoader.java create mode 100644 tests/test_data/std/jdk/internal/loader/ClassLoaderHelper.class create mode 100644 tests/test_data/std/jdk/internal/loader/ClassLoaderHelper.java create mode 100644 tests/test_data/std/jdk/internal/loader/ClassLoaderValue.class create mode 100644 tests/test_data/std/jdk/internal/loader/ClassLoaderValue.java create mode 100644 tests/test_data/std/jdk/internal/loader/ClassLoaders$AppClassLoader.class create mode 100644 tests/test_data/std/jdk/internal/loader/ClassLoaders$BootClassLoader.class create mode 100644 tests/test_data/std/jdk/internal/loader/ClassLoaders$PlatformClassLoader.class create mode 100644 tests/test_data/std/jdk/internal/loader/ClassLoaders.class create mode 100644 tests/test_data/std/jdk/internal/loader/ClassLoaders.java create mode 100644 tests/test_data/std/jdk/internal/loader/FileURLMapper.class create mode 100644 tests/test_data/std/jdk/internal/loader/FileURLMapper.java create mode 100644 tests/test_data/std/jdk/internal/loader/Loader$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/Loader$2.class create mode 100644 tests/test_data/std/jdk/internal/loader/Loader$3.class create mode 100644 tests/test_data/std/jdk/internal/loader/Loader$LoadedModule.class create mode 100644 tests/test_data/std/jdk/internal/loader/Loader$NullModuleReader.class create mode 100644 tests/test_data/std/jdk/internal/loader/Loader.class create mode 100644 tests/test_data/std/jdk/internal/loader/Loader.java create mode 100644 tests/test_data/std/jdk/internal/loader/LoaderPool.class create mode 100644 tests/test_data/std/jdk/internal/loader/LoaderPool.java create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$2.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$3.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$CountedLock.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$LibraryPaths.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$NativeLibraryContext$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$NativeLibraryContext.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$NativeLibraryImpl$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$NativeLibraryImpl.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries$Unloader.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibraries.java create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibrary.class create mode 100644 tests/test_data/std/jdk/internal/loader/NativeLibrary.java create mode 100644 tests/test_data/std/jdk/internal/loader/RawNativeLibraries$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/RawNativeLibraries$RawNativeLibraryImpl.class create mode 100644 tests/test_data/std/jdk/internal/loader/RawNativeLibraries.class create mode 100644 tests/test_data/std/jdk/internal/loader/RawNativeLibraries.java create mode 100644 tests/test_data/std/jdk/internal/loader/Resource.class create mode 100644 tests/test_data/std/jdk/internal/loader/Resource.java create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$2.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$3.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$FileLoader$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$FileLoader.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$JarLoader$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$JarLoader$2.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$JarLoader.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$Loader$1.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath$Loader.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath.class create mode 100644 tests/test_data/std/jdk/internal/loader/URLClassPath.java create mode 100644 tests/test_data/std/jdk/internal/logger/AbstractLoggerWrapper.class create mode 100644 tests/test_data/std/jdk/internal/logger/AbstractLoggerWrapper.java create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger$BootstrapExecutors$1.class create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger$BootstrapExecutors$BootstrapMessageLoggerTask.class create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger$BootstrapExecutors.class create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger$DetectBackend$1.class create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger$DetectBackend.class create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger$LogEvent.class create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger$LoggingBackend.class create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger$RedirectedLoggers.class create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger.class create mode 100644 tests/test_data/std/jdk/internal/logger/BootstrapLogger.java create mode 100644 tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder$1.class create mode 100644 tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder$SharedLoggers.class create mode 100644 tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder.class create mode 100644 tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder.java create mode 100644 tests/test_data/std/jdk/internal/logger/LazyLoggers$1.class create mode 100644 tests/test_data/std/jdk/internal/logger/LazyLoggers$JdkLazyLogger.class create mode 100644 tests/test_data/std/jdk/internal/logger/LazyLoggers$LazyLoggerAccessor.class create mode 100644 tests/test_data/std/jdk/internal/logger/LazyLoggers$LazyLoggerFactories.class create mode 100644 tests/test_data/std/jdk/internal/logger/LazyLoggers$LazyLoggerWrapper.class create mode 100644 tests/test_data/std/jdk/internal/logger/LazyLoggers$LoggerAccessor.class create mode 100644 tests/test_data/std/jdk/internal/logger/LazyLoggers.class create mode 100644 tests/test_data/std/jdk/internal/logger/LazyLoggers.java create mode 100644 tests/test_data/std/jdk/internal/logger/LocalizedLoggerWrapper.class create mode 100644 tests/test_data/std/jdk/internal/logger/LocalizedLoggerWrapper.java create mode 100644 tests/test_data/std/jdk/internal/logger/LoggerFinderLoader$ErrorPolicy.class create mode 100644 tests/test_data/std/jdk/internal/logger/LoggerFinderLoader$TemporaryLoggerFinder$1.class create mode 100644 tests/test_data/std/jdk/internal/logger/LoggerFinderLoader$TemporaryLoggerFinder.class create mode 100644 tests/test_data/std/jdk/internal/logger/LoggerFinderLoader.class create mode 100644 tests/test_data/std/jdk/internal/logger/LoggerFinderLoader.java create mode 100644 tests/test_data/std/jdk/internal/logger/LoggerWrapper.class create mode 100644 tests/test_data/std/jdk/internal/logger/LoggerWrapper.java create mode 100644 tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger$CallerFinder$1.class create mode 100644 tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger$CallerFinder.class create mode 100644 tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger$Formatting.class create mode 100644 tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger.class create mode 100644 tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger.java create mode 100644 tests/test_data/std/jdk/internal/logger/SurrogateLogger.class create mode 100644 tests/test_data/std/jdk/internal/logger/SurrogateLogger.java create mode 100644 tests/test_data/std/jdk/internal/logger/package-info.java create mode 100644 tests/test_data/std/jdk/internal/math/DoubleConsts.class create mode 100644 tests/test_data/std/jdk/internal/math/DoubleConsts.java create mode 100644 tests/test_data/std/jdk/internal/math/DoubleToDecimal.class create mode 100644 tests/test_data/std/jdk/internal/math/DoubleToDecimal.java create mode 100644 tests/test_data/std/jdk/internal/math/FDBigInteger.class create mode 100644 tests/test_data/std/jdk/internal/math/FDBigInteger.java create mode 100644 tests/test_data/std/jdk/internal/math/FloatConsts.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatConsts.java create mode 100644 tests/test_data/std/jdk/internal/math/FloatToDecimal.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatToDecimal.java create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal$1.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal$ASCIIToBinaryBuffer.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal$ASCIIToBinaryConverter.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal$BinaryToASCIIBuffer.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal$BinaryToASCIIConverter.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal$ExceptionalBinaryToASCIIBuffer.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal$HexFloatPattern.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal$PreparedASCIIToBinaryBuffer.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal.class create mode 100644 tests/test_data/std/jdk/internal/math/FloatingDecimal.java create mode 100644 tests/test_data/std/jdk/internal/math/FormattedFPDecimal.class create mode 100644 tests/test_data/std/jdk/internal/math/FormattedFPDecimal.java create mode 100644 tests/test_data/std/jdk/internal/math/MathUtils.class create mode 100644 tests/test_data/std/jdk/internal/math/MathUtils.java create mode 100644 tests/test_data/std/jdk/internal/misc/Blocker.class create mode 100644 tests/test_data/std/jdk/internal/misc/Blocker.java create mode 100644 tests/test_data/std/jdk/internal/misc/CDS.class create mode 100644 tests/test_data/std/jdk/internal/misc/CDS.java create mode 100644 tests/test_data/std/jdk/internal/misc/CarrierThread$1.class create mode 100644 tests/test_data/std/jdk/internal/misc/CarrierThread$ForkJoinPools.class create mode 100644 tests/test_data/std/jdk/internal/misc/CarrierThread.class create mode 100644 tests/test_data/std/jdk/internal/misc/CarrierThread.java create mode 100644 tests/test_data/std/jdk/internal/misc/CarrierThreadLocal.class create mode 100644 tests/test_data/std/jdk/internal/misc/CarrierThreadLocal.java create mode 100644 tests/test_data/std/jdk/internal/misc/ExtendedMapMode.class create mode 100644 tests/test_data/std/jdk/internal/misc/ExtendedMapMode.java create mode 100644 tests/test_data/std/jdk/internal/misc/FileSystemOption.class create mode 100644 tests/test_data/std/jdk/internal/misc/FileSystemOption.java create mode 100644 tests/test_data/std/jdk/internal/misc/InnocuousThread$1.class create mode 100644 tests/test_data/std/jdk/internal/misc/InnocuousThread$2.class create mode 100644 tests/test_data/std/jdk/internal/misc/InnocuousThread$3.class create mode 100644 tests/test_data/std/jdk/internal/misc/InnocuousThread$4.class create mode 100644 tests/test_data/std/jdk/internal/misc/InnocuousThread.class create mode 100644 tests/test_data/std/jdk/internal/misc/InnocuousThread.java create mode 100644 tests/test_data/std/jdk/internal/misc/InternalLock.class create mode 100644 tests/test_data/std/jdk/internal/misc/InternalLock.java create mode 100644 tests/test_data/std/jdk/internal/misc/MethodFinder.class create mode 100644 tests/test_data/std/jdk/internal/misc/MethodFinder.java create mode 100644 tests/test_data/std/jdk/internal/misc/OSEnvironment.class create mode 100644 tests/test_data/std/jdk/internal/misc/OSEnvironment.java create mode 100644 tests/test_data/std/jdk/internal/misc/PreviewFeatures.class create mode 100644 tests/test_data/std/jdk/internal/misc/PreviewFeatures.java create mode 100644 tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess$Scoped.class create mode 100644 tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess$ScopedAccessError.class create mode 100644 tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess.class create mode 100644 tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess.java create mode 100644 tests/test_data/std/jdk/internal/misc/Signal$1.class create mode 100644 tests/test_data/std/jdk/internal/misc/Signal$Handler.class create mode 100644 tests/test_data/std/jdk/internal/misc/Signal$NativeHandler.class create mode 100644 tests/test_data/std/jdk/internal/misc/Signal.class create mode 100644 tests/test_data/std/jdk/internal/misc/Signal.java create mode 100644 tests/test_data/std/jdk/internal/misc/TerminatingThreadLocal$1.class create mode 100644 tests/test_data/std/jdk/internal/misc/TerminatingThreadLocal.class create mode 100644 tests/test_data/std/jdk/internal/misc/TerminatingThreadLocal.java create mode 100644 tests/test_data/std/jdk/internal/misc/ThreadFlock$ThreadContainerImpl.class create mode 100644 tests/test_data/std/jdk/internal/misc/ThreadFlock.class create mode 100644 tests/test_data/std/jdk/internal/misc/ThreadFlock.java create mode 100644 tests/test_data/std/jdk/internal/misc/ThreadTracker$ThreadRef.class create mode 100644 tests/test_data/std/jdk/internal/misc/ThreadTracker.class create mode 100644 tests/test_data/std/jdk/internal/misc/ThreadTracker.java create mode 100644 tests/test_data/std/jdk/internal/misc/Unsafe.class create mode 100644 tests/test_data/std/jdk/internal/misc/Unsafe.java create mode 100644 tests/test_data/std/jdk/internal/misc/UnsafeConstants.class create mode 100644 tests/test_data/std/jdk/internal/misc/UnsafeConstants.java create mode 100644 tests/test_data/std/jdk/internal/misc/VM$BufferPool.class create mode 100644 tests/test_data/std/jdk/internal/misc/VM$BufferPoolsHolder.class create mode 100644 tests/test_data/std/jdk/internal/misc/VM.class create mode 100644 tests/test_data/std/jdk/internal/misc/VM.java create mode 100644 tests/test_data/std/jdk/internal/misc/VirtualThreads.class create mode 100644 tests/test_data/std/jdk/internal/misc/VirtualThreads.java create mode 100644 tests/test_data/std/jdk/internal/module/ArchivedBootLayer.class create mode 100644 tests/test_data/std/jdk/internal/module/ArchivedBootLayer.java create mode 100644 tests/test_data/std/jdk/internal/module/ArchivedModuleGraph.class create mode 100644 tests/test_data/std/jdk/internal/module/ArchivedModuleGraph.java create mode 100644 tests/test_data/std/jdk/internal/module/Builder.class create mode 100644 tests/test_data/std/jdk/internal/module/Builder.java create mode 100644 tests/test_data/std/jdk/internal/module/Checks.class create mode 100644 tests/test_data/std/jdk/internal/module/Checks.java create mode 100644 tests/test_data/std/jdk/internal/module/ClassFileConstants.class create mode 100644 tests/test_data/std/jdk/internal/module/ClassFileConstants.java create mode 100644 tests/test_data/std/jdk/internal/module/DefaultRoots.class create mode 100644 tests/test_data/std/jdk/internal/module/DefaultRoots.java create mode 100644 tests/test_data/std/jdk/internal/module/ExplodedSystemModules.class create mode 100644 tests/test_data/std/jdk/internal/module/ExplodedSystemModules.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleBootstrap$1.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleBootstrap$Counters.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleBootstrap$SafeModuleFinder.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleBootstrap.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleBootstrap.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleHashes$Builder.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleHashes$HashSupplier.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleHashes.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleHashes.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleHashesBuilder$Graph$Builder.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleHashesBuilder$Graph.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleHashesBuilder$TopoSorter.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleHashesBuilder.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleHashesBuilder.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo$Attributes.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo$ConstantPool$Entry.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo$ConstantPool$Index2Entry.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo$ConstantPool$IndexEntry.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo$ConstantPool$ValueEntry.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo$ConstantPool.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo$CountingDataInput.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo$DataInputWrapper.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfo.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfoExtender.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleInfoExtender.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleLoaderMap$Mapper.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleLoaderMap$Modules.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleLoaderMap.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleLoaderMap.java create mode 100644 tests/test_data/std/jdk/internal/module/ModulePatcher$ExplodedResourceFinder$1.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePatcher$ExplodedResourceFinder.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePatcher$JarResourceFinder$1.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePatcher$JarResourceFinder.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePatcher$PatchedModuleReader$1.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePatcher$PatchedModuleReader.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePatcher$ResourceFinder.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePatcher.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePatcher.java create mode 100644 tests/test_data/std/jdk/internal/module/ModulePath$Patterns.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePath.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePath.java create mode 100644 tests/test_data/std/jdk/internal/module/ModulePathValidator.class create mode 100644 tests/test_data/std/jdk/internal/module/ModulePathValidator.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleReferenceImpl$CachedHash.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleReferenceImpl.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleReferenceImpl.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleReferences$ExplodedModuleReader.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleReferences$JModModuleReader.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleReferences$JarModuleReader.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleReferences$SafeCloseModuleReader.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleReferences.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleReferences.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleResolution.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleResolution.java create mode 100644 tests/test_data/std/jdk/internal/module/ModuleTarget.class create mode 100644 tests/test_data/std/jdk/internal/module/ModuleTarget.java create mode 100644 tests/test_data/std/jdk/internal/module/Modules.class create mode 100644 tests/test_data/std/jdk/internal/module/Modules.java create mode 100644 tests/test_data/std/jdk/internal/module/Resources.class create mode 100644 tests/test_data/std/jdk/internal/module/Resources.java create mode 100644 tests/test_data/std/jdk/internal/module/ServicesCatalog$ServiceProvider.class create mode 100644 tests/test_data/std/jdk/internal/module/ServicesCatalog.class create mode 100644 tests/test_data/std/jdk/internal/module/ServicesCatalog.java create mode 100644 tests/test_data/std/jdk/internal/module/SystemModuleFinders$1.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModuleFinders$2.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModuleFinders$3.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModuleFinders$ModuleContentSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModuleFinders$SystemImage.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModuleFinders$SystemModuleFinder.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModuleFinders$SystemModuleReader.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModuleFinders.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModuleFinders.java create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules$0.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules$1.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules$2.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules$3.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules$4.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules$5.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules$all.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules$default.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModules.java create mode 100644 tests/test_data/std/jdk/internal/module/SystemModulesMap.class create mode 100644 tests/test_data/std/jdk/internal/module/SystemModulesMap.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/AnnotationVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/AnnotationVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/AnnotationWriter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/AnnotationWriter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Attribute$Set.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Attribute.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Attribute.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ByteVector.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ByteVector.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ClassReader.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ClassReader.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ClassTooLargeException.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ClassTooLargeException.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ClassVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ClassVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ClassWriter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ClassWriter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ConstantDynamic.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ConstantDynamic.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Constants.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Constants.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Context.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Context.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/CurrentFrame.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/CurrentFrame.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Edge.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Edge.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/FieldVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/FieldVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/FieldWriter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/FieldWriter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Frame.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Frame.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Handle.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Handle.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Handler.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Handler.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Label.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Label.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/MethodTooLargeException.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/MethodTooLargeException.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/MethodVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/MethodVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/MethodWriter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/MethodWriter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleWriter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleWriter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Opcodes.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Opcodes.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentWriter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentWriter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Symbol.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Symbol.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable$Entry.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable$LabelEntry.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Type.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/Type.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/TypePath.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/TypePath.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/TypeReference.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/TypeReference.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ClassRemapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/FieldRemapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter$Instantiation.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/Method.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/Method.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/MethodRemapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ModuleHashesAttribute.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ModuleHashesAttribute.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ModuleRemapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ModuleRemapper.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ModuleResolutionAttribute.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ModuleResolutionAttribute.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ModuleTargetAttribute.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/ModuleTargetAttribute.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/RecordComponentRemapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/RecordComponentRemapper.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/Remapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/Remapper.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder$Item.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/TableSwitchGenerator.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/TableSwitchGenerator.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter$1.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/signature/SignatureReader.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/signature/SignatureReader.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/signature/SignatureWriter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/AbstractInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/AbstractInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/AnnotationNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ClassNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ClassNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/FieldInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/FieldInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/FieldNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/FieldNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/FrameNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/FrameNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/IincInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/IincInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/InnerClassNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/InnerClassNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/InsnList$InsnListIterator.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/InsnList.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/InsnList.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/InsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/InsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/IntInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/IntInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/InvokeDynamicInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/InvokeDynamicInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/JumpInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/JumpInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LabelNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LabelNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LdcInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LdcInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LineNumberNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LineNumberNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LocalVariableAnnotationNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LocalVariableAnnotationNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LocalVariableNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LocalVariableNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LookupSwitchInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/LookupSwitchInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/MethodInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/MethodInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/MethodNode$1.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/MethodNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/MethodNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleExportNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleExportNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleOpenNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleOpenNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleProvideNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleProvideNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleRequireNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ModuleRequireNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/MultiANewArrayInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/MultiANewArrayInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ParameterNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/ParameterNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/RecordComponentNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/RecordComponentNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/TableSwitchInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/TableSwitchInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/TryCatchBlockNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/TryCatchBlockNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/TypeInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/TypeInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/UnsupportedClassVersionException.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/UnsupportedClassVersionException.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/Util.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/Util.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/VarInsnNode.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/VarInsnNode.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Analyzer.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Analyzer.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/AnalyzerException.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/AnalyzerException.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/BasicInterpreter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/BasicInterpreter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/BasicValue.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/BasicValue.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/BasicVerifier.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/BasicVerifier.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Frame.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Frame.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Interpreter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Interpreter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/SimpleVerifier.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/SimpleVerifier.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/SmallSet$IteratorImpl.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/SmallSet.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/SmallSet.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/SourceInterpreter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/SourceInterpreter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/SourceValue.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/SourceValue.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Subroutine.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Subroutine.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Value.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/tree/analysis/Value.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/ASMifier.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/ASMifier.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/ASMifierSupport.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/ASMifierSupport.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckAnnotationAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckAnnotationAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckClassAdapter$1.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckFrameAnalyzer.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckFrameAnalyzer.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter$1.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter$Method.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter$MethodWriterWrapper.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckModuleAdapter$NameSet.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckModuleAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckModuleAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckRecordComponentAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckRecordComponentAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckSignatureAdapter$State.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckSignatureAdapter.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/CheckSignatureAdapter.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/Printer.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/Printer.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/Textifier.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/Textifier.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TextifierSupport.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TextifierSupport.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceAnnotationVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceAnnotationVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceFieldVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceFieldVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceMethodVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceMethodVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceModuleVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceModuleVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceRecordComponentVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceRecordComponentVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.class create mode 100644 tests/test_data/std/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/Attributes.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/Attributes.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/ContentHandler.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/ContentHandler.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/DTDHandler.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/DTDHandler.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/EntityResolver.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/EntityResolver.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/ErrorHandler.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/ErrorHandler.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/InputSource.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/InputSource.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/Locator.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/Locator.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/SAXException.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/SAXException.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/SAXNotRecognizedException.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/SAXNotRecognizedException.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/SAXNotSupportedException.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/SAXNotSupportedException.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/SAXParseException.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/SAXParseException.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/XMLReader.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/XMLReader.java create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/helpers/DefaultHandler.class create mode 100644 tests/test_data/std/jdk/internal/org/xml/sax/helpers/DefaultHandler.java create mode 100644 tests/test_data/std/jdk/internal/perf/Perf$CleanerAction.class create mode 100644 tests/test_data/std/jdk/internal/perf/Perf$GetPerfAction.class create mode 100644 tests/test_data/std/jdk/internal/perf/Perf.class create mode 100644 tests/test_data/std/jdk/internal/perf/Perf.java create mode 100644 tests/test_data/std/jdk/internal/perf/PerfCounter$CoreCounters.class create mode 100644 tests/test_data/std/jdk/internal/perf/PerfCounter.class create mode 100644 tests/test_data/std/jdk/internal/perf/PerfCounter.java create mode 100644 tests/test_data/std/jdk/internal/platform/Container.class create mode 100644 tests/test_data/std/jdk/internal/platform/Container.java create mode 100644 tests/test_data/std/jdk/internal/platform/Metrics.class create mode 100644 tests/test_data/std/jdk/internal/platform/Metrics.java create mode 100644 tests/test_data/std/jdk/internal/platform/SystemMetrics.class create mode 100644 tests/test_data/std/jdk/internal/platform/SystemMetrics.java create mode 100644 tests/test_data/std/jdk/internal/random/L128X1024MixRandom.class create mode 100644 tests/test_data/std/jdk/internal/random/L128X1024MixRandom.java create mode 100644 tests/test_data/std/jdk/internal/random/L128X128MixRandom.class create mode 100644 tests/test_data/std/jdk/internal/random/L128X128MixRandom.java create mode 100644 tests/test_data/std/jdk/internal/random/L128X256MixRandom.class create mode 100644 tests/test_data/std/jdk/internal/random/L128X256MixRandom.java create mode 100644 tests/test_data/std/jdk/internal/random/L32X64MixRandom.class create mode 100644 tests/test_data/std/jdk/internal/random/L32X64MixRandom.java create mode 100644 tests/test_data/std/jdk/internal/random/L64X1024MixRandom.class create mode 100644 tests/test_data/std/jdk/internal/random/L64X1024MixRandom.java create mode 100644 tests/test_data/std/jdk/internal/random/L64X128MixRandom.class create mode 100644 tests/test_data/std/jdk/internal/random/L64X128MixRandom.java create mode 100644 tests/test_data/std/jdk/internal/random/L64X128StarStarRandom.class create mode 100644 tests/test_data/std/jdk/internal/random/L64X128StarStarRandom.java create mode 100644 tests/test_data/std/jdk/internal/random/L64X256MixRandom.class create mode 100644 tests/test_data/std/jdk/internal/random/L64X256MixRandom.java create mode 100644 tests/test_data/std/jdk/internal/random/Xoroshiro128PlusPlus.class create mode 100644 tests/test_data/std/jdk/internal/random/Xoroshiro128PlusPlus.java create mode 100644 tests/test_data/std/jdk/internal/random/Xoshiro256PlusPlus.class create mode 100644 tests/test_data/std/jdk/internal/random/Xoshiro256PlusPlus.java create mode 100644 tests/test_data/std/jdk/internal/ref/Cleaner$1.class create mode 100644 tests/test_data/std/jdk/internal/ref/Cleaner.class create mode 100644 tests/test_data/std/jdk/internal/ref/Cleaner.java create mode 100644 tests/test_data/std/jdk/internal/ref/CleanerFactory$1.class create mode 100644 tests/test_data/std/jdk/internal/ref/CleanerFactory.class create mode 100644 tests/test_data/std/jdk/internal/ref/CleanerFactory.java create mode 100644 tests/test_data/std/jdk/internal/ref/CleanerImpl$CleanerCleanable.class create mode 100644 tests/test_data/std/jdk/internal/ref/CleanerImpl$InnocuousThreadFactory.class create mode 100644 tests/test_data/std/jdk/internal/ref/CleanerImpl$PhantomCleanableRef.class create mode 100644 tests/test_data/std/jdk/internal/ref/CleanerImpl.class create mode 100644 tests/test_data/std/jdk/internal/ref/CleanerImpl.java create mode 100644 tests/test_data/std/jdk/internal/ref/PhantomCleanable.class create mode 100644 tests/test_data/std/jdk/internal/ref/PhantomCleanable.java create mode 100644 tests/test_data/std/jdk/internal/reflect/AccessorGenerator.class create mode 100644 tests/test_data/std/jdk/internal/reflect/AccessorGenerator.java create mode 100644 tests/test_data/std/jdk/internal/reflect/AccessorUtils.class create mode 100644 tests/test_data/std/jdk/internal/reflect/AccessorUtils.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ByteVector.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ByteVector.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ByteVectorFactory.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ByteVectorFactory.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ByteVectorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ByteVectorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/CallerSensitive.class create mode 100644 tests/test_data/std/jdk/internal/reflect/CallerSensitive.java create mode 100644 tests/test_data/std/jdk/internal/reflect/CallerSensitiveAdapter.class create mode 100644 tests/test_data/std/jdk/internal/reflect/CallerSensitiveAdapter.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ClassDefiner$1.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ClassDefiner.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ClassDefiner.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ClassFileAssembler.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ClassFileAssembler.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ClassFileConstants.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ClassFileConstants.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ConstantPool$Tag.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ConstantPool.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ConstantPool.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ConstructorAccessor.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ConstructorAccessor.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ConstructorAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ConstructorAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/CsMethodAccessorAdapter.class create mode 100644 tests/test_data/std/jdk/internal/reflect/CsMethodAccessorAdapter.java create mode 100644 tests/test_data/std/jdk/internal/reflect/DelegatingClassLoader.class create mode 100644 tests/test_data/std/jdk/internal/reflect/DirectConstructorHandleAccessor$NativeAccessor.class create mode 100644 tests/test_data/std/jdk/internal/reflect/DirectConstructorHandleAccessor.class create mode 100644 tests/test_data/std/jdk/internal/reflect/DirectConstructorHandleAccessor.java create mode 100644 tests/test_data/std/jdk/internal/reflect/DirectMethodHandleAccessor$NativeAccessor$ReflectiveInvoker.class create mode 100644 tests/test_data/std/jdk/internal/reflect/DirectMethodHandleAccessor$NativeAccessor.class create mode 100644 tests/test_data/std/jdk/internal/reflect/DirectMethodHandleAccessor.class create mode 100644 tests/test_data/std/jdk/internal/reflect/DirectMethodHandleAccessor.java create mode 100644 tests/test_data/std/jdk/internal/reflect/FieldAccessor.class create mode 100644 tests/test_data/std/jdk/internal/reflect/FieldAccessor.java create mode 100644 tests/test_data/std/jdk/internal/reflect/FieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/FieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/InstantiationExceptionConstructorAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/InstantiationExceptionConstructorAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/Label$PatchInfo.class create mode 100644 tests/test_data/std/jdk/internal/reflect/Label.class create mode 100644 tests/test_data/std/jdk/internal/reflect/Label.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MagicAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MagicAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodAccessor.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodAccessor.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleAccessorFactory$LazyStaticHolder.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleAccessorFactory.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleAccessorFactory.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleBooleanFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleBooleanFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleByteFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleByteFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleCharacterFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleCharacterFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleDoubleFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleDoubleFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleFloatFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleFloatFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleIntegerFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleIntegerFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleLongFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleLongFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleObjectFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleObjectFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleShortFieldAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/MethodHandleShortFieldAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/reflect/Reflection$1Holder.class create mode 100644 tests/test_data/std/jdk/internal/reflect/Reflection.class create mode 100644 tests/test_data/std/jdk/internal/reflect/Reflection.java create mode 100644 tests/test_data/std/jdk/internal/reflect/ReflectionFactory$Config.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ReflectionFactory$GetReflectionFactoryAction.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ReflectionFactory.class create mode 100644 tests/test_data/std/jdk/internal/reflect/ReflectionFactory.java create mode 100644 tests/test_data/std/jdk/internal/reflect/SerializationConstructorAccessorGenerator$1.class create mode 100644 tests/test_data/std/jdk/internal/reflect/SerializationConstructorAccessorGenerator.class create mode 100644 tests/test_data/std/jdk/internal/reflect/SerializationConstructorAccessorGenerator.java create mode 100644 tests/test_data/std/jdk/internal/reflect/SerializationConstructorAccessorImpl.class create mode 100644 tests/test_data/std/jdk/internal/reflect/SerializationConstructorAccessorImpl.java create mode 100644 tests/test_data/std/jdk/internal/util/Architecture.class create mode 100644 tests/test_data/std/jdk/internal/util/Architecture.java create mode 100644 tests/test_data/std/jdk/internal/util/ArraysSupport.class create mode 100644 tests/test_data/std/jdk/internal/util/ArraysSupport.java create mode 100644 tests/test_data/std/jdk/internal/util/ByteArray.class create mode 100644 tests/test_data/std/jdk/internal/util/ByteArray.java create mode 100644 tests/test_data/std/jdk/internal/util/ByteArrayLittleEndian.class create mode 100644 tests/test_data/std/jdk/internal/util/ByteArrayLittleEndian.java create mode 100644 tests/test_data/std/jdk/internal/util/ClassFileDumper$1.class create mode 100644 tests/test_data/std/jdk/internal/util/ClassFileDumper$2.class create mode 100644 tests/test_data/std/jdk/internal/util/ClassFileDumper.class create mode 100644 tests/test_data/std/jdk/internal/util/ClassFileDumper.java create mode 100644 tests/test_data/std/jdk/internal/util/DecimalDigits.class create mode 100644 tests/test_data/std/jdk/internal/util/DecimalDigits.java create mode 100644 tests/test_data/std/jdk/internal/util/HexDigits.class create mode 100644 tests/test_data/std/jdk/internal/util/HexDigits.java create mode 100644 tests/test_data/std/jdk/internal/util/ImmutableBitSetPredicate$SmallImmutableBitSetPredicate.class create mode 100644 tests/test_data/std/jdk/internal/util/ImmutableBitSetPredicate.class create mode 100644 tests/test_data/std/jdk/internal/util/ImmutableBitSetPredicate.java create mode 100644 tests/test_data/std/jdk/internal/util/NullableKeyValueHolder.class create mode 100644 tests/test_data/std/jdk/internal/util/NullableKeyValueHolder.java create mode 100644 tests/test_data/std/jdk/internal/util/OSVersion.class create mode 100644 tests/test_data/std/jdk/internal/util/OSVersion.java create mode 100644 tests/test_data/std/jdk/internal/util/OctalDigits.class create mode 100644 tests/test_data/std/jdk/internal/util/OctalDigits.java create mode 100644 tests/test_data/std/jdk/internal/util/OperatingSystem.class create mode 100644 tests/test_data/std/jdk/internal/util/OperatingSystem.java create mode 100644 tests/test_data/std/jdk/internal/util/PlatformProps.class create mode 100644 tests/test_data/std/jdk/internal/util/PlatformProps.java create mode 100644 tests/test_data/std/jdk/internal/util/Preconditions$1.class create mode 100644 tests/test_data/std/jdk/internal/util/Preconditions$2.class create mode 100644 tests/test_data/std/jdk/internal/util/Preconditions$3.class create mode 100644 tests/test_data/std/jdk/internal/util/Preconditions$4.class create mode 100644 tests/test_data/std/jdk/internal/util/Preconditions.class create mode 100644 tests/test_data/std/jdk/internal/util/Preconditions.java create mode 100644 tests/test_data/std/jdk/internal/util/ReferenceKey.class create mode 100644 tests/test_data/std/jdk/internal/util/ReferenceKey.java create mode 100644 tests/test_data/std/jdk/internal/util/ReferencedKeyMap$1.class create mode 100644 tests/test_data/std/jdk/internal/util/ReferencedKeyMap.class create mode 100644 tests/test_data/std/jdk/internal/util/ReferencedKeyMap.java create mode 100644 tests/test_data/std/jdk/internal/util/ReferencedKeySet.class create mode 100644 tests/test_data/std/jdk/internal/util/ReferencedKeySet.java create mode 100644 tests/test_data/std/jdk/internal/util/SoftReferenceKey.class create mode 100644 tests/test_data/std/jdk/internal/util/SoftReferenceKey.java create mode 100644 tests/test_data/std/jdk/internal/util/StaticProperty.class create mode 100644 tests/test_data/std/jdk/internal/util/StaticProperty.java create mode 100644 tests/test_data/std/jdk/internal/util/StrongReferenceKey.class create mode 100644 tests/test_data/std/jdk/internal/util/StrongReferenceKey.java create mode 100644 tests/test_data/std/jdk/internal/util/SystemProps$Raw.class create mode 100644 tests/test_data/std/jdk/internal/util/SystemProps.class create mode 100644 tests/test_data/std/jdk/internal/util/SystemProps.java create mode 100644 tests/test_data/std/jdk/internal/util/WeakReferenceKey.class create mode 100644 tests/test_data/std/jdk/internal/util/WeakReferenceKey.java create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractArbitrarilyJumpableGenerator$RandomArbitraryJumpsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractArbitrarilyJumpableGenerator$RandomDoublesSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractArbitrarilyJumpableGenerator$RandomIntsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractArbitrarilyJumpableGenerator$RandomJumpsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractArbitrarilyJumpableGenerator$RandomLeapsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractArbitrarilyJumpableGenerator$RandomLongsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractArbitrarilyJumpableGenerator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractSpliteratorGenerator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractSplittableGenerator$RandomDoublesSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractSplittableGenerator$RandomIntsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractSplittableGenerator$RandomLongsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractSplittableGenerator$RandomSplitsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractSplittableGenerator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractSplittableWithBrineGenerator$RandomSplitsSpliteratorWithSalt.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$AbstractSplittableWithBrineGenerator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$DoubleZigguratTables.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$RandomDoublesSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$RandomIntsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$RandomLongsSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport$RandomSpliterator.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport.class create mode 100644 tests/test_data/std/jdk/internal/util/random/RandomSupport.java create mode 100644 tests/test_data/std/jdk/internal/util/regex/Grapheme.class create mode 100644 tests/test_data/std/jdk/internal/util/regex/Grapheme.java create mode 100644 tests/test_data/std/jdk/internal/util/regex/IndicConjunctBreak.class create mode 100644 tests/test_data/std/jdk/internal/util/regex/IndicConjunctBreak.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/PropertiesDefaultHandler.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/PropertiesDefaultHandler.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/SAXParser.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/SAXParser.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/XMLStreamException.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/XMLStreamException.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/XMLStreamWriter.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/XMLStreamWriter.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/Attrs.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/Attrs.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/Input.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/Input.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/Pair.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/Pair.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/Parser.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/Parser.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/ParserSAX.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/ParserSAX.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/ReaderUTF16.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/ReaderUTF16.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/ReaderUTF8.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/ReaderUTF8.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/SAXParserImpl.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/SAXParserImpl.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/XMLStreamWriterImpl$Element.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/XMLStreamWriterImpl.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/XMLStreamWriterImpl.java create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/XMLWriter.class create mode 100644 tests/test_data/std/jdk/internal/util/xml/impl/XMLWriter.java create mode 100644 tests/test_data/std/jdk/internal/vm/Continuation$Pinned.class create mode 100644 tests/test_data/std/jdk/internal/vm/Continuation$PreemptStatus.class create mode 100644 tests/test_data/std/jdk/internal/vm/Continuation.class create mode 100644 tests/test_data/std/jdk/internal/vm/Continuation.java create mode 100644 tests/test_data/std/jdk/internal/vm/ContinuationScope.class create mode 100644 tests/test_data/std/jdk/internal/vm/ContinuationScope.java create mode 100644 tests/test_data/std/jdk/internal/vm/ContinuationSupport.class create mode 100644 tests/test_data/std/jdk/internal/vm/ContinuationSupport.java create mode 100644 tests/test_data/std/jdk/internal/vm/FillerObject.class create mode 100644 tests/test_data/std/jdk/internal/vm/FillerObject.java create mode 100644 tests/test_data/std/jdk/internal/vm/ForeignLinkerSupport.class create mode 100644 tests/test_data/std/jdk/internal/vm/ForeignLinkerSupport.java create mode 100644 tests/test_data/std/jdk/internal/vm/ScopedValueContainer$BindingsSnapshot.class create mode 100644 tests/test_data/std/jdk/internal/vm/ScopedValueContainer.class create mode 100644 tests/test_data/std/jdk/internal/vm/ScopedValueContainer.java create mode 100644 tests/test_data/std/jdk/internal/vm/SharedThreadContainer.class create mode 100644 tests/test_data/std/jdk/internal/vm/SharedThreadContainer.java create mode 100644 tests/test_data/std/jdk/internal/vm/StackChunk.class create mode 100644 tests/test_data/std/jdk/internal/vm/StackChunk.java create mode 100644 tests/test_data/std/jdk/internal/vm/StackableScope.class create mode 100644 tests/test_data/std/jdk/internal/vm/StackableScope.java create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadContainer.class create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadContainer.java create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadContainers$RootContainer$CountingRootContainer.class create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadContainers$RootContainer$TrackingRootContainer.class create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadContainers$RootContainer.class create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadContainers.class create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadContainers.java create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadDumper$BoundedByteArrayOutputStream.class create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadDumper.class create mode 100644 tests/test_data/std/jdk/internal/vm/ThreadDumper.java create mode 100644 tests/test_data/std/jdk/internal/vm/TranslatedException.class create mode 100644 tests/test_data/std/jdk/internal/vm/TranslatedException.java create mode 100644 tests/test_data/std/jdk/internal/vm/VMSupport$AnnotationDecoder.class create mode 100644 tests/test_data/std/jdk/internal/vm/VMSupport$IOReader.class create mode 100644 tests/test_data/std/jdk/internal/vm/VMSupport.class create mode 100644 tests/test_data/std/jdk/internal/vm/VMSupport.java create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/ChangesCurrentThread.class create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/ChangesCurrentThread.java create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/Contended.class create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/Contended.java create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/DontInline.class create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/DontInline.java create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/ForceInline.class create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/ForceInline.java create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/Hidden.class create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/Hidden.java create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/IntrinsicCandidate.class create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/IntrinsicCandidate.java create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/JvmtiMountTransition.class create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/JvmtiMountTransition.java create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/ReservedStackAccess.class create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/ReservedStackAccess.java create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/Stable.class create mode 100644 tests/test_data/std/jdk/internal/vm/annotation/Stable.java create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$BinaryOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$CompressExpandOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$FromBitsCoercedOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$IndexOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$IndexPartiallyInUpperRangeOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$LoadOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$LoadVectorMaskedOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$ReductionOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$ShuffleIotaOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$ShuffleToVectorOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$StoreVectorMaskedOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$StoreVectorOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$TernaryOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$UnaryOperation.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VecExtractOp.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VecInsertOp.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$Vector.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorBlendOp.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorBroadcastIntOp.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorCompareOp.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorConvertOp.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorMask.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorMaskOp.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorPayload.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorRearrangeOp.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorShuffle.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport$VectorSpecies.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport.class create mode 100644 tests/test_data/std/jdk/internal/vm/vector/VectorSupport.java diff --git a/tests/test_data/std/jdk/internal/ValueBased.class b/tests/test_data/std/jdk/internal/ValueBased.class new file mode 100644 index 0000000000000000000000000000000000000000..3c220a66a29ec9aad497b53893054e452b9bdeab GIT binary patch literal 384 zcmaiw%}N7749EYet)um$^&}#qc<9l608d(05d0|XS`bguZ78!&XJmJ_&{y-|1Ncy4 z)`NRl@Q_I+`TvrTukVjf0Am~|bO?v}{4FvraN)F#rrK6~txKLObP2;;uXJR!TSSku zoU@>?NjPn?+BqL|Fy2L1e<7j&L_FJ*kXerFMN)0as+ kA`mvjdU8yl1NHlEVO#vM{QFYdVeDcL`*rvVVhk|+0U%>;7XSbN literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/ValueBased.java b/tests/test_data/std/jdk/internal/ValueBased.java new file mode 100644 index 00000000..d27ab73c --- /dev/null +++ b/tests/test_data/std/jdk/internal/ValueBased.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.TYPE; + +/** + * Indicates the API declaration in question is associated with a Value Based class. + * References to value-based classes + * should produce warnings about behavior that is inconsistent with value based semantics. + * + * Note this internal annotation is handled specially by the javac compiler. + * To work properly with {@code --release older-release}, it requires special + * handling in {@code make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java} + * and {@code src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java}. + * + * @since 16 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value={TYPE}) +public @interface ValueBased { +} + diff --git a/tests/test_data/std/jdk/internal/access/JavaAWTAccess.class b/tests/test_data/std/jdk/internal/access/JavaAWTAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..bf95dad19ec5c0e9a651c69676b66a93870a19a0 GIT binary patch literal 177 zcmX^0Z`VEs1_oyaPId++Mh3;Klx+RXypq(Syu=*+#N_1E;$nTT#Ii)k@DN8ZkDY;q zkwG8}D5Rg0n3t~apOlrFTmlqIPc3mQD9A}Ian1+ouK)^(XlVMNE3{^0;0n$!ElN&x p%gjk-WDr6zTo0t2jgf(off?v11_nl;U91djAQl5VkYr-u005wtE^z<= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaAWTAccess.java b/tests/test_data/std/jdk/internal/access/JavaAWTAccess.java new file mode 100644 index 00000000..a4c170ca --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaAWTAccess.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +public interface JavaAWTAccess { + + // Returns the AppContext used for applet logging isolation, or null if + // no isolation is required. + // If there's no applet, or if the caller is a stand alone application, + // or running in the main app context, returns null. + // Otherwise, returns the AppContext of the calling applet. + public Object getAppletContext(); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.class b/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..c94de1d7b0e74565a2477e5cdfb3c27c13ee259b GIT binary patch literal 255 zcmZXP%?`m(5QWc_s-KOO@BoC3`v6u=6G=s4QDI?q)lIdUTWN=QHVY5np~Ni`65H>b znfd1axZVJGXgRP5{bY9#v1XNPnF<+(swl)vo~659PBYE!i#Vtf+KIs;l{ylOZK6UZ zbR)$}bzzq|kGCgQUZx9{+C+ol{M!#qtfR^32fbHJ2zIfTM@8uU4t&y$=li1-p&4YS kJXF&-HO0=K-nhI}BM>U)HNY~qHfkuX9n=jWG)j)<6C?{pTmS$7 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.java b/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.java new file mode 100644 index 00000000..139f0245 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaAWTFontAccess.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +/** + * SharedSecrets interface used for the access from java.text.Bidi + */ + +public interface JavaAWTFontAccess { + + // java.awt.font.TextAttribute constants + public Object getTextAttributeConstant(String name); + + // java.awt.font.NumericShaper + public void shape(Object shaper, char[] text, int start, int count); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaBeansAccess.class b/tests/test_data/std/jdk/internal/access/JavaBeansAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..8ede588ec570792e29a59efbe8efe8442412c23c GIT binary patch literal 519 zcmb7B!7ceBg9TP2q7kMacVPV%$W3Sx_iX8Irsn{C2DrD z6C~o+?^Rd5di7r4o?ie&SoPrvY!>N*%(WwB4TH9orS{|W$3QtNpd clazz, String property) throws Exception; + + /** + * Return the value attribute of the associated + * @ConstructorProperties annotation if that is present. + * @param ctr The constructor to extract the annotation value from + * @return The {@code value} attribute of the @ConstructorProperties + * annotation or {@code null} if the constructor is not annotated by + * this annotation or the annotation is not accessible. + */ + String[] getConstructorPropertiesValue(Constructor ctr); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaIOAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..3647ab4f3ffb4a489ed17080149061f884763a4b GIT binary patch literal 165 zcmX^0Z`VEs1_oyaPId++Mh1nflx+RXypq(Syu=*+#N_1E;$nTT#Ii(Be@8Hfoq>gs zK_Ck#qMwtPm#*)hl$DxX!pOj$oS#>mpOebSAgrP31D4Os*LQ{pS~D_m1?QI*C8xS& mf|Lj%o2Um;%*M#T$iNJA2m=En&;nKlHV}(}9Y``UZ~y?)iz(Lt literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaIOAccess.java b/tests/test_data/std/jdk/internal/access/JavaIOAccess.java new file mode 100644 index 00000000..532c1f25 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaIOAccess.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.io.Console; + +public interface JavaIOAccess { + Console console(); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..4ae3aded0841eaf39d1dddae50e4e80a42a29b05 GIT binary patch literal 776 zcmbtS%SyvQ6g^Yh#@0t)zOA^mo8|*5g;Et03Ka?>-A&Umrp8IgB;vQZ@B{oP@n$eW zk!0g0m)vva+_`7Y=hyoOfHBStlopeEo|$$gI(e` mh+U@IBxajB>4`Qv)Y&7Xgnjxy_~{?wNaM#iA&f$x8QpIzFxoNz literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.java b/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.java new file mode 100644 index 00000000..5e627abc --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaIOFileDescriptorAccess.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.access; + +import java.io.FileDescriptor; +import java.io.IOException; + +import jdk.internal.ref.PhantomCleanable; + +/* + * @author Chris Hegarty + */ + +public interface JavaIOFileDescriptorAccess { + public void set(FileDescriptor fdo, int fd); + public int get(FileDescriptor fdo); + public void setAppend(FileDescriptor fdo, boolean append); + public boolean getAppend(FileDescriptor fdo); + public void close(FileDescriptor fdo) throws IOException; + public void registerCleanup(FileDescriptor fdo); + public void registerCleanup(FileDescriptor fdo, PhantomCleanable cleanable); + public void unregisterCleanup(FileDescriptor fdo); + + // Only valid on Windows + public void setHandle(FileDescriptor fdo, long handle); + public long getHandle(FileDescriptor fdo); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..3311e2660056cc88d2952934b2439cb5365d6100 GIT binary patch literal 265 zcmZ{fO$x#=5QSgrPqi!21Gv>q18!XvK~RJi!~?__YHCcON%d|nJb;H1lOlqPt_J3N zeDmh@emnuJ5QPW`;^K6nQd?1JrYPfF7(=)0#y06%Dv^omDvgn)P8t-VOE4-Nr;6#E zrpH2XOEA{r?z5SyO`>eZ?3rLO+cim9(tp=--UbLJU(>-zo&QwPzN{-QyoO-f-Y@nC Y`ve3X_aqRwx;^yaYlnV1GVps0KmQC(MgRZ+ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.java b/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.java new file mode 100644 index 00000000..48a80ec7 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaIOFilePermissionAccess.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.access; + +import java.io.FilePermission; + +public interface JavaIOFilePermissionAccess { + + /** + * Returns a new FilePermission plus an alternative path. + * + * @param input the input + * @return the new FilePermission plus the alt path (as npath2) + * or the input itself if no alt path is available. + */ + FilePermission newPermPlusAltPath(FilePermission input); + + /** + * Returns a new FilePermission using an alternative path. + * + * @param input the input + * @return the new FilePermission using the alt path (as npath) + * or null if no alt path is available + */ + FilePermission newPermUsingAltPath(FilePermission input); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..20538b614c9bcbdfe84b8d78b6da3a6cd5e17dc8 GIT binary patch literal 206 zcmX^0Z`VEs1_oyaPId++Mh5Mylx+RXypq(Syu=*+#N_1E;$nTT#Ii(B|9~Q(cyLKk zYGSS<@noXyCfso?{b%gonD(rT><5k=Br z&B(wNoL^d$oa&aDlgh{-gTp>Oka28`42%rSKo>JGFaoV-Wncrb7}$X%69WeTL8m#+ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.java b/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.java new file mode 100644 index 00000000..ec205e27 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaIOPrintStreamAccess.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.access; + +import java.io.PrintStream; + +public interface JavaIOPrintStreamAccess { + Object lock(PrintStream ps); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.class b/tests/test_data/std/jdk/internal/access/JavaIOPrintWriterAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..c7f9370decb075616fa75978e4fbec99bdc48ef0 GIT binary patch literal 206 zcmX^0Z`VEs1_oyaPId++Mh5Mylx+RXypq(Syu=*+#N_1E;$nTT#Ii(B|9~Q(cz97J zP|gu7&d$KX$RLmfl+@2j%uCnzPs&P7E@5O~$;nU7W@OOR@BzzZ=IbMAwbq1)BI&SZ yWZ(+UFD*(=b<502Wn_@SVV@qzI5tKGMh0e}iy0Ugf!4D!uz^?%>_C!@=Hp;SWZ7xYFiZ13p>0hK^Vk(w`9HWu2D?xJL=`fVKe06wa!69fki zJy`bGGamc=dprS{VHlxBc+0b$vMzAxbfL5{TvckNzx6Wt)GqU1)28)d3%*nlI)qU! z3{_~iRmmo269`X!&u;3nITsw5@IGEQBPUW&7)ag1;~#9{Qyu^S literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.java b/tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.java new file mode 100644 index 00000000..f6c59908 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaIORandomAccessFileAccess.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + +public interface JavaIORandomAccessFileAccess { + public RandomAccessFile openAndDelete(File file, String mode) + throws IOException; +} diff --git a/tests/test_data/std/jdk/internal/access/JavaLangAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..0bc0dcae16f2431b0afba474e674bace8b226797 GIT binary patch literal 8769 zcmcgx`G4HR6@Q{84u)VSPE3Fh3M8;5z!Gk-3B(&GUgOxVcjM3)(#qP2tyn8380YN}0KqKC!e)ck4T#1`#b5b+`5 zcy=gi)6IF$b&iU7F{nir9Vtw#(U&|siiV7ZN*ucW!qA+tq-X}!N;7u7;)EN;Ll#|7 zaTk0$Zid1lHz#%Y`U9N^mSnB6hYjtaIOSnWMP>ic0qE^H<@z;+TQrkXJaocf-)KMV zwH6%~J(v?J&Fn<3v7Pp!dl8vZ;776T$J0UJS#(EEnRJL5`ouny4}Q2i$EdY;z`ND4 zql3O5#CGfkes#5h7|!S94NXK%znG}EQ~F|-wNtXe6Bdb_5^3~*U(Z(fIcudw_vCcL z)1B?mqI+}9%G;gtn8y-OI@=c4P{5pu%W@Z5%i$kIvXrMU1rFVxtEc5rTRF!BAjMy&wC0;iYn21RGFSeC6kY&K#Sn;IINwP<@N7SKyYSXpewwcw0D76eNcU0Nuc zy=JEA`_d20(&vja)x}WQwc~EQh*Q9#3DcmISlJ%IiJ=>>7S(wHXT)LPNg!6@B+Ix{ zDWTZF#jd{`EQ!M|P966V^o2}-)d|C<^o*`J0=q#s>!y7c^{<^P5Eh(~He0mYfw8fe z3Xh=i$>U}suxlcmwY{d`>_2FlZ%`!Gac(<-kBx-FkBcx~|2t+!i>f$ApRJ7H>(PZQ zy09j2xCpkwqQ-hsjl4(>n2{ELPlrK_a|_Nn6x40kH;YX3=wpw)&l+Js^nX?eWQg*}PB~+Y1VJ3dq1|8$r^3mmhx2-` zY34aXS?GjLY1^XGZrXO1>;=@!w8_fKRnfHBwc&@OL9Hpfgt4S0BE$oBtu`6>qbrRd zj4>1{RcPOrnYxsS342w9T;jXX3(y5>C}7Q@`-trGiK02vHj~z zMonNiP_M{sZcCUBdY;za(i;up9uO;EZ>%H9A?V1Aba`tuWqbQ%gtf|QVA?2mJJk?A zEZLs?o29sQT_bs2Xa&v9|eoLw;kb zMvY8JvIu5e)mC3NEk`x#yiQ|9kw^zmbs(#KBX1R#glroox{3&w zU0j4qc5HjWf<>8WOjV3-U)eiUU3Hume)N-z=F#b^foiZ8?a!N?bG6yjy56_kQ>{~dBC z$Ph_6Si*Xv8OtU9mU;#`B$J!1G!+b(si7_9yH&sIpYm`hGe+Bsl7>;P@+y=hIe_o?jR*N!WEdaFG}%%~)xb zdB*(8Tz;u+9&K6_uFHk?kss%O)fn z0$0ogPGf(+tio~RsrH zIOck5$Zf$-M`Frvp-;L7pMg&Lj8H7uo~IsIjI7n!)=i(uylfZ;%YDPM<_nQ#NCuMi zlnhsA@rX2tzwnAoH*-%Dfn(!Pln<4rSL$x$z)EBDOql5?X>}YPuC8NN2O@{7Rkp6G zW0qHH(NKrh<((;GdF0uf2OFiNouQ})%c7l$@+Q#1Zdr^h>kep>DfDs|!)I$G(4`~1 zO{ptL2f~KrQ}{Dc4D!B6R$z@E&PwY3-O@zT6zE5_alK}!2MT6a*2L10{f6WbOv9L; z(4n%`mCDvXV4!n0`L~0XkyBS;zCp>>l<*+AdgVM|EVZ2J>-8yB7*$v~StsATP zSvRb`vPqaBL9@(}!Jw@TJ6xJIg~{GM&i-loZ9Zn6MU!pAn*%&6qH7+vy(JNr`L`Yi zt_Tc7vlR# zvQvB>xI;Cj6Lbpei3b<(#ii3ND@)`tZJm6E0W}!Dh(d-D#SELY%3s~}Pak0TLHZEG57S2&ew04O@Z4d0>fGJJx*$ME~~1BOr1 z4;lW5e$4PG9rdT^Cyf7;e#Y?U^ovyPFCq6=^fa&kntsFZxAZ%Pzo$QNP5+Vq{)zq! PC@cFf^f&s){g?h5Tz0Zf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaLangAccess.java b/tests/test_data/std/jdk/internal/access/JavaLangAccess.java new file mode 100644 index 00000000..c31e745c --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaLangAccess.java @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.io.InputStream; +import java.io.PrintStream; +import java.lang.annotation.Annotation; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.net.URI; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.security.AccessControlContext; +import java.security.ProtectionDomain; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.RejectedExecutionException; +import java.util.stream.Stream; + +import jdk.internal.misc.CarrierThreadLocal; +import jdk.internal.module.ServicesCatalog; +import jdk.internal.reflect.ConstantPool; +import jdk.internal.vm.Continuation; +import jdk.internal.vm.ContinuationScope; +import jdk.internal.vm.StackableScope; +import jdk.internal.vm.ThreadContainer; +import sun.reflect.annotation.AnnotationType; +import sun.nio.ch.Interruptible; + +public interface JavaLangAccess { + + /** + * Returns the list of {@code Method} objects for the declared public + * methods of this class or interface that have the specified method name + * and parameter types. + */ + List getDeclaredPublicMethods(Class klass, String name, Class... parameterTypes); + + /** + * Return most specific method that matches name and parameterTypes. + */ + Method findMethod(Class klass, boolean publicOnly, String name, Class... parameterTypes); + + /** + * Return the constant pool for a class. + */ + ConstantPool getConstantPool(Class klass); + + /** + * Compare-And-Set the AnnotationType instance corresponding to this class. + * (This method only applies to annotation types.) + */ + boolean casAnnotationType(Class klass, AnnotationType oldType, AnnotationType newType); + + /** + * Get the AnnotationType instance corresponding to this class. + * (This method only applies to annotation types.) + */ + AnnotationType getAnnotationType(Class klass); + + /** + * Get the declared annotations for a given class, indexed by their types. + */ + Map, Annotation> getDeclaredAnnotationMap(Class klass); + + /** + * Get the array of bytes that is the class-file representation + * of this Class' annotations. + */ + byte[] getRawClassAnnotations(Class klass); + + /** + * Get the array of bytes that is the class-file representation + * of this Class' type annotations. + */ + byte[] getRawClassTypeAnnotations(Class klass); + + /** + * Get the array of bytes that is the class-file representation + * of this Executable's type annotations. + */ + byte[] getRawExecutableTypeAnnotations(Executable executable); + + /** + * Returns the elements of an enum class or null if the + * Class object does not represent an enum type; + * the result is uncloned, cached, and shared by all callers. + */ + > E[] getEnumConstantsShared(Class klass); + + /** + * Set current thread's blocker field. + */ + void blockedOn(Interruptible b); + + /** + * Registers a shutdown hook. + * + * It is expected that this method with registerShutdownInProgress=true + * is only used to register DeleteOnExitHook since the first file + * may be added to the delete on exit list by the application shutdown + * hooks. + * + * @param slot the slot in the shutdown hook array, whose element + * will be invoked in order during shutdown + * @param registerShutdownInProgress true to allow the hook + * to be registered even if the shutdown is in progress. + * @param hook the hook to be registered + * + * @throws IllegalStateException if shutdown is in progress and + * the slot is not valid to register. + */ + void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook); + + /** + * Returns a new Thread with the given Runnable and an + * inherited AccessControlContext. + */ + Thread newThreadWithAcc(Runnable target, @SuppressWarnings("removal") AccessControlContext acc); + + /** + * Invokes the finalize method of the given object. + */ + void invokeFinalize(Object o) throws Throwable; + + /** + * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s) + * associated with the given class loader, creating it if it doesn't already exist. + */ + ConcurrentHashMap createOrGetClassLoaderValueMap(ClassLoader cl); + + /** + * Defines a class with the given name to a class loader. + */ + Class defineClass(ClassLoader cl, String name, byte[] b, ProtectionDomain pd, String source); + + /** + * Defines a class with the given name to a class loader with + * the given flags and class data. + * + * @see java.lang.invoke.MethodHandles.Lookup#defineClass + */ + Class defineClass(ClassLoader cl, Class lookup, String name, byte[] b, ProtectionDomain pd, boolean initialize, int flags, Object classData); + + /** + * Returns a class loaded by the bootstrap class loader. + */ + Class findBootstrapClassOrNull(String name); + + /** + * Define a Package of the given name and module by the given class loader. + */ + Package definePackage(ClassLoader cl, String name, Module module); + + /** + * Record the non-exported packages of the modules in the given layer + */ + void addNonExportedPackages(ModuleLayer layer); + + /** + * Invalidate package access cache + */ + void invalidatePackageAccessCache(); + + /** + * Defines a new module to the Java virtual machine. The module + * is defined to the given class loader. + * + * The URI is for information purposes only, it can be {@code null}. + */ + Module defineModule(ClassLoader loader, ModuleDescriptor descriptor, URI uri); + + /** + * Defines the unnamed module for the given class loader. + */ + Module defineUnnamedModule(ClassLoader loader); + + /** + * Updates the readability so that module m1 reads m2. The new read edge + * does not result in a strong reference to m2 (m2 can be GC'ed). + * + * This method is the same as m1.addReads(m2) but without a permission check. + */ + void addReads(Module m1, Module m2); + + /** + * Updates module m to read all unnamed modules. + */ + void addReadsAllUnnamed(Module m); + + /** + * Updates module m1 to export a package unconditionally. + */ + void addExports(Module m1, String pkg); + + /** + * Updates module m1 to export a package to module m2. The export does + * not result in a strong reference to m2 (m2 can be GC'ed). + */ + void addExports(Module m1, String pkg, Module m2); + + /** + * Updates a module m to export a package to all unnamed modules. + */ + void addExportsToAllUnnamed(Module m, String pkg); + + /** + * Updates module m1 to open a package to module m2. Opening the + * package does not result in a strong reference to m2 (m2 can be GC'ed). + */ + void addOpens(Module m1, String pkg, Module m2); + + /** + * Updates module m to open a package to all unnamed modules. + */ + void addOpensToAllUnnamed(Module m, String pkg); + + /** + * Updates module m to open all packages in the given sets. + */ + void addOpensToAllUnnamed(Module m, Set concealedPkgs, Set exportedPkgs); + + /** + * Updates module m to use a service. + */ + void addUses(Module m, Class service); + + /** + * Returns true if module m reflectively exports a package to other + */ + boolean isReflectivelyExported(Module module, String pn, Module other); + + /** + * Returns true if module m reflectively opens a package to other + */ + boolean isReflectivelyOpened(Module module, String pn, Module other); + + /** + * Updates module m to allow access to restricted methods. + */ + Module addEnableNativeAccess(Module m); + + /** + * Updates module named {@code name} in layer {@code layer} to allow access to restricted methods. + * Returns true iff the given module exists in the given layer. + */ + boolean addEnableNativeAccess(ModuleLayer layer, String name); + + /** + * Updates all unnamed modules to allow access to restricted methods. + */ + void addEnableNativeAccessToAllUnnamed(); + + /** + * Ensure that the given module has native access. If not, warn or + * throw exception depending on the configuration. + */ + void ensureNativeAccess(Module m, Class owner, String methodName, Class currentClass); + + /** + * Returns the ServicesCatalog for the given Layer. + */ + ServicesCatalog getServicesCatalog(ModuleLayer layer); + + /** + * Record that this layer has at least one module defined to the given + * class loader. + */ + void bindToLoader(ModuleLayer layer, ClassLoader loader); + + /** + * Returns an ordered stream of layers. The first element is the + * given layer, the remaining elements are its parents, in DFS order. + */ + Stream layers(ModuleLayer layer); + + /** + * Returns a stream of the layers that have modules defined to the + * given class loader. + */ + Stream layers(ClassLoader loader); + + /** + * Count the number of leading positive bytes in the range. + */ + int countPositives(byte[] ba, int off, int len); + + /** + * Constructs a new {@code String} by decoding the specified subarray of + * bytes using the specified {@linkplain java.nio.charset.Charset charset}. + * + * The caller of this method shall relinquish and transfer the ownership of + * the byte array to the callee since the later will not make a copy. + * + * @param bytes the byte array source + * @param cs the Charset + * @return the newly created string + * @throws CharacterCodingException for malformed or unmappable bytes + */ + String newStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException; + + /** + * Encode the given string into a sequence of bytes using the specified Charset. + * + * This method avoids copying the String's internal representation if the input + * is ASCII. + * + * This method throws CharacterCodingException instead of replacing when + * malformed input or unmappable characters are encountered. + * + * @param s the string to encode + * @param cs the charset + * @return the encoded bytes + * @throws CharacterCodingException for malformed input or unmappable characters + */ + byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException; + + /** + * Returns a new string by decoding from the given utf8 bytes array. + * + * @param off the index of the first byte to decode + * @param len the number of bytes to decode + * @return the newly created string + * @throws IllegalArgumentException for malformed or unmappable bytes. + */ + String newStringUTF8NoRepl(byte[] bytes, int off, int len); + + /** + * Get the char at index in a byte[] in internal UTF-16 representation, + * with no bounds checks. + * + * @param bytes the UTF-16 encoded bytes + * @param index of the char to retrieve, 0 <= index < (bytes.length >> 1) + * @return the char value + */ + char getUTF16Char(byte[] bytes, int index); + + /** + * Put the char at index in a byte[] in internal UTF-16 representation, + * with no bounds checks. + * + * @param bytes the UTF-16 encoded bytes + * @param index of the char to retrieve, 0 <= index < (bytes.length >> 1) + */ + void putCharUTF16(byte[] bytes, int index, int ch); + + /** + * Encode the given string into a sequence of bytes using utf8. + * + * @param s the string to encode + * @return the encoded bytes in utf8 + * @throws IllegalArgumentException for malformed surrogates + */ + byte[] getBytesUTF8NoRepl(String s); + + /** + * Inflated copy from byte[] to char[], as defined by StringLatin1.inflate + */ + void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len); + + /** + * Decodes ASCII from the source byte array into the destination + * char array. + * + * @return the number of bytes successfully decoded, at most len + */ + int decodeASCII(byte[] src, int srcOff, char[] dst, int dstOff, int len); + + /** + * Returns the initial `System.in` to determine if it is replaced + * with `System.setIn(newIn)` method + */ + InputStream initialSystemIn(); + + /** + * Returns the initial value of System.err. + */ + PrintStream initialSystemErr(); + + /** + * Encodes ASCII codepoints as possible from the source array into + * the destination byte array, assuming that the encoding is ASCII + * compatible + * + * @return the number of bytes successfully encoded, or 0 if none + */ + int encodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len); + + /** + * Set the cause of Throwable + * @param cause set t's cause to new value + */ + void setCause(Throwable t, Throwable cause); + + /** + * Get protection domain of the given Class + */ + ProtectionDomain protectionDomain(Class c); + + /** + * Get a method handle of string concat helper method + */ + MethodHandle stringConcatHelper(String name, MethodType methodType); + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + */ + long stringConcatHelperPrepend(long indexCoder, byte[] buf, String value); + + /** + * Get the string concat initial coder + */ + long stringConcatInitialCoder(); + + /** + * Update lengthCoder for constant + */ + long stringConcatMix(long lengthCoder, String constant); + + /** + * Mix value length and coder into current length and coder. + */ + long stringConcatMix(long lengthCoder, char value); + + /** + * Join strings + */ + String join(String prefix, String suffix, String delimiter, String[] elements, int size); + + /* + * Get the class data associated with the given class. + * @param c the class + * @see java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...) + */ + Object classData(Class c); + + int stringSize(long i); + + int getCharsLatin1(long i, int index, byte[] buf); + + int getCharsUTF16(long i, int index, byte[] buf); + + long findNative(ClassLoader loader, String entry); + + /** + * Direct access to Shutdown.exit to avoid security manager checks + * @param statusCode the status code + */ + void exit(int statusCode); + + /** + * Returns an array of all platform threads. + */ + Thread[] getAllThreads(); + + /** + * Returns the ThreadContainer for a thread, may be null. + */ + ThreadContainer threadContainer(Thread thread); + + /** + * Starts a thread in the given ThreadContainer. + */ + void start(Thread thread, ThreadContainer container); + + /** + * Returns the top of the given thread's stackable scope stack. + */ + StackableScope headStackableScope(Thread thread); + + /** + * Sets the top of the current thread's stackable scope stack. + */ + void setHeadStackableScope(StackableScope scope); + + /** + * Returns the Thread object for the current platform thread. If the + * current thread is a virtual thread then this method returns the carrier. + */ + Thread currentCarrierThread(); + + /** + * Executes the given value returning task on the current carrier thread. + */ + V executeOnCarrierThread(Callable task) throws Exception; + + /** + * Returns the value of the current carrier thread's copy of a thread-local. + */ + T getCarrierThreadLocal(CarrierThreadLocal local); + + /** + * Sets the value of the current carrier thread's copy of a thread-local. + */ + void setCarrierThreadLocal(CarrierThreadLocal local, T value); + + /** + * Removes the value of the current carrier thread's copy of a thread-local. + */ + void removeCarrierThreadLocal(CarrierThreadLocal local); + + /** + * Returns {@code true} if there is a value in the current carrier thread's copy of + * thread-local, even if that values is {@code null}. + */ + boolean isCarrierThreadLocalPresent(CarrierThreadLocal local); + + /** + * Returns the current thread's scoped values cache + */ + Object[] scopedValueCache(); + + /** + * Sets the current thread's scoped values cache + */ + void setScopedValueCache(Object[] cache); + + /** + * Return the current thread's scoped value bindings. + */ + Object scopedValueBindings(); + + /** + * Returns the innermost mounted continuation + */ + Continuation getContinuation(Thread thread); + + /** + * Sets the innermost mounted continuation + */ + void setContinuation(Thread thread, Continuation continuation); + + /** + * The ContinuationScope of virtual thread continuations + */ + ContinuationScope virtualThreadContinuationScope(); + + /** + * Parks the current virtual thread. + * @throws WrongThreadException if the current thread is not a virtual thread + */ + void parkVirtualThread(); + + /** + * Parks the current virtual thread for up to the given waiting time. + * @param nanos the maximum number of nanoseconds to wait + * @throws WrongThreadException if the current thread is not a virtual thread + */ + void parkVirtualThread(long nanos); + + /** + * Re-enables a virtual thread for scheduling. If the thread was parked then + * it will be unblocked, otherwise its next attempt to park will not block + * @param thread the virtual thread to unpark + * @throws IllegalArgumentException if the thread is not a virtual thread + * @throws RejectedExecutionException if the scheduler cannot accept a task + */ + void unparkVirtualThread(Thread thread); + + /** + * Creates a new StackWalker + */ + StackWalker newStackWalkerInstance(Set options, + ContinuationScope contScope, + Continuation continuation); + /** + * Returns '' @ if classloader has a name + * explicitly set otherwise @ + */ + String getLoaderNameID(ClassLoader loader); + + /** + * Copy the string bytes to an existing segment, avoiding intermediate copies. + */ + void copyToSegmentRaw(String string, MemorySegment segment, long offset); + + /** + * Are the string bytes compatible with the given charset? + */ + boolean bytesCompatible(String string, Charset charset); + + /** + * Is a security manager already set or allowed to be set + * (using -Djava.security.manager=allow)? + */ + boolean allowSecurityManager(); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..d50bc25960d34fc8f2d6ff5f596cc492143c47bc GIT binary patch literal 2941 zcmb_eSyK~15bi|;0XYQ`Pdw0o$|?vRp(rJQgbIfhDptYMWVeX}o7vRt1i?4|mJj{_ zf0SkK!7@1@0eqU8>7MWFd*;vIU%vq$1<7`3F(9#L@0(mGl!7@Xvn=#HbCn&i3=@U4 zIB@szQ*hW0tp@b%k;HUJWNzg5&{78U7f>yt}a7Ghi%{sa8ymYe#`v(twUE zF9@c}63LKe?#xZh)3t7*TtoHEwYQE+bah3)npM6b$!fNY%WRYtR`9?(^8|^Y`?;55 zj)O9b!sCh`5PWMQJ-%%~5BFBMZKGJjVjiUdLj@ElnZgyw%Mw@y`_(_Dz0ny&_^qqDQ%hiJHnMOPkWu~0;zavZ;}Fkw67&7vNx zFcGUEli;qoaHMcUo)W1XlOYNbe6E4`Q?~XCi4z;+$cjQyjn;qvKN`v zK&+Qw4K(FGG$iG^(&ki_elB;;G$*}tImTXFx}^%fwdVQ4+%@oN^PG5o5*t7clu#DS z3M=f+oXHbLDX97k_f&Ex-GC#19yq-Tf}r?L%r_<(uw3eNOI0|seI|4Ia{2D(!b4d} zxPCUFUSZ+LZI~Y_U7B0rSUc`|KR^1Q-*qL@>@``Qo9lu8l2Gz!)1{}N9)XTV-9K0s z5_iMk2^w)_OSv==KkB|j3TDcUHJU)~TspL{q&Qt_hlBy6Cl5)QvQ=PC_#DM*2BaFW zo>J3QF7?DNEpv2i1CsS%16gvrPWe{B(Nq(5j!RW$jsZ-^3L96eq-eTpCl$lZf8?5o zoL$4=JFbELADT|zv8b6QKEr8tpinr zF?u7$^^OWtVZiM9Z~6AoJ4^k{nZtjuyh9T)u5<&w=#VujzgTm8t--8HaUIy^;@FvW z%hJMS?tc+R>iz#F{YGpvzEDM3f!-)Q40s;F<6wOPV`Rxw zvZs~wpGB69(~SvuPA9R1PF}#vI=Yi2F;A7eg4eMfQ=~Z!Z{qz7?PuX_9n5#6^FD~t Fhkp+voGt(W literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.java b/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.java new file mode 100644 index 00000000..56387038 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaLangInvokeAccess.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import jdk.internal.foreign.abi.NativeEntryPoint; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.nio.ByteOrder; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +public interface JavaLangInvokeAccess { + /** + * Returns the declaring class for the given ResolvedMethodName. + * Used by {@code StackFrameInfo}. + */ + Class getDeclaringClass(Object rmname); + + /** + * Returns the {@code MethodType} for the given method descriptor + * and class loader. + * Used by {@code StackFrameInfo}. + */ + MethodType getMethodType(String descriptor, ClassLoader loader); + + /** + * Returns true if the given flags has MN_CALLER_SENSITIVE flag set. + */ + boolean isCallerSensitive(int flags); + + /** + * Returns true if the given flags has MN_HIDDEN_MEMBER flag set. + */ + boolean isHiddenMember(int flags); + + /** + * Returns a map of class name in internal forms to its corresponding + * class bytes per the given stream of LF_RESOLVE and SPECIES_RESOLVE + * trace logs. Used by GenerateJLIClassesPlugin to enable generation + * of such classes during the jlink phase. + */ + Map generateHolderClasses(Stream traces); + + /** + * Returns a var handle view of a given memory segment. + * Used by {@code jdk.internal.foreign.LayoutPath} and + * {@code java.lang.invoke.MethodHandles}. + */ + VarHandle memorySegmentViewHandle(Class carrier, long alignmentMask, ByteOrder order); + + /** + * Var handle carrier combinator. + * Used by {@code java.lang.invoke.MethodHandles}. + */ + VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget); + + /** + * Var handle filter coordinates combinator. + * Used by {@code java.lang.invoke.MethodHandles}. + */ + VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters); + + /** + * Var handle drop coordinates combinator. + * Used by {@code java.lang.invoke.MethodHandles}. + */ + VarHandle dropCoordinates(VarHandle target, int pos, Class... valueTypes); + + /** + * Var handle permute coordinates combinator. + * Used by {@code java.lang.invoke.MethodHandles}. + */ + VarHandle permuteCoordinates(VarHandle target, List> newCoordinates, int... reorder); + + /** + * Var handle collect coordinates combinator. + * Used by {@code java.lang.invoke.MethodHandles}. + */ + VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter); + + /** + * Var handle insert coordinates combinator. + * Used by {@code java.lang.invoke.MethodHandles}. + */ + VarHandle insertCoordinates(VarHandle target, int pos, Object... values); + + /** + * Returns a native method handle with given arguments as fallback and steering info. + * + * Will allow JIT to intrinsify. + * + * @param nep the native entry point + * @return the native method handle + */ + MethodHandle nativeMethodHandle(NativeEntryPoint nep); + + /** + * Produces a method handle unreflecting from a {@code Constructor} with + * the trusted lookup + */ + MethodHandle unreflectConstructor(Constructor ctor) throws IllegalAccessException; + + /** + * Produces a method handle unreflecting from a {@code Field} with + * the trusted lookup + */ + MethodHandle unreflectField(Field field, boolean isSetter) throws IllegalAccessException; + + /** + * Produces a method handle of a virtual method with the trusted lookup. + */ + MethodHandle findVirtual(Class defc, String name, MethodType type) throws IllegalAccessException; + + /** + * Produces a method handle of a static method with the trusted lookup. + */ + MethodHandle findStatic(Class defc, String name, MethodType type) throws IllegalAccessException; + + /** + * Returns a method handle of an invoker class injected for core reflection + * implementation with the following signature: + * reflect_invoke_V(MethodHandle mh, Object target, Object[] args) + * + * The invoker class is a hidden class which has the same + * defining class loader, runtime package, and protection domain + * as the given caller class. + */ + MethodHandle reflectiveInvoker(Class caller); + + /** + * A best-effort method that tries to find any exceptions thrown by the given method handle. + * @param handle the handle to check + * @return an array of exceptions, or {@code null}. + */ + Class[] exceptionTypes(MethodHandle handle); + + /** + * Returns a method handle that allocates an instance of the given class + * and then invoke the given constructor of one of its superclasses. + * + * This method should only be used by ReflectionFactory::newConstructorForSerialization. + */ + MethodHandle serializableConstructor(Class decl, Constructor ctorToCall) throws IllegalAccessException; +} diff --git a/tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangModuleAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..a70682132d8659f0b65d6ed477a4154705ebd554 GIT binary patch literal 4439 zcmcIoTT|0O6h5m$%0)!+R_`dvMI{K{ixnuKI7Jvb!-I|wv0XX~A*o4~4Sk{qYk3a`04v0|Z7kOIs>4 z9BLVwu4=_1wQcp8wxi`Wqr7aEsydzZ1{F9&pnns8QFZ)DU3tApiw+JM^lfe4T$Sl1 zY7tl&$=Bx<9E%y{%!}Gk)nU3?piX8~n6m9Hqt?94Q@d!fiep+szQYWGt^z9?np3qX zfe)>{PfIw*)z}83RwkQ}ORAz3x3n^~2~3MrT1DYU%oQN8x({?Lm5SU z>)rQ4G8(TUG-BeaMas8LGXLKq{@WI2n3d?3*MekBQ<(0R3N``jS5cxRiEk-G$e(rwDCVJ=G^lZKJqpJ!W6aOKY(z^LD|~-rh`oht3+MIcAgy=wj|e`C7!^@dhh|k~4K3ujTF~r8de;brmn*4#rKj z?YP30GmQ;au3DOBRWI0$U(RmJiJ6UPoScIDrU=oBRIC;vENc~+KtCtY6l znwSaM_}4`!Hmsf91+!`u=_1qdeUpxReT};hDgwPrhC!{IuGu!V6}UlQwEofxsZy_w z!81yMaRP%arxQ^8cb5XU2#mEf;O8{HK7y*Dz-=khpirP`&{g0bfvMK32J`vy3OtaK z!!P<6r{7axTFQ`LhZVo4z+(cFt*J(Dt_sW&7;bInRWkw|UaP=7feA??L6k+QL~4nPWV7j$#ngSZzCbKHmc2=sG&6!9?_;P|+QPjGw^ z@hLdXaoWRYI6jN`9GvI)0^*BsiQ_@Um*EP>Lx``!HI9do^N7cM6vnV!L+;n%Ca92x s32Y~4(lCYX9mIFB=i>W_A0p0R`v}`C_T2Fq#B+#q*mLm$;wO;)2X ms); + + /** + * Returns a snapshot of the packages in the module. + */ + Set packages(ModuleDescriptor.Builder builder); + + /** + * Adds a dependence on a module with the given (possibly un-parsable) + * version string. + */ + void requires(ModuleDescriptor.Builder builder, + Set ms, + String mn, + String rawCompiledVersion); + + /** + * Returns a {@code ModuleDescriptor.Requires} of the given modifiers + * and module name. + */ + Requires newRequires(Set ms, String mn, Version v); + + /** + * Returns an unqualified {@code ModuleDescriptor.Exports} + * of the given modifiers and package name source. + */ + Exports newExports(Set ms, + String source); + + /** + * Returns a qualified {@code ModuleDescriptor.Exports} + * of the given modifiers, package name source and targets. + */ + Exports newExports(Set ms, + String source, + Set targets); + + /** + * Returns an unqualified {@code ModuleDescriptor.Opens} + * of the given modifiers and package name source. + */ + Opens newOpens(Set ms, String source); + + /** + * Returns a qualified {@code ModuleDescriptor.Opens} + * of the given modifiers, package name source and targets. + */ + Opens newOpens(Set ms, String source, Set targets); + + /** + * Returns a {@code ModuleDescriptor.Provides} + * of the given service name and providers. + */ + Provides newProvides(String service, List providers); + + /** + * Returns a new {@code ModuleDescriptor} instance. + */ + ModuleDescriptor newModuleDescriptor(String name, + Version version, + Set ms, + Set requires, + Set exports, + Set opens, + Set uses, + Set provides, + Set packages, + String mainClass, + int hashCode); + + /** + * Resolves a collection of root modules, with service binding + * and the empty configuration as the parent. + */ + Configuration resolveAndBind(ModuleFinder finder, + Collection roots, + PrintStream traceOutput); + + /** + * Creates a configuration from a pre-generated readability graph. + */ + Configuration newConfiguration(ModuleFinder finder, + Map> graph); + +} diff --git a/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..209408f7dc65a8c289769883d889317b048044f3 GIT binary patch literal 443 zcmaiwPfx-?5XIjhQb82dL=z9jiwRup-4YUFB+(H6(RlE-mI1etE!l3t_|ZK00sK(L zDH_mt@U$<#dGmH=-alU70GwjSLxFG<51xE&99yHtzKSAFQ~yFuRZp4GEe|_$;-N^W z$AbN_aR2Hd=ExDMsZ-X4kCxRSC9E`>cZB_!(yp6W>1N9&;%l4avD%F0mU}|w>^b6z z(}_tvtP>8F(dYRrHk&veEKG!&%}iIzi26n4ZG=6;vrExaUi@>DamIwhMzgofvpn>F zI|4$vuSZ6?%!)l|g(pA!U#kV}e?nSe7_=p+(oZrQaaWHeYWL6Kj`KlE1X)~;4ix2% ht0;*ecvur&&Z)c=A=U571~!G%q*6d#)Ye>We*&1gdFTKD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.java b/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.java new file mode 100644 index 00000000..ed9967ec --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaLangRefAccess.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.lang.ref.ReferenceQueue; + +public interface JavaLangRefAccess { + + /** + * Starts the Finalizer and Reference Handler threads. + */ + void startThreads(); + + /** + * Wait for progress in {@link java.lang.ref.Reference} + * processing. If there aren't any pending {@link + * java.lang.ref.Reference}s, return immediately. + * + * @return {@code true} if there were any pending + * {@link java.lang.ref.Reference}s, {@code false} otherwise. + */ + boolean waitForReferenceProcessing() throws InterruptedException; + + /** + * Runs the finalization methods of any objects pending finalization. + * + * Invoked by Runtime.runFinalization() + */ + void runFinalization(); + + /** + * Constructs a new NativeReferenceQueue. + * + * Invoked by jdk.internal.util.ReferencedKeyMap + */ + ReferenceQueue newNativeReferenceQueue(); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.class b/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..2c558e5b05c48cb28b2c12c6f6f9b45c4b3af86e GIT binary patch literal 2753 zcmbVOZBx@g5Z*(jP?T2%K~!D@DJVhSRMKIj9hfPiIJBcP_KQb)lweGlBt`fi{u)2{ z1N>2ro6FmUTn+f4)7jhSo_%)rZZE(8{QLy~WhmyLgFxY=@m0}Hm)RyY6sl>=ag<$p zM)#=MJYYu#)7&k-nuD7J`cKfM80b^>4^PlXpx0#I%a-Z5c1v?Dn}9jD7o*AsbsV*R zg_TN0099REH=Am`R4)~TW!o2|2=P<`-BrD5QnzI@0zZni4Pk>XQr%2RD%NW1W?ENq zzRlu)s`JAT7-%y09dnPZhF?stPFtd=Ff$*dV$xz?lHQO4Qy*~ByrqBeUWvBwk-#tt z7OEVEB=AVKcX=JlgZE#!p5SP+Saz+OfqRbCnim+IALKZDK_em%ws ztoZgh(^@V)G+6E8lx>-&I1duH-=L)5pxnjaXYHV)Mkwc>2(x!Ez2Utn^2ZeB7b@kSiANnPdEXYpzU*woqC5V z5R})f(+hv>v}r{=lcE+R2NFi=H5ffA3ryV}?T*fj27y(XeC|seh>+Cx5a{zLg!4z> zjf_Y@Na;jBfiKw)M5sg9=+ANS^tJ^N$l)CMN#&t{ z6moM8-?jq&2n^{?&2Bj^YwYOwz6b3Xm#GTc@tHsmKIj#E ^5gZfDZ7Ali?LxY4; zCs@odz!1nsC(+5lDuIc3G*k?OHL2mJ7Qu3`oA?6C}R58yijYDhH z<`*@%2Lz6im6d%oge*el=}(9@>GL7N`;o6&En8zdx`CA)+r{gY`pjDNly?#!a05Tn z0EY0Z>lSpPokObwy3p>1Ja}JYJ#d@<-+|u9--qk{Fc8^;Xb-_%j=KlL(fSCk--pr2 z9z**9j7RoEv>#ovAHziCpG5!EC3_m4@HjKU|13P^_8b(Vee<|)0iH$nbF>#h;kYGu Zff+7io?V#z3ar7)AnVtN-{ASHe*u3WX=MNa literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.java b/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.java new file mode 100644 index 00000000..f49221e4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaLangReflectAccess.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.lang.reflect.*; +import jdk.internal.reflect.*; + +/** An interface which gives privileged packages Java-level access to + internals of java.lang.reflect. */ + +public interface JavaLangReflectAccess { + /** Creates a new java.lang.reflect.Constructor. Access checks as + per java.lang.reflect.AccessibleObject are not overridden. */ + public Constructor newConstructor(Class declaringClass, + Class[] parameterTypes, + Class[] checkedExceptions, + int modifiers, + int slot, + String signature, + byte[] annotations, + byte[] parameterAnnotations); + + /** Gets the MethodAccessor object for a java.lang.reflect.Method */ + public MethodAccessor getMethodAccessor(Method m); + + /** Sets the MethodAccessor object for a java.lang.reflect.Method */ + public void setMethodAccessor(Method m, MethodAccessor accessor); + + /** Gets the ConstructorAccessor object for a + java.lang.reflect.Constructor */ + public ConstructorAccessor getConstructorAccessor(Constructor c); + + /** Sets the ConstructorAccessor object for a + java.lang.reflect.Constructor */ + public void setConstructorAccessor(Constructor c, + ConstructorAccessor accessor); + + /** Gets the byte[] that encodes TypeAnnotations on an Executable. */ + public byte[] getExecutableTypeAnnotationBytes(Executable ex); + + /** Gets the "slot" field from a Constructor (used for serialization) */ + public int getConstructorSlot(Constructor c); + + /** Gets the "signature" field from a Constructor (used for serialization) */ + public String getConstructorSignature(Constructor c); + + /** Gets the "annotations" field from a Constructor (used for serialization) */ + public byte[] getConstructorAnnotations(Constructor c); + + /** Gets the "parameterAnnotations" field from a Constructor (used for serialization) */ + public byte[] getConstructorParameterAnnotations(Constructor c); + + /** Gets the shared array of parameter types of an Executable. */ + public Class[] getExecutableSharedParameterTypes(Executable ex); + + /** Gets the shared array of exception types of an Executable. */ + public Class[] getExecutableSharedExceptionTypes(Executable ex); + + // + // Copying routines, needed to quickly fabricate new Field, + // Method, and Constructor objects from templates + // + + /** Makes a "child" copy of a Method */ + public Method copyMethod(Method arg); + + /** Makes a copy of this non-root a Method */ + public Method leafCopyMethod(Method arg); + + /** Makes a "child" copy of a Field */ + public Field copyField(Field arg); + + /** Makes a "child" copy of a Constructor */ + public Constructor copyConstructor(Constructor arg); + + /** Gets the root of the given AccessibleObject object; null if arg is the root */ + public T getRoot(T obj); + + /** Tests if this is a trusted final field */ + public boolean isTrustedFinalField(Field f); + + /** Returns a new instance created by the given constructor with access check */ + public T newInstance(Constructor ctor, Object[] args, Class caller) + throws IllegalAccessException, InstantiationException, InvocationTargetException; +} diff --git a/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.class b/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..7ae0b1bd2255c79e7d248faffc2cc9a1c41e5eb7 GIT binary patch literal 345 zcma)2QA)#55S*PJrSOqckQ@KRnj9+v`o00ug=X(g7ZbXI8mLr+N@kFDIv*R;jMH*SJHp1Jf0*xi#a<= zpHwOOWV_)&SPU}1W`^Uv*})HCnl)X>`Nh?G|Mril562)8fpDSE0!EsAj7V{OM3^W} LFx8rH)ibjnrH^A9 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.java b/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.java new file mode 100644 index 00000000..b76dbf33 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaNetHttpCookieAccess.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.net.HttpCookie; +import java.util.List; + +public interface JavaNetHttpCookieAccess { + /* + * Constructs cookies from Set-Cookie or Set-Cookie2 header string, + * retaining the original header String in the cookie itself. + */ + public List parse(String header); + + /* + * Returns the original header this cookie was constructed from, if it was + * constructed by parsing a header, otherwise null. + */ + public String header(HttpCookie cookie); +} + diff --git a/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.class b/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..d9e1f1475f2e4a97cc9c297f4c37127386cdc1fc GIT binary patch literal 329 zcmX^0Z`VEs1_oyaUUmj1Mh2a%lx+RXypq(Syu=*+#N_1E;$nTT#Ii)c)Dq9U)Dp*( zlp>&zBUpl+frXJlAPXp~pOcuEuJ50em6}|_$RM1aTH;@nnVtzW!y~`A#4j;7m61V9 z!w0MsXo^0PQP!FeVXz6oB}JKe>DG)4Jc$sC!V+^zfqJFT^qN53VXf(jQ0r7#l3L8j zAdRNh46ZiXiIIUTIKQ+gIn^yQ2WYG;E}!XvT*}7Cz{tQ13>*dqW}rt|8Q2&=9%g6Y T0MncdTtFE{25un9#J~dp9jslX literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.java b/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.java new file mode 100644 index 00000000..d3e0e658 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaNetInetAddressAccess.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; + +public interface JavaNetInetAddressAccess { + /** + * Return the original application specified hostname of + * the given InetAddress object. + */ + String getOriginalHostName(InetAddress ia); + + /** + * Returns the 32-bit IPv4 address. + */ + int addressValue(Inet4Address inet4Address); + + /** + * Returns a reference to the byte[] with the IPv6 address. + */ + byte[] addressBytes(Inet6Address inet6Address); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.class b/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..7b1faf8ecc1010be6dde4a3bbd9e810c6a130903 GIT binary patch literal 200 zcmZ8bOA5j;6r5MJQCDuffeS@22k1%!5h)554-nHwX^j!m=;2&=01qXm#f@$r^M?7o z-j64M6$SzkVN&I1Sz6D|DkGKFT-S1|?rO*Wcu1EmApQf$CvX{Y`%zoa?J64ykI0@G5dUKlBrD4MOzi`nc#RNhpYy~Lv_YgM-BHRf5 E4=tBAg8%>k literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.java b/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.java new file mode 100644 index 00000000..0ad25d80 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaNetURLAccess.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.access; + +import java.net.URL; +import java.net.URLStreamHandler; + +public interface JavaNetURLAccess { + URLStreamHandler getHandler(URL u); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaNetUriAccess.class b/tests/test_data/std/jdk/internal/access/JavaNetUriAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..730b18d77e3b62921ed4672348515d87c835c13c GIT binary patch literal 205 zcmX^0Z`VEs1_oyaPId++Mh2Cvlx+RXypq(Syu=*+#N_1E;$nTT#Ii)c)RNGmOh>Q) zI|B`dy;N&cEj3f37^IT zAHYW;#%sq(D@%aHi;rh^XXebA-TnFN`wswUf?a?G23rH~vn^zZT5{j!u8TonJN%r# z7i!;F1z2QI8Ia5Nx$N7Arvr3D2Gu@>2SU?-W8CYZK2pkOux-`amr@Qz;M&KXo!O>3 z#Y((LVkaTSOAOkU(`sKWRG;(olt$5)b_a(_PrBG2q73U)Fd`>~vKwi(q)3O4M(EAl z3@)t8{F0WZsXxkL6rzu``Z}rqS3Yah^gHCEc{Z=DPmR`m(^DRQ*J7Dw5UbbV0W#R7 z=29)pRHo|8jgF+Lq;dP6r)lI2HZnpT2E}nA2!l5nJN`jS2IW&jDVZCCSD6XZgO)7? zgB9+68Pmb*5^teoHuYoLr_o1}CEZsM!G|-A+-oY?6B51b&=UrwGajU2IU?ecxSI)G zI%jW%j|UjIT8u)a>&}Ve)TrX3uQ(;mTjYrB{8+}Gq6pfw6jh8DsYaP}M}3a*q#5L_ zILYc*URf!Qcptms8*#X1)mlWatHwkrV!>eDA;r?$x);r#!E#GV)J>lU0R{zlPVE11 zD+}4QZHduxggR4+6xCZM6tFU44 z2HZ4wE5X}v$Jlohya)G<{Qw>s+)VHhY#IA8Y#ZE3a2K8svjuo+z82I7OT_pYynwy@ F(r;)LYh?fc literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaNioAccess.java b/tests/test_data/std/jdk/internal/access/JavaNioAccess.java new file mode 100644 index 00000000..b34a0d42 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaNioAccess.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import jdk.internal.access.foreign.UnmapperProxy; +import jdk.internal.misc.VM.BufferPool; + +import java.lang.foreign.MemorySegment; +import java.io.FileDescriptor; +import java.nio.Buffer; +import java.nio.ByteBuffer; + +public interface JavaNioAccess { + + /** + * Used by {@code jdk.internal.misc.VM}. + */ + BufferPool getDirectBufferPool(); + + /** + * Constructs a direct ByteBuffer referring to the block of memory starting + * at the given memory address and extending {@code cap} bytes. + * The {@code ob} parameter is an arbitrary object that is attached + * to the resulting buffer. + * Used by {@code jdk.internal.foreignMemorySegmentImpl}. + */ + ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegment segment); + + /** + * Constructs a mapped ByteBuffer referring to the block of memory starting + * at the given memory address and extending {@code cap} bytes. + * The {@code ob} parameter is an arbitrary object that is attached + * to the resulting buffer. The {@code sync} and {@code fd} parameters of the mapped + * buffer are derived from the {@code UnmapperProxy}. + * Used by {@code jdk.internal.foreignMemorySegmentImpl}. + */ + ByteBuffer newMappedByteBuffer(UnmapperProxy unmapperProxy, long addr, int cap, Object obj, MemorySegment segment); + + /** + * Constructs an heap ByteBuffer with given backing array, offset, capacity and segment. + * Used by {@code jdk.internal.foreignMemorySegmentImpl}. + */ + ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegment segment); + + /** + * Used by {@code jdk.internal.foreign.Utils}. + */ + Object getBufferBase(Buffer bb); + + /** + * Used by {@code jdk.internal.foreign.Utils}. + */ + long getBufferAddress(Buffer buffer); + + /** + * Used by {@code jdk.internal.foreign.Utils}. + */ + UnmapperProxy unmapper(Buffer buffer); + + /** + * Used by {@code jdk.internal.foreign.AbstractMemorySegmentImpl} and byte buffer var handle views. + */ + MemorySegment bufferSegment(Buffer buffer); + + /** + * Used by operations to make a buffer's session non-closeable + * (for the duration of the operation) by acquiring the session. + * {@snippet lang = java: + * acquireSession(buffer); + * try { + * performOperation(buffer); + * } finally { + * releaseSession(buffer); + * } + *} + * + * @see #releaseSession(Buffer) + */ + void acquireSession(Buffer buffer); + + void releaseSession(Buffer buffer); + + boolean isThreadConfined(Buffer buffer); + + boolean hasSession(Buffer buffer); + + /** + * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views. + */ + void force(FileDescriptor fd, long address, boolean isSync, long offset, long size); + + /** + * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views. + */ + void load(long address, boolean isSync, long size); + + /** + * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl}. + */ + void unload(long address, boolean isSync, long size); + + /** + * Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views. + */ + boolean isLoaded(long address, boolean isSync, long size); + + /** + * Used by {@code jdk.internal.foreign.NativeMemorySegmentImpl}. + */ + void reserveMemory(long size, long cap); + + /** + * Used by {@code jdk.internal.foreign.NativeMemorySegmentImpl}. + */ + void unreserveMemory(long size, long cap); + + /** + * Used by {@code jdk.internal.foreign.NativeMemorySegmentImpl}. + */ + int pageSize(); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.class b/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..8a5242e41081ed1f52f997c17dd80baa64a3275c GIT binary patch literal 229 zcmX^0Z`VEs1_oyaPId++Mh5+?lx+RXypq(Syu=*+#N_1E;$nTT#Ii*Hq^#8B63@JX z(h|4K9H6`-SdN{6g^@uZ3#dRpCowNwAEJzrfj7A*HL)ZWqSOdzu7(dnQE*97W?s6r zCPXMRAF2zsf-K?c$}aIGMJ5#fsuh3=n)16MxcvW8Q4H926iCH H#J~XnZCXP# literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.java b/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.java new file mode 100644 index 00000000..bc60cbbb --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaObjectInputFilterAccess.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.io.ObjectInputFilter; + +/** + * Access to the alternative ObjectInputFilter.Config.createFilter2 for RMI. + */ +public interface JavaObjectInputFilterAccess { + /** + * Creates a filter from the pattern. + */ + ObjectInputFilter createFilter2(String pattern); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.class b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..85420383876bd7263c773347c6ef06727e48d396 GIT binary patch literal 433 zcmb7AO-lnY5PezeuB~6adJsLT2P1e~5td?MMG#!*eHvrUHqDkKEBe@z83>PPNEkji+d`%|pptgCW$++@~3 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.java b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.java new file mode 100644 index 00000000..a47add47 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamAccess.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.io.ObjectStreamException; +import java.io.ObjectInputStream; + +/** + * Interface to specify methods for accessing {@code ObjectInputStream}. + */ +@FunctionalInterface +public interface JavaObjectInputStreamAccess { + void checkArray(ObjectInputStream ois, Class arrayType, int arrayLength) + throws ObjectStreamException; +} diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.class b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.class new file mode 100644 index 0000000000000000000000000000000000000000..9366ed49be6066fb54c4cb7cefe3b87454d04e81 GIT binary patch literal 356 zcmaiwzfQwI48}i)(m?qmBqk;n23WX(F%v>mN`+LZmDsOWQ(d?^RdPW*8v_r(Lm`}` zpl(dI@B8_)&tKmkp8y_knj#_G70XxSC2}P;80#F@wVBvAJ6#m)VlJB|&SS-PJ!8An z%*!gpfN)kQWP+8I=~2Q+u`NO{*H0bc%dNg+mEH7O*WG(&+Wz?NcoTgob&5m6`EP$d z{Zo{hmrdn(>;n_7{@L`lwIE!~8i{_*&%XAH!1p3$wA~=W<<2VOMqK-BL*8EG#X8Q0 g1j3$P3?TjXK89MSS`9QFAi+rU1V=d5*lH)h4;Dgai~s-t literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.java b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.java new file mode 100644 index 00000000..1ae489b7 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaObjectInputStreamReadString.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * Interface to specify methods for accessing {@code ObjectInputStream}. + */ +@FunctionalInterface +public interface JavaObjectInputStreamReadString { + String readString(ObjectInputStream ois) throws IOException; +} + diff --git a/tests/test_data/std/jdk/internal/access/JavaSecurityAccess$ProtectionDomainCache.class b/tests/test_data/std/jdk/internal/access/JavaSecurityAccess$ProtectionDomainCache.class new file mode 100644 index 0000000000000000000000000000000000000000..66dcadec26316ea811bfe028de544308f5186031 GIT binary patch literal 452 zcma)(O-{ow5QU#xNZL@K8^i?=q8ogGvOz)RM^!8oTDdjRy{sT;}Qj@tW;W4jPgdkswL?&D9EH-V7%2)I rbX~W}WddxA{{iT6hTF){WSL{YN*}{UM}eKTj#>ibM<_kzyofcaC!%~RL9 z94HW|jnVH$RD|x$Xv};=U@wrp__0QdOVL++#v>Lo0?&<03&)7%ap$q1Yq70VJW1q9 zVU&#GgFTu|m}WxsqplW#(twA8nyJE4UfRRs-^S)EE|U)GAv1j?4KDmtPAC_ezg}ZFtrRMZSgSttWa6bFr>~ptA{d?TvNdw!? zB-Vp8v1LH^@<2|N&(2VyDBa&GKZ+GgpmNQ$xnh$M>e_)V0`0%#B~a}N!IT$Ktr<>h zXJL6o0tE8-GXVhtHCRVX9yTnp2KD$oA~#_hZ)JPK Hl*Q5~he1og literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaSecurityAccess.java b/tests/test_data/std/jdk/internal/access/JavaSecurityAccess.java new file mode 100644 index 00000000..cb1fd49c --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaSecurityAccess.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.security.AccessControlContext; +import java.security.PermissionCollection; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; + +public interface JavaSecurityAccess { + + T doIntersectionPrivilege(PrivilegedAction action, + @SuppressWarnings("removal") AccessControlContext stack, + @SuppressWarnings("removal") AccessControlContext context); + + T doIntersectionPrivilege(PrivilegedAction action, + @SuppressWarnings("removal") AccessControlContext context); + + ProtectionDomain[] getProtectDomains(@SuppressWarnings("removal") AccessControlContext context); + + interface ProtectionDomainCache { + void put(ProtectionDomain pd, PermissionCollection pc); + PermissionCollection get(ProtectionDomain pd); + } + + /** + * Returns the ProtectionDomainCache. + */ + ProtectionDomainCache getProtectionDomainCache(); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.class b/tests/test_data/std/jdk/internal/access/JavaSecurityPropertiesAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..2a8d1771b1c62c4fa3a39aa91d950fb9e13dd588 GIT binary patch literal 215 zcmaJ*Jqp4w7=2&WR-GIiT-|gr?oJ{IilERFr17JqhE&p2@M;boz(a{?mu@bP2k-au zeZ2wfFiH>+*2VQEwDs()G(sxHRV9w{AyZbh)BbsJ<(-|^Ty0x1L7y-wfXx|x zI|A(q6J(-nEFVS_(q5ottnou~X1ox1I=?R&*>4S573r)b2Kgv4`i>T>iEKt%c9S^e z9-gNI<@Yc>%Vj?bF@dE4%T>VK~*QtI9#2XKz z$$8o1$Bd0up0=H-S$J4jCGfVf=)jpdYi()a${NaL)1$IcI{mRXOmnB{#v~+g+W-F^ pE(=2&0s?iuDxl8iv5N-B0Y?qg&_t`m4%VTt@0 zOTv(I(ROXPNF>=w;~JcjFp7m!mgZ7IT*s_ zaB}f;X!IYa;c`-r#BT6gn(NFQD`x*>8bW{JbEwVKvaCG%>)i8o_%4C4B_9Jia{Ugv RqKmb{uIS!ZEu_C8dmqozXGZ`4 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.java b/tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.java new file mode 100644 index 00000000..f88d5752 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaUtilCollectionAccess.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.util.List; + +public interface JavaUtilCollectionAccess { + List listFromTrustedArray(Object[] array); + List listFromTrustedArrayNullsAllowed(Object[] array); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.class b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentFJPAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..ece6306869c75908eb7241330ed7f18f81f045d2 GIT binary patch literal 300 zcma)&y-ou$5QJwF$c4~ELiAMmY2pW-zzC2utJOB@c@TH(Z zLbS6pqy6Ud>v#fC;<~_ypqjc>P7+5kUKwk->y$PJ^O~G5gV;VsmQ?BO!}(U=f-rBg zL3ty4^}K7?Cc^EG_fE?2{=w3j#Py>Owk0f9PiJ$V>y-WJQ&otq4oIr# zy&q2i8HOo30XJaIIIostgNE{;(EbOd=46@i8DG Nx{u`RkVfrb@B!*zI_3ZX literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.java b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.java new file mode 100644 index 00000000..5683146e --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaUtilConcurrentTLRAccess.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +public interface JavaUtilConcurrentTLRAccess { + int nextSecondaryThreadLocalRandomSeed(); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.class b/tests/test_data/std/jdk/internal/access/JavaUtilJarAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..dcfaab98dcabe2438a155e8250c39651be17c915 GIT binary patch literal 535 zcmaix!A=4(5QhIjU=bBjhzH}<1TOXg_Cz)iAsS3j58ldBvFoO5+OAO_&4Ul%Lm6k+ zhzTZo>13vV|M{l#{_*+-AVN1lg>alK?u9m9StC;+<5)Q-Ch}2Ud7VzA9h8*-RYE)A zvPh*_is?L2u_qiQ(vEbhPNj=d>D-0%cLVROp66Z>4trI0yW-I4Ry`~&Z-<6Txnv96T&uj%Gkng8Qa)n6=9#x3Ob+g CP@56p{qYH4f&(8tg0nn%p_$aYluS?-$6P5oWpC_JXJXD(QI#>ju4E$k zmHqUwN-)Tcf(j;6djFjBSQ7+_>jzeHY4Y*W%nB;Qpj}9~{AcuJDCr;N+(8*F$26nN zikJybKpl`4qmhU82)R5 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.java b/tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.java new file mode 100644 index 00000000..fb8fda8f --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaUtilResourceBundleAccess.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * Provides access to non-public methods in java.util.ResourceBundle. + */ +public interface JavaUtilResourceBundleAccess { + /** + * Sets the bundle's parent to the given parent. + */ + void setParent(ResourceBundle bundle, ResourceBundle parent); + + /** + * Returns the parent of the given bundle or null if the bundle has no parent. + */ + ResourceBundle getParent(ResourceBundle bundle); + + /** + * Sets the bundle's locale to the given locale. + */ + void setLocale(ResourceBundle bundle, Locale locale); + + /** + * Sets the bundle's base name to the given name. + */ + void setName(ResourceBundle bundle, String name); + + /** + * Returns a {@code ResourceBundle} of the given baseName and locale + * loaded on behalf of the given module with no caller module + * access check. + */ + ResourceBundle getBundle(String baseName, Locale locale, Module module); + + /** + * Instantiates a {@code ResourceBundle} of the given bundle class. + */ + ResourceBundle newResourceBundle(Class bundleClass); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.class b/tests/test_data/std/jdk/internal/access/JavaUtilZipFileAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..b645b19c01d0a816714047184e1e101e7112f766 GIT binary patch literal 1099 zcmbVLT~AX%5S;~VDJaDv%9rxsi#H)$!)wu`F(s4~O>D%ZJ}tLH-FmwvyK@Qkr}^Ly z@JAVD_ue#H`3U&5+1WW~&Yao#^Y_XIfQ>h8pPDgE{8OFB z1y?=l3V7W|I+j|Up{0iIbyQzV$_#$SR1)@FP0P|kih(pN%ebd{6i~O7rMiI1ghRl) z`{MR<9^XxejMDx3d*-SJ>ORUL3fQ@gv0F$9DFiHq1ljN(Gp0Ie38=YjB-zquCupo1 zY3_aVwu;d=hLlmWT<6i-FmKA{z@w(lhG--)HMe*4KuF<|A7r7u$>qo1tCA&yl3U!n z4{M$rv)7DaDeVV??i5pXwv64#@(KbD{Tl7O8njMmC6@Kh4OQzjXt9ZcQsX z$p?E4Gd0*^U^yn@!7g-0nMu(7a{e_puHmj*tC9c#v%JOt3%r$&pagC^%P`OJ3P)#r xd=Vb|_!C(2XBC$H`4noCycNbhgVo9XIp1Fd_cgw+!-mIg!WMH2c getManifestAndSignatureRelatedFiles(JarFile zip); + public String getManifestName(JarFile zip, boolean onlyIfSignatureRelatedFiles); + public int getManifestNum(JarFile zip); + public int[] getMetaInfVersions(JarFile zip); + public Enumeration entries(ZipFile zip); + public Stream stream(ZipFile zip); + public Stream entryNameStream(ZipFile zip); + public void setExtraAttributes(ZipEntry ze, int extraAttrs); + public int getExtraAttributes(ZipEntry ze); +} + diff --git a/tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.class b/tests/test_data/std/jdk/internal/access/JavaxCryptoSealedObjectAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..ae2865cf52ab2d1d4f86495e826dab49638acdfa GIT binary patch literal 407 zcmaKo%}T>S6ot>N+SK}2aN$;5h;AHQXJtc$6s1C*V4Pgyq~jzcQ;9yB3m?FT5~rz@ zWaIMu@Llft{`vd@5MdHvK)B7*rO?)KWu*~PDXwcVmv6F(s`t_r2}{H2;yGvK?%FiK zE@6`UiZIeNtdW(^n;2s?gkfc$2A7w$0X&qrNhjDmhBxo` z{ybj*VvIxd2vK&qsWf+Db8VDnma0-a{m^x6o6;3YDZJ^}5Cg(A^Dkv|epSbFChQ0^ zHll4JY{l)RX$^$M^3W=4#a)W3Jga^*>*z$7B*opbY*QnI`QO@An-dTSeLou@zha1> Ky%2irVe|zrIXuGv literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.java b/tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.java new file mode 100644 index 00000000..f8904cae --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/JavaxCryptoSpecAccess.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import javax.crypto.spec.SecretKeySpec; + +public interface JavaxCryptoSpecAccess { + void clearSecretKeySpec(SecretKeySpec keySpec); +} diff --git a/tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.class b/tests/test_data/std/jdk/internal/access/JavaxSecurityAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..387f09ee33373181f42334774bc21ef0f73f5ea7 GIT binary patch literal 332 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/SharedSecrets.java b/tests/test_data/std/jdk/internal/access/SharedSecrets.java new file mode 100644 index 00000000..0dacbef9 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/SharedSecrets.java @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import javax.crypto.SealedObject; +import javax.crypto.spec.SecretKeySpec; +import java.io.ObjectInputFilter; +import java.lang.invoke.MethodHandles; +import java.lang.module.ModuleDescriptor; +import java.security.Security; +import java.security.spec.EncodedKeySpec; +import java.util.ResourceBundle; +import java.util.concurrent.ForkJoinPool; +import java.util.jar.JarFile; +import java.io.Console; +import java.io.FileDescriptor; +import java.io.FilePermission; +import java.io.ObjectInputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.RandomAccessFile; +import java.security.ProtectionDomain; +import java.security.Signature; +import javax.security.auth.x500.X500Principal; + +/** A repository of "shared secrets", which are a mechanism for + calling implementation-private methods in another package without + using reflection. A package-private class implements a public + interface and provides the ability to call package-private methods + within that package; the object implementing that interface is + provided through a third package to which access is restricted. + This framework avoids the primary disadvantage of using reflection + for this purpose, namely the loss of compile-time checking. */ + +public class SharedSecrets { + private static JavaAWTAccess javaAWTAccess; + private static JavaAWTFontAccess javaAWTFontAccess; + private static JavaBeansAccess javaBeansAccess; + private static JavaLangAccess javaLangAccess; + private static JavaLangInvokeAccess javaLangInvokeAccess; + private static JavaLangModuleAccess javaLangModuleAccess; + private static JavaLangRefAccess javaLangRefAccess; + private static JavaLangReflectAccess javaLangReflectAccess; + private static JavaIOAccess javaIOAccess; + private static JavaIOPrintStreamAccess javaIOPrintStreamAccess; + private static JavaIOPrintWriterAccess javaIOPrintWriterAccess; + private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; + private static JavaIOFilePermissionAccess javaIOFilePermissionAccess; + private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess; + private static JavaObjectInputStreamReadString javaObjectInputStreamReadString; + private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; + private static JavaObjectInputFilterAccess javaObjectInputFilterAccess; + private static JavaNetInetAddressAccess javaNetInetAddressAccess; + private static JavaNetHttpCookieAccess javaNetHttpCookieAccess; + private static JavaNetUriAccess javaNetUriAccess; + private static JavaNetURLAccess javaNetURLAccess; + private static JavaNioAccess javaNioAccess; + private static JavaUtilCollectionAccess javaUtilCollectionAccess; + private static JavaUtilConcurrentTLRAccess javaUtilConcurrentTLRAccess; + private static JavaUtilConcurrentFJPAccess javaUtilConcurrentFJPAccess; + private static JavaUtilJarAccess javaUtilJarAccess; + private static JavaUtilZipFileAccess javaUtilZipFileAccess; + private static JavaUtilResourceBundleAccess javaUtilResourceBundleAccess; + private static JavaSecurityAccess javaSecurityAccess; + private static JavaSecurityPropertiesAccess javaSecurityPropertiesAccess; + private static JavaSecuritySignatureAccess javaSecuritySignatureAccess; + private static JavaSecuritySpecAccess javaSecuritySpecAccess; + private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess; + private static JavaxCryptoSpecAccess javaxCryptoSpecAccess; + private static JavaxSecurityAccess javaxSecurityAccess; + + public static void setJavaUtilCollectionAccess(JavaUtilCollectionAccess juca) { + javaUtilCollectionAccess = juca; + } + + public static JavaUtilCollectionAccess getJavaUtilCollectionAccess() { + var access = javaUtilCollectionAccess; + if (access == null) { + try { + Class.forName("java.util.ImmutableCollections$Access", true, null); + access = javaUtilCollectionAccess; + } catch (ClassNotFoundException e) {} + } + return access; + } + + public static void setJavaUtilConcurrentTLRAccess(JavaUtilConcurrentTLRAccess access) { + javaUtilConcurrentTLRAccess = access; + } + + public static JavaUtilConcurrentTLRAccess getJavaUtilConcurrentTLRAccess() { + var access = javaUtilConcurrentTLRAccess; + if (access == null) { + try { + Class.forName("java.util.concurrent.ThreadLocalRandom$Access", true, null); + access = javaUtilConcurrentTLRAccess; + } catch (ClassNotFoundException e) {} + } + return access; + } + + public static void setJavaUtilConcurrentFJPAccess(JavaUtilConcurrentFJPAccess access) { + javaUtilConcurrentFJPAccess = access; + } + + public static JavaUtilConcurrentFJPAccess getJavaUtilConcurrentFJPAccess() { + var access = javaUtilConcurrentFJPAccess; + if (access == null) { + ensureClassInitialized(ForkJoinPool.class); + access = javaUtilConcurrentFJPAccess; + } + return access; + } + + public static JavaUtilJarAccess javaUtilJarAccess() { + var access = javaUtilJarAccess; + if (access == null) { + // Ensure JarFile is initialized; we know that this class + // provides the shared secret + ensureClassInitialized(JarFile.class); + access = javaUtilJarAccess; + } + return access; + } + + public static void setJavaUtilJarAccess(JavaUtilJarAccess access) { + javaUtilJarAccess = access; + } + + public static void setJavaLangAccess(JavaLangAccess jla) { + javaLangAccess = jla; + } + + public static JavaLangAccess getJavaLangAccess() { + return javaLangAccess; + } + + public static void setJavaLangInvokeAccess(JavaLangInvokeAccess jlia) { + javaLangInvokeAccess = jlia; + } + + public static JavaLangInvokeAccess getJavaLangInvokeAccess() { + var access = javaLangInvokeAccess; + if (access == null) { + try { + Class.forName("java.lang.invoke.MethodHandleImpl", true, null); + access = javaLangInvokeAccess; + } catch (ClassNotFoundException e) {} + } + return access; + } + + public static void setJavaLangModuleAccess(JavaLangModuleAccess jlrma) { + javaLangModuleAccess = jlrma; + } + + public static JavaLangModuleAccess getJavaLangModuleAccess() { + var access = javaLangModuleAccess; + if (access == null) { + ensureClassInitialized(ModuleDescriptor.class); + access = javaLangModuleAccess; + } + return access; + } + + public static void setJavaLangRefAccess(JavaLangRefAccess jlra) { + javaLangRefAccess = jlra; + } + + public static JavaLangRefAccess getJavaLangRefAccess() { + return javaLangRefAccess; + } + + public static void setJavaLangReflectAccess(JavaLangReflectAccess jlra) { + javaLangReflectAccess = jlra; + } + + public static JavaLangReflectAccess getJavaLangReflectAccess() { + return javaLangReflectAccess; + } + + public static void setJavaNetUriAccess(JavaNetUriAccess jnua) { + javaNetUriAccess = jnua; + } + + public static JavaNetUriAccess getJavaNetUriAccess() { + var access = javaNetUriAccess; + if (access == null) { + ensureClassInitialized(java.net.URI.class); + access = javaNetUriAccess; + } + return access; + } + + public static void setJavaNetURLAccess(JavaNetURLAccess jnua) { + javaNetURLAccess = jnua; + } + + public static JavaNetURLAccess getJavaNetURLAccess() { + var access = javaNetURLAccess; + if (access == null) { + ensureClassInitialized(java.net.URL.class); + access = javaNetURLAccess; + } + return access; + } + + public static void setJavaNetInetAddressAccess(JavaNetInetAddressAccess jna) { + javaNetInetAddressAccess = jna; + } + + public static JavaNetInetAddressAccess getJavaNetInetAddressAccess() { + var access = javaNetInetAddressAccess; + if (access == null) { + ensureClassInitialized(java.net.InetAddress.class); + access = javaNetInetAddressAccess; + } + return access; + } + + public static void setJavaNetHttpCookieAccess(JavaNetHttpCookieAccess a) { + javaNetHttpCookieAccess = a; + } + + public static JavaNetHttpCookieAccess getJavaNetHttpCookieAccess() { + var access = javaNetHttpCookieAccess; + if (access == null) { + ensureClassInitialized(java.net.HttpCookie.class); + access = javaNetHttpCookieAccess; + } + return access; + } + + public static void setJavaNioAccess(JavaNioAccess jna) { + javaNioAccess = jna; + } + + public static JavaNioAccess getJavaNioAccess() { + var access = javaNioAccess; + if (access == null) { + // Ensure java.nio.Buffer is initialized, which provides the + // shared secret. + ensureClassInitialized(java.nio.Buffer.class); + access = javaNioAccess; + } + return access; + } + + public static void setJavaIOAccess(JavaIOAccess jia) { + javaIOAccess = jia; + } + + public static JavaIOAccess getJavaIOAccess() { + var access = javaIOAccess; + if (access == null) { + ensureClassInitialized(Console.class); + access = javaIOAccess; + } + return access; + } + + public static void setJavaIOCPrintWriterAccess(JavaIOPrintWriterAccess a) { + javaIOPrintWriterAccess = a; + } + + public static JavaIOPrintWriterAccess getJavaIOPrintWriterAccess() { + var access = javaIOPrintWriterAccess; + if (access == null) { + ensureClassInitialized(PrintWriter.class); + access = javaIOPrintWriterAccess; + } + return access; + } + + public static void setJavaIOCPrintStreamAccess(JavaIOPrintStreamAccess a) { + javaIOPrintStreamAccess = a; + } + + public static JavaIOPrintStreamAccess getJavaIOPrintStreamAccess() { + var access = javaIOPrintStreamAccess; + if (access == null) { + ensureClassInitialized(PrintStream.class); + access = javaIOPrintStreamAccess; + } + return access; + } + + public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiofda) { + javaIOFileDescriptorAccess = jiofda; + } + + public static JavaIOFilePermissionAccess getJavaIOFilePermissionAccess() { + var access = javaIOFilePermissionAccess; + if (access == null) { + ensureClassInitialized(FilePermission.class); + access = javaIOFilePermissionAccess; + } + return access; + } + + public static void setJavaIOFilePermissionAccess(JavaIOFilePermissionAccess jiofpa) { + javaIOFilePermissionAccess = jiofpa; + } + + public static JavaIOFileDescriptorAccess getJavaIOFileDescriptorAccess() { + var access = javaIOFileDescriptorAccess; + if (access == null) { + ensureClassInitialized(FileDescriptor.class); + access = javaIOFileDescriptorAccess; + } + return access; + } + + public static void setJavaSecurityAccess(JavaSecurityAccess jsa) { + javaSecurityAccess = jsa; + } + + public static JavaSecurityAccess getJavaSecurityAccess() { + var access = javaSecurityAccess; + if (access == null) { + ensureClassInitialized(ProtectionDomain.class); + access = javaSecurityAccess; + } + return access; + } + + public static void setJavaSecurityPropertiesAccess(JavaSecurityPropertiesAccess jspa) { + javaSecurityPropertiesAccess = jspa; + } + + public static JavaSecurityPropertiesAccess getJavaSecurityPropertiesAccess() { + var access = javaSecurityPropertiesAccess; + if (access == null) { + ensureClassInitialized(Security.class); + access = javaSecurityPropertiesAccess; + } + return access; + } + + public static JavaUtilZipFileAccess getJavaUtilZipFileAccess() { + var access = javaUtilZipFileAccess; + if (access == null) { + ensureClassInitialized(java.util.zip.ZipFile.class); + access = javaUtilZipFileAccess; + } + return access; + } + + public static void setJavaUtilZipFileAccess(JavaUtilZipFileAccess access) { + javaUtilZipFileAccess = access; + } + + public static void setJavaAWTAccess(JavaAWTAccess jaa) { + javaAWTAccess = jaa; + } + + public static JavaAWTAccess getJavaAWTAccess() { + // this may return null in which case calling code needs to + // provision for. + return javaAWTAccess; + } + + public static void setJavaAWTFontAccess(JavaAWTFontAccess jafa) { + javaAWTFontAccess = jafa; + } + + public static JavaAWTFontAccess getJavaAWTFontAccess() { + // this may return null in which case calling code needs to + // provision for. + return javaAWTFontAccess; + } + + public static JavaBeansAccess getJavaBeansAccess() { + return javaBeansAccess; + } + + public static void setJavaBeansAccess(JavaBeansAccess access) { + javaBeansAccess = access; + } + + public static JavaUtilResourceBundleAccess getJavaUtilResourceBundleAccess() { + var access = javaUtilResourceBundleAccess; + if (access == null) { + ensureClassInitialized(ResourceBundle.class); + access = javaUtilResourceBundleAccess; + } + return access; + } + + public static void setJavaUtilResourceBundleAccess(JavaUtilResourceBundleAccess access) { + javaUtilResourceBundleAccess = access; + } + + public static JavaObjectInputStreamReadString getJavaObjectInputStreamReadString() { + var access = javaObjectInputStreamReadString; + if (access == null) { + ensureClassInitialized(ObjectInputStream.class); + access = javaObjectInputStreamReadString; + } + return access; + } + + public static void setJavaObjectInputStreamReadString(JavaObjectInputStreamReadString access) { + javaObjectInputStreamReadString = access; + } + + public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() { + var access = javaObjectInputStreamAccess; + if (access == null) { + ensureClassInitialized(ObjectInputStream.class); + access = javaObjectInputStreamAccess; + } + return access; + } + + public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) { + javaObjectInputStreamAccess = access; + } + + public static JavaObjectInputFilterAccess getJavaObjectInputFilterAccess() { + var access = javaObjectInputFilterAccess; + if (access == null) { + ensureClassInitialized(ObjectInputFilter.Config.class); + access = javaObjectInputFilterAccess; + } + return access; + } + + public static void setJavaObjectInputFilterAccess(JavaObjectInputFilterAccess access) { + javaObjectInputFilterAccess = access; + } + + public static void setJavaIORandomAccessFileAccess(JavaIORandomAccessFileAccess jirafa) { + javaIORandomAccessFileAccess = jirafa; + } + + public static JavaIORandomAccessFileAccess getJavaIORandomAccessFileAccess() { + var access = javaIORandomAccessFileAccess; + if (access == null) { + ensureClassInitialized(RandomAccessFile.class); + access = javaIORandomAccessFileAccess; + } + return access; + } + + public static void setJavaSecuritySignatureAccess(JavaSecuritySignatureAccess jssa) { + javaSecuritySignatureAccess = jssa; + } + + public static JavaSecuritySignatureAccess getJavaSecuritySignatureAccess() { + var access = javaSecuritySignatureAccess; + if (access == null) { + ensureClassInitialized(Signature.class); + access = javaSecuritySignatureAccess; + } + return access; + } + + public static void setJavaSecuritySpecAccess(JavaSecuritySpecAccess jssa) { + javaSecuritySpecAccess = jssa; + } + + public static JavaSecuritySpecAccess getJavaSecuritySpecAccess() { + var access = javaSecuritySpecAccess; + if (access == null) { + ensureClassInitialized(EncodedKeySpec.class); + access = javaSecuritySpecAccess; + } + return access; + } + + public static void setJavaxCryptoSpecAccess(JavaxCryptoSpecAccess jcsa) { + javaxCryptoSpecAccess = jcsa; + } + + public static JavaxCryptoSpecAccess getJavaxCryptoSpecAccess() { + var access = javaxCryptoSpecAccess; + if (access == null) { + ensureClassInitialized(SecretKeySpec.class); + access = javaxCryptoSpecAccess; + } + return access; + } + + public static void setJavaxCryptoSealedObjectAccess(JavaxCryptoSealedObjectAccess jcsoa) { + javaxCryptoSealedObjectAccess = jcsoa; + } + + public static JavaxCryptoSealedObjectAccess getJavaxCryptoSealedObjectAccess() { + var access = javaxCryptoSealedObjectAccess; + if (access == null) { + ensureClassInitialized(SealedObject.class); + access = javaxCryptoSealedObjectAccess; + } + return access; + } + + public static void setJavaxSecurityAccess(JavaxSecurityAccess jsa) { + javaxSecurityAccess = jsa; + } + + public static JavaxSecurityAccess getJavaxSecurityAccess() { + var access = javaxSecurityAccess; + if (access == null) { + ensureClassInitialized(X500Principal.class); + access = javaxSecurityAccess; + } + return access; + } + + private static void ensureClassInitialized(Class c) { + try { + MethodHandles.lookup().ensureInitialized(c); + } catch (IllegalAccessException e) {} + } +} diff --git a/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.class b/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.class new file mode 100644 index 0000000000000000000000000000000000000000..1235d5a9092850b200ce1541abad4c758d018d61 GIT binary patch literal 258 zcmY+9IS#@w5Jms6B(fl{_ z=ktBN0nE@3Q6WT0d|^r#(rTVEE`-c;b~09~vt~Pe=_?@$q>oZ#) z6DbNp$m7^LiclR#OG59YQaP8ouqrEzC5*<=%45o~#oug72voj(YT@Anp?)h*`fg8X tZOzRJSwe*2pPNa!F(5dp`v#~vb9Dr+aE{RMxrvs~ZFHQ1&~>qb-ValpK8FAR literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.java b/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.java new file mode 100644 index 00000000..23781301 --- /dev/null +++ b/tests/test_data/std/jdk/internal/access/foreign/UnmapperProxy.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package jdk.internal.access.foreign; + +import java.io.FileDescriptor; + +/** + * This proxy interface is required to allow instances of the {@code FileChannelImpl.Unmapper} interface (which is a non-public class + * inside the {@code sun.nio.ch} package) to be accessed from the mapped memory segment factory. + */ +public interface UnmapperProxy { + long address(); + FileDescriptor fileDescriptor(); + boolean isSync(); + void unmap(); +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$AnnotationDefaultMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$AnnotationDefaultMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..cfd4b86d33ffebb9a63dc89116ab0107af7efd00 GIT binary patch literal 2792 zcmb_eYg5}s6g_JkH|muZ6yiSwW-jVX;Wrg35n#nfr~%B*bxqC%pw+)jT$ z|4$z?VUo^t`nf-<)4P%^E3kGLCd`=CO1o#zJ@?!z{rlg`zX6o+m4XPvrG5Sr&l}v_ z&9@BR>Fnr+mM=Pvtv9=l)`=m?Fjh28%i)f0nXB3k?;1`VqfivYRK$^BxHlAJogW@* z_Dld;cX(4bbmtcarL_5MtGrfcSgf86qmY1#l!EgrE+EZtcfb8ZUN;@hHn|ZBNk2F= z^2KJyv3bi0sCd*EMwfI`ca|B}XG1*dq=LCy2;GrLG%&hCwxM90p*)Pyiq$pS0i79d zdR%SsJb^L1En<9!;Zc}mpHfNWZ%gBC%{~?9LM7WsVgm0em{c)^_bCgqB=DXa@+W){ zFlSKPo;4cW=xPktXR~tMg5cbRg(RkNNx@|mS8$afBO}m1)(2O9wsl9_wivF-rC90i zJP}K5N}WMqSrRS%zt; zI=%FWN|;kIj~fiR3@Mvz7CdD5RgNC4XqOG`KrOpalvH(UR3B$6u)G zrdI17G&OshHx0ToUbR}>XmDE>bN^=4+0#1=Ow@?f5GO@rh_rSXu1c4O#Ut25`c)|W zW|wwcmhR{m2XPm|GTfIgJeBAS>2=N7v)Y^7<_8+p97VSv_e1~W(0LopeXZq?!5F@i zZ#$_-XuG`sy<#K(1Tw)=%kUe0ysqz>-09kshab;kh$Sh9Q%SZ=rb*PTuHDks=yl6* zaX{a>De9eQ*R+oF(CRqUWh29Yj)JX09kW+1y*@P_Xc)YG6@1B%8&(RhzML4Q z2EU#dCI<9K+@>m2>5GG5Qj{WH(T9g9Qo8dA%@#32S3n{+KJo|79U=KU%_6uj?$HQ* zPhT0&P@pT-TZttXhlyt7qttN@QCgAw3u8~`bJIt7>o=NuFr)6amJ5;dmiZ900iR;o zeV)W;c;FtGL=h`QD=J`n+{~vq^5C8xG literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$BootstrapMethodsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$BootstrapMethodsMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..760cefc7e8df290976f415824fa72c29cbe070f2 GIT binary patch literal 2755 zcmb_e`)}J+6#h<{)p$bq`XuChe9z%GQxmmSio-#$AJKy>4x%aQX-~0ifg3l#H2$%MiZrO}M+?`MRJPmTDS`9*9Wm z_Vq%kC4y*MJ`@)kVR}U~G;5WxF(1IuU=obIVqheMp|Q~wb4>{uLUj_Na?dt8KAbtH zJ4&`coxo|F6>+{pcoGCUgjEqK+*Xy2Y90x9v6^cpaUSnVn2~V-?-A~YB|;8()nyz+L!wP30sK}}(hLLKc z{JXgLm}hZUXn%vp%L znmbBM=aEdU*H-kVVrruA4Mwe(+JHbje|>V%@F^oi+Pj3Sq058RvDrTVs~mmH<{g(q zcMR3Y*afYG2cZj(LOCC3x7=?jrqWgUG;(lD;bIs%4!GNF?W=8z)kXL+eA|E3kmrFV zu+rAO5*}}8dxm1!Ca0l)96786LKs%oqcFD0l1Vgrw%JzK`5Gl$98+;_ilWD;>*~OI z+!Liut{R4FIvH0761EB1u)^pQc37e^{)m6AN_a-dPdW#0-#YvTn0)UL&V^S<+~!j# z^J9WABaR|}@tZ;%QXYB0y=6@C7m&zjrhdhV10;XpUIZVBF>ZlAzaYLrk-ubjB~~0e zBx;dorGXQO@`~i|IQ?QVKYM^PKXcbLGwp1%9TRzXnP-AG;A5;h^GSSyhmOM}N+>g| zsJJgY2b(-I#THWwi?4Bx@ER8*7)AO6BmB{EbH!ckyGik5>XG9ng*B`rl77U-Z?I9p z!4j_)#uNF4#XoWW72Y3OcERf*@qfxY;!IGQ+ceT8uKbTf4bC4Re=LKyQ1uMnVKM~2 zF-AE13O7f|4dRP=Q44%24$H;ov@tyK6Q5<%;>Rh=zBs_0-|(RTNlxb7sJra*Gaiee jh7G5!W7BD6Y;k*mS)0aFG#<|IyJrVY)|gP+bIkk$MacVg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CharacterRangeTableMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CharacterRangeTableMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..8d4f497740d010ac5e3bc9f88aa36a739a9239c4 GIT binary patch literal 3542 zcmbVPYf}?f7=8`}7Lr8~triunl~!&VFO;gG)__=}AzGs-w%Trz1s21G?r!kXR;{-6 zOYfHt{RN$V>t#lUcBbR!{-n+b+Y@lZp9 zz>ZmC!HDJ!dperU8?HNL<;`f^^BgNv^h~z}A%TsfGlpYiJ<~Z)J@bN*$(yZchNhuK zM=QbtLv_uJ8}sv~)9ss0dq&2}Tiz{!=45o0 zmQAp>k+1T}nw!r@;~CeJp7=;g$OvQDvMukJK&qz-N18O))3GW^07o^Qi(ToR(9j`} ztOseNP_%PCo^G`a;M>;-V*@rxU!M^;T@7{_+NccVdDF<5&J$seC3+_!*n(#@bn4iO zZ30Jwf?-tBB3ch1^CkP=d=cpA=`9gi^sIa|X}Ml3f-daPuv5o#*d?$|9qNA;2)Wj6 zQ=qY@Hxa>ZbZdA)$BWn_&=rJlq&RiSu^4#)?S`COJV+Zo%DXP~>gYqiK#SBcyaKg0 zuYi;&%L!{Q_GyUf*pCAQz6`6P!UJXuH)Y=R6uK*N#~~eqc!>wvO1!CJTh-Rt%&eL9 zVj5l+*dK(w7Pkp|st~~tj_5clInrFuaJ+L_DI3=Dij*~(cCI9ORmX8DSrq}+o8w6a zM|2iG>1$E+By0+YFs9?A+_Yh3*v9Of{CY}9LLD-dH>TY%&LF8_Tt^CL1;*=Tc8y}| z4oIF#8MZ21BZVA0!?ob#_JbUp+O>F8P0KH$n5@j#Yow8{B|A%6#|2zuZYpH{CxQ5y z;Q0oKKyrCW$7M_kv^gwS|D(XeVC%j{ZY*!knYI^9LUjX3l&fx4i#MLAmf2j-;0@Vr z-c*S`(aQBT9dF@nCQ%}lz7S81jtQKt+v1)&5n`;O(L#=;zdmW%W~w-sF&z~_R%5b| zHS!aNW65i%EDU)wmMb8*V^95V?Gq=^kew3P6{ucKAkEJ6H$hAmi&5ZU;Fem1$^xc8 zjhP}(+ZniZIi-1qv?DMas95WaRmsik%#jy08EG%s@p~$fY+gy=t@#RxCsye`9R}s+ zG1_lqx5-{-MVDjKK5lw5h1@wlA?8fBSfUyX&hBL%s=P0E&fW=utHImil~nd)TeUs- zR$NgO6rHSjlJ7Br?KMhhpS(&4 zJY~Axse;SfNKe?d>8SiQT@4=y><+qae9kJJx5Jk(e5J>kh7Se$>UH>)Zx@b}1i7I;!B?ebV5aJAo^mR1;jHb{cB0q82fDHeJIRf`NK0uZ; zy`+kqG9+Z1Et^TBiH2zAH*A<3=<8a<#vi#XnQ2zr9x4-kCAG2%Zh(oYve{|Or~@Og zFpEZN@fAUgP^nHCoYmav&m%Kp7e*e;4!v5!s+EOmiWI@6~b^C#R7M< zGREy3+tD89y?i6k;JHPdUz5ShxLG!MkPONcX(7U{N0?ZhAJzC;s_?bZtr9*pw&0eZ zyt`>y{xIv#OfKTeFSsf}3Kgl6*LQj5ZOR((F5Xk)`?#Y<9d|iyC2P&Nhx^An`A@(D Ne8f7D74tDV{{@To)Rq7M literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CodeMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CodeMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..670be80d4de6ba72b851c154b700b8741ab7ee50 GIT binary patch literal 2547 zcmbtWU31$+6g}&h*jAO+HM9_DT9pKnI3K2MC z{t3*$11~)DF@tBw4Dig4Vz?{IlA6jHCOjm&tKEC8fM!9LAB!Agdw=h2j3WcH4Tl%iWm}rzP~Z zX_?|{hD>$$vq!bf7Q=(a#W2bWR7_-WS;ZCP8SWh$pO;KqaM#wYmjLCjAStDL`}g}ydWi9WB4M@ zA;F_jv-kyN)Zku|uiTh3VL}Cmr6E zlPo3~7A0{_AC`t@INZ~0M`(eeW|%JT2<01W~^V zUT2s}5*L%BVot?8iVT;1D&ZDGMJn`SFtv;XF zDf+NTp3WdOu7)>cRor11o15Ry(fXc>6}-uitv6eHm1ecZu-^E8xh*qXX_z)|_DLj(@Ba2&! z7Ey`OJuBnJu#|XkR7@H2+gv<$j9uN;PdF7T30g_caO5oJVyAsfZA&G?@M*Hyvq6ZN zN8J(^|5RZF9w^7F9V@tXb1n18)I)Y_i7@CQBhi>nowF!&+YI{df^yujJP6} zWz!PVCilda;|T_}Zrj}T#c?l#Cd2f(jXk_y3Srn{ub&d#K)6HIuhLV@FezJrX7nP< z=AbWWT0OuR%>boX82bg!^>OKETBUGbexniij^5($@fOY0!AY`_I8;Me4p8>!-Ii$T zDXtzYEEcEwc>X6^4{*kPyB~av;^16>Au->^JN~|kGFE+$D&EB!@k+}}IPkDV>oG!9 zPI3L9@KPTy|9J-gM;~7soC@(3yoYrkUqJ;MNaY_AYLWa%zAHo2;=vMaXe`jqIJU8~ LKIzxjE++p47}>Dy literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CompilationIDMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$CompilationIDMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..b47bf758fa344eb4236f308fbfe3e98762f2ee4a GIT binary patch literal 2776 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 LBt0R*E%g5ffSpsVZaTs;H6!4Qe$X=t zrIzhjTHEod45$$%mvvKjRtOuj0Uix@-`pz(Mnbe1>0L3`RFEN*$1z&%_RWq@XU6Rg zW%ef$IEy!=hi?)d2PqB-m1Wqrh1L<)zhYdh=9)>I#{~sbDlXz}!a`UGw4)>_gz(~| z5Pnh+GPAjXSbaw~3N_t!ib+i4vVtoruHqVDI?TjsfA^`SbI1tkujGf^Sv5O)TiAqi zp1(uPTr+_zW)xgkaRWCAYvUvy5%ig%J4aa%ca5)hJDizM!d3REhHE@lEH@!?BQywv zTE(1-dE6qLb_w}Ygwlyv`2fs7Dpyc(2MdIh#p&Wt621*b_g8c(hBy$W6YhI30jpjf z94jc=xLo3soW(tvT%N>W#&V+A)M#k&X#6r2ZE0syR{e|`k~2yq0QF5Xgi!sgwMja z{nw1~EO6MD+lE(};|+b!)SSM>0oXrD3M>a)7?#cPTCH%JBpThm)fVe~BN8r+s3x~% zU1Pp=VLOkywnI>>rYS5p%EDH#O~{7TK3}S%B9!q*{CiTt6GDDm*8lSwAzT=Bk#O*j z*F7xoIaB#9K$wz;jlcLwAdexBywANQOz;v-$k=ALGT7Vz=}Jc#D{q3 z8cd>uRi+h{_1`nF$ukp-n3|h^iMI$ZaVdghOo`({5!cMs!D8P`ir+$Ou9*}nSVtti z#^ARYRBEuut0j0MKR5px=U?ERA@YFyuOa?_#5>|FP@3B`(j~6yk3s=w50O6+;2l&w zz`HDl)HlWqr(fXqadCtEVxHHMUy9ut@N?T39{YjMGPL}0$g~f98QPhSpZk+K)608KlFddJ#$n0~vwO~Y&vTylc`tkN=Rd#w0bml}NeD0; zT~Y2Raa}Q%;(1-M?V_fu@o~qov|QOy?N$UC$Ne)( zsia!HE?&k_a+3Wl8G^QUPi1K8>rX|{gI)>G z$T)$M4BdWYCd$R@mPX;FW7ql1wX=lLCtT@9zl;G4GPH6F#WBgMvw>2oI#0At;k1Of zjAwC%h}UV=Oz41R#ZIet9l>sq?>Hx880YCgLrm|lVT;n4&8?_;Cn4cEh9N)henO^< zq8Y&mo|kbE35KxdmKj650lyyUylL2uVmKw!)Z-%TNyD)=$f+K@AY%+K5|B_QWfauA z9LP6`8*t_btOCQ+Vg%zdCNN1rCiQ?y;XkV8Y{}6~sxvCWB&H<1B;yKF4Qkd*sK!hy zsoNCl6J9b^(W+_FsN>5F1AaRC)8@|4$VhYNqjl$Jtwq%m63@wag*y}y5~r0lmAjdd zvA`2ERMeFvdq%NW!^q;ggjZ$Uz#_xcPW8J@N9pxeO0CI+1gQzLK#lLZSA%+B-R$-+ zV7~-XZMR2=j`R99h2vWBhWUn!TewZtC@8s04CA}vJZZ|6>6~M}+v<5s9&-$a^S*|D_}&br z(yi=szYuhCXQNabrJ7uq9P$pVI{?)1+!1mC%h1S-Gw$RCt9z3;$BMe)3Iskg@W4IWM1-CH7 z@I4mz8(pRzV&r1;V61ry7r5zY0Ag^7ddCA?eu%4En6A#v`pnH&@qhUDN3KawXmWyn zCxGpP#P(w!J3u$CPK>dGm}iGjWHH#R3wPLI;p{M}a)z!Rcd$-xMBa6K9e1%I++N2$ zyhUzHBt#e9CO6+9ORjWf=3Sb3k7n8t_#1~MbW1q(7Z#(JNu1lXkH>JBY?|m99vB>Y zh=UJstscXQ_{~1?yH7hpq<55_QAEe-JNmva;A@+>xhudtKBxkoCG~iIv=YPa2T&eO z4llpfs!E(+8@W~CC!VeN&`sPPg64mea@iZ3P=CcTC&@&VDqgqHnIF+y03YKM@%$8@ eiKi^sbdhQ;_#9teiqUV9uka1k2(OlJ5&I8x`TG|D literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LineNumberTableMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LineNumberTableMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..1b4392a59889760d9d6faa8038d3e99adc4e8788 GIT binary patch literal 3312 zcmb_eYf}?f7=8`}7Lr9H-iiuVp_NM@g4C*^Xh5xz5Uf$Gw6@(O3oM2W-Q9Tm+F#LM z(67DB$k5Jo{M=9d2mK$N>E$^mnCexnhScR%*x?P9}9L`#{nX7IVOy_}7D4X5rgr=cOM>nDZ zm-jWXXl!kn&QM@7?->QFYKP)-ss;iG2i;))4p3BL@DcTrT9`$2H$0)`Gx}=8TRj74h52TDQ zC#-QyXh`a~h)Dw9g;iJK1?z^JGhcWL-HJSMNyjuk;DxplAFJC|b+lC2FpFMF!-oQi zFzjJ`X6)5U43}|L$2G~1=6Z(X-78AjjE;|_EV|2a6xVS>Lt4ii<^?kQWm${FA8HC_ zy&Sp~opY5ED|971(E{?r(=5zC)i{D=PRZ)H)grWkmaOiNb=*OQ`Jzw-TLS3=K?@8J zf#h&OM;40$Jr2tz*cA9C+YteP1_46ps^4$ekC-uSmQryip}jhmSn}>Q;E0S z&Gmg9c|2fZXL9)m>D)XyT*&@!!A~)x=PM%A&H3B?h2Y1L7dpj+smywcQ=}JXF_p?U9a4mrR^SmI*U(PrhYi$i>9|;Dcv(1 zW7A|mBckc>wB2>T;a0y*jVud12|t#u=V%blhU4L%ojuv^-@t60DUvevjqT1`YqsH4 z9fr7akj#C1;+oiBP|A>yrHex?;*+wxC9D}HNMB?J34w2skTX66-r(}Jj)YVhVZZXd{C7EgVHQ$A~5MA-itcbkLVh_9;wUk}}?;ZtK5 z%0VU$(zN_z3SED^joeT8M1o|e=Kq@4XF1>GstqHiXa{{niui0uFX literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTableMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTableMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..a848e331da68acfd63ceeff5736b38e49b4cad18 GIT binary patch literal 3614 zcmb_f`%@EF6#i}qEF_CYv??k-3at>(R7EO;QbRzEgh&md(AsvBEU>uj#?1|ieZOq~ zh5iMd{?^Bg40WdC&;64+)5p0t%aY(GwY1E@eVu#Gch3FJ*~4#t{_-n;B)(A)U^u>_ zt!Xh+vzB6cQ!AAg4O5RLICqR(nd_xi1Q|Ngc3v~*G{?|#ramkFw4nuxf>sr62r&#b z)H1CVi@MX}Y0YviXP5?GXJ|<$#wXKRhD+()sfdT5qFuor6?+k3xUf>V7c(rbJCQWUJEc-4+ii0V2QU+9}t(7`a(2-3J+ zwhA7e9=Uuz+@3%P`*1+G`VzzaYOFrU3X`V3s$1OOfuwlto4Que9e)AOX2rvJs&6ig zLpZFUQ^gS+Wf=B*GHr`Hu?B81>@ll3RU(r0_EiF1=7t$d8zmkOqYK9soKSHRr|60_ z=N&TyOU5Iep{cho6-GCD6uhG1Rh(w%@zswr#H4r2(zDn>+zloHn*K9d)FqblAIdo8AJE%9Zs^`?r; zNC*ttDh2Lr4Tfz7KP1HdM66LW zL%J$z1dWDpRmC+4g|8QNv2k6+lzn69Wf+!h0aqz2t*|3 zRV?6bhIWV2-8*D>?62LEc<};~a&vdbcSL)UT0j+i8h1radsk-5TpO+5SD_(C*_g^? zXA_wuQ7-epvLH@OOWFm>g1u?O(lh1NobJf?qXWKdP(@;Nc)D@%_aej)$S*RS@)fTx zwWPL4zbUd}Q1UXI^Sx3haw6Xec~h=T#!mR&+-5GB5Na6y3x^q+1x^Y_q+-sizl7sp zZH`eUyAe$8kRA1f+Q`W^zG+uUyP0ns8{I6oSqXLO2hO&0q z$?I3Bv12$^r&^vBA05J-(M$ZAU83)nnzAh2k*?|`1)no?`+bK&jzJDOvwSoOVczRmI zJvJsKqOPWj4xw`qOH!|jWf;OD?XBP*nn;qqcohq*gHBrLY;9l@2dMz|pV`DQhE2R2 z08M)tMuMHeO$;!6i>#PYL-PznBhCGt&6~L7ipm8MLEe)KYIHX-9)Mh2sa{ZBl49Te z^}UEmP{t%mQ2|RrVH4QTCaLMUf-!a#Q|ub3O+fu;*rPRZc;6N!cQ?hzkzpt#(M%JlP^{AdWdX( qKzjjvh>zs>F+P!_ice`gLQ!kMXZYfBC;dC|B_30vh?Mynoqq#oWau0K literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTypeTableMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$LocalVariableTypeTableMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..451fe0c82e11a4113ba760043ed753fe9087bc7a GIT binary patch literal 3675 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleHashesMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleHashesMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..9aae69a0e179df549f7089d96066a55ac4415254 GIT binary patch literal 3540 zcmb_fYf}?v6n;(!ED4K7v|6l4tyB^~;{`1xNFfL%mPBeac&W9UWP!!aZo1j1*qgoo zhW>(nX=k*Z%Al>ae(X=`OfTo%B%4GR#$n39y!)O#?>WzT&ShWz{O93g08{u@f{(C& zMY*X&b;VeU=5(c0TGVtkI%(UMmMz zG+LpkM<=r-+fs723#9^$&^D$SnmtZPh8u9CnE+!c)*$g% zyKwrPZ6nd{s~~n@mx%Et!r4ZUbx2bpb>~$juUapJIhKfIIQUY61F**+}8wuNxP#GTEdZpfPYxV5k$F`9c&kmvqIQmwjal29LEVlyFjnl zCP%Ql$zP%>XP+l=O2Qj5M(`%1s{5>|umi@NQg7Ri>nq|!OvV^avqQrX@2c5$I{937 zMa|hU32zaGymYrv^nRvK*|iK{)BD z=w-jLcnP7(Id|5v=iSXLtrlxcO+2GJ_QF1$n8w+5C*K5eH@G{i;^6^q9W zPex9}uy?`MV{Y(T9e9xp;hOic=abiPygttwlh#z{RS#UMV>!KgV+f?RB}1{x7MF~^ zm9l+t;u@1B_zR}ZvXxV3__jvax4|SlB1S(WPN^k()-3VYLrxfmYB@owB?+Gs4tjka zT(WB8v&)sZH#iAj5e7Ev)#eKhVeiIQ9B#?yr#6o9gpm2JO6V42f}i-xDh3Eka=aTs z3qJwDfv%RH(7J|>`@HiZFJ!!e?jb<;q4Hj?XkyW^Lt;i&t)$TkKWlV6!j8*B13hcl zdCxV|CXUfBj){SaTGa#}z!H`nvmMZ|A{?^p26Tqy7vHan1L7&ccV<8v99qY2!aDZ( zz>lvHQiF%raY%@UeBj5Ugi(LDe;vbw?=UK!MhQS9-R%vu}n;){uH{)ga8e9c`U`r{jP{|8z3+6e#v literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMainClassMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleMainClassMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..77ef437a719047f119323541711d8575a920d69e GIT binary patch literal 2795 zcmb_eYi}Dx6g}5*vwo~wH&9AS(+3VTcG9|!Py!C2j_VM&wiDvuQY3`d_9We~-nG_i zpr83eJfubisp1Pr^aEeo--Ecbb~f8|?L-lgqVc@WJ@?F+JNx|K-<|;|;7bJ|!i62} zJ1uKy=61GeXx;9XZisB&acsTOb3`|SFyU0iYV{0J(R8yQ*F-T6ML|SG6fwf>kq{NF z(-HQx2U&BphHmK2V}epx|7N4OQX?#skB5bRAo3Iv$liHNyC!ZtBhwp)%v+QDY6v?VN8UK%k-7<~#*pG8@OyPopiz+VRGGQvn3(LK&2e!@!ONf0h zf0WFY_(8@xJk&bJ>qko0V@P3I!Fwv+#}z_p)bR{4%=7^j_G}b&c`aKlw)R)Sw7e{W z&*yNVU0bDxXyo&XidhwNxJo$bvht<~`D0P@0GNT)FstG^ZV(bS`^}pq{1}Yxt!Nbu z(H5o?EP&s^rC<|jhnkU#LJGI!RhcJ@&7|v5?%!7NAr=UcQnj|3uNI1g`{n=b@N`kp<@W@2jYHCJZvvt`Y42GRYdY3>vehgS?Vh`^g5a0J1Y*f6o0 z)w7#og&$nP`60FDnyiIPx+=QPs?~J}YRNQ(?dB=E3N{F-pnB=)wO5@cyb7L9T||v@>phCVfjuB0<7`O7|$hU=bqv%!c&|N;ULo&Q0b)`=2CyL z7bd|UU3c9u2^6t{Q1UK=Uu96K!91^);IYi?+#fjm1n=%6_sRbmkpE}ABg%Y}+$NFC zbIo531f1DL=2(E&Q5pc=WHF?^5oS2`1lJCV>*p64WG(q6IITWEw~gSQckn5OmVbO? zsfW9``71tRjhM+j#V4S=cwJ8iF9iD@4gq0PuR@R(z=A6C1 z{q5J8`8?9!=8RN_=Q-v`!86=SR1lW-+Sx+R zsKQcc8Y%^{fjzDQW+ zqu!I#$J}1sogkDqHK!$-bplOj=7?0P9@tE%XbMbENcL_h znj&8_MXq_mkej*$cB7lcNq^~{%|0t-CmpP_$a}C?Lt5Zo+*iU*xP^T%uDgB4F;>9d zIV4Z?3iP3$6?DtB9lfIXIFynj6OZe4EqOD04A@LCM7}a`b?}kTi68$VwC_ z^6ggz4$3%K7QPK4LGt-Efy0td%{Z2~9naP9b;5>)faz8Td@RFwNI=I3>+t0m*#SK> zp^tH-Y$~z2nERyx;O`ETY#3PqLt0c9;EEYEj4^?63A!qHxu5B1#1VlBH2TX6g8mI9?4L=e%gC_~QuGcE&Xc9y&A{qf>bL>U#<_5q+xl*w-(*H{jp)4~>xIJ-uoF*2V=l?XNv!7Aaq3mIN9& z+_z_P!EL%~&>XXLui$X-jV>nix5rE<7O?qw+ri9L584GMW9;Ft7s9G}s-|kqjJ3~j zy}h=)%ZRjP8IFo>*&%*MSe?|uBAUX2TOX}N-!&ROk+-$$e2A1@`w1(OF8+)uUfZ#W zYl`6SH9~_dEIi`RHd%6b zyr$%ktfzsLK`cQ9@2L40%MZ4-G*08j_aZS%b+1tRzWUdJ0sYz^MT6{(Qd z-oo1qt3viSUqRVLo-bi3Q>|??xQQ@>Rb`OlJLGt+KW^c&aupk{Ve1U;^q0OOU*8?< z;q7YPN$6WYgFS@v*vW$)!Zi%sRngi|F@t@fa5>o@N|%!ZrQ)xAHY))fnxjF@;~KVw z8ioT655_fQ;u^R*%)l(emCrtrq9^BwR`W#B`9L&R4WAi_w-6W2-#~HE-w38s&9~(^ z#*v!G)wG5doC?%@SDug#kZQgcN&cG*opKdA4pyDCcK&OKaOTth|aRiV5Xs!pVeWn&uN#9Q<|stV3M~Uxj{|DDbIiJhLc)=h$UF z!p&^EOx8+9*mxDs&&||0zRG|hiLaK;^6{x>B|eI($Z8fX|2Y3oADqVd4{=d~Bozz3 w)u&kJ$GldCU*Xs4Ig8(@r{L@Zd!?LzANnnRzpH_NyZ8hC$OTK5u0NsSzx9PdnE(I) literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModulePackagesMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModulePackagesMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..7e1b40ed935690e131efc224aed63ea36ab49d6c GIT binary patch literal 2732 zcmb_e+in|G6kXeKGro*l*DaKkrWYJ&?4)%sX&Z0|b=;(Jv7HbHmpmXewolSYCu3_o z2Jy-lagiDoB*Zg601`a(rF;frpYdcoiN+2JShCKX+d6Bnz0RKb_3s~l22jLj3POa- zyV{pp&d|)AT+`6H-EG|vxq@w5dZTBHZUkY%=}NoRGsL>qe6Hk*ROy7pkTEhBQtn;NzJ&p@_OTmPSi+G!GFDMP# zff;f`xDg^9*BXS>bfzy^&(@7xS?}8UI3{sf!4(x(ag8t;bjVU~`>CaK;t0vF+m9VPUT)K47_=)ezAhrm+1#U9-X*4m>Rtn{&x zIrhj5(ZZK>6*DSkaf9!mL&}>X6i&p<17HSH!JLX)xJ^h{Y#eWr@J%qfx1zOdh&^H2 z!SVa8SaSVvq{L{)xr*<08h54T=LlodnR=A__fHiWPom z5-ts?GB;(tW6o94wO89+o1m6VQ&>*6MOVQFAsti`J-H4FQ_36h-l7UVC1gk4fWt2t zra9_0LpUE)6LFjGp2}Yhgb8^8`H4RsD7nIH352xU~9wu&{URk6`zgKU~oA=Kufz literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleResolutionMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleResolutionMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..2df8afa91d76d874d30513cccf818ad20f6b8957 GIT binary patch literal 2724 zcmb_eU2hXd6g}55S%0j-1PTo$eAJ=DPQVaS2z8p`1gDrf4vm8;s`{|DCt=gguC-pb z>U)1sKO`brsp>QTq?Ou-zO+wO@2s8862@*65h)ta*O_zAJ#%MY{`=D}0G9EYh6v%p zw(*sbw+wqL-?WTQXVbJqzUXfZh-4^a-fLZg5hH07JH-va?qqtG3lxj7?eC22;g#>h@G#uA)0%^jn?berh)AodG z8&)VLbEj?Pi;a%w8ci=C(<4V1T`+CaTO_Pbg?Q9h279Xz8c}F8Fup>zu3?N&9>!?N z>DsM;&ZOTxD0eWOz)75zalS=(7$&+;Ygs07T^KFl9*TFNoUJEu7H?}9*KrQ-5bmfF zVeDBVKad^agd137#WJ=!gpsLiIf)5e&~Q=5C0r&T7r6|Isbc7*Mz6$l%yoK;>GX1a(%N&rY3gzA-_~&l^MqKr%7vo3Tq0B|Z!Z4@cG$Ah671WGX^U!iry<-8qhayL zSjA}?R^4z-+3ycVy=NwSnt1-IGSJs0BSe~;gv-k1Vd)sQ&HrVNzR~3!7nM8q-N@Xf ztc1JDg@=(`7Ixu1b6SrK*Vqw!`8c>awHfvg4js4F*cMHX-9`99z3p{DLfh3v>lF|6 zPhblyG_8Jxj@QgB+wi(Br=fimJ1i(U97eH4woIbtbls*{;dhd7en7>!E^8dKu8NNL z!0C7dy=>dU^)oIy8rBIJRUHfj+bdCH!AS6KYIsb@4Z8=gJ}Ugk4}Vq&XVeuEH~ALo z{Ix(BmsgR0@kfKaq&#w$d-E9KUqB)^Hu3|G?IQU-_agW}j&Te619AEj1@7y;m00j` zNY}uhsgDo^&xlzKE$FAo5V-BClBPYB9@p| zRK6Ge1J-zEgy&MzGcRz4@B-%}ILP#G==6_&%%$Gq;FuJDE#3EzNuh)lMAG*e{2GHw z4d!^Y1W)9qXMV-m=XiG?xkvstMf@N0jyUs8bDKuG$d&(r5^!o4xg!DIK)DY%%VJ1< zW6W^kIj$cRH_R{Ak6Q9eaacWmejCHXAn_T7mVcbG%+p=W{)qP_N%Aw_i~4sy^AjG6 kpn_Gutzyk@bv)ws9IG~pPf@!!&Yv|KsI$kU+n!+jKXm=``~Uy| literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleTargetMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$ModuleTargetMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..1a904ff43458acb27068b5bad64c855280328b90 GIT binary patch literal 2766 zcmb_eYfl?T6g}5CtZmkbLmw$LD%?T6s-i}1ark}wjHry`P)J!(GSBw!bB1&!h;j{uULC~!XFFm zRi#z89a}yp7z=CPtd|z6gqh{D*(ju7B5mNji3`XO?(HtqwfJ=DKz>tYyysy~P2*ElKLSBoEa9#$Y zSaU47<@vjWsqw6qw1(%lq~*#z&vWum07h`dz*Q61aGfxs12Ny;+VpKs zDem7_nNHg zO+BVC1buc+p*fIKwg)>AnV6U`F^OB8mH<*XMJS#LS7?9{DE9IuZsQIi?X%RvNy3kM z>*0!K$q~E4mHOzT;w|gdW1Xx+t^}jFr;f-pp>I4}OLG5#iH|TtNR%tpjbde?L|9t> ze{xMU2(iW% z;ktHtlrlEE$Nw@%UT^b`tJ)oh3S{hxPQrcd!qccGWLAWH<~7$W-`W*?EIF`gy#NlK zMqI7dcSJ+7q6lB>w;d-VvRz;Fj_9WAfm1)*aJtn!S+%!aOSXMZfpZoa%xW>5#?~B5 zB~|s>enTws%}Ti3qq0n?%EyQ+q9vESmgHNv?7G4aGA&vL)(NA!>KKxBP>u$}k?^)P z@Pv>%N&81HBf@a+>xd6@(#m?D&hH7wSOr$j989K_7nssoY@SFF3c4 zfuFe-!zXHtThPBqa#P^G*;$F%zz(UJ)3s8?ImCIz!0)*DbTT)xkGFmb&Gf5nv3Ou2 z*ICvz!5i=?<^r<=_zVw~Lmn$)o?*q+eb9BV$}@dDm!6n>iFXMvaXE%Jkj9cQW2wN+ zwa((uO`6|Tj{-Mol(2|c<`Eme#YPne)4W<4Pvs^iU*XaV+&HuxfTzDS@qf-c6f+ra zGsqOV!Y^qJj_)IPCWE(8?i#$yWGH?UjBw-yrrsd;2);x&YK1S&VRi5YZ32(O#E-IR z_2ZO{KHbONUvXc7q#*O1sQ+f4U+`EA%UB883RZ*G#2UB5%vwLbMD^hiKZQ0>V~r`b HZDQy(k+=T1 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestHostMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$NestHostMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..63649e5e1f5b2100f892c2e5e34636122ac11ac1 GIT binary patch literal 2706 zcmbtWZExFD6n?Io)p>EcG(bnUb}yu`CheAWE2EH7mZT}mNYm1kO#6V4#jEel}M3&U(PwtdCqgs^3Lgs z4)cbsce@9cZRU%ddseH*&2AJChG^aF@~3W>$1n+1MN~r!afZiZZMXGK$MhBgUk$Fe zEZgEQ8PxLbH+z+>2E$tIay|-iXh^D<(r^_ihDXQkZ}XPJP0!KoP$t$%$Icg9UGC`y z51{m+F-)#oj>R_^wiiP<8kD?qSP0EXm>HQ}A=^}uW+;wBRC0SxJAkv`4~HZN({W7W zZIRzQ49~&<&)}3r$@WaWZF>I+Z=srPCU6b!s+iSq9XA;AvI6Ks0pu^BA~`q%Igs&U zR!WoMI$f?iyyLod-UnH6xc9PDVwZXc&pnGO$q@fuyi}dG`Gbh{ z@1b@nUO!T{8Ak>SD&E)d0q!!C#?@nlLKcSE4+RtR0hQb~iMS!h6Tp`jWDK*ua z38_NEl7?m6W0>;c1WP2kOJNEe5CXwkUc&>dFeE)vRy7hq$5a4t;&mj7BCcMr*&)^oK(c{wcP9? z5g~IUxPZb0oYTr60+oE-um{aM*02s8o%cMV|L8L1UzcJS$J7Q%B;Ig)o?&j$g~>2C zqJ!KQ9gab(I*#f2S(#lGUovE5tuJ6_*l*IoOmKUu*k{O%6Z!eeg<(d1y-@o&-`=o7 zM@pk_1BO{~uIPRf7t{_FYchr4e&`n3POw|ZDqaU9bg;Lvg zEVbkKR0h-tlk2*vI~#<0Ho&9F{+oxzz(`1NMtWDwwPd6TTjLmQ_WEYmr!((%19A3e z;+Vo)!o{}vu4CZBgpx{H?CRD~nc|_jl0}h=jA?8}&>~&e4t?)qmT*JdWK3=XWawDP;NVkFo z1&dfBTy`1xQ-somX!!ulK*X+~;12E*k`_zGpCtSkj_$AMRt)V}Go5hfgCeYYN;p?m z)UkTv^PIswq4ZV4L^juoasR%8kFiFGRvXRzQlnfUJgogM2`>^N3x_!p*(uL${Z!hiKXAxw|FQ3zA7l|S6& z!=~`NfH#U0$6x$B5NDA`KH=UPCin}8=hG9v;L<4)KXXsQr(%p-NEyVWc@(*?3|3;@ z#UW8`Jd`FbA;K#Xzhmm@Vt(cnSAX(hCdD=>>q6uQ%RC6)fX}eu!Y1%J9teXxR>CIJ ziimr_GqA%m6Fiq(SbT|h2rqF%!g;1kP^4wo%-mqHZzjp_qAk}<5*2JiN^LRt5`&5u ztnz9B9?vf<{)uZZ@cs~aKz=sF|A)LI#(Y!UrjROeZGRLBm_0@QLV$Nr^#E5m7$Uw= zW;pW#%jbg|I`$88nta(kVlHi<9Md@#+AnSHcaV?u3DF#QkRL*YOG literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$PermittedSubclassesMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$PermittedSubclassesMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..50e4d92a0d0730a25c559279ec9bd7603696fcb8 GIT binary patch literal 2798 zcmbtW>r&fB7(FW-LzRIM6sXhGOb8KhlnDFGN(98EMr{ zpP;YP%S@QGGoAkKLv{MCEM%3DT}qfStKI$fd}q&|z5Mm}Z+`%&;42jh!}SCGJH2S? z)_$>V>W;H#n7mjP!Zup2;7%MdhD+Pr?ixbyPQz_^QQS#j9IA@Ah6Iuf3nO7R^}|DM zPX(|Ip|=dv5I-=emF;hK);Agqi?y?1l#qFr#4>_ZZH5%z`e4@|oxb0K`CQS=8_Va|~&lEERMz{1}ZMM0D0o-sP5v79niX zs_%>w$B=$1ztR5B;gQ@C^9*Ct`DTLZ3mQJgB161dZ|s)qm34-#k=yWp8==GytModY z;X=)@c-`%`xV@{lOlry2dTrfo>b4>4eq&6$HpsDz`tOcDPy*o?l=dFOt;q1OfCPI; zzbXmPa%sek$Poiu5_c&s!*XQcDTSvUxyi-rUT0gk^)9D9O7okKcEuofDC1V^fVTzN zjNw)Euy-|+pMi|9+&29aKG87tEnT=at%P$HQ@oRCD`cExqvzUfzCm{_!?hvSyDv{e zB3|c?c-C_SgI2XHZhPy_9Thtaxu_E}(Cqlc$_6dL#jD~=hQg?m@!$6nneabvCWeWj z$0p`zQ)=|?pdh(3>5HBpa?euBCsbR+7<~cBLU!yIoI675XR0Y!l5JE%d5nazfD+ZU zek7JX941dEAEkkFh*3o9cU*iqTbMk;rJn+raXCy`@*oQRFdu>j;8U!4uqiyjs!T|2 zWvmgcn7l{)1Y6WIMt$j-*|&I~;VrHyILY)0G-cIGbF&{Dq)F4e>#3I}jdg55$vh?S zdju*qn5Sq7o-EAF{)sDZ@X-LdPkt_9{-4o^1o6#KnL(yZcfqqr!096t&II@XRUhyn zi6Qlk6T`_jxPMaIFu%AzYsoK7)9Ul{$~c|}3!fus`A18ZdwGP1zv8hZNly^^-=DS2 o`Z?7U)UfH5b!>U1hHWaZl4|4l0*%!PdK~SdNgk7Kdx43605`h|-2eap literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RecordMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RecordMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..b1ce3396c2b02a2ac2f299bc8306f8cef77c3e5f GIT binary patch literal 3439 zcmbtWYf}?f7=F$Y*jyHkXtk(l68yibIy79ocDd6_jbQ>vy~(+u+i4LGtyU0aJcNPPUVE4%n$PDB^O<-HKi=vA%g!RfP? zj*C5E7>96#vwMxb=hl0aJaZFtiN}rXuJ? zpNKalyoG*-9zP^A)zTe9rKnQQJmHh&^Q2?I=Fx*e2}2lW2=X1WrPHpXO^{NqoM4UO zoQRl&w=qV*>#%BD$iTX6W|XIvjqV;laY4d3-XVjUEk07yZP&`J{DxAn;v(K<81uv4 z>cwQub1AK)M=*hl5-uUm)ytdYlXFe#>rpP~nrX?JRnhfwY}qPJ&T5viMU;B+o`h*! zrl{DyNohspDMQRZS(?-=kS<3J&xi>mB+PIq;i6&|47EbO5}n1((1ORIwwMH`6`(^?R&PKtYm~MqVo0K*lHwEixnA& zIw$ItM{Tg#S6h{uzh+zZPQ8+~W=hj!vy*P~!Xqk6HxAKx#ah>k3$j7IjJhtxWZXYr z>y#TzyUlbk$MC@am`B))W5e-!vuuoCQ<}RLC|{=vW%t$(Wz{uJwyFkYPia57`)c0v zpvSrA!dbm)6qIZ9%3?UVOWQlgFBHO>QA}%2=lxYmX_{i#^b}LXXAHf5myTzv)-k(0 ziTC~z@g>91UZvXnJYhKE_dp>`jm;Tj)D$FoS2A?-&OkGIUh)as8RBRBe0KcGI1Aow$4*Iq_vV)@xnc>kLoMhO+SphU1 zV7L_M4(wor;agnfGkTJ|#Kfic;qLYwO!BQ$0_??=#zm4Zt_k?=pWis~fKB`?f`s@s zL}3w!g)GK|B}@y;xGChYBHY1!VZ~-MPPE6+k4GrejL>xa#uPMlOz^N4nX(|Cq(p!82uBMqgRRjGM(c=8mB#NG=_(UM_%IC3*4v&$?m*tZ zK6?z}sh63(q?-RIr*7We#=W2LfP-XqgdEma$>tWx1U$n>_V_VAu}2A?(s-P_)`92v T{7N^y+rPk9R0O;nzDD=IpscY` literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleAnnotationsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeInvisibleAnnotationsMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..e17ff7c21b25e751e3e08c36fb666a889e99b9e8 GIT binary patch literal 2843 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 Q(+jPJI*Clm?E%LB0c&VZD*ylh literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleAnnotationsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleAnnotationsMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..43e8fb05d5555af6b07186f8f89f66b918fe486c GIT binary patch literal 2821 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 Cg5quf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleTypeAnnotationsMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$RuntimeVisibleTypeAnnotationsMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..237bfd59756cb4ef8e469265ed7e0803db3e2b6c GIT binary patch literal 2934 zcmcImTXWk)6#iB*kuP%Vra(z)dUK$$oz}gC5^xB$bD;*uDY5I22Oea5lPJh?kk&AL z;79OJxXd(D!ayH*p+Ac0SxJ#iM)Aa9@Qi1*yJx@iowMJb-B)E z6;TZ_#2FqA1zgkj_qjbCIH(D|X_$t1#t?m4t<{UA$_m4LiUk_#TX!OjmuG6H*jxs60G54YRn-aL!FuFvUxO&?KyR7ui!AWzgB!`Muw5u^S?4Ig5jDpgrls_GI| zs;$cZB$EO|WU1Tc4CgC`#jCweliPKj$}gRTO1Gt(4c#_m-ye*KUBh8uG=FP&kqVN@ zptQCbZiJc-76O9Zr+=AJ(d^NRYoROpq9yJ!;S8&xh9hqVLu!qS-ERAdZtERR$C)CX z3)f7a#enbi<{obe5+TFa;miK3)O-&lj)j)#-ygA>v193?XVaeia2BB~4200HL4(8JFvn zzg�XXj%`%ulfB;%fL5kEBN$E22caBJyJLJ*?Br7|kVfvoG*A!wXzdaGdJj(3DrM zo9mu&;3i4$zh&1=5-V7Rl3FJ4+XO0;Fh|xBJf6+XzQm>HxYyi>;vAXWXJ?ZiQ&|9+&P}yL4Hv`YRNB2VR`)AHj2-Kolg_A z{3Q;N-a5ejU-5w?$=t2?qW+zHenDdjDp+&dD%Rar!xL&RQ`W}uC2Ef*={;6QgG46f Hwu#Bt8O%o6 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SignatureMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SignatureMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..9a1dc0bfa091b05e7ca2f1adfd62e2c8d485e65f GIT binary patch literal 2716 zcmb_eTW=dh7(KIbv%aibH(WwW(+dtXcG5UaLkT#9+O9)g94Ex7t3DvKwkPR^&Dz=> z1AX8>agiDoB*b$ikl=xr_O~FuSv#9eGOnwDIL;d9}{4R6QF;J`Mv(9p?>PK#Jk^Zu_g8T>t$@ZW#BA!?t1EcX9$}MqHBnGXu&2U{g zJuDW%cIjWCw3|IzaaFnE(0IgM3dyjboH$fuhSVAtPde=l(>3=v?L*3HQC;`Lh@m*^ z&0XFSWF&?!)XPpP5n8T3-HzC05P^!m+_DE}xOJAIFDv5?m1l*F5wCZ8Zi}zdZOL%? zl(S<_o^3?2#yxSr;|T_%;yB#(>&iVHpEIOY=U<@C!I?7_^aPivjxC1lFqnX zkv$XOJSqdg1rkH*8zqL5&oFmf+%UiBAZy7lNon=@`OhdG1cgr%wER)Y(vSDC@Dtvb vB$;3Ne%5~sqH6dIRT|T~H`4^b3F$e5OJn zoY~R8(({&XZ|7T<-tBIgmXR;Iu46WPuF;JmLO5CP^qiKlYBYP>b~~Um>vd(42UFrWfspHm zFpake1z9rm18d}mG9*M>9ZrDlb_tP8_F*Z38JtmZR>L`*C(OveOTDf8j>%~w#J?5~ zrN`_+!g%IkDcgu6jae0MYj_723AJI84oLE>jPybNV}8g^n_c;ZT-AV}T+`Nsc?^CizO+CQB_-J>%{#cbDM8c!s!8( z=(4DP%)DlF-8-GGOVBE|Z8%=$jjoD>V+i2BIC5t;t{{xK&krO2`d66E9vlgbV+D z=@6y|S5I8!ld17{1z}1YPk!Rh3vqCHM zhqxsI@>mfirWFzQNk70kzZv6q$+`Kbc!Tg1rxm=+^e<@2-(Hw={^TG`lE14~y)a3X zaT`i%mBBADsL)`6XAAInZf^cpoO*%_hsZwp-zEG1h*!jzZ;IO#QboQI?nnVM`^X&$ z@Cqt@z-ugq&^O8qXP)5l%i@OlMft;js#Z;o5=m zm7&{)v#+;o!}s?r+tiDkdsef{O+StpL$dC6y_UI7O9_laRT0;aK$7A9$kQ7}r(=54 zAzGaqP0P0UGX}M^^~H91z0R;yJsU2uF$@sLW78pHUq<#~6AYzMj8@&Q(+=rO2g8BP z;X)D@@w&+H4TeWiiUUF=QMPToom+-5i*5DJ$Vif3XK0uTeCoUY*x78ueV87y36_*RY{?r4{7 z^U!p-Jol(&D{|);qufV#KZ|?fS}Zb*&Ey&h8sFFOK9(5bm0EqLSSyto)~o+VwF?Zf zlG`>JE>tbYtaT5Yrnh4>ZJL>=x-G+Q7@j4@{mB@AYWWO|)^AC##j7$gD6Kt)o6_x3 zxd^sH{}sx+*`*WLr6&g7Bkn><>W|Wmqh)5uY?%D1+ukxfejwv@UBM%I5>+1mZcmv`6lAG$tg&?=5&dO=}LU&Ut(Sy>Yd)j94v6X8twGF7p|kRN6AlkXaa%fsF_ zRPWQR4hwX(H2Pp*m=yPme$jV>xOp`50gaY0M!$e$eq!tgoI675dm1VDP|VR2${$E5 zf1*HRt+x})0S*(brH@j_ImBp3>StVhGMAq^!fW4!FyrEw@>c+n?``Wt&;fjel>jz{ zkMTeRq`4wiiB?Rs{C4Rx42$Mz` z>rgUl1b&-9g$9eXTYx9?vva@V(sR5$K<<(MO_Kj7bRt1~GxW?LQ=~@zPzpG6g#4KR z@1W8Lyh~yTedEM%>N)05iyP$^?`JLer75i*zu+0iqpewZZ3AZ&c`7cq7@yh@J literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceIDMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper$SourceIDMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..32c84eb1a40441b9acf49e4d1d90a8f88130e4f6 GIT binary patch literal 2716 zcmbtWYjfK~6g_LZksosF7-&gp`oMw4P8v6DC;^91+i|FiV3RG1E+8hT$_mis7zgD@wEWFu^mP)!yB`_uO;OUg__De*Y6d6<;feFx))SzSoMT zW*ro}rslf)hN&0JoI6Hmz;!o{7(={e51g)E-$-Bzih{U`1d z)-gU~!^MaXV{t#;b>9v)Mk#?<$y4aUJh56lDd_Mgl0FLq&3MeL3_P zmge(Pn!2{-a?Rp>+ct~O`2K3m;?B!b3bVMW;FgNpxWh0j3tbuPKX(i&Bt!BC@ldyV z`j3QD&cK;SI~2~3ly4`I!<>Q-RD6iL43$ac7$cCmQSu|bBs@SByGI&s$?*j6<@K0A ztS6lO7*;}}P_dw55%(A_dvJm!(%gkG1r7*-V6CX)K9(8M4hbt*WcW$$J=oE!nfkGA zae3xpsn+GH(Z;Ke?t2ao#bsDwh|cHR37S7r@iA6Oko9J3uiUKG7&aRJzs@CwSk><7 z3|AV4r8fu19o^Z}Iwo1N4ZEwEZOt*nd}xgEL&IfYw0>859nMq45b5qS+>ve%Q$=q3 z^siIaodKP=B|UMfI>Ih!WLTDNoJ280W=rRXc5g>>v}2vFASJaTFZyY~P?+t`k>2H` zB8G3|$IcTGIxcT(XS6bmKqX)6n#10mXc-5V#s?13e|VAduSqdXVrrcvlJuLyCcQ5i zZj9+5OQORO+NSREC$`HO)VgKqj#pvbRj|vDlXby>s8Q?52A1GGs^A$zVUpg@zGfJ% z%3n0pNzQgUEYs~$=_`R@MqDv^qK^e}`N;AK%~lbmCm>nKMt{Yn6Qq8jSp=U78;yu6 zNJQf((OmU+V$JizL~j{-Y2gxLv?KKgre7=;W>4_e&w-mMaV)BOE(-p(p$j^I&#>;f zP2qDq76HjtMulL-M86*f*rt^zt)&+hU*jsnYut$7O{CLMqggM^ZGUqRCQV;S8(x?+ zYS=_1vq8@9kyF9J3hfrolZA!Fzi{mp-aqy1gO5t`|AI~=2yceQ3^HZvLe2!d;AC)Zk;sg(V!$$%n u^D6IWEnjS^#lBrOWGmPi_B{II}Dy6Lho%cA2) z|B;uOM(vE#&;3zO-?P9%Gn=iA%rIy7T%PxNpZ9Y1)xUrL1E7fS6$A(iN7|2C*3itu zY}3$sy#w74*}QFAdZTZPUKk<5bj{Y9&njAXS8Es|f+;8p!YU$&67Ko}@S(1-k}e=4 zHFQI_eP&71IjNshB~WuzJ*bmeoyLSf*x7c%!$wMmFE**_PI{ zT_yu&Ok+bgb$gRgS(@NcV*$*=+{BEBI;T39OVt(35_bF;6*_&h<P=v|aiymQiDK*f)Z|g?3toLk=_*Gm}a9za>ED|z)4vq|Li6*OK z5n?}Cx-E7rtu4`4Cc`}rZlQm$C%28<9@|dUqqvEW6x>p=gcRYvpY>DnEjeQ4l+q{% zBM!4dr^RLQVVcsh!ZY*U%eXQa(vV?OECwGaEKNB$*fEh^r?x;JUB&14f)FlM zYrFYsahp)`t*UnjdyWv2MM#(_>!zso+YMnkX~C&q?ld){u35V5xWmbi{Z!|~B|dS> zzcIOD5dzHv!gbH>lcF(fm;WXHHwaff_m4}1nQL6g-26Q^$~EWuIHkzh^LRzrPdlwg znyf~yHuh`HI|Ig6Cu}`z9EqmQDMk3f``G_YoS_8{{YKLm-Vl+RerRfT-{J_g&yofk z6E2Kf&RgZ$WWl1fPTy*Z9lo9kS58T@+p@Zua#i%~2c4cxP)nvMEGN>Ur(l<`=-UBC z9ck9pj~mwD##XRLNc;7?H*Yk;WuH5ZaKWP$;tm&`%AY61cL`S>Kk-+JtVy29@!L9r z`~*bPv%%l--Z5go@ml~Ja*js?6Nm)o@Fl;igPquPaJb`Rb%?UZpD-cbG4lfF_cJeX zVL3g2jEldzP*d_~aKV8|54H|r_z=FrJqLOQc@(5ko-1ODsfFatFf>x(l_0OhGRuGA zL&Bd}ILUPp(O}Xsa&55HH4?)%b{r!y+{Xh1;#&-zWk{*Q8t<0S(R60{B@)k(93u~? zU-VF*#3v%mHqK)l@jUnWuRQ_N$5=iS;0nGO0G@|$M2 z2K<~cjIta0MTVBY*bCg;KgQZ0_)L-{C-wucFR{%E&jnD$LuY)1Z=F%aV;<*NwJFr_ T-Ms{VDAnH+&!T7x zXS>+3MZdpg*|Jzx%C*`9CHonq2-((KN9{;ub+Q;kI*p8pEDXX*?BaE?zc1bC0Ia1% z+p;b7RwHhdH)@Sqt3|leI2lUGfQj)m&X_oh9O3qE_ot%eDCs)F4vDe$_U&T1-B+&Y zsDR9n9ARwLaxAq*XwHUsv{=8hT?&mvm@`se>DAn38WV&{9HmNc;B*5%(_S|)Iv6)_ z4i~h-&j^ph6psj1b=;my(UtE1VqB_gdKU?cQO1kI*cYS7c8kGX3j2}_X^V@)RH z)}`9%b)N}W>`BgJR<#@*_oE#{`#f#$%8uehBD{`X_OTP8<pcH{%Ti3pcR)R9~IJTu*(XP?$Wx`CkH!yP1fCKrBxgS$MQ}DO-Dj{VhS#E(dA0^K3iAtpUq` z%rD1n4!JTH@U=+5D+joCBEXxt>jN&acx8{4yba<1A~)&ucTd7erc% z*B=g1{^bE?f5*Hg$rm&K4!xY^JGWDh{y&kUup0mX literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractAttributeMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..54fb33107a10d17b7401da20148fa5cdfdd58061 GIT binary patch literal 7321 zcmb_h`+pSG9X&VMut``Tfq=#m1d`ZflNv1#fdJ-B788gpgc8(tc6X8tY-X3;Ss+?e zYNy#QqLVH`I)-Bs=0sC7T`Bl4^%Gl}>ha$FfF7i5uO9 zkO5Y9i_)Z?}wJ`}=IGzc^}(j6x~ zx$)f@jjBdMZm87VaR!>=$Rhm{Ey{=Dsa#}K>W;*BMb}SEKMF=a=D6rbg z?fa21J~?B2UB7N*rUkk@QhEd8c3BLRRFCEm?!boyst?KjM)ZVwSfInr>_nwVo(xA` zNN4M)Bx(&Ij5dMF0uf6f&=N7Ec2S$-WUs8vP0iW%jV(XBi>3 zLfM_65Qb$U=jRh?zY1czK%)~Qr;=a+z?qr$;hTV1r z!LD98UzT|Dil*cX^rjMYzhFqy)or<{n3~zC#N?c@a3~d5lA}sSlfMg%0b^3j3alCO zF)w$rIEp!^(-!XrKZF|@lFekTE2^hLOgP|TIo9Ltp22a#$_OZ2KV~zuqewp$92FT> zmWZ(6Wzr3mrC&}J`O!Vbk!Pe#_nhk7d2+JiICkl>N|EWP8CH$SRANNQaBy-eX0X+b zJ2x;s_B!T}+2YJdY<3wHC|xZcpP6-Ng|RxC%4Oo}0M}Q6rL!!qcS;=sbGNBkV_22t zk`00@M6Zv6Xo^nj#-wU!aZ^YT4CfYKM1~UIPm+9BW_1dH?%2rRLg2|p5U17*7cO3 z7!;Yc$R8GX;O5EgQQ_g?lLFD3_uxVNsKB0^AdctPYLY$Abfa4 z=hNJg`Jz_isZ7EukI!&j^TRTtW~SscoQURP`T0$?EAF!b{eCE26Pu;(DW4OGq#8_d zp3EOhf_O$?z>lQiR3ax=;LL<-bA3)=tADN?YBrV3$q{O4`@F!Qf4&h;zsiIY{4WSZ z{Id-!n%*mqdX~5^-c;ZQmF%P=?Mprj)=Yw>=*xb?U$VMed|we5@e?rb{glP}RRKTy zs-|LAx&5;kzveTsCA&+D?(04i8_{(&lP?h`vET5yO!ps-tLdV}>YF}0*{{cwsVwgp z%srgd$#3}-)~BX3YFy#$W-)!+=k~}tnUBgtnnm^<-(*v1Ety~5ojua40-OERuRMHM zg1+l>5$K)dW;xEi@($kemfA9cDA{;Z2j73Nr#w~K2VBd%@dmbw0xiW>v+r$qY%4Z(B3(!tPu2yC>+i$_!licCbGxF{ z*u!yXhij7~Q16jzD=f9wY&#hJ;{5}2dF@7kM{2XNbVcW>*nCmEGz%=Y7P6u>)+To^ zmMlce*t}O=QhGSGoxNkF9w~7iHVzahGF=9GtS<8z3-^4%!*5T&O%1y7ICBEYt~@D&8ZZI=)Vw_id{xZx7& z9Is3G1+a#eYf*)J=wltZ*XI?4&F^gmb+&@Ke4nM>I(cbLrH+=mf|goZj}^3Z6Q$0I z@EZud&Ihy0QYx@1@67B-MZuXvCtGCKYUPC;yCj47E`>?iU2SbMxRs-ytTR|vh8Z-K zp{;xdErc1gb7fAA7@ov&JdG207ANr>PT_f+#tS%u7jYIZ;T&GZdAx!Pc#XyN{Q}=b z{<^@{^L%@bR%dB_hF_iL*QdyGl58i)dYtUX=;bKA9ii80de2eC0jimzsy8^m!)V4O z&OcYW>e*6;tNcU86mf=_BECsHK>PtQOZ*`*M|_KTi1;>fn)oB)BgA)zM~FWrK1Tcr z@hI`9#3zV9BOW9EocJX1UE*=#FNjYQe@Q$+{1x$8;(NrC#9tGiBmRbXiuhaN^Tgi~ zPZNJne1Z4};u+!}i7yiWL_ACUGw~(jUx??3e> + implements AttributeMapper { + + private final String name; + private final AttributeMapper.AttributeStability stability; + private final boolean allowMultiple; + + protected abstract void writeBody(BufWriter buf, T attr); + + public AbstractAttributeMapper(String name, AttributeMapper.AttributeStability stability) { + this(name, stability, false); + } + + public AbstractAttributeMapper(String name, + AttributeMapper.AttributeStability stability, + boolean allowMultiple) { + this.name = name; + this.stability = stability; + this.allowMultiple = allowMultiple; + } + + @Override + public final String name() { + return name; + } + + @Override + public final void writeAttribute(BufWriter buf, T attr) { + buf.writeIndex(buf.constantPool().utf8Entry(name)); + buf.writeInt(0); + int start = buf.size(); + writeBody(buf, attr); + int written = buf.size() - start; + buf.patchInt(start - 4, 4, written); + } + + @Override + public AttributeMapper.AttributeStability stability() { + return stability; + } + + @Override + public boolean allowMultiple() { + return allowMultiple; + } + + @Override + public String toString() { + return String.format("AttributeMapper[name=%s, allowMultiple=%b, stability=%s]", + name, allowMultiple, stability()); + } + + public static final class AnnotationDefaultMapper extends AbstractAttributeMapper { + public static final AnnotationDefaultMapper INSTANCE = new AnnotationDefaultMapper(); + + private AnnotationDefaultMapper() { + super(NAME_ANNOTATION_DEFAULT, AttributeStability.CP_REFS); + } + + @Override + public AnnotationDefaultAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundAnnotationDefaultAttr(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, AnnotationDefaultAttribute attr) { + attr.defaultValue().writeTo(buf); + } + } + + public static final class BootstrapMethodsMapper extends AbstractAttributeMapper { + public static final BootstrapMethodsMapper INSTANCE = new BootstrapMethodsMapper(); + + private BootstrapMethodsMapper() { + super(NAME_BOOTSTRAP_METHODS, AttributeStability.CP_REFS); + } + + @Override + public BootstrapMethodsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundBootstrapMethodsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, BootstrapMethodsAttribute attr) { + buf.writeList(attr.bootstrapMethods()); + } + } + + public static final class CharacterRangeTableMapper extends AbstractAttributeMapper { + public static final CharacterRangeTableMapper INSTANCE = new CharacterRangeTableMapper(); + + private CharacterRangeTableMapper() { + super(NAME_CHARACTER_RANGE_TABLE, AttributeStability.LABELS, true); + } + + @Override + public CharacterRangeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundCharacterRangeTableAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, CharacterRangeTableAttribute attr) { + List ranges = attr.characterRangeTable(); + buf.writeU2(ranges.size()); + for (CharacterRangeInfo info : ranges) { + buf.writeU2(info.startPc()); + buf.writeU2(info.endPc()); + buf.writeInt(info.characterRangeStart()); + buf.writeInt(info.characterRangeEnd()); + buf.writeU2(info.flags()); + } + } + } + + public static final class CodeMapper extends AbstractAttributeMapper { + public static final CodeMapper INSTANCE = new CodeMapper(); + + private CodeMapper() { + super(NAME_CODE, AttributeStability.CP_REFS); + } + + @Override + public CodeAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new CodeImpl(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, CodeAttribute attr) { + throw new UnsupportedOperationException("Code attribute does not support direct write"); + } + } + + public static final class CompilationIDMapper extends AbstractAttributeMapper { + public static final CompilationIDMapper INSTANCE = new CompilationIDMapper(); + + private CompilationIDMapper() { + super(NAME_COMPILATION_ID, AttributeStability.CP_REFS); + } + + @Override + public CompilationIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundCompilationIDAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, CompilationIDAttribute attr) { + buf.writeIndex(attr.compilationId()); + } + } + + public static final class ConstantValueMapper extends AbstractAttributeMapper { + public static final ConstantValueMapper INSTANCE = new ConstantValueMapper(); + + private ConstantValueMapper() { + super(NAME_CONSTANT_VALUE, AttributeStability.CP_REFS); + } + + @Override + public ConstantValueAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundConstantValueAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ConstantValueAttribute attr) { + buf.writeIndex(attr.constant()); + } + } + + public static final class DeprecatedMapper extends AbstractAttributeMapper { + public static final DeprecatedMapper INSTANCE = new DeprecatedMapper(); + + private DeprecatedMapper() { + super(NAME_DEPRECATED, AttributeStability.STATELESS, true); + } + + @Override + public DeprecatedAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundDeprecatedAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, DeprecatedAttribute attr) { + // empty + } + } + + public static final class EnclosingMethodMapper extends AbstractAttributeMapper { + public static final EnclosingMethodMapper INSTANCE = new EnclosingMethodMapper(); + + private EnclosingMethodMapper() { + super(NAME_ENCLOSING_METHOD, AttributeStability.CP_REFS); + } + + @Override + public EnclosingMethodAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundEnclosingMethodAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, EnclosingMethodAttribute attr) { + buf.writeIndex(attr.enclosingClass()); + buf.writeIndexOrZero(attr.enclosingMethod().orElse(null)); + } + } + + public static final class ExceptionsMapper extends AbstractAttributeMapper { + public static final ExceptionsMapper INSTANCE = new ExceptionsMapper(); + + private ExceptionsMapper() { + super(NAME_EXCEPTIONS, AttributeStability.CP_REFS); + } + + @Override + public ExceptionsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundExceptionsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ExceptionsAttribute attr) { + buf.writeListIndices(attr.exceptions()); + } + } + + public static final class InnerClassesMapper extends AbstractAttributeMapper { + public static final InnerClassesMapper INSTANCE = new InnerClassesMapper(); + + private InnerClassesMapper() { + super(NAME_INNER_CLASSES, AttributeStability.CP_REFS); + } + + @Override + public InnerClassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundInnerClassesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, InnerClassesAttribute attr) { + List classes = attr.classes(); + buf.writeU2(classes.size()); + for (InnerClassInfo ic : classes) { + buf.writeIndex(ic.innerClass()); + buf.writeIndexOrZero(ic.outerClass().orElse(null)); + buf.writeIndexOrZero(ic.innerName().orElse(null)); + buf.writeU2(ic.flagsMask()); + } + } + } + + public static final class LineNumberTableMapper extends AbstractAttributeMapper { + public static final LineNumberTableMapper INSTANCE = new LineNumberTableMapper(); + + private LineNumberTableMapper() { + super(NAME_LINE_NUMBER_TABLE, AttributeStability.LABELS, true); + } + + @Override + public LineNumberTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundLineNumberTableAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, LineNumberTableAttribute attr) { + List lines = attr.lineNumbers(); + buf.writeU2(lines.size()); + for (LineNumberInfo line : lines) { + buf.writeU2(line.startPc()); + buf.writeU2(line.lineNumber()); + } + } + } + + public static final class LocalVariableTableMapper extends AbstractAttributeMapper { + public static final LocalVariableTableMapper INSTANCE = new LocalVariableTableMapper(); + + private LocalVariableTableMapper() { + super(NAME_LOCAL_VARIABLE_TABLE, AttributeStability.LABELS, true); + } + + @Override + public LocalVariableTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundLocalVariableTableAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, LocalVariableTableAttribute attr) { + List infos = attr.localVariables(); + buf.writeU2(infos.size()); + for (LocalVariableInfo info : infos) { + buf.writeU2(info.startPc()); + buf.writeU2(info.length()); + buf.writeIndex(info.name()); + buf.writeIndex(info.type()); + buf.writeU2(info.slot()); + } + } + } + + public static final class LocalVariableTypeTableMapper extends AbstractAttributeMapper { + public static final LocalVariableTypeTableMapper INSTANCE = new LocalVariableTypeTableMapper(); + + private LocalVariableTypeTableMapper() { + super(NAME_LOCAL_VARIABLE_TYPE_TABLE, AttributeStability.LABELS, true); + } + + @Override + public LocalVariableTypeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundLocalVariableTypeTableAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, LocalVariableTypeTableAttribute attr) { + List infos = attr.localVariableTypes(); + buf.writeU2(infos.size()); + for (LocalVariableTypeInfo info : infos) { + buf.writeU2(info.startPc()); + buf.writeU2(info.length()); + buf.writeIndex(info.name()); + buf.writeIndex(info.signature()); + buf.writeU2(info.slot()); + } + } + } + + public static final class MethodParametersMapper extends AbstractAttributeMapper { + public static final MethodParametersMapper INSTANCE = new MethodParametersMapper(); + + private MethodParametersMapper() { + super(NAME_METHOD_PARAMETERS, AttributeStability.CP_REFS); + } + + @Override + public MethodParametersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundMethodParametersAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, MethodParametersAttribute attr) { + List parameters = attr.parameters(); + buf.writeU1(parameters.size()); + for (MethodParameterInfo info : parameters) { + buf.writeIndexOrZero(info.name().orElse(null)); + buf.writeU2(info.flagsMask()); + } + } + } + + public static final class ModuleMapper extends AbstractAttributeMapper { + public static final ModuleMapper INSTANCE = new ModuleMapper(); + + private ModuleMapper() { + super(NAME_MODULE, AttributeStability.CP_REFS); + } + + @Override + public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleAttribute attr) { + buf.writeIndex(attr.moduleName()); + buf.writeU2(attr.moduleFlagsMask()); + buf.writeIndexOrZero(attr.moduleVersion().orElse(null)); + buf.writeU2(attr.requires().size()); + for (ModuleRequireInfo require : attr.requires()) { + buf.writeIndex(require.requires()); + buf.writeU2(require.requiresFlagsMask()); + buf.writeIndexOrZero(require.requiresVersion().orElse(null)); + } + buf.writeU2(attr.exports().size()); + for (ModuleExportInfo export : attr.exports()) { + buf.writeIndex(export.exportedPackage()); + buf.writeU2(export.exportsFlagsMask()); + buf.writeListIndices(export.exportsTo()); + } + buf.writeU2(attr.opens().size()); + for (ModuleOpenInfo open : attr.opens()) { + buf.writeIndex(open.openedPackage()); + buf.writeU2(open.opensFlagsMask()); + buf.writeListIndices(open.opensTo()); + } + buf.writeListIndices(attr.uses()); + buf.writeU2(attr.provides().size()); + for (ModuleProvideInfo provide : attr.provides()) { + buf.writeIndex(provide.provides()); + buf.writeListIndices(provide.providesWith()); + } + } + } + + public static final class ModuleHashesMapper extends AbstractAttributeMapper { + public static final ModuleHashesMapper INSTANCE = new ModuleHashesMapper(); + + private ModuleHashesMapper() { + super(NAME_MODULE_HASHES, AttributeStability.CP_REFS); + } + + @Override + public ModuleHashesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleHashesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleHashesAttribute attr) { + buf.writeIndex(attr.algorithm()); + List hashes = attr.hashes(); + buf.writeU2(hashes.size()); + for (ModuleHashInfo hash : hashes) { + buf.writeIndex(hash.moduleName()); + buf.writeU2(hash.hash().length); + buf.writeBytes(hash.hash()); + } + } + } + + public static final class ModuleMainClassMapper extends AbstractAttributeMapper { + public static final ModuleMainClassMapper INSTANCE = new ModuleMainClassMapper(); + + private ModuleMainClassMapper() { + super(NAME_MODULE_MAIN_CLASS, AttributeStability.CP_REFS); + } + + @Override + public ModuleMainClassAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleMainClassAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleMainClassAttribute attr) { + buf.writeIndex(attr.mainClass()); + } + } + + public static final class ModulePackagesMapper extends AbstractAttributeMapper { + public static final ModulePackagesMapper INSTANCE = new ModulePackagesMapper(); + + private ModulePackagesMapper() { + super(NAME_MODULE_PACKAGES, AttributeStability.CP_REFS); + } + + @Override + public ModulePackagesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModulePackagesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) { + buf.writeListIndices(attr.packages()); + } + } + + public static final class ModuleResolutionMapper extends AbstractAttributeMapper { + public static final ModuleResolutionMapper INSTANCE = new ModuleResolutionMapper(); + + private ModuleResolutionMapper() { + super(NAME_MODULE_RESOLUTION, AttributeStability.STATELESS); + } + + @Override + public ModuleResolutionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleResolutionAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleResolutionAttribute attr) { + buf.writeU2(attr.resolutionFlags()); + } + } + + public static final class ModuleTargetMapper extends AbstractAttributeMapper { + public static final ModuleTargetMapper INSTANCE = new ModuleTargetMapper(); + + private ModuleTargetMapper() { + super(NAME_MODULE_TARGET, AttributeStability.CP_REFS); + } + + @Override + public ModuleTargetAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleTargetAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleTargetAttribute attr) { + buf.writeIndex(attr.targetPlatform()); + } + } + + public static final class NestHostMapper extends AbstractAttributeMapper { + public static final NestHostMapper INSTANCE = new NestHostMapper(); + + private NestHostMapper() { + super(NAME_NEST_HOST, AttributeStability.CP_REFS); + } + + @Override + public NestHostAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundNestHostAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, NestHostAttribute attr) { + buf.writeIndex(attr.nestHost()); + } + } + + public static final class NestMembersMapper extends AbstractAttributeMapper { + public static final NestMembersMapper INSTANCE = new NestMembersMapper(); + + private NestMembersMapper() { + super(NAME_NEST_MEMBERS, AttributeStability.CP_REFS); + } + + @Override + public NestMembersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundNestMembersAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, NestMembersAttribute attr) { + buf.writeListIndices(attr.nestMembers()); + } + } + + public static final class PermittedSubclassesMapper extends AbstractAttributeMapper { + public static final PermittedSubclassesMapper INSTANCE = new PermittedSubclassesMapper(); + + private PermittedSubclassesMapper() { + super(NAME_PERMITTED_SUBCLASSES, AttributeStability.CP_REFS); + } + + @Override + public PermittedSubclassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundPermittedSubclassesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, PermittedSubclassesAttribute attr) { + buf.writeListIndices(attr.permittedSubclasses()); + } + } + + public static final class RecordMapper extends AbstractAttributeMapper { + public static final RecordMapper INSTANCE = new RecordMapper(); + + private RecordMapper() { + super(NAME_RECORD, AttributeStability.CP_REFS); + } + + @Override + public RecordAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRecordAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RecordAttribute attr) { + List components = attr.components(); + buf.writeU2(components.size()); + for (RecordComponentInfo info : components) { + buf.writeIndex(info.name()); + buf.writeIndex(info.descriptor()); + buf.writeList(info.attributes()); + } + } + } + + public static final class RuntimeInvisibleAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeInvisibleAnnotationsMapper INSTANCE = new RuntimeInvisibleAnnotationsMapper(); + + private RuntimeInvisibleAnnotationsMapper() { + super(NAME_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeInvisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { + return new BoundAttribute.BoundRuntimeInvisibleAnnotationsAttribute(cf, pos); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeInvisibleAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class RuntimeInvisibleParameterAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeInvisibleParameterAnnotationsMapper INSTANCE = new RuntimeInvisibleParameterAnnotationsMapper(); + + private RuntimeInvisibleParameterAnnotationsMapper() { + super(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeInvisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeInvisibleParameterAnnotationsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeInvisibleParameterAnnotationsAttribute attr) { + List> lists = attr.parameterAnnotations(); + buf.writeU1(lists.size()); + for (List list : lists) + buf.writeList(list); + } + } + + public static final class RuntimeInvisibleTypeAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeInvisibleTypeAnnotationsMapper INSTANCE = new RuntimeInvisibleTypeAnnotationsMapper(); + + private RuntimeInvisibleTypeAnnotationsMapper() { + super(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, AttributeStability.UNSTABLE); + } + + @Override + public RuntimeInvisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeInvisibleTypeAnnotationsAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class RuntimeVisibleAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeVisibleAnnotationsMapper INSTANCE = new RuntimeVisibleAnnotationsMapper(); + + private RuntimeVisibleAnnotationsMapper() { + super(NAME_RUNTIME_VISIBLE_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeVisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { + return new BoundAttribute.BoundRuntimeVisibleAnnotationsAttribute(cf, pos); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeVisibleAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class RuntimeVisibleParameterAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeVisibleParameterAnnotationsMapper INSTANCE = new RuntimeVisibleParameterAnnotationsMapper(); + + private RuntimeVisibleParameterAnnotationsMapper() { + super(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeVisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeVisibleParameterAnnotationsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeVisibleParameterAnnotationsAttribute attr) { + List> lists = attr.parameterAnnotations(); + buf.writeU1(lists.size()); + for (List list : lists) + buf.writeList(list); + } + } + + public static final class RuntimeVisibleTypeAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeVisibleTypeAnnotationsMapper INSTANCE = new RuntimeVisibleTypeAnnotationsMapper(); + + private RuntimeVisibleTypeAnnotationsMapper() { + super(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS, AttributeStability.UNSTABLE); + } + + @Override + public RuntimeVisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeVisibleTypeAnnotationsAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class SignatureMapper extends AbstractAttributeMapper { + public static final SignatureMapper INSTANCE = new SignatureMapper(); + + private SignatureMapper() { + super(NAME_SIGNATURE, AttributeStability.CP_REFS); + } + + @Override + public SignatureAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSignatureAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SignatureAttribute attr) { + buf.writeIndex(attr.signature()); + } + } + + public static final class SourceDebugExtensionMapper extends AbstractAttributeMapper { + public static final SourceDebugExtensionMapper INSTANCE = new SourceDebugExtensionMapper(); + + private SourceDebugExtensionMapper() { + super(NAME_SOURCE_DEBUG_EXTENSION, AttributeStability.STATELESS); + } + + @Override + public SourceDebugExtensionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSourceDebugExtensionAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SourceDebugExtensionAttribute attr) { + buf.writeBytes(attr.contents()); + } + } + + public static final class SourceFileMapper extends AbstractAttributeMapper { + public static final SourceFileMapper INSTANCE = new SourceFileMapper(); + + private SourceFileMapper() { + super(NAME_SOURCE_FILE, AttributeStability.CP_REFS); + } + + @Override + public SourceFileAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSourceFileAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SourceFileAttribute attr) { + buf.writeIndex(attr.sourceFile()); + } + } + + public static final class SourceIDMapper extends AbstractAttributeMapper { + public static final SourceIDMapper INSTANCE = new SourceIDMapper(); + + private SourceIDMapper() { + super(NAME_SOURCE_ID, AttributeStability.CP_REFS); + } + + @Override + public SourceIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSourceIDAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SourceIDAttribute attr) { + buf.writeIndex(attr.sourceId()); + } + } + + public static final class StackMapTableMapper extends AbstractAttributeMapper { + public static final StackMapTableMapper INSTANCE = new StackMapTableMapper(); + + private StackMapTableMapper() { + super(NAME_STACK_MAP_TABLE, AttributeStability.LABELS); + } + + @Override + public StackMapTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundStackMapTableAttribute((CodeImpl)e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter b, StackMapTableAttribute attr) { + StackMapDecoder.writeFrames(b, attr.entries()); + } + } + + public static final class SyntheticMapper extends AbstractAttributeMapper { + public static final SyntheticMapper INSTANCE = new SyntheticMapper(); + + private SyntheticMapper() { + super(NAME_SYNTHETIC, AttributeStability.STATELESS, true); + } + + @Override + public SyntheticAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSyntheticAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SyntheticAttribute attr) { + // empty + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.class new file mode 100644 index 0000000000000000000000000000000000000000..869e5d6eb22a163fc00cc1dbdf975bb1c2215039 GIT binary patch literal 3109 zcma)8TUQfT7~LlXCWIp>NNufnt7tB0gj%YGQU$f9jTQxB#p`4;f#@)ylR>5Rp-)}@ zg+8@!eet1POX;EyUA}d#{-!Qh_c#o@x0P9ede!eSxltid*p~1v(PR zLN{XQHV~KSffN|u4$@S0)h*?#mgy8suVNM*TOevxOB{~o+W}1TOpctg%4)AfA9j*X zwOp>*g zAhmsFJs81p11BUhI7yY?c{9v}zA*E=wW+m$!MQ{(3A`HDWP>cv zY=ccRrIQ6kWl<%ysb&?42P(ayHK$6~QUq(06OGoIOBQ%XeG2sDE3SQYb-8GJbM-de zzol&li&1~6QWH4c*1+a7@@DhT3hbEmP3z$mb0t8m$84@DaJaPwjreAh3+((wfdefQ zsd-Ky;#icSEy*pF!IWd5Jzpnk7qd@K;{bsX zXS>y_#WA8fy&lM{SroM-%ITHol6lc^S7Unz)}7l zLpKuWMG`Jo4%V-siWPnlK${hMrVK~)jYME3%hPIaSLy|f7kb!X++W9@=Ul8C>e2^B zG`OrE4#0&<`T*!YVHMCYfrkFZzLWx7$D!0ZhWnEnNO#~Bk}ol&_J8BS4(&y+W_uC_ zM#+3EWMnun@~u8A4icXoIj}Yn(C!b>-r3cP_jm}hKY)y?3TeT6bSv*uVcw&(H2Qzu zXURKD-V-4sZ}1kXwFcJ4si{&)D&Cal({-FxpkbxYg}`J(X?DN>V@t>s2LC4M`WrwO zLO{D3KzzFbpfdrPzL1D5B7Zpq)7OCE!_|sUkV2iULXi&vHTkeb1wbu>8f%3#6GGYy zs(^=D9Z8JQvo6Z|Ed2`S*D-x%gc^OZfv+N%RMTsEIvyR0{EY6wXyg}kc03=94wc3` z(?c7Wiy%GNSs#@)OydnKMDP>#rg?if*jdLZJ^K}V)bia86nT-ea$~ln4@6Zl)$@Il z^$5(dDa>O41-5`2NbwmP!2+}Y7XP!j&1d}%uHi1f?qLZ<`eorMZ2X9__ItAKTM!C* z2_LKUJcb|e2#@Le0KcEG);ow_!5U{#q8Iqz#!j{vRZ(1djg*1B5aM5C#Q^Vr$Mp!l F{|^=p)MWqw literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java new file mode 100644 index 00000000..d3f49e31 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.BufWriter; +import java.lang.classfile.Label; +import java.lang.classfile.constantpool.Utf8Entry; + +public class AbstractBoundLocalVariable + extends AbstractElement { + protected final CodeImpl code; + protected final int offset; + private Utf8Entry nameEntry; + private Utf8Entry secondaryEntry; + + public AbstractBoundLocalVariable(CodeImpl code, int offset) { + this.code = code; + this.offset = offset; + } + + protected int nameIndex() { + return code.classReader.readU2(offset + 4); + } + + public Utf8Entry name() { + if (nameEntry == null) + nameEntry = code.constantPool().entryByIndex(nameIndex(), Utf8Entry.class); + return nameEntry; + } + + protected int secondaryIndex() { + return code.classReader.readU2(offset + 6); + } + + protected Utf8Entry secondaryEntry() { + if (secondaryEntry == null) + secondaryEntry = code.constantPool().entryByIndex(secondaryIndex(), Utf8Entry.class); + return secondaryEntry; + } + + public Label startScope() { + return code.getLabel(startPc()); + } + + public Label endScope() { + return code.getLabel(startPc() + length()); + } + + public int startPc() { + return code.classReader.readU2(offset); + } + + public int length() { + return code.classReader.readU2(offset+2); + } + + public int slot() { + return code.classReader.readU2(offset + 8); + } + + public boolean writeTo(BufWriter b) { + var lc = ((BufWriterImpl)b).labelContext(); + int startBci = lc.labelToBci(startScope()); + int endBci = lc.labelToBci(endScope()); + if (startBci == -1 || endBci == -1) { + return false; + } + int length = endBci - startBci; + b.writeU2(startBci); + b.writeU2(length); + if (b.canWriteDirect(code.constantPool())) { + b.writeU2(nameIndex()); + b.writeU2(secondaryIndex()); + } + else { + b.writeIndex(name()); + b.writeIndex(secondaryEntry()); + } + b.writeU2(slot()); + return true; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractDirectBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..6be7f61bfd9635edff98a2dcaa1ddae665781b47 GIT binary patch literal 2364 zcmb7Ge{<7D5PfGmR^lijO@l*1DIpN>4?v`$#f{yR5DKI?KbX+WlqrA6jtCco_R$B?=8`6<#MIc)$?`jwps2=RSGNhv{&oOPIZJWOTLfV!gUw3R{ zRVh!ly2^Uw+IyB)fQIY{MxkpM(=m=S0*k5fEnj(NTiur)rN7sej3Q7ld$_*9jbMo`LnLkd+>QPxB3>Vxzl9=$R=UiAX!Pc`&Xjrx|_iZA5Z{^JZ=VV(8Nmxvip#t%KI ztiA#erohEht1EV*4b7)}G%CF7u^nZ$Uu~G3=vWr|$s|=9<8l;pDm6Bi`|u;$D}zha zPj}p|*S5GX(XBr9NN;k-p_aMsIF=VwmgQ^M5U3@+Dj^e>UdkocuqALIHJZuv`u9MS zz$I$s8G3Q$Fvb0xW>egZgOOe>frVNt1U{pA221o-6ZC(Zem|#`pOK|MV7BrOqVgxS z@84nM2!%@Z2osg-N0|DJtXX_PzeS1z7AV&|Az!6T*D!+;?$GL7h=Llvq$k1)*oa`p zd@@+3xlUQxRzsaeYFKDQJXUFB+fe0qO#DidFl9bitOhB<;Grl*0>>*M+$_GLM7*v0 z5!^7roqLZ@P9hq8h{FSjyuyf~WGjUAHSR{p&uC=9^Q_RhL>&HXKp^k!0J|7^McCxe zZ#Y6?-ieK~gtjHJh51;Ddsw7+-pLyp8F{)&TbX)``S&ROf>C-XRNvwz6UYUpGaj74 z9r~cCQG(?@64Nn>Y5KrnX%Z4_3rVo;8?rqh#4JQHV)Kw5LSB!sPNodL#bX)^ { + protected final SplitConstantPool constantPool; + protected final ClassFileImpl context; + protected final AttributeHolder attributes = new AttributeHolder(); + protected M original; + + public AbstractDirectBuilder(SplitConstantPool constantPool, ClassFileImpl context) { + this.constantPool = constantPool; + this.context = context; + } + + public SplitConstantPool constantPool() { + return constantPool; + } + + public Optional original() { + return Optional.ofNullable(original); + } + + public void setOriginal(M original) { + this.original = original; + } + + public void writeAttribute(Attribute a) { + if (Util.isAttributeAllowed(a, context.attributesProcessingOption())) { + attributes.withAttribute(a); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.class new file mode 100644 index 0000000000000000000000000000000000000000..580bfe2fab1eea7fccb49f8a971e6217faad40b6 GIT binary patch literal 1112 zcmb7?%TL=t5XQfOfN4kxuTowWsyOfxxU{{2DwWqMz@ao!k868@4IA59Zz%s(Pe`rQ z-up*YolPQFiMzgh+7eAkzR%8QA5U- zFuJc&Wj_&y*Ei|`#t3TP z-}(6TiU=Qlj83J!&XQiIT@R;zmFJmGl+=ArK4Q~zOxz0>i&(oN}EE62*l_zO+AZe~kdhJPC8%Ub(k`_EkTLVdpZPHTvHkSVb D02m3_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.java new file mode 100644 index 00000000..37081ca5 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractElement.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +public abstract class AbstractElement { + public AbstractElement() { } + + public void writeTo(DirectCodeBuilder builder) { + throw new UnsupportedOperationException(); + } + + public void writeTo(DirectClassBuilder builder) { + throw new UnsupportedOperationException(); + } + + public void writeTo(DirectMethodBuilder builder) { + throw new UnsupportedOperationException(); + } + + public void writeTo(DirectFieldBuilder builder) { + throw new UnsupportedOperationException(); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundArgumentConstantInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundArgumentConstantInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..f8a3cbf50e10a28423091c0e737773ca60e16e1c GIT binary patch literal 2140 zcmbVNU31e$6g}%NIm)J(0BK102ql2y7}SKXf`O8l21HGq#xx~OJ5xp8qzaDYkz}UB z&)@+bcxWG(;iV6Bh6xNa?GNaW>TuVRv222-@S>}|+P(MObM9UJ``?>?0F?2wf&_!M zRll!Uwl7@UXlQ1`@VpJHAv9~d+0f?JJ>NAB6)B_@WH=OL8OFAZ2Zq)# z?9Is8YSVP;f??3J9twS9!TL?q8It)aU4@E41)O6DpD|qj$mEmrPRp)G&@g1KShnR~ zW4M{Gd>Bhfuf(M)6I`7NF6mP%DstGXV3=c{EO06A+%EhC5a-;@*0!+yvO~-nc9cM( z#eC=WRUE*Gg3mcdagbqew*;Lu*%U5=^1x`cM0JBx6vJd30UhFGQL=TGg;AH7PsgX~Zf&zJu}*Om zWC6*hiWmM}@J94>KOMv0<1VV57tM@8vQP%s50dFCp|HGIu5)KPv# zO3HAc=V(Vy6?2$ZQ0BOSZ+cMFeAlu!DffosZW}(srD)R!UrTF|771XNq5#8P3T`q~ zy9IV}Tis#TcIn^Ae&%|{aUlw*8#Cl0zAGX_Nb1SfV%Sr$Y_ZtdUKj3NW4%G1;fiA# zjTOVS@~y85#u@3=8!CNs}GIEqdy-x<~62Szef)-a)c>_!S2JqICkd z>8X-M;xPsjPw*|R3&CDgaEDfO3X7;xB>6@cp4?4ube$kcUYfix%Pd*BD_hvXp4Zs_ zg5HA+8R<_vZAa(9o-jI-zX9?{ltw!qP%ON}SmqCmkUjDeUy#YCe%ZnFbL{JL&HPE{ zlI<#j9KT0$6vG@#v?q`8G+w=A@a^4?}x#X(Z^ JNBoo-cnjw%JzM|) literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundBranchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundBranchInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..7c36153eb5272765476b6268513a1c8902bcea35 GIT binary patch literal 2214 zcmb7FTXz#x6#h<=cG`3zX~1%^EnW)d(lS!K!2m)Ep#z~oQleN(AOA572=^9k9ZWNmtT2fZ| zGT`-2$LE0v^rDJs9AwD4QncpQ%ogu5%oU8{&~oItK0&63RUE-f3~2!}12cqhR>d5S zk}zz*@n@@g0`UNMctKTxyj8o_ZSwFLkV7msuE|B>+32CqJUJ- z^)o1;tYAUKB2F-r6EoQ9izwhx4!4%5YC?@DR>B)9P6|JYI58Xv^(hr^;w{p4BX-Ue zhC>{(R~PMhN5#81O*Vn)ZSa6$_9-@DTQbmbR>3(H=kXpvl2pYd+v8Rs(5&?Bu7q&% zbI%TVNF9bViF{5VN3l7Mi$tl=(R%&Hxnuqv1ca*NQe|Vyf|w+g4G3lKB=J zXyS!{nPFeecKB+4tHr%Fv(+U@zUEqHw`qE|*hj*2aL@J`RuTg|`{e5kBW{mjCI;4? zVyIn>z_jjPH+xYQiX_9D%dkW+B;3(^h@=;r)Hi8PbE!S2F~fM^KI#5}9dwWS$&hKd zeb3@mdM6kT4T0i>=r(y;<$kc@`a~bqa2)O}i_zr-Zf@^IJ}pIiXh4IUqep|`Dm_}G zv}RGG|Le5-koIX>)l#`UKx$$32TVMm{Rmd+KSL|hx6#b#Vjl(~hig6Akht zzUa=B+VVz1ilj95QIu13BD5w-r2+O0aNv8|gdxV{!SB+&8Y)HZnRq-R2aa?IES4VP z(AYOPNbAf)yiCjS^xXl9Uw@1JyJXsT6eK0<$jiJRle<4KgFmr=$FYEmQNT6QAH~Q_ zon8XmLNkhenVbk1vSmtsiGFVnaAr3~e-Q$IOP|xB^8XlR@d2SMT;9e{ME$G9U`hEHhCQ&`dBPt)REV7QCJ{{e4FPk8_U literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundFieldInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundFieldInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..901ab76f3e5e7e8bde956ef8adf3aba0934812e9 GIT binary patch literal 2816 zcmb7G-BTM?6#rckSO}L7V~cI26@^q1C@EF6ZQ9C5fkr7Hp=l{kOt&)##-@BGfky?_7n+aCaC@R@=Z zhV*t}Cv8}s?pUgs)=brPi-xJEjZ)c6Pi?xMqiSB(qOqcRhHb?VMXQ1~4h8KDXSUTx zYT8t-ts32>vSt@_hECUbqGyY9#$&y}5E)KpV~C+s0q5vKH^b!rG(I$KSFAz}8iuxO zhGlp+80Lo;8e_?17n+%xA-Gv`IFn80JJ5@l6vR1R#tDYmW_oq_@gdF`x*5h9D+n;A`fF==x_*o!1m-YMgJg8XT;V_vPN>4^dT_I6b7ID7;!ktaRFltyt+qxW*8qn z#z`|lV1-I1hKm?iaEaqByiMFTbL*zz=$a?OGF>rD8H;XBweC8Gr~BU+F4fQbDomM7 zApptyq6**Pco&x$lwEPys_h@tq!%2)lJRThDn|y_7+UNyLw{Xb{eD26_u>Y}dzfTs zmE|Ce9)rJdEeHaqIW@4G480P){63{=x=YEnRG*IkLtT6!uENHW`F6~aUsAfhw0u3` zjt&$>Dbs8$;a*L+A1k;;NDeb>X>*&RCcJ&0;{z;Eld^-3c&>rFH4H6sEMb`#vUe>} zeCY-%A<#0Z{bcRL3UUfoIqo1Y%H|;R8|3++E4oio9x8bV0Jpu_=*wdu0+7 zperbHY~f)jDn53KMbUOjs>g7pHc5G-prtYk&n3IeL9CoT`II-XEm0sJq@R z+ocfltVJ~<6Idq?dyhU3PD+ui-kMNgobo0H27`Vr;-aS)QIzIg*r9)uR`<|K5`d>h zM)naIJ^LITKhwGeCHjxi2=+NT*%z>Ao$~j>MwwQmC3+&ABxZDJi`_J%D-jWrQU?sI zY)Gp>BJ~VCf1y7`IeIHZ8Ro_-zxW>Mw z=h`>uW8c!P{++bf=O1<8@*o_zWJp+!qNT5s<{t8a=?6ropkpFFtNf1nwFueC=GLM# z+tfzU^9_IgD>UJ_&wHCVgneJ*@I(M0f{NVr2)lA*cuZrQ^hBKZ MqT*G;@C2v-1$9; literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundIncrementInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundIncrementInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..037a3a4619ff791f22466608ef30b5093de375d1 GIT binary patch literal 1965 zcmb7ETT|3X6#kmI1VXbSB8sA-GB^yE5m(*C5m#kJqa%ZkqKH~%G7TFH$yAcDEdPc7 zz&BoeaH}lVvPxgIEMI)_=WKa82~H54l9!zBlhfz>&h^v(Z{Gu$!b1fu4Eg2i}u5S36O|owIremu}BBdbBp`evv-?IKh&s(~^6nk5$ z8BSF&w0q_=p)F3EPeqj>ksZ=hsAyNfIXdtg!})E34_tKWb~VO^A$``gP5&Ije% zQ*jgn3NjpnIL0vCl)*+{R4tb{+&)23XEoUkM=`{alYYWK<5D%kG5TFqJ|R_kj^hp0 zcq_=oVa<+`yil5*%y=XHp5^$Hnd(UY6Wt>DK*33d&PG?1D$By~RSM`d#~=8UP@Sk% z4`zp&wU2yrhNB=`J}F^TOyZn^zc|k00>jP*h(@!tB-5-Ai@GQ+GW1ZeG4GK@K{}n{ z_**({H5{5T-6qG=xUAp`hlZ;g*q43Rw3mqUqT{aUKEp)37<(5G$ zJ9XC()3inz_HMyxOlF>HJ|jH;isMl!xn|qKos#1sD9X;wd#*Q9ZQd&wr#@0axuLb5 zB-w%M^qryGU8G0@@Z9k58WJN1{zKcpbZ`QW+2xz1O zh|d899-K!b3b)B7g_gb&?Myi)5uOp@jctXekn`bHbjR={g|X*90)B}Bj{N{QD*@+l zCju-H3z>#Y*LeCJexFa|)^MskpCmEy24~CjDLP%0r#HCtiVVa2hJk&J;bbD51XV^_ Y&EsAm85T%(kw(_>ep2pSh6m{V27uB3Jpcdz literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..dba846f8769e33c4541184ac65d1f4ffba75072d GIT binary patch literal 3836 zcmbtXYf~Fl7=BJjlR|@~0YVX4ielv=jn=!=S`sc@2m}Z%t+lqB%?T`QcH`~_Ow}1b z>HqK-=nSnhe((qQqa5FJl0cTMtKCjMJUO@Ly}x_TUw{AcCx9%T^&o<-IHC!hLyRH4 zUph$Zrps+pHPV`)I!;+Pcv`Pijr4rcacxy|6_c>0xw>UC#BS-P?%rm&HksR357o4x zn!9Z$^Ht3%@i}GcemBmeJC2?NE+D~h=Osl=WUQK5^2m+~YKH5%AgV0wQAqtcA^)`m zE~1a2t72H}EDM4$^)>x4GsDXJl%+ zA%!K2b(afMoJ_5}W9t-khB05gPc}#|zLmgr;jXBoKjS@^#8e#93C!RfhM6EGvR(s( z^;Wf>AvK(Bi`?&@LZ`wNN+X74|81>I3wB{E8zfUy_=DkMPB-~_ty1Lnwpui3CYiG| z)wr+Px)?VnqwbzgS(6DA;8P?WnLEc2v8oKCzP@hS!O&}!%MN$9t!7rm8e@j|kqDOX z*iCXpK*e?heNOlh8bPhhz0W9tpk1E?0(x#Qlo9G9VggWDC| zb$O{!E6QZ&P8@d_7J@YQp>DV_XQ}N?AdU>fVkoA9YuUW5pTx1ipoF4QOwHyMZnn3^ zIF=ZeLeXVx)ztPps@-J>3|4@@tbL_ zJhTqHLET`;hqAN9MQyRHYF^SUhP789U8tLCMb|tL-VU35>-;ER+^6R5p`$wA45cB_ zZP+?htbWMnZCkB-Xdk=+?G`U{o12;s?UxJ>!fLx#GhDr-Q~5b`BT%@8ows*uqDy2gxTD(qSK4-Tc7~Rber3)uF3$$lY}=lHEkK6J7SDfGQ%fDc z(x69xqzTCLQ}6pGEnOERgEs?Pv)*)yj?;xcLeH28`oxoh{`HC5Jz*E3^q!do!wni$ zX?%__IXyG_JJ|H>bHt|yqtDU%8_hkPqQg zd`6^E%t>W#;d6-*+$NkvKfb^`y%iU+3w93{0Fi+tk-jpyY zBa0kEzAgMX5QZLy2!y)NPEt7>*KJXl7P66@W*5W|tx`gQ6r@PVDH+qa#2`0p#A}9` z$y0bLhA9?D3MssW83~tVT*2EUa64M_+%a@d!}U`TjvWb-m|gG29fnNo)#l3TtqFH(tl}QfIyT`xmN3sS*esWo z${wXa5M7XQ4~sN{>~P+VK8Im24=K@ucwfc`C@~CFY}*sVwYFqGt`6 zv28mCn#XV>s%G%Euo-ENfPbuCLMsUmDH%oG;;HBs9yWI6B*z% z6-9%P#wBhU%k_hb;jC#DlXlW2Ti48W&EeuX+)R4AoK#zB8{mZ}eSx9Ft}zTpq&vZh za#!{=eSb--gn++YRfDWrmf;k|h%`u~!IKy8NVpZbry^O!3>AF}3=il7ai!9Cl0JRdpq)qb z>mfS*9XXfJA0aU{@(exS(0&It={rR$*sthizu{wg&IPu3j8EtZknt(DeBb_+D6DCZ zE*vCimj+Q7WsA-U1QWTZ82A~(Ia*(NigUDNl3VEuN0|5t7rw=Sc>gsSCj9XIw1WK( ziT!~w_NNa)4jhFLG~bqu(I(B$Fd8Qu0!bz>!W@B!DPN*Dmw$$Bjd7o&7q&>afg9MjF90-b`0s7Z7TN%Xr4BMhsOl!9a?J=gUEiW>=v zbGN*aq(v=nbked^{th1sdV#uK!n`9Hp_K_kC9v&V?O@km891$JIw!KZmlQWU!#>Xa E2kI*I(EtDd literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..f51ee7d34c350d3a94aa15ee5e1330e8880f851d GIT binary patch literal 3053 zcmb7G-B%k`5dYmIu#j9Jjfic9iUJi9AW}tJ(<+6Q66H%mX@Su>!?%v#)`OVC4X71nrJbwXT0zXLbFhsYK z+fhxoR8yDJQ6(+saw#pXMzu^f9lgGuvrJjB;ySH)#nKGj4<8yNG;&C2VmQAg@5s@# ztZ!7v&Se!NsWJp|+9Nfdn$#YuNd|BKK->>M0une!3tAb*{-^QYaU-uME6^}BUe$EX z`hek9|MbaNV)5yErX~n(oE(nD2bP)<#2E=8j+fBRFj-HoMtq78cZ_Yd3TPmsTAN1l zrf!*g3?ntcDh35w)~&2zq@y!xW?eNG)RZj}6Sz7!Ucp%gpA+AUr*ovv4eQl0-8F4eBSB21gm zRR9K7L@yZQxQ=lKX;&y)G#o{BI?^#LF{fg0aNNWsgU84+bk5qc6Y>OEhE_QjcL&L=oT2{TUS&ODnVP;q@ekrtjt5wyKBn8}hO5q0~z)!DolGK=zhns!3dh9akzWK$F0?xxS$)Tn_^)g1t*AA~W6mV_lM+cR?3wGhx8 z-lSxOK+rW|g$S(Bq^CGH+7&98T-W~bw!qM28O5~u6Gq-tRMADL6l;JT7Wp8NSv6-( z896e{<2qH4T^cI6A3T2Z=y11=OnU0C z6A1dk&(QW4I>WTS{0!%4dCj*L>M5Y_PxSnTHu3+jbkJ*?Z>1INXGrW9bhCXM0(TU- z5O(deteZ9;V$Zb}Cmh0Bd$@qeA)*wrz+*_hefYdjO3FnXz@AhnZLd(;08eO)?h1H> zCVGlc4bm#qdTb?5fE*=HE0lO#B}_~cS29C>h|u&zgx>{>7I5W91j3O6e7KJ`u{$BK z7H~_%-f=!8V$BM4H$6ZHJEZ%|bK6XZqpFmH9(;~3$dCwy51x(yy?=>&uIUGqUjceF z^s)2@W|qBVXD+eqqa|^OI}C~C2714L2;y8~xsl#e&in7sL?$Zzd{N=&s0+Z0uk2G_ Y;~RTr_?FfX$qC|p=M(oYhVOCiU#ihgcmMzZ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInterfaceInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundInvokeInterfaceInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..daddeedb26934096f1423b83fb5d79edca7cade1 GIT binary patch literal 3092 zcmbVOTXz#x6#jObcG~pNmRKubfg&xoX=wyRfdCc?g=lZIP-qe9bTWZylbJY~P{8}; zPxuRb@j=(ZAg-m$H!o|cFTVJqOCS6hF84VzNhdUo)rZWv)C{n)eD7;l{FJqE}u=DSuS|4Zg?r1$D-j`jvYk=O&Xd7G_(+Q zt>}03L{_(Ng=DAmhLbi4Z3XMTnaYe?cg-}RabPeNMHFosguphm6Gs1|^1ic9(N2fZ z5SmX~w&k5BTo{|`VLrmZabP=ZO$<^Se4DpV$YNjNu z8QtJXg+FE`XL`4t^m*HJ?-5SaL~S@Mq1#^Gak7cZHIqtk*32l`q(s^+@Dz3sB0l2> zwq|B4cHwCaJp#M2htOBg#xgeyTt&yMsi#esaIn5A8A$$7MXbcyE3gmGa3JKJ0)bK* z`UuBrIc+QEM{xkpY8Vh0M4T{G*M@2|gjScW2s|)4z`;?8;xTzNIT+em&xtBnGwd4Q z4-(0+z(I^~ILeE!9AbwIq-417!gB(LaF`&<(o&FcXkZIE#)2@ABFQM8$59P02)u}6 z%zr(D&snZ%c+z!ei&j?otKHD;tFGml{(pqSwG*ZcQ-xj?fWbwXz9$5dI7!gfnEt_s7W8_8S z0vBZEYBIQ%c#_nVz{_}r(4{O&*;T1aSgg%cfUPF(Dh@YGU#>MRm?Z3bOyl+GnN$6R z;ocm7NBRr>g&P{C37zXPI=#HY-j&8&5}3stv*H9Lch4rQgqXY{FpsNDfU{=HL{4lX zQe}in3qRc3uz*Dk*9Bh14VieA+}R{k)@2FpdO`8Q&1Oo^agXS#(mv<8mVHY({HDMX zbWS8&og1k-w~3}JUglUCq=B>sQy?Qj#{U&$MO3yeg<@XM7EMX=Z2?Om@$Th$V-;Bq zIRP6S`ysFR*x45u$Ia;;;dnT30?V$4;>CAkRjmn5X?UG0L@mtLdMDw&;72OM^?Ng6 zJgjn^q)M#TNz-zjmpzbKmrFv&gk_skMVUmG_2n$@#3md=&(7ANxxLL zCH#+OnIvqR^K@f%QqKpf+AKeSWLs5libZBzC9VwRx&Ss7B0`Jjl>HW+bBeBEj`Qn> zu%iar5$O;XnKBFBMW?_X7Ac!kNX56w_IGZ4p6m^_s%lE;Il#T4lZz@L&p*f~2Y;J+ zz6~ya3%t69CVq1PB0e-!LgVo6hiLtb*A4La8|4x79op!76nP!@&*Bc&c*Rn($f~>5 zOF^FIJ?_J3F8OOnvY{f$tt*i9*kDOUd`My_AyLASkI)t$dWhp6qg(EtikEPP zt>)o;2^S^lzSS{FGX2I+*x%7je_)XQRNA`z8!P0;@dn;xeUby#)*a*dTeuM*xXF%{ z*pJ30w68F=(8zjb<`yD6Tz-UWgt>(#p1<}8%W~e#^IQJ>3#>>Ngo*kqWbV-bKqKB( ar{2N4Y9zeJV~piw#JwMpk21ms*!d60FJrv` literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundJsrInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundJsrInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..df4181da4a021222580b25a80424ea9ea437fe3f GIT binary patch literal 2317 zcmbVNOLyBu6#hnbEZdP=Cn=##n(#`CA88FKP+IkACvH{TxYWT=LZPxePL(>6k0kT@ zHSE~1fOC2bhjZWuu!02(U;_*O28TP6O5`NfX<68#xijifMV=vGjh$=mu8i$5w+Ex}xOvp$nkdbDX+txqU zD}CMCikxi@47iD9GUu! z#z6g(PZn|pFW^NPFDY2U35KP(cpvFRsr4)6HrKn{VK^1SO()*lz)dfv{oo;QjO}XgjW>2DsW`6qFKJwXB51K*J-yMmgZvN zV2Oj$RYiKvDtHs;=!~a3TijzN=Txm|q=J$8^ z8Q(Ns05UoZXa8q0F&r94qh67xM~UGEJ&F@F=Fp)3n>2fm=1CfrQn@@rVtL_PWWJ%f zgmwDQ(g^8iOiI6?N%K;$7q{>>&FBz5|O#&Awu^|2G!z;n25T0&0(jmZ(4+t!m9^z=~3(V4Z{2`vF;bijO2*ockv&U5V zihLyeFs21<={KaM-!U)!fiiuIZ~}kJp}!5XOhB4%(p!Uf&<bgk2xD`{!gMD-X)O*pLaKfefT`&#$sbU?lMu+Q@36X8mcJu3r$WdC jHi?ad4{+BX89ts! literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadConstantInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLoadConstantInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..4aa33bb6ddf382b79f1966d0b3032cfc4232834b GIT binary patch literal 2821 zcmbVOe|OVV7=CWrEnA!Y1k2n8A{(qf25|$YtbnkNL8WYyj*c-wvNRjnvZSUdg5SXp z;1`g;^eFBW_)p&4n|q)4dEWQE@6BI-zxWkE295}ULEbLz z$hzrhwy7AhYAEIMrfz7mzFRWnD;s6UR#YczlC7wYZkZ8;(IKK!f`~4L;cexSA{&ai z71+B}QmvxK5H0IpYT3;N{jpYL2*nfG2qK7zkR1?9VjeZP>7?f}bhZ)-LYY`uhV$M>E8H=K(n8DyNguTd| zY71MZ(~TI8h!~RaHij9-Uq=Il-Ob`HO(|+N!|C>}c*4DGYOIDeIQOYL}7m<*VM2aERRzouz%C1c+ZckC%;#poj z6F4p549D@lOpADrVWw5$RX_YC%Q9r14`sv9YB{-TI`$I|H!a~T&M`*mur&ewX#aIVz?yXBU~oQHCmiC!&LM3dLyWi z60Tx_3awpc=XG0C9bVXT72R+PvsYEjRal1u1fy7&&bljM75BUr;-5$h5@#l0rrykqO; z7Qt;=_O9YEoDWL&zNXg$N2y{NPqwSdw0~GIv`&nNXps&Q2-1_4uHfIm2U(L_vz=QgKQ5T z&{Lt&9U6zpO375JiqPcI=ji@{#sW6z86gYdTSSHLpwc+$twj+Ujc6CY>G2wTd5dLu8#5|~agvYRjhvbNh2}6iQ>0QUR?|RP7CNMO()bR^GSqqV$ ze10uVW;Op4?z}4H&w!L6-$w{Lu3!VZu4ORE4iisaF;6Nv*#yoq^b5c1g$J{v?qtd}EN^zS{8+*; zLtg`%!p0Uac`~JWUcp;P5r$S+u=B@w2@0AOXD%psM-)CT%*z;zwCB-~@T5UHkN@QP;4Ih9(Ko8IDXiQ8frNVv~%x}g`KJzvueN>N50 z1<~ja{N7(p;2|+|#pJs-@sF2NmYou%xRw%{%L-PoN)c$b%?0D9S`_;A^JLsbS)f3a zJJl+sRSCrLOasKo3~r3w%#n$biyCX330t*2xgz6^zz__jnUmK|zErDjaA#TDFi4Wj zTP4j{)f`>yLt)%|s=Exiwhmr*E@lOO2Q#j>=xL?x`+42Dg*8RN9};wk;>w0ne3k^sv1 z#6%sj$#Z+?{+;$6*rI=#R^S`-;9G3d+jyW016A75DRGIACGkdc#@F_{7%`HX7!1A4 z&?>YN<1cWcj#IzUd*GqVmw)G5R|1{TIuisWiHLHMq7>(cl4m;q#L!x7ypD6lwKy$r zzr;xKCB_e%{61oG=)fe+_R!?M4+P**NSA*h+w_~KMkGpI8$gk~TDfvkqMN*+eV|9F*{On-+c^zNwq4f8!WH;smJV1#7 zKOlu4aRomiho9lnUVt6I;f1kVB$24IlSzZ-4Q$$W;43)(%IFY~B#Ef97Z>A{p@uX6 E0js2DdH?_b literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLookupSwitchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundLookupSwitchInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..854bbe1ba78e2626a1a1c1520801ba8df82a4004 GIT binary patch literal 3465 zcmbVOYf}?f7=BI?vJe*uQM@2g1hEj%6m7i)sff2|1S^!5T3eQ6frYS}ZZ>M^z1sWz zW2fIbo#~f;XlE1|9oujH&|lHt(V5mhXE%^VF{7Pf*^@ozyzlcq&-=dT{Q2*l-vA8a zTLl4uj;SRBXUTfn)y*&?*q&KEpJeeu2}3pm z(K}p_jHJ?!iLq;}j+|{$v00K{t4&d_3tCQ!u~kJgwh63rwY#WmIo%f6Q{AwX*;^|0 zNktIHb_F|Bv|=Zzs}}#@>b(MrO`mC#%7!}0r3BipVwVIOHVc|z7bVQyDxQ*`A~Nob zZcaNh3c3W^D(s~5d3{>T57^VCdEInQUd!qQnQ{uc1vXdKjX1VpP9HBBd4?K60(+!x zdj*1>U1PO)TA)2`UeWSKt~Ku_NzqM`Ru4=oXG;2!R=IJXiv4(oIJH7SH*=)Tua@U0 z)#Vd#m21+LzyWFEpg;>_ue$KCiX%u-Jje2^2yE5A z2V61b&ZpL~!<qT&{xflx5FrB=xW#e7X1@Eu`B}%c~TS;e!>pmB{@WRc{;|UZtOEOyuL2$li3wh?=(?Uqa(3>#R&Wt1cvql#Efzf{n6Q3v zDn9&_S6WF*!FApPMvQ4wb4oTjIkucQD;e3hCgw-j>u02jTLPn&z&=V?@AfQUDx}NxLG$i7o z35AdRmjlSQ1rMDoi@P9MHfT%%KDA+A(c{JAHoM7J&Dz0)q;UU8{yun|@hy}b! z+;YSdjj_qmTZ}4*w>jR3z(1Rcd@(TH{tbHVm|hFxG>ObK}D zb;0(!5Carsrz=H}|C{k1XG3TwG$~6Bt@Cs#!#vDiGRy|zd9F-2>8^kX%W1L6b*y?z z%Pa|blyJM$_6{LPZ8K7Udl<|FkG9C+4>-hE6N8J^w#-cQcgwHRPn=E?%VU>@MVwqh zdgMkx{B-}1?j@Z6h4%dFZR16)1u+rF4zV2r9G@1gE9&h)8{TJlLFVI8e87>^EK|l> zixWh9o%p4CDgysV;cke((T5NDC4i4O$3vC>Wjy=KwA3XMi?~Q=5{##cM@WZ{kh&E@ zKE@|y11AYY0;un%fiXTWFXC01kDif;oD>PDqT4mJ$y>aVfA#njpV5?%x3jXz6s40= zHO6wGdzcyz((25}67mmXOZu=imQ4onx$FE3eCfUgzT!JZw-Fls8e82W{w7rSACRbu Axc~qF literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewMultidimensionalArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewMultidimensionalArrayInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..c43577d61b9045f1f8a2bbe0cc723fcba9692891 GIT binary patch literal 2631 zcmbtWYg5}s6g?{&1h#lKrAZo65+L|NqL99lIxiq0aRQjcgzzYB*0KPBEO}%(Dg7t? z1^vW;-tRWo_5wquyOYE-JGI$Nr_4%ghgMPpra4ckf}jxHJ93S{&!oZsiKxoUE2H*~g8 z)$Fp)kgOR$>iL}o;|IOW5KE==2_%q|p(yA>Kg0e1=zL<%u3P008iwxMhGn>S86Kq; zPsWnVFGjhVC%AbEIG0ba^tv$_y1$K(K$DpF#TA<0MeVHQoc~|CB9;i-w0!?wr?n+ zUXNkPrPmUq;!Op&M71W4^06kCa|&+b4nr>&xw(2+rJ7YwMb?p09#!`g+{Y}#sE6~U z+!sPn8FuIw?L4$>r`LKg&v2<}(JP^?!pfb=+Vq%9aOq`hvb?=5;~~Rf%XFc%Pnw7j zA1Qc@Jf)r;^rVX?#OL>{ToO;QC}T;%G72KUPY;)}nAh?_Ctcx@}uoaTQ=PDO2kzkjMZHAjIc%jRobswm0;K=mZ7ica_wM=SA&pxT)U}jqG;D0O<$lpn&E7RFs=!~7eagVdN9zNJryE*ksr9X-FN**eYRG%A^Fwt?96=sWcO zMso?T=$W7q(mImT1~|<#{$7-z(Tq-^44o{AH@bJlZhE7u2QgZu<`sC!d2?VW^A-bd z@i7gbcE4)ivtQ_d@2Xpvk+wZIif3{taKl8qi!c-?LzBOLV5rp55cTE2P=yc)wBuO; zseyC@SARk>lYNKJf5t#I)42(aAWZktDqvCA9za<9^KY_003CXKDCV_0ScVGPL_=8!SMFnOT;pec3D-0#`D z-l$qNogq|Q*=Cq7yxS%pC3jJd7&t?$Y5b(Cd#lEedW|-xGinrZjLJxGoJEr1?kTx0 zELknH)0*S z<~iQOMTUi-cse>z>RhUux>nO|muo;#ximdfS46>ef#VV`Q_>q&lYvp<)5yrka^!G@ zAs5I(gx&SW5Vwg(R}6;hX*F{y`JyDkH4X*W8F)wI4bqrlF?|wOepx6BNsR!=@?_x-PYhx+`Y9s+rri;ppBsh8u$`w?oq_gr~0g zlt*x%A?114UEjEKsd;7IdD+nE<%x_{hD5gmdFM>T@qk0cm(&t0zg^9~BM7gZj9dd~dP(Rx-X}xH*Wu(QWg}Q9kU{N~Y5gL}R4JBc=?a1;f;f zt;33LZ)ue}tt1OpRjZdZ+YobqG3-1u=AkBdy_s47;^PElLT5 zIbQk_awuG0i3Q0b!kgcZ#oaGCZ&t3rm5R*Q_?BQ#POSH!d)69 zI~J*0<6zjPKg2yl&oKSZVuw~9)7vJ75TY@W{T(6twGqipzs8y0XidT{J)<;2qU%%| z#kVw{_w4Zm-_eYAip#?FpAfB>teH6GzW-gq6WH_FR~Y*b=d(0Uyuu6(?}wkZ@xdP$ z6Q6!1n~;ka7yhL&$kI5bq;oDN_k8%6-@CSKiWaFc(NhFs5HJzNTuvagakY)bpApOE zUgMKr5X)uT$hYx@h|9xC3MHgT#HA^uq#4Xgvo2Q3b8{5m9G*fW5P=$ol#=Paf(;*b zjr0@o%_NtH{=v#lh;Y_QJ7EF$7alT{{=`=zI8V%BVJuzj32Md%3Zd#+)u6j0!yb)E Q+9wjY9~PG#!!u0$4`4H=-~a#s literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewPrimitiveArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundNewPrimitiveArrayInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..29504bdd23646f677b804fc84b1f9c3480dacc77 GIT binary patch literal 1794 zcmbVN?NZZF5Iwgo1WFLBRRIA(0ZUsbsHj*#J`|1A7A-O|j5DU~Ee6}9lcp#>mCi88 zIHM2XLpknEf}~P9>Yr?GdUwy+J-gces=nj#%~bM6firYewU1mW zu4*56fx#acSAqzlLxL=$6XzHf{}Fs-*{JCS4;zNoIZfBB1%}6w)Y)8;N~#&u3ei<4 z;iNLY*^X|Umk^S10bz#c&HNhF$Dx?!@7GPOtXbL~UouT~zm9XjDbLv7acajUT$a!y zqZfS)Bh3gMCqlKirF_BF0yh~ZnnMZIovU^gL<#z33}BE{s~A-VM#>FgSi&_K*D=Bn zYs#WN9*JZUkC)R7fruiSU<@}TL}ZL3%Fy3PwvGJ?U(JEg*QW_^CN8XvMKI=#G>Fi8L>_?g@;&s#xCe@ezQZW43D?d8EpV@Rjh zlfvh=j2YZvXcOTb@E4n+^D%dlrf14e20L-8T6I0U>P0^Z;HKZay*$%JE#PR_mC|&cu9b7#+)#5R zQZQH8pW|KL)I~8ueecDZqb?VUodTRH*$tB|Mdv5YsqTB3vh?TU&-;)~K0z zzDiq@p{D_tNl|%LuJ_)1?z#7#ef#dOe*hF=$dDM+-TDjFv|R33 zdP6lDdb_=2Hn?gwTMc!w)^;7;a5an8j^UcNl|URrGKLk%7-2ZGtN)~{4c&SkvR!K# zcAYaM+vYD^+gUb$=5>ZxCaWcoKvIUHU<~67cRn!q?2_HF>LD}?!waTmy0;isGNt!p zDQKmrP(^~PQNjf+TOGv&CS{})9LEWUhf#I|`0*i@`O6Ky!yRrJe9>|Ay&lYQpPoxc z!!(LCK9X@t!D*afn2iFop9pd9m2!jYb?z`+i4G;I?qBs-5EPtKFokKVTFY)TFsj^n zT#)gxf=@8ZkdH*s>yKgFAsj_qI^1H`GfDhJ6^lj?0P z(803aB>GPD1gp4?X+0;7zQKJNB?S*q?t$%JAh0{O)6`vt8)2pb^X(9Mex8MJ_Xf9Q ztTQYOLT?@_vD#Oh9+6oNM?ci{fT?Ib2+1KsTr@w!v65-=a;I72&Zb^#&`GLf8+xOv zJEqtNhjI5ulLVs@8Q_2EW`RMnTMXwy6!zss^m~m z-Y;sRVs{*aFVoY=aB2YltD;&ABW2!pSM4^HU(qa!JD!GdVq~KK?YiI{MU{~RVuF-{ zVU3>bIIUxNNWUAj`wl~N0w}qBzKhu0)N73XL3;@m`c2RZ=@ydGZEVs$=ikM*sM3zC z@Q6Gx?~C3!ahuLa@e!j_Qj;J`!P^6qxmP&$3MXkf8-Lct%4Uwg@tl7oNJf*hThNBy;)KP=7-*pX=h&F1{2Q#Jmhr0FpTQQ1ryRsD*;r>LC8ubmd m|K_qD%4I4D6vI<;BjJ1e;H?bLXid?HD32Z&Zze+xr~d_K=%|qZ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundRetInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundRetInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..55c7f13a1e9cddd09a7d429dcf0253a4206f0e85 GIT binary patch literal 2197 zcmbVNTXWk~5dMzrM2@1gsgvG9T1-ic4!MH!eblv66s;v6ZXYM*;GiieQLw2Xp^ z8JuUB>POhKx=<^1I&*~^4em1(`$LH)j!Zj66|r7WQ4$HHJU37P)6-fy;cxDzh!n%onEB;zW> z@vdFO_Cm|DDMbYuu8Sf0pffkrl=BSZs}A4wsONYi=XyC&iYqx`Sypiqixh$3dEB8< zD;`kn7b_cMX@Z|yDsDq(kX(;pGSL^^jSx+>CICMYfK@Ui4idIKDQFoi5lgvZu@mE6 z@yf@~h4#{>dls4itEsq$RfbIHMgYV_&sfBLs$dSE2+r;^96gADH5s2WRJxRRbF;b& zu9O`8#HyKken=}xjIOJgrv4q8*f+$HXmf_cRmF|*iFf8^3c*RYl5qMy`v>rxkpsktrR~@DxD=fu*r5NX{)cI3;82XN62@mLBp%c5f)P z2Zj1GM$rgGSRKh8PXB-->#0H;W3{I^`7J3Us6k;M{nmj|BjXr`!9XT*Xd mvss%~7EBT)G{8G2!zP^*q!+bmrp3l#c!ZNwCkxwyL;nEMT3W~e literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundStoreInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundStoreInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..277d7e6a6841ab6b17dbd485f932f9f620c0c1b9 GIT binary patch literal 2320 zcmb7F|5wvi6#qP02!t@P6GTDRIdFWd72G$iI4A>+R&W+NJLYC+9~elJkfa>kKjaVk zgF8nHN9OkX{-~YZmqeRF>2W@P$ZyT$qyK}IJqDIulc3epWg^PZ!dn*?veaw?j~a6Ovj;A>_r!b=cYCh8^B z5^0@MFpX;hIn^ZtQ-$zr1>fLX5(YJU`Qr+u3)gW&LPo(&%rFeMs*?BBMGfKi*F&zA z1u?1Cu0$&as(xt-tluk`6#>L-%axJEyo4VVEMSpgq9uYxTSTZs7*?k!YDx)pWfpf7 zsKQS0Wm>{LhD(ub8V29gj5%ksTH&U*uvg-?7zYyWGn}pK1#D-lxa)f| zYXC)!vPN+yQz_r;V{zoyBhF4Nqo}hd3N)-Ubb40cfMRRtp0M&{+(lWiKqc4LETn=2 zs`0CJ5+hT%K6ul|XUbyKTK!PitF5amGVzEFQKB?;a=OWvs+D!_tZ3^7NfJ4$q!|Ux z(ZxO##=WPyO9Qv1gO47K8NuL(G1rs#w9@u{%?^FZd8_J__#$0N3{Lbj}MMwF>6m^&kh7GzNIE&I6s&;*ZvNJ#n^Za7xKk8EuSA?IDdfg zqbA=(Ob&i9N#i{=2}@FUU6ivh;|6#WO^YASO-Uzj}@DXt@=CQp4PH%tl1* zB)a_^sYBc?9wJxV$5P_Q8uG$w4L>D*4&Eu~UuyVmAEm!vlF^vYZa+l@yhRd+xQ0Km vh4JiqXJ8=A!!KF1p5|LsrF2*TC73cl~kbr5C literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTableSwitchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$BoundTableSwitchInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..d122ce5839543103e3e6e9ab5d99f35cf81e7708 GIT binary patch literal 4062 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayLoadInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundArrayLoadInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..d7cb7e574be5c6a8dcf8bdf06e02790f3fdcdeaa GIT binary patch literal 925 zcmb_bO-~d-5PdZaJIgYPj*1|-;KufG+N};9(+wA7T;>!uDbRZLGAFMvE*? zGf|eWR3>9JD6)8~S6U-dyQ4V{Q>$`)|E2EbL*2iSA~YT=t?VXYX(c%nM z!l;2Tqy14Kca`oFmRDA5#m^a?0M`kR>O|Gg1;+Kw`(54;znUm5_lAR>H2b2LaVARg zRAdLjD2K;M-@Z{L;aTz@7uX>*?T=wwFY=*Duydi*^{MxnwK`f5+VM} zehA@?*3xvH?<7wY)!A!doUGd%HrP@g2-n!&F0!lnyuoObvB$Bo_TW9}xVoR^)BOPW zpD^iv#!bevXDrNNo)Pn%Iaz}Zf@rMuu);ud?F7LoF1=%($CZvvtoF51a#hS3D@|ab aVlCo!728Yw3SAS zG)_`c6bCAmu^Q%SyxlLX5sBT=97l;&nSS_M_p^~6oJ$dEPnA}7i?FoXJreIkoC^Ks zoY<>8$p*5$wm*Y9W&$)qTtP_a{^RA_#)$E*&5Zn`4KK?H&C5Dy;2LHFTn}*r5n=J- zW(l*oQA1(Id*fWbRC+*IUR|pc|H)_vxJB5k5>>x97+=u6-{BqcwOyrUZ#3*nvnTo~ zXQFPFh;&~V~VjZ7k+vmFTY6<&DkCgqZzEbNP{umP3` z@n8N^Lb#)~G#zI>$s})=7GumS8ajdOB`V9I|exKvh zy#n}OG3|fD9maD%SeVBGBj!7UvIctu(L`&b#6W%hBZ5!3`kr|nS2{Ma+G(les+coT dn!??Z)x^Crwy?}G;yMp4-1pssXki5l-vMLw0IdK3 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundBranchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundBranchInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..4716d8d5bf99b2ad3f8c823fe7d73a4d78975e8e GIT binary patch literal 1554 zcmbVMTTj$L6#izrOQCcHR>VcFDk!^LDtN`JiJ%6|1~edvAwG1w0~AY3+OD?;U-ZGB zqluz1(I4QCGM;G*TcmD+5AB&bGxMGAeCN#k`u+VUfO+ULG7Q>w?YU+-0rwok)=b;* z{SC|JnzgfQYj>-D;2CDH=#Z_Of#o_1vdGD3Q6Zz1VeXj6N1ixUx9-#uhzu>aEXNA& zFbs`Vwv88tW*g3Cg3I!*>DIVjT5E%Xb{VRQJWeny{Achv&v4AG!xRF;+vEX5Un+x& zQRTKS!gs3ZLV+RU?lSbJZjR|H=*B4-Jt|J4$S~QA>^;llW-w1#&ebiu#yy7im!1{y zh$_R)rplz!h&Y$lT5*OU9|5f|Ke|2YKaZ6qz%{GF-Y0jWD3!$zMjC2Na)FM@h%x-4ATv|i7st4 zrj}CGtWcDpqhdLHslHR?-l|cx$y2DfreUuco+ak7GaGDKKEuOGvr460iT$2FLO^F2 z_=kK^aTw&V%BwEJ49U~vDjw+&x(+06c$~ULJLX}A*1+8_QTHK|vFHrSid*+g{(znX zhGI(MQ=%kZ0RtZ(h72oTMzI-S%SaJR%pSsR6TKxJX~8xZ?CqiMfm- z{Yx}^j0_~Q?d9>WkjfKZ(DsR@8Ita#1nVL|U74#bzg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundConvertInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundConvertInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..91dced49515ec0e33293dc9f6c8c63742d863d06 GIT binary patch literal 1020 zcmb_bQE$^Q5dNGdO9Cy`Rp~Y;0{;g8#_qI{0f5t~>0dQlwgCa{wW3Fzi-Q%Ad7bo0=r(|r&GK7t^?D*4OPEZoEzd6e(8OBf8d5YMo7CqB^F`GD{v zF2AF^DVk$L(3~K-D$1E5G2FhW{_3yw3l;S>tWQ`raA#sW*d!YhuZIrq`R=cEa3AgO DvVsRw literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundFieldInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundFieldInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..0eaa090fdf53d98c0b398fdb3a47a6dd5c3db2c9 GIT binary patch literal 1980 zcmbVN2~*Qh5dL195=g^gMZgnOP$<}dilX%bM6Ff|a?CJ}2r`(6TVvDBk8&FIHKte)Bn+h5240HdeKD_1>-Kw)$XOW@pmgQK%9frZt{I>o^ z*KFO{s>4#K81AN-9b4~!f}{*pMJKu#9{#8E2bO6!B2Y?PwBQ8ZF2iI~5Qa-h(4C;- zy0#`PJTpr|Bg+g#(T@R!ORa*qZ+WH>%v1DpRmj>ALL4pC_UJkAg$l0oA+*$lH)+YRAZG>o>ydzYa*Z#m{-wOlm4 zRlR7FB$am!-Cox{i=QK*6uh#ipL6+EGtp!z?QIp&vUUEm)Kj8!87}`#wS@luSTo3C z)>d7v-V)Pqb4tsK@-EbQL;s^PLwn%vRZm%QtDZp<&(k*0B>D_53#lxce(=cksm^N7 zp+OQ8Vp2X+&6aL|Bs`ciOi_bLV7N{H9=>SlYr)Sl2IzU0PRocPPBfVw|AcsY;sZL~ z(J_X5^z7oVq!?c41HrFGL0z9^fHKIJO0H6(ia?PTJkv!bcpfp;P!vsS~QyB@Fe2m-mr%;t_IW zis3QRk;#`x5C=@Bj?3S0awDGph|?<@5|OiCFv761ksyBj3pCER5q~x0KjZpA{HZ$p f(~;Xao`@*(cq%BvBGD8<<9RPg{QJVNgyX*e_9q)e literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIncrementInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIncrementInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..e3c74cf33625b336ec9001ccd40ebbe4d6b2cbb9 GIT binary patch literal 1822 zcmbVNS##206g?jS(qga_wN}AORg|R~_YLdP+G-SwGibF|M?*+!+BE5eps)Hjd{k$A z@j)H8aYlcDKT5q{h>%)jMu&lK$-VcSoV)P-$CqyaCNU!-#2_!#mu16pb;nXoSu@o} zW5F!_NmShO}Z*RZXAgb@)Dl^~*zVf&K$NR>_1S`7GBRyDh>GlUgo zW|ARY{<~3$$BRkWz=K7({ry`p#IaGtfP@4F87BUb;hvjT&2C!t0BH(+#;^?cEW^%R zFE;tver&>K5nCh-VJpMc{|46_eMPr|(vcty({>q{!cn$K*v=vPG@ImAEjNZVc8C~} zuoD@E{k@=~)w0%8axjvq4jAb~J z@oar8^GG#my(eN1L!y(YN^OY%V#IT=gnh`7gtnj7kzBr)hTNyXxx5m?ejE@X zOE`!_41*mEh01P`Qx}OuQ?D#A4CRzyaNnZDV;^8x0qS1bkbd@B(phNB&#fwt&$g51`0O{Il-QWyrxhNaImS8BR* zL#>%~lPuesYR;;T!O#9>*nMa;7_OCjCA&)-c8Yv`oe}qV)m63SYwD^GBYL%Q!)7>4 zqV(wab#+zB&yu8`J0(i~M`x;T*Z!TD&1>q$mzp6~wVRHnPt(+481C|}2Y4bV(v044 zFWU{utfW|$?o9GwrIUKeZXKU$U#?dOhp3+7U^tBs4H@cmnurPBjNPR%Ekp6(-w`4D1oPI}WNM-Xr;%HX)BdlwS%DJRqrM-~-X@?&>`Jr?cMGd4m2yS_(}O{}2Jj ziyWH1!yl3260{h^_(Nd{lCbOr8fqE0UpJ16n4(Y&)41e^tawQPvdPitSL~h>3LlZJ z&V^~of5upKE<(G*eD@hg-?X7xFKY+*W_=g|mpv;5SG<)5JFTRtR|VxTpU2dN*!BzP C%f9&l literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..06fead7c019c4c88416372ac04923ebe9f42616f GIT binary patch literal 4721 zcmbuD`Et`%6vn?BJ2-YspG4^reQm z(^b_dNr7%lyDzhgliEF55{UH=WK$4GrO}PFz_#<6uGy~%9O=(JTxB>rFqgy=*pa}_ zG@e9{!002IeBy>)G-`UO!3%*7qbhK)-HTJ$jXeqMO=BPS3!HBE)^W|0sy#-pM{8QS zBu#!xPQ(G6SH7vpeSF9+tja6lk=(poU87fxEY6F4Za(_feA;tJo8LLZ(=<1mg0 zbS+7H%!!x4uKs}rPu#}g6prC|0w>ZqiBkeQd?|0zcFr$2VU~HN!f5Rdh!kv7)0e2y zkAVaR(-^`t0fXuT7{*1ztSGj?*+vJw=?e{J)jb$)wA33V5OkK=4+LrG-s7! znJqmzLsiOiim5rzUSr%|*68(ku3bn%_HM{V7#2vlftoc0o~H+GPD4wOhX>~9zdM}) z&phH}M$k4MtYWHQ)J#=Q^5_Zd53&7>6F*MLOUu4&SX}R2*Q8m|Y+IHJwW51)rIo;W zfys7Ggh)SFmYkt9o{P=6}TKxaMVH(*(L=W)nvT3Xb#B$Na zCN)_OZoPbTKePIpu^QZa*94{`2BNMuzM(4>O%3=v6MaMH<$66E1_WmX3K6ZO;5AcY zHqh4Oh-oSt0bypT#}J;8i_(<38Y29Lz^&*OPu0q{R?>K|EnX~?a;xFDqA#&4){@cQ z6lj~J+hj*qur;l{72U+yjj9}5mg;ICSZ_x^Mg?1G5-SR1BL-;9(AT6HOu4+pU5O|+ zU6rQ7q7d+PG5W^L>dpnl(p1`M*-BGwSQeOxXy}N!RC8)gsP4++R0*XNs#%U6qbY+o z=%zK*1tuc8o;Rw2@bHElRqBcrj5O~@QKeY78mtmXXLVhg?j=_87T6PZyWi_IHYEUo zeO^cNK^ExS(rLYH@Ji=rus#kT)Q_ru*701==^ax!U?Y&85?qYpH_* zhqrumN@QzM^H(9PLJ1uA=C><1fl&{w9Rh>C*8dd(->k5#&d)ecDl|p=lf&|@zmUzz zQ=r$AZOw%I?)CaY(we^j?Q)dBu`R0~ns6F7S7`R|jciQ?0(-nS1kbhK9z3Led+@}? zkMi?d@FxQx#=mat=hJEaH_GP@GBr3fw29bnNdCg74xDk?oSs-5$yg^ceBN6hiD&T~ zpPYVv%2S6QU3kIM8{rs7FF7>$E4FW9SF>CSU9s*4x#X5y5-;KTV(6EXM4BUmq`TyXMyQ+3PNgaV2 zdZ{L`MqVV>$r17%IYw@f6XbpJ68R39CEq2llJAjI_D1{En=U-;)OU19_MH5xxHb D6Hg7# literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIntrinsicConstantInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundIntrinsicConstantInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..931492e85eaff50f8c267e0bb43a10716e9d84f6 GIT binary patch literal 1335 zcmbVM+iuf95IyU}b`qSn1ZYbrl#-<60$9LfP$ilQ5fl}qwt07)1-7{B$QSr6khn-Z z@Bw@jVm5Vx5s8udVDHZC?AbGCXZGi>?>_+aaK8i%ITLvcIt+&W)A2i7$cP8h@od*~ z!tk~5xGl~mp8a$bMuFo-eMw{NM#7i%6FKr@IZnA4j3+{hXpdpLIXHFRJGSS@Hz}}} z6W1T}ZfjUV0Ywuf3zuLqRF?-clwF^Wb!0SjyqGi8nyoZ=vS{~`$pH`DZV@Y3HL+&l zGAay57fvn;gbal{1OF@A!i*Th&VLyxxvyHdhIIz>Lm(o4>@z$foicPk5CM0i9%;58 z3vbK=lFq~?!>dJt5!2c2%+*K{uJ>hDHhFan!|Fgtei)yPcyR2DJn~cqzUz2HClJa` zocZXj2pLW?>1USBaxPs4&7UxArA3_=WKu&^Y*Q5j20N3)zZx=>j{G=q`7u zA1Hkp3Wq$5p8H{BVwcXzx~c^r3|3!C9`qD>)Q<)?V)b?ABnWqlVn z$hUsJ16#OBmWsKBZNg)!{1e>01lLfwSN`CsK7rmQyiN+sm}42Zjh!hLy&MUaJ+;-g z&nSPS1J9|c6rkHv7!^uJ0+Yj?X;cmM>Da(s8mp9wh6b8>^?WqYA^|qg#yz9>8^;fE At^fc4 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeDynamicInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeDynamicInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..ab423bc721a6612e7a10e47f874006a7a6d1c69d GIT binary patch literal 1854 zcmbVNYg5xe6g>-p&>9|Ad@IEVN(&g@f)y27l#aF4sdk28{E(&*7t>uP+3N7G)bTaW z=nwEmIo>3Nrdn}yI?YY)?mc_%xi>f8e|-4{AdgiYeGKMi#MO*ebL+8MNBQUC z6p@Fn6<}y9 zSRmh_C;&H+qbCXtff)hP&}qY(WErguWZz@-4c$a=gMm{khA>97p$)@u3yb6lI4#lc zfKy^7`w<5};%J9YGFZ^c7}6>+E{R<(3EajVf?>EzFgqy@&>fIYr3b&_)LK8Go~f>B vWX@OD2FT1*Kg0Z$Wi`e!-9Dfn%V92g6hh0eLN-OD0+sJ+!S{jTK92qb0;2yE literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundInvokeInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..7a55dc92cbdde9a5866c8705ddbd6057afa0213b GIT binary patch literal 2918 zcmbtWTUQ%Z6#h;!VIUbUMQnjmNVOmdmk3CuOD)wq(Ul8MIauTQiL?1cXF1Nf6P@F!z?~w>FKOSuyf8 z78#oEX@+J$U>F!)-j`p=30*dJYp|@A6f>_TW7!sj5fLFtXhj>t(tmdT$~;hg5F$m@ z-ZS$HhHV`&Ow@&;m_&nY*d^1{6Dw*lr&{Z3!BI(aWE~Q&ppzkBmKgf#n(!iNK^NW? zaaF=KuF%^!XomJwI=lL0A(h@(SYMo-Ul7s5FjG&%hcCrbT96fW#R=>TXav{MC*p>L zehl#J*P+{I#~&v{#E^^XtdZY1Dya<9!?C(?`b?zHHC(d7xQX{fyf5Jv1{tE4rE$~N zbcPN$J=|&LsF*Wp>skF;x!ki4t(Q(pB~LxK{YWh35)wYd1Vc!n&aoMS!`#6XJ`yo4;Wj>I z7`u$ZN1CN7_B^%FTt(CKs>RTCXlXWefZGRNr7&#!qN~mVuWH|%=>|oYOvSPs@Er+v zkz}}1<2`L!MVZpM_CH-;;4PMI#(jovH^iOQwflqR(P)vLodpSt_>?ka9vYn9L<1FHan5so-G+!Dg~uYENLa=S z!^kvy&h)m{Bld2bp*k6uR9`(Hx7;AWzA626+ZMgo>si^-_`A0$*n1j{iO0*AHDsM@_55DEa5Yi8L^L}UOomCK=#ne_AH#sIRU+6?=au`G$_&l6d6uSd#;jP1x=7y-)OvNI9OwL#N?I-3 zOJ=WDcbGk>7_D~Q5t2*GdZ zRM3IyS{$me*y~x;=u8uWUBQPO3SAVQb=k8X^{jt`Yux%NdKpd-J;9Lh((j{_xP&l5 zRE(lu7{dU`oDw&JXpO%R0{xD=eH?i14oNvchsUb!dPcYyKSum_bkj0^jLFw%ukIdW zhNr@f&-Fb?zNZisrZFnqc6?uTjaJh!1|3Cm$)hHR(Fn-~Ry+_d5F!bf?z|`diU(Uk za{Dl|CD8Kd6iW=5tq{rSQ>=5jiR8~*`2^b+(|5Nf_-PM75GI)qpoA}-mBFI5lXiF+ MmIeM9$Y7)AZ+DR)1ONa4 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundJsrInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundJsrInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..3b4ce3e6af22916265cdb98231fb8c928a99f160 GIT binary patch literal 1658 zcmbVMTTc@~6#k~|c4^siDHpke3QEgm6)%Vd60VAAKm(E(;=^{kz~Hh=cDMShKKP;! z{u50UjfwsMf0Xe|ccELXP2gd7X3orf=R4mybAJE%@e9Bb=4C_})Pv#+m0O3Y=#SkJxe3o0> zn`amt%^zqlHPzIty%3j;Bi$|YNa;SaGaqG51&nVOo+|UoadIYUOFro&X!g%$&$|7x@K-`4j1dd81weI z%kUsyFNrmt%1NzPd(ScS|3^?iX$*2X`&%}{6bV-6eg0E9^hQYT@^z{r^_-U(8a(?X zY3)@cgETNCH|>(68>`eK7`kdiJt>kzNb82{J+xiQy0T_jhO;DEi$OZ3Yqfxmz*w!7 zj9G^13uc|6sTvJ8sk&oexK3Y-Xd%=G#ac!e{WG+Bf(W8CHfG1ZA(|ckio|DHMv$d{ zlh~48Lz3PgDZRxQ*@pb%7{>&y=%Q#41SV#}L4@WhOa|~OjbcyAenH|BO?=?EFiP*r zfQo-00Hhq^23Z8R6>=4!F*QcFn+3u#+A8dlVpDn#Mfy+%>huqvGD}hTQv}6u3%3Kv z93+|nt?BOAPxL;EW{=Uo`5l+fa{CzK)*3)Yai<)?T}+ophI=&j5KE!yOiVOP>Rsq2 Ky>pn0C;kFNvb_WV literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadConstantInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLoadConstantInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..5c30a57ada6d425142aac3dc9e96e0d52f1957d9 GIT binary patch literal 2016 zcmbVNYg5xu5Ix&A1VWI9h^Pptpimz1{h**i!O^k9!y*iWen``R!H_U%s^h=X8Q(Md z1N>2rd(#vySgP=$-TT^e&z{}8`SttzPXJjwQjs7STgBIgj%Ogf$u-Y4`8<+jW> zrs102ro?4o$MTDIW_YCu8k$w;I$CgoFn`R;bG}*3`W%z#$)OP%t$3Aiw=13{tlr>cG=Bstfz*vIH#gV$9eP;#_Fj#>jbtHW;qQrWydYr0ipeE;DolU zC1JI00&9|~hFM3_;gv@86VAzZtuHK24VFgx-u^{;i6Jb`8Tws~FKSim`pb`7m(2O@`a>gKaY;+>=AD>}J-bNGnV-a`NI+ zDh$HYJmQ-g~uv-`Tr`j2%U1VlXih7bJLm3%6rr~JT$wPgA;F6Gx!Y_8q#L&*L@}I%;mUSZ0iTAeYAO0)?Vvoi6NOvH*{XRk(JPgeh~vQZeoyO zqFJ^}x~&!6MWSh;q8la6W{7>Vbyv$70ZyjEk6%F$smC zs~#gqHMz(05D!(OqOI>T^rUh@%KRI|(|t^dcp&2;9-YCt;o7>nN9cAf`#>dyr-K|+ zPqRA#6{?A4gHiljBA)Qa(x5u^`r}Y8Ru-3p)X(dtwpKYPX!fRBFlZ-U6GrE2e>3cU z&>e==d^4#VJj&XuIu}065Oq)MP4wzv(_)w+7Mi^J3$;Wqk2v(qNe|_U#vFuIQ=^tERy+#*3UGlI&R^c!l36+u3qpRGRz`DI~>~- zjodg&#vRAF_T`-YaKJu#YCnhPzWp*m4UtW3j62{6j?r7sPU43`3bK&)9Q9N$pJo=r z3(R{E7U*B33TfG+59p5%MSkJdwvai-@WytShPx-oY@FcUd6W|Yl>NSQ0ZU#k%UJP7 UhL<$P2>@4XHO$*HLk_+F0L728y8r+H literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLookupSwitchInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundLookupSwitchInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..5ad008084ee4116c2700acd9bb908b2a48d912a2 GIT binary patch literal 2156 zcmbVNTXWM!6#mw-t;EPAaYDF+1lk6O9f&BsP*4aE15JvEGvg430Ul&o2^$p2m8CNL zj$R&k=}URwt!20kGwl!HM=?Ds$yhc@X2Oehb$0jrzH|1Rv+qB=`wu`Bw`61()UD!WIfkv8w$W~HaNAP(cFR_;Hrl>tnEtXuV_^E+bq0||PDWmVi~)utTgESjY8%dG z;%u#Dx=o8g(QCDvw^!?Tme;CF3`g~yH){nHuuq1fposkpi+hwcecNfcfzwPVWysHS zhx-c*$7Xh;F0T(_7$Y)D3Pv%;u=1JYy6Zj)TJ^`=Hy`#0DK@PQBe4B7!`rlchKW=; zy3w#~Z6C&QP{ttzhjD~qe;BjC=eDZzHl59zZtF>HgJC9iDqO3&wrzzMq?IG^k4H4& z-BAUTm}1D8M%!vL4EJv;;5fdJ@uh;VFwJmgw-8+89&uIaju!)NH!Y809#o63Z#sq_cvL_OeNmcE2uO#GlCMgatSx8^S#e1WLppb?m0-JJd22?)CQC_o zO~YO{JTCrYW7dDjDK}R2-7Y_+Cv=K$2cJmCcrV?PR)_L_GR$3Qs<5X7a9uG4N_--ec$9hD@ z*~w6-yMbp~H>k@q97?&)Igz`Bv|_dWC0FzuW!Z5ouPPn~(L73N&2}m_?vMmjal_Q& z8NNXVCDCW;5h{tMM7Hl}p27FX(Y%Ohnx7}j&ooLj9;m#4^ag{K*;g23y+9c6uVj-8v zHi?B;hDv{8Pp}S{Q3!q;w+t vFHYT+Dz8zlzr~q;ZO;?hMq)?_KZfK>SPn;qpJ*%*t+?QuS@Ga7=s5g8miMVdNqU+B5AXSF7LDJRAcLm?4|$JQ_w>{pdS?- zOGr?HA_mTx?_=hC=l1sg@(Q4hwIVEJ9M~mfks}=Udk?PCiHx)e-5?Zke5*p~s=+XH zkNh}^M38he`!qvJTP=wr}(kf{YHnzOJcoc3Z^xZ_Ti(z1TvblZZAW!K0 zQS#idh>0eY9TW)%vlP{L#_se#g5BnX2xU)c*-Zz&jIM+qGE?zPAi^6FsSzHNc5<&` z!kPDPnKucR84}ii>KCDSY0@Z=Cp-~Cea1NUM#U5IT^T2*CQcmG2<|V_B$PT@%cwn? zzT`qHvxeLllhf_QJ{;aELV;I|`0!@2onzEu-eRBI*?k5*@y$Ys?Pv>;)yQTI<{8(% nUSR=cM*JR&SmGENR2W%U#>%I!VwHV`84Fd^?E))T(Lmz^#Jkpp literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewMultidimensionalArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewMultidimensionalArrayInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..f4564b7cd4c8e443678111be87962f2ac164f1d2 GIT binary patch literal 2095 zcmbVNTXWM!6#kB_Scy??22w5o!X=IE0BWEuPy?+K0tg%%;t(bcJjk|^DwU;-B*Ww< zwdH|!8cOK^@BFAv&&o<9gPkFLuy^ixWsMj8iXC<+EKM3~(tv2%~?n$xlyF|LHvb<;Nen}k!@ zy`Xc;0~o=mjEsVVI7ImIe}b2d=L;>%HydWtussf!ZWUcu-|8SWqzlo~)}}FU`|cLu zLRW5ehoi3B{-)zt>YPYS@Vp?Xjw$#8M+oU%Adf&=ny-$DtK)=ZHW!>vC^(5zgn?aD zPI@-CFUT}bWRo$mDq2G6Q@|mtWEw^sm=9x`6(#5BXB2lbTHa!2X<8kH{&9)6Um?#EEDbsCm z=0o9UL;^G1PiYW-K!SHXKl$@ABIXmXeJmfuEdS5(=?T9`@|wy2f#hEp$WL!$I6uCP z!@sjMfm`B^KQNGffh_$BMfwe+(hJP9e4?$1+qlCg@lGI7uoGAb-t*uKkyKvAU0?oB z9Dc!@w(*n@N-qP0O8Y@*ki?W^iJ%!*9)9_e@^)9{yU;@AdFGj5ox$n+D;(wD_$y3A z?xn@0^oCvgConYDe!T0}AnxHlnVf=4gBve=W s1lVhQU44!3K4$zr#&{|ON@5}KtBgvp5+3lHVKO3<4<+%DAuQtPe=~hIP5=M^ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewObjectInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewObjectInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..1dd295a0c217ad10e4ce935fa9662fcfc0cdb62a GIT binary patch literal 1739 zcmbVN3s2Kf6#g#j=r#(>iO3sNP__X@#0L&g7^sVLm<(qKV$y8|ie0<3orHg-M)8s8 z5Aa7BPam>PyCs-qz4xBp^WE=!=iJkuzrOtdkj5sD4hHe4{6 zi%O-cifcvFGNh7~(P*rdEJfGC;1J}|DS$_aVdzMDD~YP49W?lERZDtVW(edqUownj zTklCl5J49YK|nWp7}n3pX7Ytr)N5L~fgnTYvZ5*0D#Q46yQAZUFrv7?BPQS?`WT-6 z=ixc|c&m6MH_5~hakSjjEaQY>)|W_0CtW4Ys_MEbrfun+?IcPR{Q@pyfFbO_HHwp3Kf63gl(Ni9f*Vy`_T zXB{dg!?SF=itxGof3BM!hZFo;?VV$1CvM9t7?+?vkzFb-+C= z(TZFhU`Bw{7(7^!Mn>;~iI3=gM-vyW(>8KN2S#u=crXn2ks^!DX^nQ@Qs;5h2R2k^j&hAwF!|1qaJ6*=}iwFZ$sB zQKM)~^auE(jAz;{-P+Ow({yL{%sFSi^PS87{`2D(fJLmx@Gz(cxi=~|Y~3=nyqe8x zg~A@s>ncAy%B%5A!M3!loiu1IW^Ha7?U3M;(WXF#pP~OiJJ!^^X6(Cc*N?JhPG|71 zEx(L!ZpL>Q23F5kj0F%thYUqQCoVB0E(mFC+sK$jBj-ZN&^E^nZZ9wlg7@;eA99-?>v7A{PU_J3?UN(@1vhdGgH7RVIp@Sh53b4RRnUii z;;k8NRb>Xn&`X-QZLv(aHylX@Fn}8}1{Dlpm|?0_JWJftv$n8J6nQ?UTMRuVi`#lb zGz?NW8A6BFdS)0 zNTr5|jv%5UH4_ZO=crccAmu4c%TN{E!Au>1lx=ZipRV0AtwYUbm~~f0p!;EfiX_-8ARcO`B zYWcKgaq;d5CHplmFl?{3N_UfXuJ%qVyfFs3Toqd;!(D>jVq!E@R7}LuRyL>VQZHys zGsHHl$?LAmzmpDzK*}syS$&137DI277^g+D#5B?i_H(m9*;kT=p<9b$*y+StsM!D+ zb%d>$!3>pW0K^LYgJOWtWR+;&iTm_?KyOKS=m&I0Kg0VC?a_&^==wwg4<6F<61-$l zge)CHkxF<(vYv_o9%Gi?$h7R3kwa<&$E`{$qcdOh3%WkirsA$m2&K1WH%djpal`Ng zF_H*OOQbC@DHFo_6jx7iy#^^D&ZKwfklwrCC}(gK%we89F)ZMz<1qmr?SS6Ui0>yx zcf8S4jHh-aS|X|MnEV&v2N%L#$FmpD$b$!QB+4tJZxj$BiC}n15`&sy8GU~NvhveP literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewReferenceArrayInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNewReferenceArrayInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..63cf7da5e3ca727c6d14fbcb6c069a0c28baeaf6 GIT binary patch literal 1802 zcmbVNT~8B16g@*1wuJ?1MdTY4P}%~E_=yFz6jYL?7z#Cn_^@3DT-?q!+pUB@p+5Mc z5B>%zYGu03dw}ob^ zx~UZkJBG}8MJw85C<@xq!LWErPGcJ)YZb+I6-|bgc|#b^9fskFMn{J; z0R(YIMo7U~bTOp=^Y9ekU*kL6=0fLj+tv zA$BQ6(@z8rtOzM0UrrbDG02SFM!izEzdOa-6a1w0gT_Tw|E8$KI%1Q}tMK zYRXY^)5*}8Gz3o-b6IY$Ygv;lp`@j2W=69OckLM^=c!R(*hn@ilRCZP=w3GB5@V1{ z)wFIg%#tV#+R?E}jD<5KX~~_cQazQgz9ynQP0>&0xFguH9&@|^bfjSi2Acc^L7l;^E$0o&_q9=J@OI0 zF9<}UpV9e&3{AK}&kp#=;{{~tB^2ouZj!CL?0{RCqZPT9fEfW&2k~H48X3K7j(kGr zdzzHtT3n;_x&)(?H+V1%w-Fb{WPz%RY6;u84FC4hM> z5Ddc|OnPt+&`dL6Ff`o!0~a=ZggTnulw9y{xJ-@tE2jSC_^yiMpa<{6-BKj?h@l%1 UeNSi%(ahC2A-VmYVF|r|0GN65rvLx| literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNopInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundNopInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..da252361b815d5eca56d30dcd45608b350e01f3b GIT binary patch literal 762 zcmb_aO;5r=5PbuMLaCzo1&DI-pdM_zc)^$`@hc%{qHJ;IG|`w%=Iu;o_RYMV=a>2!cMny#EkbqqC+d}!iE+a2A1RxDe~8t@1YvE|pz5<*=W7iMw7k+H81-1K zd_!s39Q4{UI2CP=^(!=dS9mQEs5k#3XhfGPBPC)kHt%b@<$+p1W2CpMA zW>)V(4>0fep1>4aixH_Cn5kP#vv0rWVFt78B{3Ig7Ey|^j0$6cYceQf!N@XW8H*^r E0=%KyjQ{`u literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundOperatorInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundOperatorInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..abfc1bf48d9ae13431bec67a1b35b45d5bd89881 GIT binary patch literal 921 zcmb_bT~E|N6g{`>ZkMHsR9!w@P?mFLQHl&pr1erx%xBzX9lBwFM6oK57B#Xb^Ue2FH=oRvInRC`m<8 zyjQ7=)G$w@7yZH-k=R|$ag9u#dpN;h3T8hwkuC%h-gyr@4NPH4eD)fhIV*7cL z4PS`e+51LO^)^kInaUX@t$pjUl`&CoKJ`e+#!U?c+{>8H9v|-;YX|&W#!h zb8>K!%Qs372rKIwmEu1cT_5)d&#FY#)%~K%*=s$%4>ygKmV2XNUz!8aPdO9DSt8Oy zVU)w;WX*n51tE_A-}$uokNiG0aMAk0;`;ECIkOZH@8UuA{$u}p~mavVai ztF<&eXFACXg;m~K7$+<4hAp;}2f|&pwu|g&e(y8dX6$inY(D-1IxWAq`E~9`y^VT( z7PE}oKUkQG54j$IrkI=y*%zpC@0^*x|9<@eu!wmX5rVo~eyN(aZ@9K* zsk)_k-nMBOs=2pssrO5s?`pbVuz9TLzUkOW#30FtE0EDbSUBbJ(WiFFso3QZA|XC& z+NM8G7|s-TwO5*IY4%Qt%i6x~l#P6LGl3*pWhe?#Xd^72G58ZBoDm`BS&mPjg23-k z(1|o5;_MR!oAF7a8$B|56`VsKVWJtECDS!@f05HzsF+sSa0#i`uIU>^N7t-PjqQ=9 z$rrMlEf^qlEt#I~*uH63jPlmnqq#Bfxr{+VM_swK(k=%}axy~-hB3klJ5>n@Lz!&z zlrG`2j8O$+xYB^R?z^VF!${kXyQi^QGhw>5)%;cnyG9}(4j1f_ks++q>4uuF-e+n! z&rr9F9xI*@mC#-^ZDX~vS2ElUtz@w$eI%_Z?7$iGUzi@@L9tn}PH6k1zHN-2Cqy&Z z0zt0Ua>F4^u`Eq))UiI`u4YlI$GHd8QywO?_|8#jx*KX6h)qbYI~7+qR`^yE`cBAg zQj~&`Rt?X8=y+UPrC{5JyC@z5gVjo(bZL76XQLuAW(m`0tSzCf5e+xEhhrdI<*!3r zdVaZtEu)YBS+*V{f+&xzx$z%}<_5nb@s-U8a{O--OVS%i(pw~@cNk~iNNqc=VS+6_ zD6Tt$iJ1rx;du&^0ldniSd((!koe4#8gN`VrT0}prM4jegxTs(0IV-}!K literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundReturnInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundReturnInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..3b1bb650b2ba78662ecfabbc3efdc42c31f25e37 GIT binary patch literal 1214 zcmb_b+iuf95Iq|wacW%Jgiz8_+5#;kDb%DqAwwmIgj$FiL`o%8@!&Xaad6g=y+P_< zfrJV|f)C&);DHx@0x`anIFKTNkR{K~?ChDdXLde)fBz9c9XDm97_@HZg=TYMdE9U` z(=mL1-*zm`?)4q*Zrc~0VTvtIc3=wI8hUOUjAi<^CH{Fhl2R8m?(LyM|{6 zejH4T=eE!Apz*(&uQTMt&qn2hd#p)uMAZ0}3`)x#c&2rqri7t1W<=Hk4G47G^2Mg> zlc?$z=ayFwhRY)Eg>gerii5uigc@}`4Tj4!wh~zyJo>MYw}BLWK(@O27Sd~4rErD* zN)VMkBO`smRq|(|ER<0pkMe{0Aq<8piZRxD=mWXx8%!Kw>J{ZhXj$5U^fg3MgEiHU zkQi2REk3U!6Yk{;XVV{W?x|Eg!ffjuF8m7gEdi8|fh1fH%dJ5REyE461tJh!yp|3I JpJ5%dKL9u@LyrIe literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStackInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStackInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..f386857df835f044e649e156141af40db09e23fc GIT binary patch literal 729 zcmb_aT}uK%6g_v{Ts6zG{EDEL9{PZ`o(-XdN)UUnd>_}TM%P){9s6HB1wHfw`b$N0 zw}eC_C}QB=Ift41d0yV1o&nUck%5JT13QZaBnhYe-oRDb$WRO4^?VUUH_Df;8jgJT zq#Kz~c&4G*k3FLTy?w2_!C3dEC_?gBX=Q4Jt(|6H+zZzi`gSVV<;V+qvbx)GkRqJ_ zF=g8bZ!neDL56TRFQ59Z*PZ=EucGdFw4r$k|ci2o9@>kY;HSA669GMMgE|E%wR1{YTIP-z;R=#_EIpiUs=(ON@(O nuds|9BYuw+ta6M5@{BC3Vg1t=P-35F#zFyQJI$F3sG#xzrHIqc literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStoreInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundStoreInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..da19d550d14fb034fce342b2ff7c6e47b10801dd GIT binary patch literal 1738 zcmbVNYfsZ)6n@@yqob7D{(JfO#5FrswGDL(KmT#y&`qs=_6|?BG$k4Q)o4T{eFcQlg zs>iBgsOEtWOSV+7idr(h(+mkMB4in@Xk*y;Pv<$uvb9SHf@Q;U7+9Kn=#bHg2t&Xs zF$^_AB%ur4B6?)>qK{$VdhiVGC0jpI?UU`3lJ-hBiwx0Nysq){7fA^N7!)xi<2HsF zCL4vjs@qz@Ss|X5E4oqCY=+j4w(e*dtDqV?D(#~U*-giH!iX|-yX@>`U#G^(6H(4f zYOMH9#9fAtT7233A-R)?tx*|cxKBy6+$=E+UlW#>MXnR$35+ucv3Od-I3`3)%9w(} z&{^}5rm8&Pfr!VdQPHyd3_Y>5pEK_T5%mx=A|Adx8>ok2B`s#!@#knU-TUy!Kw91rBIc=Jny~2l zGJKXXJf&X;A1E{xL$nq#Oy4=$y+Hs1$(F?UcL<50Z)pBP+W_Y2+s3biS%ic+NWwgx z(OI%`hF9k!8hEP^643 zk?B9-NALg)386Feg%^eyUf`ksro&xHZWLGbjQb$(dUx+V=iWW{?%yw;JqJ+6V-X1k zd8hrIY*?=DSgI*&rrPap8Ky29yL+a**6O;Bs<{=5Mo)7M+sYt`l!&wh5hDyUJL>nU zY^qi#Vq4qO?6%G@+E`n!-m8CAX_Pk@&Q;%hR>>lZQ4x}aQ#j4AJ|wHf$5zYstagMb zLwd!q40n}bzAy;7*v#Mz#zo{LoW%sggSP~4s4Y{k?;EbReS*h`Y40~x)1!>A3dfq1 z@D2ycY#W_ze}}J5OPIkd!>P8urFy2@P@RtMGR(%3uc|HGR7Np}^CIRYT)?{wr~M3j zu3^emqf54F&E9)j+hQn$De(8owrT4AZ7RjU`70BJGkH(KA}%tdG_|XD8P4<{%HlE# zB8n19SYlWnl(4&oLs(@J#JXpgZQUV%`;Ou2k#sR!EmSH4;_N3-Y>r@=As6xSr1tRk z#qKvEWCA!=TCKH1@L7uLnuP24fO2Ao@;qM%qmPv@N%BM76!DRSk8$gS&${avR);)o z+0L#?X}%Q|Sg@-+iG&l7=q1~S3r~qq7;YZZjTGQ<&B>84Pbe!>H#(N;dJaizwJ%32 z5&U?sfmF+M$I2?PNb);k7^@nVzUl3@bjOFKELUw!HJhqqaDj)5Nq5^IY1FEN?mnh} z^eQzzB%(2S67A_;5AoZfBr;_9#U_JLC{`He-k^%0;3ylt{o|TpxbxcLkoXK@P!u-9 zbyCxSrucu~hcspwaqXU>Cwg&2HOi2!+n%H8_vv9^n2Nd8D_p_kX;bgI z8#eDeQpK`#r_A3I-a>M54SFtIjMoCLQPF0>@CiLRIo_J-*~;5tSa{gFBqomruI z0=MZ=q6Ug3ny=Ez4>YD|yiocD!f(iwW)Cn{I(LA4Y54$CrRn4m=-9GYQV#d!e z63b-B_b#oS#Xb7vY-JkxnN;aljQvQHgik5W7lr3OeBdM%!ZS)noN>P2_|I758QhOS zp8BZ|`L9^xMSK<}IZAt>-}s*x!Vke=#Ba=R2MZj9y(w9$%nJF6j}+X6RZW*F3G`x%ZQQ;L6uR=@3`zN4U|?^+km1 ec<53<%?E#oNB+q0C5<_P<;tul`E$w8!1Vuz(_c&g literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundThrowInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundThrowInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..4713fed4ef66162869aaf8a1cace70efcd6abae4 GIT binary patch literal 1073 zcmb_bO>fgc5PciFabjHBm_k1&<*S7xKn)ipWI!sBppl{mkr0F`4z}aA8=Q4zZ{TkM z2S7;h1Nb>`;D#8xMsc820&&^V?7p3OZ}#oy?;kz^Xu#4?V6X=L=N1>zkAxFgUf{&> z4i9{b5BCFW!;NL+c(N%djy%ajQHF{s4MhVQN(@T_=Y?Yhj@ZrJZSQ+w-)AUpbT=Qh zpD--9{tUBq=s2dqFffhd4EO$$(CTC1h9l9>aiq?-x#03H!`bRlt!up!W*Lm`UKGCE zZa=)U7C+NqGR%(ow%vj6NgZ=Iso|7?c`PtI_(zgyqe-S=HmsFu?I@}`mT+3bvVk*L znIPDa5f{6pc_)m9j%2u%*L-klZ|7grYiS%%+PH8r%~DrB^mx4#@xg-GkFYpCmcnd zf1e!AuyBaI*AwwnY0Ho0W*E~njiwNO)JQ&tPkhb8>^7fm{yG`lAlv958`6&}P@Kkj zS}#y`GtGfg{SB0ND8Eh-7irb$1j-j^%2%vXZqNPJ+b yD)qNG(Rq)>R|G5|DOOAX%C}shN>)fgEk)IFC5;SMDVlUIA$(0O6Lp4lEdBtM#wjxZ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTypeCheckInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction$UnboundTypeCheckInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..f59b7c6b86ccd92d2ede6389294af9c205f13a3c GIT binary patch literal 1743 zcmbVNTT|0e5dKb^5*otAiU@L5L1_y_5ieL!p`tQY&?z#*Fg~PdfIymb(o~0kr8A0` z8T|qN4fVkneem6JPa1mB&>4K`p0nBg&Ue1uv;F-0!zTb~q(y`nl->NEVpy*3SgNUL zrdld(8K$lng`%k}N3TgEB$FbMoiD#Ca? zFyp8LCG?_C#2Fd=7$COIbhv9cy5^=yz{Rp*=5>dmMGiXn!+ zD*EQ?Ly{ zbqv1uor1e#lo%dmnl((oqd$DLK^#&HVx^yKhG`O^$vpX|7wJutgkC!JrE<(i3;NSI1@QS^fsb7J_d(wugjd?( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..7dede9e3a6e823a42a599df654682ec71fa91df8 GIT binary patch literal 8205 zcmbtZdwd*K75;7-l1-a7u@6dLGzFq*ijCAarAU)Buq7{=5P@28vO7s8+02C5*~EYd zh=|BbKtx1EL_`FH3bg_PBGw1K-|zSP{eJ&`{`}_d%i&Jtc=-VP0wUHc8+E} z*GPFuo0v;^mSYRlI5Pt4dnb)qqa$P3;}NBSnUs?@xBF8h8qt8o0<~G|LQ_B_7o!nN z>#?j6O=uR_vXFUqWz1>Q_5|uqv24pbRbWxu=8<|V7uXm#zhdXgp1$Gpce>*_pQ6j* z5)7YedBpM|&$aCF?E*`~{t+XSGZR?N2})J>4h-&S&7RmYYh;M~1Qz=fbh?I}nn++R zN%GJ6aqMsK`+F=ilTKg*T_ztxmNCDbJX>3{Crh@a{^+Ega^;c}Xc5>{5JRnO#_@Kv zrUN6=p%F=Y)|sN&#|s>je-0I<^Hazfo|T`$AKE={8`D-QfoF4}d5xecR2T%hj6#^*!cTpvZ7v zN5!zATtx=p9@ERYb^<#YfcfYAKw2aNaL999?p8Mql#d}z(fM-bVPiC7hJHMquSujq zB^;h`ow)>d3pC2dLa&VAVLGpC!c0vi&?m5_AcoTh&ZTur`~{zFk2*P2qg> zo@b}r+-@tIa%|7Cb0$X&adV?Bg?Z~7nRWz@ZQC4qxr@0hNJ~scT})2`O}&WMI-t3beFUGcLJ# zM4*1owLEj!5!lATRT6Wz<(erbwY1rpvodMZ-R`R|9&&PS%IsnOW+I45-dp{oN$dK} ztk-Ay>(ACBEwHQFTroT+1lz`Vi>$jIWBOFPv#vrlp-aQLU^G-)wjFK8z)PH%;O5U?_ zx(=78(?8ypo|E3KOH_JFdXGjWkrq`viM&@}P-~4<&mr&ADDTqF_yYQVfpfHsTu^QL zfWTS0?EF}(RGIEO0@^Bd>4Unijju`%YNSHBQuzRw4f=#Y_u+a>+>GEpHGt)!4QF*=L-!3#JZQFFa z{F_@}TowCmUTjxONU>f0YUb5Vz*GJS%!`(wuR;|OI4&4ar6>p-9}KGYr75sB7!~u` zSTwTy8&F_%pji4r$6K|aC$6~go;K)>{nRQd$9*>mv124+=C(!4HGMkrwyI#cZ5<0Q4o)6e;DFHKGfjl{H>FXCeGorzcCzub8#L~U@u<5-%{oJ z``8&(o{Uv)!oEQHT#jBuou>AKSkk`b07U!x1E}9$pjl2+focBQG~K~6%t*?Xyjoxn z3FHEO8=K@3Yib2viSsGf;#K^ufq_xt7`7n=6XUQjMP3INAd4L4FprCHF)qPnxExpD zN?e7jaV@UL4Y&z6;}+bC+we}@jyrHC?!w);2lwKBJb?Xp2nTQwkKi#pjwkUHp2i`3 zigVR*)R_*>#V#NQF`CH|gxKk*O52Z(~W!~?{?5DyanN_>R)H{xT& ezY`xP{)6}=@t?$}i2ou!P5d|U5b-~?4gUu^5P<*y literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.java new file mode 100644 index 00000000..0e528cd0 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractInstruction.java @@ -0,0 +1,1453 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.constant.ConstantDesc; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.lang.classfile.ClassFile; +import java.lang.classfile.Instruction; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.instruction.SwitchCase; +import java.lang.classfile.constantpool.FieldRefEntry; +import java.lang.classfile.constantpool.InterfaceMethodRefEntry; +import java.lang.classfile.constantpool.InvokeDynamicEntry; +import java.lang.classfile.constantpool.LoadableConstantEntry; +import java.lang.classfile.constantpool.MemberRefEntry; +import java.lang.classfile.instruction.ArrayLoadInstruction; +import java.lang.classfile.instruction.ArrayStoreInstruction; +import java.lang.classfile.instruction.BranchInstruction; +import java.lang.classfile.instruction.ConstantInstruction; +import java.lang.classfile.instruction.ConvertInstruction; +import java.lang.classfile.instruction.DiscontinuedInstruction; +import java.lang.classfile.instruction.FieldInstruction; +import java.lang.classfile.instruction.IncrementInstruction; +import java.lang.classfile.instruction.InvokeDynamicInstruction; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.classfile.instruction.LoadInstruction; +import java.lang.classfile.instruction.LookupSwitchInstruction; +import java.lang.classfile.instruction.MonitorInstruction; +import java.lang.classfile.instruction.NewMultiArrayInstruction; +import java.lang.classfile.instruction.NewObjectInstruction; +import java.lang.classfile.instruction.NewPrimitiveArrayInstruction; +import java.lang.classfile.instruction.NewReferenceArrayInstruction; +import java.lang.classfile.instruction.NopInstruction; +import java.lang.classfile.instruction.OperatorInstruction; +import java.lang.classfile.instruction.ReturnInstruction; +import java.lang.classfile.instruction.StackInstruction; +import java.lang.classfile.instruction.StoreInstruction; +import java.lang.classfile.instruction.TableSwitchInstruction; +import java.lang.classfile.instruction.ThrowInstruction; +import java.lang.classfile.instruction.TypeCheckInstruction; +import java.lang.classfile.Label; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; + +public abstract sealed class AbstractInstruction + extends AbstractElement + implements Instruction { + + private static final String + FMT_ArgumentConstant = "ArgumentConstant[OP=%s, val=%s]", + FMT_Branch = "Branch[OP=%s]", + FMT_Field = "Field[OP=%s, field=%s.%s:%s]", + FMT_Increment = "Increment[OP=%s, slot=%d, val=%d]", + FMT_Invoke = "Invoke[OP=%s, m=%s.%s%s]", + FMT_InvokeDynamic = "InvokeDynamic[OP=%s, bsm=%s %s]", + FMT_InvokeInterface = "InvokeInterface[OP=%s, m=%s.%s%s]", + FMT_Load = "Load[OP=%s, slot=%d]", + FMT_LoadConstant = "LoadConstant[OP=%s, val=%s]", + FMT_LookupSwitch = "LookupSwitch[OP=%s]", + FMT_NewMultiArray = "NewMultiArray[OP=%s, type=%s[%d]]", + FMT_NewObj = "NewObj[OP=%s, type=%s]", + FMT_NewPrimitiveArray = "NewPrimitiveArray[OP=%s, type=%s]", + FMT_NewRefArray = "NewRefArray[OP=%s, type=%s]", + FMT_Return = "Return[OP=%s]", + FMT_Store = "Store[OP=%s, slot=%d]", + FMT_TableSwitch = "TableSwitch[OP=%s]", + FMT_Throw = "Throw[OP=%s]", + FMT_TypeCheck = "TypeCheck[OP=%s, type=%s]", + FMT_Unbound = "%s[op=%s]", + FMT_Discontinued = "Discontinued[OP=%s]"; + + final Opcode op; + final int size; + + @Override + public Opcode opcode() { + return op; + } + + @Override + public int sizeInBytes() { + return size; + } + + public AbstractInstruction(Opcode op, int size) { + this.op = op; + this.size = size; + } + + @Override + public abstract void writeTo(DirectCodeBuilder writer); + + public abstract static sealed class BoundInstruction extends AbstractInstruction { + final CodeImpl code; + final int pos; + + protected BoundInstruction(Opcode op, int size, CodeImpl code, int pos) { + super(op, size); + this.code = code; + this.pos = pos; + } + + protected Label offsetToLabel(int offset) { + return code.getLabel(pos - code.codeStart + offset); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + // Override this if the instruction has any CP references or labels! + code.classReader.copyBytesTo(writer.bytecodesBufWriter, pos, size); + } + } + + public static final class BoundLoadInstruction + extends BoundInstruction implements LoadInstruction { + + public BoundLoadInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + + @Override + public TypeKind typeKind() { + return op.primaryTypeKind(); + } + + @Override + public String toString() { + return String.format(FMT_Load, this.opcode(), slot()); + } + + @Override + public int slot() { + return switch (size) { + case 2 -> code.classReader.readU1(pos + 1); + case 4 -> code.classReader.readU2(pos + 2); + default -> throw new IllegalArgumentException("Unexpected op size: " + op.sizeIfFixed() + " -- " + op); + }; + } + + } + + public static final class BoundStoreInstruction + extends BoundInstruction implements StoreInstruction { + + public BoundStoreInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public TypeKind typeKind() { + return op.primaryTypeKind(); + } + + @Override + public String toString() { + return String.format(FMT_Store, this.opcode(), slot()); + } + + @Override + public int slot() { + return switch (size) { + case 2 -> code.classReader.readU1(pos + 1); + case 4 -> code.classReader.readU2(pos + 2); + default -> throw new IllegalArgumentException("Unexpected op size: " + size + " -- " + op); + }; + } + + } + + public static final class BoundIncrementInstruction + extends BoundInstruction implements IncrementInstruction { + + public BoundIncrementInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public int slot() { + return size == 6 ? code.classReader.readU2(pos + 2) : code.classReader.readU1(pos + 1); + } + + @Override + public int constant() { + return size == 6 ? code.classReader.readS2(pos + 4) : (byte) code.classReader.readS1(pos + 2); + } + + @Override + public String toString() { + return String.format(FMT_Increment, this.opcode(), slot(), constant()); + } + + } + + public static final class BoundBranchInstruction + extends BoundInstruction implements BranchInstruction { + + public BoundBranchInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public Label target() { + return offsetToLabel(branchByteOffset()); + } + + public int branchByteOffset() { + return size == 3 + ? (int) (short) code.classReader.readU2(pos + 1) + : code.classReader.readInt(pos + 1); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeBranch(opcode(), target()); + } + + @Override + public String toString() { + return String.format(FMT_Branch, this.opcode()); + } + + } + + public record SwitchCaseImpl(int caseValue, Label target) + implements SwitchCase { + } + + public static final class BoundLookupSwitchInstruction + extends BoundInstruction implements LookupSwitchInstruction { + + // will always need size, cache everything to there + private final int afterPad; + private final int npairs; + + BoundLookupSwitchInstruction(Opcode op, CodeImpl code, int pos) { + super(op, size(code, code.codeStart, pos), code, pos); + + this.afterPad = pos + 1 + ((4 - ((pos + 1 - code.codeStart) & 3)) & 3); + this.npairs = code.classReader.readInt(afterPad + 4); + if (npairs < 0 || npairs > code.codeLength >> 3) { + throw new IllegalArgumentException("Invalid lookupswitch npairs value: " + npairs); + } + } + + static int size(CodeImpl code, int codeStart, int pos) { + int afterPad = pos + 1 + ((4 - ((pos + 1 - codeStart) & 3)) & 3); + int pad = afterPad - (pos + 1); + int npairs = code.classReader.readInt(afterPad + 4); + return 1 + pad + 8 + npairs * 8; + } + + private int defaultOffset() { + return code.classReader.readInt(afterPad); + } + + @Override + public List cases() { + var cases = new SwitchCase[npairs]; + for (int i = 0; i < npairs; ++i) { + int z = afterPad + 8 + 8 * i; + cases[i] = SwitchCase.of(code.classReader.readInt(z), offsetToLabel(code.classReader.readInt(z + 4))); + } + return List.of(cases); + } + + @Override + public Label defaultTarget() { + return offsetToLabel(defaultOffset()); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeLookupSwitch(defaultTarget(), cases()); + } + + @Override + public String toString() { + return String.format(FMT_LookupSwitch, this.opcode()); + } + + } + + public static final class BoundTableSwitchInstruction + extends BoundInstruction implements TableSwitchInstruction { + + BoundTableSwitchInstruction(Opcode op, CodeImpl code, int pos) { + super(op, size(code, code.codeStart, pos), code, pos); + } + + static int size(CodeImpl code, int codeStart, int pos) { + int ap = pos + 1 + ((4 - ((pos + 1 - codeStart) & 3)) & 3); + int pad = ap - (pos + 1); + int low = code.classReader.readInt(ap + 4); + int high = code.classReader.readInt(ap + 8); + if (high < low || high - low > code.codeLength >> 2) { + throw new IllegalArgumentException("Invalid tableswitch values low: " + low + " high: " + high); + } + int cnt = high - low + 1; + return 1 + pad + 12 + cnt * 4; + } + + private int afterPadding() { + int p = pos; + return p + 1 + ((4 - ((p + 1 - code.codeStart) & 3)) & 3); + } + + @Override + public Label defaultTarget() { + return offsetToLabel(defaultOffset()); + } + + @Override + public int lowValue() { + return code.classReader.readInt(afterPadding() + 4); + } + + @Override + public int highValue() { + return code.classReader.readInt(afterPadding() + 8); + } + + @Override + public List cases() { + int low = lowValue(); + int high = highValue(); + int defOff = defaultOffset(); + var cases = new ArrayList(high - low + 1); + int z = afterPadding() + 12; + for (int i = lowValue(); i <= high; ++i) { + int off = code.classReader.readInt(z); + if (defOff != off) { + cases.add(SwitchCase.of(i, offsetToLabel(off))); + } + z += 4; + } + return Collections.unmodifiableList(cases); + } + + private int defaultOffset() { + return code.classReader.readInt(afterPadding()); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeTableSwitch(lowValue(), highValue(), defaultTarget(), cases()); + } + + @Override + public String toString() { + return String.format(FMT_TableSwitch, this.opcode()); + } + + } + + public static final class BoundFieldInstruction + extends BoundInstruction implements FieldInstruction { + + private FieldRefEntry fieldEntry; + + public BoundFieldInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public FieldRefEntry field() { + if (fieldEntry == null) + fieldEntry = code.classReader.readEntry(pos + 1, FieldRefEntry.class); + return fieldEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (writer.canWriteDirect(code.constantPool())) + super.writeTo(writer); + else + writer.writeFieldAccess(op, field()); + } + + @Override + public String toString() { + return String.format(FMT_Field, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue()); + } + + } + + public static final class BoundInvokeInstruction + extends BoundInstruction implements InvokeInstruction { + MemberRefEntry methodEntry; + + public BoundInvokeInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public MemberRefEntry method() { + if (methodEntry == null) + methodEntry = code.classReader.readEntry(pos + 1, MemberRefEntry.class); + return methodEntry; + } + + @Override + public boolean isInterface() { + return method().tag() == ClassFile.TAG_INTERFACEMETHODREF; + } + + @Override + public int count() { + return 0; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (writer.canWriteDirect(code.constantPool())) + super.writeTo(writer); + else + writer.writeInvokeNormal(op, method()); + } + + @Override + public String toString() { + return String.format(FMT_Invoke, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue()); + } + + } + + public static final class BoundInvokeInterfaceInstruction + extends BoundInstruction implements InvokeInstruction { + InterfaceMethodRefEntry methodEntry; + + public BoundInvokeInterfaceInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public MemberRefEntry method() { + if (methodEntry == null) + methodEntry = code.classReader.readEntry(pos + 1, InterfaceMethodRefEntry.class); + return methodEntry; + } + + @Override + public int count() { + return code.classReader.readU1(pos + 3); + } + + @Override + public boolean isInterface() { + return true; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (writer.canWriteDirect(code.constantPool())) + super.writeTo(writer); + else + writer.writeInvokeInterface(op, (InterfaceMethodRefEntry) method(), count()); + } + + @Override + public String toString() { + return String.format(FMT_InvokeInterface, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue()); + } + + } + + public static final class BoundInvokeDynamicInstruction + extends BoundInstruction implements InvokeDynamicInstruction { + InvokeDynamicEntry indyEntry; + + BoundInvokeDynamicInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public InvokeDynamicEntry invokedynamic() { + if (indyEntry == null) + indyEntry = code.classReader.readEntry(pos + 1, InvokeDynamicEntry.class); + return indyEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (writer.canWriteDirect(code.constantPool())) + super.writeTo(writer); + else + writer.writeInvokeDynamic(invokedynamic()); + } + + @Override + public String toString() { + return String.format(FMT_InvokeDynamic, this.opcode(), bootstrapMethod(), bootstrapArgs()); + } + + } + + public static final class BoundNewObjectInstruction + extends BoundInstruction implements NewObjectInstruction { + ClassEntry classEntry; + + BoundNewObjectInstruction(CodeImpl code, int pos) { + super(Opcode.NEW, Opcode.NEW.sizeIfFixed(), code, pos); + } + + @Override + public ClassEntry className() { + if (classEntry == null) + classEntry = code.classReader.readClassEntry(pos + 1); + return classEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (writer.canWriteDirect(code.constantPool())) + super.writeTo(writer); + else + writer.writeNewObject(className()); + } + + @Override + public String toString() { + return String.format(FMT_NewObj, this.opcode(), className().asInternalName()); + } + + } + + public static final class BoundNewPrimitiveArrayInstruction + extends BoundInstruction implements NewPrimitiveArrayInstruction { + + public BoundNewPrimitiveArrayInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public TypeKind typeKind() { + return TypeKind.fromNewarrayCode(code.classReader.readU1(pos + 1)); + } + + @Override + public String toString() { + return String.format(FMT_NewPrimitiveArray, this.opcode(), typeKind()); + } + + } + + public static final class BoundNewReferenceArrayInstruction + extends BoundInstruction implements NewReferenceArrayInstruction { + + public BoundNewReferenceArrayInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public ClassEntry componentType() { + return code.classReader.readClassEntry(pos + 1); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (writer.canWriteDirect(code.constantPool())) + super.writeTo(writer); + else + writer.writeNewReferenceArray(componentType()); + } + + @Override + public String toString() { + return String.format(FMT_NewRefArray, this.opcode(), componentType().asInternalName()); + } + } + + public static final class BoundNewMultidimensionalArrayInstruction + extends BoundInstruction implements NewMultiArrayInstruction { + + public BoundNewMultidimensionalArrayInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public int dimensions() { + return code.classReader.readU1(pos + 3); + } + + @Override + public ClassEntry arrayType() { + return code.classReader.readClassEntry(pos + 1); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (writer.canWriteDirect(code.constantPool())) + super.writeTo(writer); + else + writer.writeNewMultidimensionalArray(dimensions(), arrayType()); + } + + @Override + public String toString() { + return String.format(FMT_NewMultiArray, this.opcode(), arrayType().asInternalName(), dimensions()); + } + + } + + public static final class BoundTypeCheckInstruction + extends BoundInstruction implements TypeCheckInstruction { + ClassEntry typeEntry; + + public BoundTypeCheckInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public ClassEntry type() { + if (typeEntry == null) + typeEntry = code.classReader.readClassEntry(pos + 1); + return typeEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (writer.canWriteDirect(code.constantPool())) + super.writeTo(writer); + else + writer.writeTypeCheck(op, type()); + } + + @Override + public String toString() { + return String.format(FMT_TypeCheck, this.opcode(), type().asInternalName()); + } + + } + + public static final class BoundArgumentConstantInstruction + extends BoundInstruction implements ConstantInstruction.ArgumentConstantInstruction { + + public BoundArgumentConstantInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public Integer constantValue() { + return constantInt(); + } + + public int constantInt() { + return size == 3 ? code.classReader.readS2(pos + 1) : code.classReader.readS1(pos + 1); + } + + @Override + public String toString() { + return String.format(FMT_ArgumentConstant, this.opcode(), constantValue()); + } + + } + + public static final class BoundLoadConstantInstruction + extends BoundInstruction implements ConstantInstruction.LoadConstantInstruction { + + public BoundLoadConstantInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public LoadableConstantEntry constantEntry() { + return code.classReader.entryByIndex(op == Opcode.LDC + ? code.classReader.readU1(pos + 1) + : code.classReader.readU2(pos + 1), + LoadableConstantEntry.class); + } + + @Override + public ConstantDesc constantValue() { + return constantEntry().constantValue(); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (writer.canWriteDirect(code.constantPool())) + super.writeTo(writer); + else + writer.writeLoadConstant(op, constantEntry()); + } + + @Override + public String toString() { + return String.format(FMT_LoadConstant, this.opcode(), constantValue()); + } + + } + + public static final class BoundJsrInstruction + extends BoundInstruction implements DiscontinuedInstruction.JsrInstruction { + + public BoundJsrInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public Label target() { + return offsetToLabel(branchByteOffset()); + } + + public int branchByteOffset() { + return size == 3 + ? code.classReader.readS2(pos + 1) + : code.classReader.readInt(pos + 1); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeBranch(opcode(), target()); + } + + @Override + public String toString() { + return String.format(FMT_Discontinued, this.opcode()); + } + + } + + public static final class BoundRetInstruction + extends BoundInstruction implements DiscontinuedInstruction.RetInstruction { + + public BoundRetInstruction(Opcode op, CodeImpl code, int pos) { + super(op, op.sizeIfFixed(), code, pos); + } + + @Override + public String toString() { + return String.format(FMT_Discontinued, this.opcode()); + } + + @Override + public int slot() { + return switch (size) { + case 2 -> code.classReader.readU1(pos + 1); + case 4 -> code.classReader.readU2(pos + 2); + default -> throw new IllegalArgumentException("Unexpected op size: " + op.sizeIfFixed() + " -- " + op); + }; + } + + } + + public abstract static sealed class UnboundInstruction extends AbstractInstruction { + + UnboundInstruction(Opcode op) { + super(op, op.sizeIfFixed()); + } + + @Override + // Override this if there is anything more that just the bytecode + public void writeTo(DirectCodeBuilder writer) { + writer.writeBytecode(op); + } + + @Override + public String toString() { + return String.format(FMT_Unbound, this.getClass().getSimpleName(), op); + } + } + + public static final class UnboundLoadInstruction + extends UnboundInstruction implements LoadInstruction { + final int slot; + + public UnboundLoadInstruction(Opcode op, int slot) { + super(op); + this.slot = slot; + } + + @Override + public int slot() { + return slot; + } + + @Override + public TypeKind typeKind() { + return op.primaryTypeKind(); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeLocalVar(op, slot); + } + + @Override + public String toString() { + return String.format(FMT_Load, this.opcode(), slot()); + } + + } + + public static final class UnboundStoreInstruction + extends UnboundInstruction implements StoreInstruction { + final int slot; + + public UnboundStoreInstruction(Opcode op, int slot) { + super(op); + this.slot = slot; + } + + @Override + public int slot() { + return slot; + } + + @Override + public TypeKind typeKind() { + return op.primaryTypeKind(); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeLocalVar(op, slot); + } + + @Override + public String toString() { + return String.format(FMT_Store, this.opcode(), slot()); + } + + } + + public static final class UnboundIncrementInstruction + extends UnboundInstruction implements IncrementInstruction { + final int slot; + final int constant; + + public UnboundIncrementInstruction(int slot, int constant) { + super(slot <= 255 && constant < 128 && constant > -127 + ? Opcode.IINC + : Opcode.IINC_W); + this.slot = slot; + this.constant = constant; + } + + @Override + public int slot() { + return slot; + } + + @Override + public int constant() { + return constant; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeIncrement(slot, constant); + } + + @Override + public String toString() { + return String.format(FMT_Increment, this.opcode(), slot(), constant()); + } + } + + public static final class UnboundBranchInstruction + extends UnboundInstruction implements BranchInstruction { + final Label target; + + public UnboundBranchInstruction(Opcode op, Label target) { + super(op); + this.target = target; + } + + @Override + public Label target() { + return target; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeBranch(op, target); + } + + @Override + public String toString() { + return String.format(FMT_Branch, this.opcode()); + } + } + + public static final class UnboundLookupSwitchInstruction + extends UnboundInstruction implements LookupSwitchInstruction { + + private final Label defaultTarget; + private final List cases; + + public UnboundLookupSwitchInstruction(Label defaultTarget, List cases) { + super(Opcode.LOOKUPSWITCH); + this.defaultTarget = defaultTarget; + this.cases = List.copyOf(cases); + } + + @Override + public List cases() { + return cases; + } + + @Override + public Label defaultTarget() { + return defaultTarget; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeLookupSwitch(defaultTarget, cases); + } + + @Override + public String toString() { + return String.format(FMT_LookupSwitch, this.opcode()); + } + } + + public static final class UnboundTableSwitchInstruction + extends UnboundInstruction implements TableSwitchInstruction { + + private final int lowValue, highValue; + private final Label defaultTarget; + private final List cases; + + public UnboundTableSwitchInstruction(int lowValue, int highValue, Label defaultTarget, List cases) { + super(Opcode.TABLESWITCH); + this.lowValue = lowValue; + this.highValue = highValue; + this.defaultTarget = defaultTarget; + this.cases = List.copyOf(cases); + } + + @Override + public int lowValue() { + return lowValue; + } + + @Override + public int highValue() { + return highValue; + } + + @Override + public Label defaultTarget() { + return defaultTarget; + } + + @Override + public List cases() { + return cases; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeTableSwitch(lowValue, highValue, defaultTarget, cases); + } + + @Override + public String toString() { + return String.format(FMT_TableSwitch, this.opcode()); + } + } + + public static final class UnboundReturnInstruction + extends UnboundInstruction implements ReturnInstruction { + + public UnboundReturnInstruction(Opcode op) { + super(op); + } + + @Override + public TypeKind typeKind() { + return op.primaryTypeKind(); + } + + @Override + public String toString() { + return String.format(FMT_Return, this.opcode()); + } + + } + + public static final class UnboundThrowInstruction + extends UnboundInstruction implements ThrowInstruction { + + public UnboundThrowInstruction() { + super(Opcode.ATHROW); + } + + @Override + public String toString() { + return String.format(FMT_Throw, this.opcode()); + } + + } + + public static final class UnboundFieldInstruction + extends UnboundInstruction implements FieldInstruction { + final FieldRefEntry fieldEntry; + + public UnboundFieldInstruction(Opcode op, + FieldRefEntry fieldEntry) { + super(op); + this.fieldEntry = fieldEntry; + } + + @Override + public FieldRefEntry field() { + return fieldEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeFieldAccess(op, fieldEntry); + } + + @Override + public String toString() { + return String.format(FMT_Field, this.opcode(), this.owner().asInternalName(), this.name().stringValue(), this.type().stringValue()); + } + } + + public static final class UnboundInvokeInstruction + extends UnboundInstruction implements InvokeInstruction { + final MemberRefEntry methodEntry; + + public UnboundInvokeInstruction(Opcode op, MemberRefEntry methodEntry) { + super(op); + this.methodEntry = methodEntry; + } + + @Override + public MemberRefEntry method() { + return methodEntry; + } + + @Override + public boolean isInterface() { + return op == Opcode.INVOKEINTERFACE || methodEntry instanceof InterfaceMethodRefEntry; + } + + @Override + public int count() { + return op == Opcode.INVOKEINTERFACE + ? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.nameAndType())) + 1 + : 0; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + if (op == Opcode.INVOKEINTERFACE) + writer.writeInvokeInterface(op, (InterfaceMethodRefEntry) method(), count()); + else + writer.writeInvokeNormal(op, method()); + } + + @Override + public String toString() { + return String.format(FMT_Invoke, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue()); + } + } + + public static final class UnboundInvokeDynamicInstruction + extends UnboundInstruction implements InvokeDynamicInstruction { + final InvokeDynamicEntry indyEntry; + + public UnboundInvokeDynamicInstruction(InvokeDynamicEntry indyEntry) { + super(Opcode.INVOKEDYNAMIC); + this.indyEntry = indyEntry; + } + + @Override + public InvokeDynamicEntry invokedynamic() { + return indyEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeInvokeDynamic(invokedynamic()); + } + + @Override + public String toString() { + return String.format(FMT_InvokeDynamic, this.opcode(), bootstrapMethod(), bootstrapArgs()); + } + } + + public static final class UnboundNewObjectInstruction + extends UnboundInstruction implements NewObjectInstruction { + final ClassEntry classEntry; + + public UnboundNewObjectInstruction(ClassEntry classEntry) { + super(Opcode.NEW); + this.classEntry = classEntry; + } + + @Override + public ClassEntry className() { + return classEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeNewObject(className()); + } + + @Override + public String toString() { + return String.format(FMT_NewObj, this.opcode(), className().asInternalName()); + } + } + + public static final class UnboundNewPrimitiveArrayInstruction + extends UnboundInstruction implements NewPrimitiveArrayInstruction { + final TypeKind typeKind; + + public UnboundNewPrimitiveArrayInstruction(TypeKind typeKind) { + super(Opcode.NEWARRAY); + this.typeKind = typeKind; + } + + @Override + public TypeKind typeKind() { + return typeKind; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeNewPrimitiveArray(typeKind.newarrayCode()); + } + + @Override + public String toString() { + return String.format(FMT_NewPrimitiveArray, this.opcode(), typeKind()); + } + } + + public static final class UnboundNewReferenceArrayInstruction + extends UnboundInstruction implements NewReferenceArrayInstruction { + final ClassEntry componentTypeEntry; + + public UnboundNewReferenceArrayInstruction(ClassEntry componentTypeEntry) { + super(Opcode.ANEWARRAY); + this.componentTypeEntry = componentTypeEntry; + } + + @Override + public ClassEntry componentType() { + return componentTypeEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeNewReferenceArray(componentType()); + } + + @Override + public String toString() { + return String.format(FMT_NewRefArray, this.opcode(), componentType().asInternalName()); + } + } + + public static final class UnboundNewMultidimensionalArrayInstruction + extends UnboundInstruction implements NewMultiArrayInstruction { + final ClassEntry arrayTypeEntry; + final int dimensions; + + public UnboundNewMultidimensionalArrayInstruction(ClassEntry arrayTypeEntry, + int dimensions) { + super(Opcode.MULTIANEWARRAY); + this.arrayTypeEntry = arrayTypeEntry; + this.dimensions = dimensions; + } + + @Override + public int dimensions() { + return dimensions; + } + + @Override + public ClassEntry arrayType() { + return arrayTypeEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeNewMultidimensionalArray(dimensions(), arrayType()); + } + + @Override + public String toString() { + return String.format(FMT_NewMultiArray, this.opcode(), arrayType().asInternalName(), dimensions()); + } + + } + + public static final class UnboundArrayLoadInstruction + extends UnboundInstruction implements ArrayLoadInstruction { + + public UnboundArrayLoadInstruction(Opcode op) { + super(op); + } + + @Override + public TypeKind typeKind() { + return op.primaryTypeKind(); + } + } + + public static final class UnboundArrayStoreInstruction + extends UnboundInstruction implements ArrayStoreInstruction { + + public UnboundArrayStoreInstruction(Opcode op) { + super(op); + } + + @Override + public TypeKind typeKind() { + return op.primaryTypeKind(); + } + } + + public static final class UnboundTypeCheckInstruction + extends UnboundInstruction implements TypeCheckInstruction { + final ClassEntry typeEntry; + + public UnboundTypeCheckInstruction(Opcode op, ClassEntry typeEntry) { + super(op); + this.typeEntry = typeEntry; + } + + @Override + public ClassEntry type() { + return typeEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeTypeCheck(op, type()); + } + + @Override + public String toString() { + return String.format(FMT_TypeCheck, this.opcode(), type().asInternalName()); + } + } + + public static final class UnboundStackInstruction + extends UnboundInstruction implements StackInstruction { + + public UnboundStackInstruction(Opcode op) { + super(op); + } + + } + + public static final class UnboundConvertInstruction + extends UnboundInstruction implements ConvertInstruction { + + public UnboundConvertInstruction(Opcode op) { + super(op); + } + + @Override + public TypeKind fromType() { + return op.primaryTypeKind(); + } + + @Override + public TypeKind toType() { + return op.secondaryTypeKind(); + } + } + + public static final class UnboundOperatorInstruction + extends UnboundInstruction implements OperatorInstruction { + + public UnboundOperatorInstruction(Opcode op) { + super(op); + } + + @Override + public TypeKind typeKind() { + return op.primaryTypeKind(); + } + } + + public static final class UnboundIntrinsicConstantInstruction + extends UnboundInstruction implements ConstantInstruction.IntrinsicConstantInstruction { + final ConstantDesc constant; + + public UnboundIntrinsicConstantInstruction(Opcode op) { + super(op); + constant = op.constantValue(); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + super.writeTo(writer); + } + + @Override + public ConstantDesc constantValue() { + return constant; + } + } + + public static final class UnboundArgumentConstantInstruction + extends UnboundInstruction implements ConstantInstruction.ArgumentConstantInstruction { + final int value; + + public UnboundArgumentConstantInstruction(Opcode op, int value) { + super(op); + this.value = value; + } + + @Override + public Integer constantValue() { + return value; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeArgumentConstant(op, value); + } + + @Override + public String toString() { + return String.format(FMT_ArgumentConstant, this.opcode(), constantValue()); + } + } + + public static final class UnboundLoadConstantInstruction + extends UnboundInstruction implements ConstantInstruction.LoadConstantInstruction { + final LoadableConstantEntry constant; + + public UnboundLoadConstantInstruction(Opcode op, LoadableConstantEntry constant) { + super(op); + this.constant = constant; + } + + @Override + public LoadableConstantEntry constantEntry() { + return constant; + } + + @Override + public ConstantDesc constantValue() { + return constant.constantValue(); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeLoadConstant(op, constant); + } + + @Override + public String toString() { + return String.format(FMT_LoadConstant, this.opcode(), constantValue()); + } + } + + public static final class UnboundMonitorInstruction + extends UnboundInstruction implements MonitorInstruction { + + public UnboundMonitorInstruction(Opcode op) { + super(op); + } + + } + + public static final class UnboundNopInstruction + extends UnboundInstruction implements NopInstruction { + + public UnboundNopInstruction() { + super(Opcode.NOP); + } + + } + + public static final class UnboundJsrInstruction + extends UnboundInstruction implements DiscontinuedInstruction.JsrInstruction { + final Label target; + + public UnboundJsrInstruction(Opcode op, Label target) { + super(op); + this.target = target; + } + + @Override + public Label target() { + return target; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeBranch(op, target); + } + + @Override + public String toString() { + return String.format(FMT_Discontinued, this.opcode()); + } + } + + public static final class UnboundRetInstruction + extends UnboundInstruction implements DiscontinuedInstruction.RetInstruction { + final int slot; + + public UnboundRetInstruction(Opcode op, int slot) { + super(op); + this.slot = slot; + } + + @Override + public int slot() { + return slot; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.writeLocalVar(op, slot); + } + + @Override + public String toString() { + return String.format(FMT_Discontinued, this.opcode()); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractDynamicConstantPoolEntry.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractDynamicConstantPoolEntry.class new file mode 100644 index 0000000000000000000000000000000000000000..9ca1d4c6356dd435cd8cf99366dc71e806e46014 GIT binary patch literal 3598 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefsEntry.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefsEntry.class new file mode 100644 index 0000000000000000000000000000000000000000..5f32c6088376ed124ef98dce6ca5f938f3d20101 GIT binary patch literal 2633 zcmbtW>vG#v5dMxWM~)*>>RgPALqh4rcAA(5$|VkNW49#+Hx0GpQZ5DAmJ_DC|& z;T4$SRbZxd3C!>SJPs{0{9qV%CEw$a@$g6I>}vPhZ+Fkp>i2(s`3*n@l__}Ol_4qc zVL~8&pnk0;YO1l9DA!cWs_Hc@QLY=7tr~WtUauu~=yA)i%|`-0-Kc2a3V5TjYyf^t z$_OZ!f+BGJpz>8hH*C!`)LI{ue%PobHcOUms%5(ib)loVr&X;E_`YiGuL(>&4Ps#gWBoQ~7Y zFUkHdDF}D`*I4ngf(RCV%9 zM3KEOD!9b1?N@6uq5`2FPTn?kV=vv*YZc85;4cHtZwSDy6i^iPO z!YiK__qrA80_R8b=-%3-)6a%e&c%`C?3oJuuu)iFA8FNT3?ucv$jROD%v0lafHDo_ z>rJz)-KMEPo$Y+JyGMJKKQ(mowl&M%s#~_e%#LOr>b9*_^39S{TFsL2xj=fnfiydcLthmJ zA*ChyoKDk>^v0CRyGhi^q^LLF=XXa%3SAmX06wLLwcr^x+Qem)h^PuuT%bn?t&5#TmG{-6h;P?6fo4B#Gnr;*T-& zBW+xw6RZ?}Iph@ApiPcL^)wvHh5d-E!Xsfr!?1sk0eg>N^C-}h>;4_F=32y-iSD^0 zyy5}xW}Lzw;esoMdg4&&$v5C3o*oaP9>4yn7+C-}4 z#bt~Cipvk4A{KAqN(+hL8!cR8LM^-#OuG9J?OS+ns0bdpuL$vDwPg**>@@8@J|@Y7 n2l&KUr|~JR6QubJ5Ah}K&r#?2FsqWEbkitNHy+YjmL~rN8{wNr literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ClassEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$ClassEntryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..5aae4dc85574c3065cb7399fe3c03e00152fb550 GIT binary patch literal 3347 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 WOsIh$a?_Yc7ZzA9vW&1yqw6p9c@Gu< literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FloatEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$FloatEntryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f62e7e393843977e969dccbd8b93efc846e6ae75 GIT binary patch literal 2824 zcmb7GTUQ%Z6#h;!$v`qd8Yo(5ElrE$(l$_Ayacfj8XM(i!=<8CCzA;bOlEL0L4EPf zpWs9N0qqORrE9sU^r5T1`jcEPm-|d6$wY!B50i7-mv4W2?{o6!KhIwP$YM`~kKxj; zd?2TF+1O4ix?HW6HC;_-`7B4X5CjB71SN>*VHju$=X6uH8N>rwuc<3#hM{;avG||! zOb8)_MMx6*(9bZlTiQ!&hOJtLtb6=vm3=)uSFGBWtk|ojsoyhf>$_{KmR8Yh?Lc*w z48a-A(Ck@;^|;4V3$|h!Ra-XfeX@|wx(jYDlh1n<+>@rrf?8EFiH%-Fa85*2!XSpa z2I~;w0L@c041QbQW?=JS4C6HsuS>XqkyH4dua!3~jc6f4zu}YhDFz{)uVcC>;S$~; zi^MglQt&d3StbQGSAZnPZAl3CvqIlH3{Q*lMWqUZYBlFpF=@hLIOz!sX-@a zkRk2$+pLs^%t^|_xQ-hlZc0dFlHqo%G|rH)`I@GeI34|pY&g^`XqKu_!QJXM^@%Nx zAF;wdvP)oxb@%!d>pDuVK^4BDXTl?PVn_;2z;nbkm^Zs$CM}Qk-c+-#M=y z21IMgx?HOiRclQy>a-JGG!#>ccy)@8AXC0dadmT8YUvlXmzY1;b)58$WW0@hqFn{>j@ zMpMb(FmR0XKJeM-O9)4}e2l9;w4C;nGK2>R2?dM@YmVdLx_Z;`DAut-#u>lHTqla_ zB*slo93$n!V~EM87;N)3<-;!o#qR_dBwYv(Jw9ShA2DnaJq(|cH2vE-w;~dM^n@bj zI=n+8k3F0`!kv03Khv^KUET5{$Ffuxb1gG$;WO974|Vj`J(f`D+C`U8>27)iaP zGAFC=UZ?NJpCAfPA@~pdha_4D9_5)3igco2P$*$sC_Apk=zI`Sd`=nSj88PfnZP4_ zL2h|C{Sd^zF)AW*m;D7q=J>loa2dO}@GnZq$Cm&A literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$IntegerEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$IntegerEntryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..67b0e26bab1f886d0490d44920cb34a1b0476074 GIT binary patch literal 2826 zcmbtWTUQ%Z6#h<_WFQPQK#Ky!(iD*-&=gu)HAsO#ZIqjGQ@jq70fvSNP9~_YF8@T| ze6lY*=vpo+KDg?uKgs2C`JKrGCW~NU`7k-Refjpc_dX|o{`1@K0J5-Dgamqb^#eU! z(CzKCQP4}JEvsOrvvT%`vnUjVRYWwXXcTBW70%hNxotWE>VaM;n~PflorAf=+!={X z6j3y*&@{B5RbYHK|0Hcu+p+aRz^AphUr0}FmRv_S+@)f%Fl)QcxBW|wwP(53f$1#; zBIA~Axf24bg8^Ts(2b&9a&_C?r-gLZUr2MATrQ~KpPY!ym?a~VSZhKIZ7SL|bl|GM z#O1*HqyAZYNb1*evN|H5kW>%Vbq&3E zjTXtbz|EJ&B2(9=;U?k&jpTbxrito z&Q6M?Dsz_UW~4BrVpzj%qy_Gs*2D$!G+nj|dC5Vmq1zrGGnQi-uE6MJGoILxNJcb_ z;%y!ECaMV;IwL9}fh=UdapG8VuHZm5V+>!8l>K#bwvA zY?j5<8vV+y*Dezp9!f_oRhwS&q?IvgZ(3vf&Jc%DDB8^F_9cn&DbCcOubq6tHcR0pT#@?Jf!o5l; zhg?>ut5_cQENc}p-?AX-ANwZ0r!=F*Kr;0s!pdRl55%6LEA@iKPOEPY@%sU)@(fDD zVS}_@!QCzsp-k~)8XZa&{mQK8sgLI!Xu}2*BnclliDm$w;8S{)(X>KQ|3*+p-y8VcAV>7L}i3m3OaN z<)iRmarOs!&?>cO^WY&Ew!C;qdZxFhzkW^keEs?P3xG*HQV<}tZfei9q^Vi!N!`?P zxi!NS$w|4I;Z+17R453mP*6#j+RSVv4a*gdrJ0B1jqR+N9AC}3j;6bdwrx&ZuCv=- zG3S#Fj!B_|6TsWz2P&-pXK^TdNqvyCaA zrx&zsF>Ym+ceCO^N7qUfB8VzbRaB#fkoIR%TE=fp)5W}SH|$I?EYd!LTJ&AIOGx^R zPZTlKDX3R*4h@7sU(ub|G0co`2sOH9J#`FMOc{>QUBZChJas*jF=|xNgbRd_Bi8x} z-Q}Gr)lN#mMM9#y{jyTM+(^JnDq4$x0}8GX`parKo?{upYbx4sozUdf`k%QXygo}r zO15#`op8&FsrJhJxEZOg@@Gz|q*R1MaYIE1ZW1bV)3yY`Ig7!Eu3DiO{>2OhU4-GX zo}c0c;e$_;Q~yPC;Bud|GaT{SIl~eQJF@jHYpW)6>gQ}-Ggmankoy8N6EB>U5*gcv)i0|!^()41WNPTeqqVGJ?azZSOX6Tzpt<7Hm3H=t(;L**;} z@GvM=D4}}E)%2}-En5g_#%JLaHJ#zg9W*FHEZ@KvHHRa@J)N@{S+aK=UC7Z%Xe`dZ z(xF~?83>gNBInN9Iak30LXWTU!6PDVaVEXI2!<@79G$WXrU)axRJR|^HP3;g3;FhZ@!-SN#}}(!9FGauP+wZ47z1+)WF3>-3;f8uJ=TR&?MFhWYzlmgaX^ z-I9XN*f_WFdn_oO>|-iH!|}vNv`eLV_wq`=c}i8!jc`F}ie)MoF(&axyaV?!>d`Tb dGi_tPLKwqDsEVJ1W0*!WW|+=0jWA84`8SbNEGPf~ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InvokeDynamicEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$InvokeDynamicEntryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..5dd87de587743d188f2a328b3b5203014cc9ebc7 GIT binary patch literal 3146 zcmb_e+j84f6kW%Xt;SJO$CMbi4FnpfFKyMPX(_m*P2z?M95-z;W~OhlEQlIe@<>Xj z;X8QY3wYx)!z7dkK7fy6*hjLR5G#t6;X&5c@!5N=eLd&zfByUnz#6tCq!{L2X|FZK z((LaP-O@boThlU>H7>1_l!b`2gp3Rc7Z{qaI=hN#`-W?4*0KF&w`VCUZO?Z#-QRQ^ z>xu2V`wN4W`o67oO?}O=JzukrHZWu!nzrdLGyGC&L=n;ZDm}8P9M`X@s@jNSv+6iL z=hNFT{2iwg5K@U|Emmv5_{fK*)-_h_&h~!KII>Z0Ws$|C1X;!urWsb_sElWnA#K_n z;|+sQDyv!KFe4!^;~iXLs3)_p+OM5mqaXGmZ9>@5yq!e~dx^rwK}5{*)D{@NKSu)M zGccapwQ_5Md@ahjj4KTCAmcm(3`)YPn8Y03m+*m%d3?yQl&Gdw_e`r}xD3;}W`E40&^;f*5{?jzSb;>avKjGRSSv%_keHMsYbyXSA+sJS>Wg+qgsJty_+5 zFm$7d{s;c}FzF}$+zdoq=dE;2!aat&=kS8z=Y*7L{++LkVztJslyZwfTyr`U>WdB2 zHky0gw&8ATZHrd&4M*3kmgbuLyT2&NsTxfe;H9SjFdM^mYS)CQt4h&OUzNYVPXuWSlgZ`1Jnr;g`Kc*bxu(b-H#oNC*K8(gsr@@#&9a{4Xl(n-g7r4qmB_P`w)i6ZFq zqibG<9trp9>r;|!lKIMXrJBoMohypP^dW@bXeEUQ^qZwOglCu%Ht`vKFNeGFIcoGp zdU%K{WQ$8v_=4{yX_+J;kRIVNA@j8oR*)u1!fGG8OEO<61lYMep&wx44_qYS5bvHO zv5i@w6_8j8)rKSrLlT7{i2~hcLlT7mn!8U&LLXWqdYtNfwemaOdyA_n{0OP?6K1NF z1AIi!CvQ;^@GI>RfT(|;?JXwC-nb%;9hEGL&8#Sh2XxVjXcV?>CNFX zmFfX*aid{$L!)Y7ROSE_-7vCGNlw#34rHhVmHy<06ngV*>B=D%RGWDD^ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$LongEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$LongEntryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..4d057b800a4538b87ba59a0b784f4584c67892a7 GIT binary patch literal 2811 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodRefEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodRefEntryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..e0400d66249cda5dec0730a82fe1578dd8b6e7ba GIT binary patch literal 2542 zcmd5;%Tg0T6g{2SKr%o;1f$>s5lI3JAmSqkga8@~C`u@-ayLvG7?{kYCWFd%xbh3! zYL#N)!eZ^8xX^_kV0nA;fJCaoxN?!)?w;G{+*jZ3Z@<5M1(3m02|kA2UG=4^7^=Cg zXogxWZs`VBGGeqyqc8#pN(jl2(8Msmo7+=#)8V$M8mIL2e8EuCn?=V~HD}ebj0MxN z5Be)B%RIly?Pq+;U1kVP>89>XGaL>sokg!%X3{z)ZrgC4=HIED=P} zE}=ul1#~h@cna#=zHa2W&Csf;=5t$j_`Gg&&0!e#nx6Oz5t=R;-MGXMu=&;)!%$;q zswI<>aG4?5*nUxQgI1ctb`XZc-rfH7R0vbDls{O`=t!Bdn(>|Pi@_#!sPfZ83VY@5Y!CI^yaz%BlYcb_sDR(}sT5+RX6D zqk*aa;=EHSXRI8>w{1x``O3cNX6x#vK`R|gmZlmTs;!H8c`@MZ=tYJ(kKLv=SZ=>! z@N0!UC0I9e{51p1(%5=sisL%%5x%Y!GDOUi_C~$kBV2t6m+kdw1%}DS)qJ|GSIUr~ zWzA8wy=Apfj%3bby;P9Sahy(i4nwpQ`c>7Yh|uju$qTPp`?ki#CCJcKxyh=VMnvf| zG_CNW^TaAT5@s2OJzWIU^|K~r(#;De$|_6keJNp{VagM9e{HU*qtz}*cueK#4f3pf zGjyK4-0^oUV~iSB01Sil`tZ|FLV{*V8f_wkAW1oqjD~xLV}Z}`f1tS!L-Zde3EvMy zd_OTv^NEr!MxfA)c3~8)gd|2|7#G?!xwdf^O}}eNNU->RxmI+Q5UN%T;2!SN_Xng+53BYy34_rz zwdaSVD4ZN6DM&+!=m!n7-AkS5tjeg!at Wxj-|$=Vq{g7#2xBAsHr_MeGl-vJ$-j literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodTypeEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$MethodTypeEntryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..dbeaa3620969a1cb6d8439da0f4f2328e7cebb12 GIT binary patch literal 3363 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..ef0d83e7be84084791f28a96edfc736269a02720 GIT binary patch literal 8511 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 GlK%s@N`3*n<--Zzo zxOpx&AJ=qCHFc#B&lZ$YX+|rkac!Ykh!1BXx}2T>r<9e+7rAA3-z1 zVYI~fD=M&UPFYmqx@N?)dBrTLRy=JfdQLHO31?gqXgQodKAcV@lLDRNtL9hc4Mq{e znlRSJunw&Pt@gx%qR*1i)bv^M%&OMNvZa#p+TP0(^&K4vqg`Oo*A9CQTQhgtdri^< zQMBRe7&f3opn12ZYt|ltyDE#?My+@(Yv?8J*(%am@kC`HJvW#eEW0%x5jBgQ?>Wj~+Tmi=}Nl zh`n?_vo4e{a-6YlT+`K5c_E{kQ%XkiwT~NFr7*3SnjBYzfhDObDQ;u%NnvvYmN<$^ zshf_WUi(3mrNZ<)z$f&Xshq4P(wJ#1xYaOhaaN{msVQZF3lDk2?-2f%&{nAjxhdUd zYWMiLLc}oA41vJW5t_W9EN9e&lXb6omtFC&8@W{(>}H*3jmv1QB%QAerIFd9z@1lK zz>T(C$Tf>$Qe}5y5?+~L#X^CO+PE(l-Pi}GrsTAS4st86k-#_p+IyZo^4`JX=K z%6<0gclab2lo>kBgs}1&TO$k4PiN;n0ftA9X1XYR*S3$r?@C!wl$s9au(}g z4f8%bKcN&WH5E-8WizWfRot=ac)3N^y}(r|wPa1GvOr5=JSuRHudVbXila+ewP#Hjd;O{JGs^4&)iWRrn&k5k88`G<4?$L7w?7-k3Wj2N7?^>3{4peXrq8OThl3s6 zrxlZ?wxC(sqT`G(G~d2-T9LllMpnCB7-fN^KTerK=8Te6oe&&S zXFQwb!7}8Jt`Q4+_FjK1W13pX)td5zZ@;_Va+-|G7RFNoBmT^h=lHN*pPtY7E|du) zSFTCS)4nTylC4&m^;XHVzAN5-$?`<`Ip0xsT`L`vvzfwp-glH;7KWx&A$h^KLp&rE zju(A*pX#fYybkp6IJ4M_*H5Y@8>6M>(&dc(CL}K-v81l6rtLvFTvMaUQ_XWM@g=nG zl;QlELqlL~?HR!L_WG92Ikg>{v~>-awl?UW0vjA@T|4Cc#BCh)J&7+%jhmG~x9jK2 z^&Ww)e`zIr{a)P}1lm>=I!$m_s;ygrs~eRey-`nem)$8J&wXy&~%&oML3u{5Tsvw?+an=s}~ zz+T(J2!=3RQBHv$CaB!e|09}y##Q6LqU|9O90(5lb_wgh=M!hYQG3=AwBRAno;xtY zZyTU=E%srQoDqy+Kj%vS9VANb$iVLq{Xb))qzii7cg#Z-!2u-sTz>4h5BHO5oWC8z zrDTGV6eR(hb^|6W8#ql#6Xjj~m-x5&^^554-*OQ>{To6T(c3?85d%NiYBFk_j2ke6 z5M~*rJl(1BmOe-Mylu)(hYAni5a*H9&KK$2E;|@$8>|0yX%!tHdKDFy7B}= zAoskHd+u)e6fudd&7UFM^esXmN#~9F6CS#a6;~hOoMr^uf!Ih<#aU%*S$TubIQj?ZysftoK< z_9xleX!I*KtH7&F;bR=X#_%|h)cweiH{RM;qxbnpK|;(@iXEn;^)LO#4m_viC=QvbHuNR P=ZRkvFK`Fn3~l-cOQpRg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.java new file mode 100644 index 00000000..f846ca6f --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -0,0 +1,1201 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.constant.*; +import java.lang.invoke.TypeDescriptor; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantDynamicEntry; +import java.lang.classfile.constantpool.ConstantPool; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.BufWriter; +import java.lang.classfile.constantpool.DoubleEntry; +import java.lang.classfile.constantpool.FieldRefEntry; +import java.lang.classfile.constantpool.FloatEntry; +import java.lang.classfile.constantpool.IntegerEntry; +import java.lang.classfile.constantpool.InterfaceMethodRefEntry; +import java.lang.classfile.constantpool.InvokeDynamicEntry; +import java.lang.classfile.constantpool.LongEntry; +import java.lang.classfile.constantpool.MemberRefEntry; +import java.lang.classfile.constantpool.MethodHandleEntry; +import java.lang.classfile.constantpool.MethodRefEntry; +import java.lang.classfile.constantpool.MethodTypeEntry; +import java.lang.classfile.constantpool.ModuleEntry; +import java.lang.classfile.constantpool.NameAndTypeEntry; +import java.lang.classfile.constantpool.PackageEntry; +import java.lang.classfile.constantpool.PoolEntry; +import java.lang.classfile.constantpool.StringEntry; +import java.lang.classfile.constantpool.Utf8Entry; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.util.ArraysSupport; + +public abstract sealed class AbstractPoolEntry { + /* + Invariant: a {CP,BSM} entry for pool P refer only to {CP,BSM} entries + from P or P's parent. This is enforced by the various xxxEntry methods + in SplitConstantPool. As a result, code in this file can use writeU2 + instead of writeIndex. + + Cloning of entries may be a no-op if the entry is already on the right pool + (which implies that the referenced entries will also be on the right pool.) + */ + + private static final int TAG_SMEAR = 0x13C4B2D1; + static final int NON_ZERO = 0x40000000; + + public static int hash1(int tag, int x1) { + return (tag * TAG_SMEAR + x1) | NON_ZERO; + } + + public static int hash2(int tag, int x1, int x2) { + return (tag * TAG_SMEAR + x1 + 31 * x2) | NON_ZERO; + } + + // Ensure that hash is never zero + public static int hashString(int stringHash) { + return stringHash | NON_ZERO; + } + + public static Utf8Entry rawUtf8EntryFromStandardAttributeName(String name) { + //assuming standard attribute names are all US_ASCII + var raw = name.getBytes(StandardCharsets.US_ASCII); + return new Utf8EntryImpl(null, 0, raw, 0, raw.length); + } + + @SuppressWarnings("unchecked") + public static T maybeClone(ConstantPoolBuilder cp, T entry) { + return (T)((AbstractPoolEntry)entry).clone(cp); + } + + final ConstantPool constantPool; + public final byte tag; + private final int index; + private final int hash; + + private AbstractPoolEntry(ConstantPool constantPool, int tag, int index, int hash) { + this.tag = (byte) tag; + this.index = index; + this.hash = hash; + this.constantPool = constantPool; + } + + public ConstantPool constantPool() { return constantPool; } + + public int index() { return index; } + + @Override + public int hashCode() { + return hash; + } + + public byte tag() { + return tag; + } + + public int width() { + return (tag == ClassFile.TAG_LONG || tag == ClassFile.TAG_DOUBLE) ? 2 : 1; + } + + abstract PoolEntry clone(ConstantPoolBuilder cp); + + public static final class Utf8EntryImpl extends AbstractPoolEntry implements Utf8Entry { + // Processing UTF8 from the constant pool is one of the more expensive + // operations, and often, we don't actually need access to the constant + // as a string. So there are multiple layers of laziness in UTF8 + // constants. In the first stage, all we do is record the range of + // bytes in the classfile. If the size or hashCode is needed, then we + // process the raw bytes into a byte[] or char[], but do not inflate + // a String. If a string is needed, it too is inflated lazily. + // If we construct a Utf8Entry from a string, we generate the encoding + // at write time. + + enum State { RAW, BYTE, CHAR, STRING } + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + private State state; + private final byte[] rawBytes; // null if initialized directly from a string + private final int offset; + private final int rawLen; + // Set in any state other than RAW + private int hash; + private int charLen; + // Set in CHAR state + private char[] chars; + // Only set in STRING state + private String stringValue; + + Utf8EntryImpl(ConstantPool cpm, int index, + byte[] rawBytes, int offset, int rawLen) { + super(cpm, ClassFile.TAG_UTF8, index, 0); + this.rawBytes = rawBytes; + this.offset = offset; + this.rawLen = rawLen; + this.state = State.RAW; + } + + Utf8EntryImpl(ConstantPool cpm, int index, String s) { + this(cpm, index, s, hashString(s.hashCode())); + } + + Utf8EntryImpl(ConstantPool cpm, int index, String s, int hash) { + super(cpm, ClassFile.TAG_UTF8, index, 0); + this.rawBytes = null; + this.offset = 0; + this.rawLen = 0; + this.state = State.STRING; + this.stringValue = s; + this.charLen = s.length(); + this.hash = hash; + } + + Utf8EntryImpl(ConstantPool cpm, int index, Utf8EntryImpl u) { + super(cpm, ClassFile.TAG_UTF8, index, 0); + this.rawBytes = u.rawBytes; + this.offset = u.offset; + this.rawLen = u.rawLen; + this.state = u.state; + this.hash = u.hash; + this.charLen = u.charLen; + this.chars = u.chars; + this.stringValue = u.stringValue; + } + + /** + * {@jvms 4.4.7} String content is encoded in modified UTF-8. + * + * Modified UTF-8 strings are encoded so that code point sequences that + * contain only non-null ASCII characters can be represented using only 1 + * byte per code point, but all code points in the Unicode codespace can be + * represented. + * + * Modified UTF-8 strings are not null-terminated. + * + * Code points in the range '\u0001' to '\u007F' are represented by a single + * byte. + * + * The null code point ('\u0000') and code points in the range '\u0080' to + * '\u07FF' are represented by a pair of bytes. + * + * Code points in the range '\u0800' to '\uFFFF' are represented by 3 bytes. + * + * Characters with code points above U+FFFF (so-called supplementary + * characters) are represented by separately encoding the two surrogate code + * units of their UTF-16 representation. Each of the surrogate code units is + * represented by three bytes. This means supplementary characters are + * represented by six bytes. + * + * The bytes of multibyte characters are stored in the class file in + * big-endian (high byte first) order. + * + * There are two differences between this format and the "standard" UTF-8 + * format. First, the null character (char)0 is encoded using the 2-byte + * format rather than the 1-byte format, so that modified UTF-8 strings + * never have embedded nulls. Second, only the 1-byte, 2-byte, and 3-byte + * formats of standard UTF-8 are used. The Java Virtual Machine does not + * recognize the four-byte format of standard UTF-8; it uses its own + * two-times-three-byte format instead. + */ + private void inflate() { + int singleBytes = JLA.countPositives(rawBytes, offset, rawLen); + int hash = ArraysSupport.hashCodeOfUnsigned(rawBytes, offset, singleBytes, 0); + if (singleBytes == rawLen) { + this.hash = hashString(hash); + charLen = rawLen; + state = State.BYTE; + } + else { + char[] chararr = new char[rawLen]; + int chararr_count = singleBytes; + // Inflate prefix of bytes to characters + JLA.inflateBytesToChars(rawBytes, offset, chararr, 0, singleBytes); + + int px = offset + singleBytes; + int utfend = offset + rawLen; + while (px < utfend) { + int c = (int) rawBytes[px] & 0xff; + switch (c >> 4) { + case 0, 1, 2, 3, 4, 5, 6, 7: { + // 0xxx xxxx + px++; + chararr[chararr_count++] = (char) c; + hash = 31 * hash + c; + break; + } + case 12, 13: { + // 110x xxxx 10xx xxxx + px += 2; + if (px > utfend) { + throw new CpException("malformed input: partial character at end"); + } + int char2 = rawBytes[px - 1]; + if ((char2 & 0xC0) != 0x80) { + throw new CpException("malformed input around byte " + px); + } + char v = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); + chararr[chararr_count++] = v; + hash = 31 * hash + v; + break; + } + case 14: { + // 1110 xxxx 10xx xxxx 10xx xxxx + px += 3; + if (px > utfend) { + throw new CpException("malformed input: partial character at end"); + } + int char2 = rawBytes[px - 2]; + int char3 = rawBytes[px - 1]; + if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { + throw new CpException("malformed input around byte " + (px - 1)); + } + char v = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | (char3 & 0x3F)); + chararr[chararr_count++] = v; + hash = 31 * hash + v; + break; + } + default: + // 10xx xxxx, 1111 xxxx + throw new CpException("malformed input around byte " + px); + } + } + this.hash = hashString(hash); + charLen = chararr_count; + this.chars = chararr; + state = State.CHAR; + } + + } + + @Override + public Utf8EntryImpl clone(ConstantPoolBuilder cp) { + if (cp.canWriteDirect(constantPool)) + return this; + return (state == State.STRING && rawBytes == null) + ? (Utf8EntryImpl) cp.utf8Entry(stringValue) + : ((SplitConstantPool) cp).maybeCloneUtf8Entry(this); + } + + @Override + public int hashCode() { + if (state == State.RAW) + inflate(); + return hash; + } + + @Override + public String toString() { + if (state == State.RAW) + inflate(); + if (state != State.STRING) { + stringValue = (chars != null) + ? new String(chars, 0, charLen) + : new String(rawBytes, offset, charLen, StandardCharsets.ISO_8859_1); + state = State.STRING; + } + return stringValue; + } + + @Override + public String stringValue() { + return toString(); + } + + @Override + public ConstantDesc constantValue() { + return stringValue(); + } + + @Override + public int length() { + if (state == State.RAW) + inflate(); + return charLen; + } + + @Override + public char charAt(int index) { + if (state == State.STRING) + return stringValue.charAt(index); + if (state == State.RAW) + inflate(); + return (chars != null) + ? chars[index] + : (char) rawBytes[index + offset]; + } + + @Override + public CharSequence subSequence(int start, int end) { + return toString().subSequence(start, end); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (o instanceof Utf8EntryImpl u) { + return equalsUtf8(u); + } + return false; + } + + public boolean equalsUtf8(Utf8EntryImpl u) { + if (hashCode() != u.hashCode() + || length() != u.length()) + return false; + if (rawBytes != null && u.rawBytes != null) + return Arrays.equals(rawBytes, offset, offset + rawLen, + u.rawBytes, u.offset, u.offset + u.rawLen); + else if ((state == State.STRING && u.state == State.STRING)) + return stringValue.equals(u.stringValue); + else + return stringValue().equals(u.stringValue()); + } + + @Override + public boolean equalsString(String s) { + if (state == State.RAW) + inflate(); + switch (state) { + case STRING: + return stringValue.equals(s); + case CHAR: + if (charLen != s.length() || hash != hashString(s.hashCode())) + return false; + for (int i=0; i 65535) { + throw new IllegalArgumentException("string too long"); + } + pool.writeU1(tag); + pool.writeU2(charLen); + for (int i = 0; i < charLen; ++i) { + char c = stringValue.charAt(i); + if (c >= '\001' && c <= '\177') { + // Optimistic writing -- hope everything is bytes + // If not, we bail out, and alternate path patches the length + pool.writeU1((byte) c); + } + else { + int charLength = stringValue.length(); + int byteLength = i; + char c1; + for (int j = i; j < charLength; ++j) { + c1 = (stringValue).charAt(j); + if (c1 >= '\001' && c1 <= '\177') { + byteLength++; + } else if (c1 > '\u07FF') { + byteLength += 3; + } else { + byteLength += 2; + } + } + if (byteLength > 65535) { + throw new IllegalArgumentException(); + } + int byteLengthFinal = byteLength; + pool.patchInt(pool.size() - i - 2, 2, byteLengthFinal); + for (int j = i; j < charLength; ++j) { + c1 = (stringValue).charAt(j); + if (c1 >= '\001' && c1 <= '\177') { + pool.writeU1((byte) c1); + } else if (c1 > '\u07FF') { + pool.writeU1((byte) (0xE0 | c1 >> 12 & 0xF)); + pool.writeU1((byte) (0x80 | c1 >> 6 & 0x3F)); + pool.writeU1((byte) (0x80 | c1 & 0x3F)); + } else { + pool.writeU1((byte) (0xC0 | c1 >> 6 & 0x1F)); + pool.writeU1((byte) (0x80 | c1 & 0x3F)); + } + } + break; + } + } + } + } + } + + abstract static sealed class AbstractRefEntry extends AbstractPoolEntry { + protected final T ref1; + + public AbstractRefEntry(ConstantPool constantPool, int tag, int index, T ref1) { + super(constantPool, tag, index, hash1(tag, ref1.index())); + this.ref1 = ref1; + } + + public T ref1() { + return ref1; + } + + public void writeTo(BufWriter pool) { + pool.writeU1(tag); + pool.writeU2(ref1.index()); + } + + @Override + public String toString() { + return tag() + " " + ref1(); + } + } + + abstract static sealed class AbstractRefsEntry + extends AbstractPoolEntry { + protected final T ref1; + protected final U ref2; + + public AbstractRefsEntry(ConstantPool constantPool, int tag, int index, T ref1, U ref2) { + super(constantPool, tag, index, hash2(tag, ref1.index(), ref2.index())); + this.ref1 = ref1; + this.ref2 = ref2; + } + + public T ref1() { + return ref1; + } + + public U ref2() { + return ref2; + } + + public void writeTo(BufWriter pool) { + pool.writeU1(tag); + pool.writeU2(ref1.index()); + pool.writeU2(ref2.index()); + } + + @Override + public String toString() { + return tag() + " " + ref1 + "-" + ref2; + } + } + + abstract static sealed class AbstractNamedEntry extends AbstractRefEntry { + + public AbstractNamedEntry(ConstantPool constantPool, int tag, int index, Utf8EntryImpl ref1) { + super(constantPool, tag, index, ref1); + } + + public Utf8Entry name() { + return ref1; + } + + public String asInternalName() { + return ref1.stringValue(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { return true; } + if (o instanceof AbstractNamedEntry ne) { + return tag == ne.tag() && name().equals(ref1()); + } + return false; + } + } + + public static final class ClassEntryImpl extends AbstractNamedEntry implements ClassEntry { + + public ClassDesc sym = null; + + ClassEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name) { + super(cpm, ClassFile.TAG_CLASS, index, name); + } + + @Override + public ClassEntry clone(ConstantPoolBuilder cp) { + if (cp.canWriteDirect(constantPool)) { + return this; + } else { + ClassEntryImpl ret = (ClassEntryImpl)cp.classEntry(ref1); + ret.sym = sym; + return ret; + } + } + + @Override + public ClassDesc asSymbol() { + var sym = this.sym; + if (sym != null) { + return sym; + } + return this.sym = Util.toClassDesc(asInternalName()); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (o instanceof ClassEntryImpl cce) { + return cce.name().equals(this.name()); + } else if (o instanceof ClassEntry c) { + return c.asSymbol().equals(this.asSymbol()); + } + return false; + } + } + + public static final class PackageEntryImpl extends AbstractNamedEntry implements PackageEntry { + + PackageEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name) { + super(cpm, ClassFile.TAG_PACKAGE, index, name); + } + + @Override + public PackageEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.packageEntry(ref1); + } + + @Override + public PackageDesc asSymbol() { + return PackageDesc.ofInternalName(asInternalName()); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (o instanceof PackageEntry p) { + return name().equals(p.name()); + } + return false; + } + } + + public static final class ModuleEntryImpl extends AbstractNamedEntry implements ModuleEntry { + + ModuleEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name) { + super(cpm, ClassFile.TAG_MODULE, index, name); + } + + @Override + public ModuleEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.moduleEntry(ref1); + } + + @Override + public ModuleDesc asSymbol() { + return ModuleDesc.of(asInternalName()); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (o instanceof ModuleEntryImpl m) { + return name().equals(m.name()); + } + return false; + } + } + + public static final class NameAndTypeEntryImpl extends AbstractRefsEntry + implements NameAndTypeEntry { + + public TypeDescriptor typeSym = null; + + NameAndTypeEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name, Utf8EntryImpl type) { + super(cpm, ClassFile.TAG_NAMEANDTYPE, index, name, type); + } + + @Override + public Utf8Entry name() { + return ref1; + } + + @Override + public Utf8Entry type() { + return ref2; + } + + public ClassDesc fieldTypeSymbol() { + if (typeSym instanceof ClassDesc cd) { + return cd; + } else { + return (ClassDesc)(typeSym = ClassDesc.ofDescriptor(ref2.stringValue())); + } + } + + public MethodTypeDesc methodTypeSymbol() { + if (typeSym instanceof MethodTypeDesc mtd) { + return mtd; + } else { + return (MethodTypeDesc)(typeSym = MethodTypeDesc.ofDescriptor(ref2.stringValue())); + } + } + + @Override + public NameAndTypeEntry clone(ConstantPoolBuilder cp) { + if (cp.canWriteDirect(constantPool)) { + return this; + } else { + var ret = (NameAndTypeEntryImpl)cp.nameAndTypeEntry(ref1, ref2); + ret.typeSym = typeSym; + return ret; + } + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (o instanceof NameAndTypeEntryImpl nat) { + return name().equals(nat.name()) && type().equals(nat.type()); + } + return false; + } + } + + public abstract static sealed class AbstractMemberRefEntry + extends AbstractRefsEntry + implements MemberRefEntry { + + AbstractMemberRefEntry(ConstantPool cpm, int tag, int index, ClassEntryImpl owner, + NameAndTypeEntryImpl nameAndType) { + super(cpm, tag, index, owner, nameAndType); + } + + @Override + public ClassEntryImpl owner() { + return ref1; + } + + @Override + public NameAndTypeEntryImpl nameAndType() { + return ref2; + } + + @Override + public String toString() { + return tag() + " " + owner().asInternalName() + "." + nameAndType().name().stringValue() + + "-" + nameAndType().type().stringValue(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof AbstractMemberRefEntry m) { + return tag == m.tag() + && owner().equals(m.owner()) + && nameAndType().equals(m.nameAndType()); + } + return false; + } + } + + public static final class FieldRefEntryImpl extends AbstractMemberRefEntry implements FieldRefEntry { + + FieldRefEntryImpl(ConstantPool cpm, int index, + ClassEntryImpl owner, NameAndTypeEntryImpl nameAndType) { + super(cpm, ClassFile.TAG_FIELDREF, index, owner, nameAndType); + } + + @Override + public FieldRefEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.fieldRefEntry(ref1, ref2); + } + } + + public static final class MethodRefEntryImpl extends AbstractMemberRefEntry implements MethodRefEntry { + + MethodRefEntryImpl(ConstantPool cpm, int index, + ClassEntryImpl owner, NameAndTypeEntryImpl nameAndType) { + super(cpm, ClassFile.TAG_METHODREF, index, owner, nameAndType); + } + + @Override + public MethodRefEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.methodRefEntry(ref1, ref2); + } + } + + public static final class InterfaceMethodRefEntryImpl extends AbstractMemberRefEntry implements InterfaceMethodRefEntry { + + InterfaceMethodRefEntryImpl(ConstantPool cpm, int index, ClassEntryImpl owner, + NameAndTypeEntryImpl nameAndType) { + super(cpm, ClassFile.TAG_INTERFACEMETHODREF, index, owner, nameAndType); + } + + @Override + public InterfaceMethodRefEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.interfaceMethodRefEntry(ref1, ref2); + } + } + + public abstract static sealed class AbstractDynamicConstantPoolEntry extends AbstractPoolEntry { + + private final int bsmIndex; + private BootstrapMethodEntryImpl bootstrapMethod; + private final NameAndTypeEntryImpl nameAndType; + + AbstractDynamicConstantPoolEntry(ConstantPool cpm, int tag, int index, int hash, BootstrapMethodEntryImpl bootstrapMethod, + NameAndTypeEntryImpl nameAndType) { + super(cpm, tag, index, hash); + this.bsmIndex = bootstrapMethod.bsmIndex(); + this.bootstrapMethod = bootstrapMethod; + this.nameAndType = nameAndType; + } + + AbstractDynamicConstantPoolEntry(ConstantPool cpm, int tag, int index, int hash, int bsmIndex, + NameAndTypeEntryImpl nameAndType) { + super(cpm, tag, index, hash); + this.bsmIndex = bsmIndex; + this.bootstrapMethod = null; + this.nameAndType = nameAndType; + } + + /** + * @return the bootstrapMethod + */ + public BootstrapMethodEntryImpl bootstrap() { + if (bootstrapMethod == null) { + bootstrapMethod = (BootstrapMethodEntryImpl) constantPool.bootstrapMethodEntry(bsmIndex); + } + return bootstrapMethod; + } + + /** + * @return the bsmIndex + */ + public int bootstrapMethodIndex() { + return bsmIndex; + } + + /** + * @return the nameAndType + */ + public NameAndTypeEntryImpl nameAndType() { + return nameAndType; + } + + public void writeTo(BufWriter pool) { + pool.writeU1(tag); + pool.writeU2(bsmIndex); + pool.writeU2(nameAndType.index()); + } + + @Override + public String toString() { + return tag() + " " + bootstrap() + "." + nameAndType().name().stringValue() + + "-" + nameAndType().type().stringValue(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof AbstractDynamicConstantPoolEntry d) { + return this.tag() == d.tag() + && bootstrap().equals(d.bootstrap()) + && nameAndType.equals(d.nameAndType()); + } + return false; + } + } + + public static final class InvokeDynamicEntryImpl + extends AbstractDynamicConstantPoolEntry + implements InvokeDynamicEntry { + + InvokeDynamicEntryImpl(ConstantPool cpm, int index, int hash, BootstrapMethodEntryImpl bootstrapMethod, + NameAndTypeEntryImpl nameAndType) { + super(cpm, ClassFile.TAG_INVOKEDYNAMIC, index, hash, bootstrapMethod, nameAndType); + } + + InvokeDynamicEntryImpl(ConstantPool cpm, int index, int bsmIndex, + NameAndTypeEntryImpl nameAndType) { + super(cpm, ClassFile.TAG_INVOKEDYNAMIC, index, hash2(ClassFile.TAG_INVOKEDYNAMIC, bsmIndex, nameAndType.index()), + bsmIndex, nameAndType); + } + + @Override + public InvokeDynamicEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.invokeDynamicEntry(bootstrap(), nameAndType()); + } + } + + public static final class ConstantDynamicEntryImpl extends AbstractDynamicConstantPoolEntry + implements ConstantDynamicEntry { + + ConstantDynamicEntryImpl(ConstantPool cpm, int index, int hash, BootstrapMethodEntryImpl bootstrapMethod, + NameAndTypeEntryImpl nameAndType) { + super(cpm, ClassFile.TAG_CONSTANTDYNAMIC, index, hash, bootstrapMethod, nameAndType); + } + + ConstantDynamicEntryImpl(ConstantPool cpm, int index, int bsmIndex, + NameAndTypeEntryImpl nameAndType) { + super(cpm, ClassFile.TAG_CONSTANTDYNAMIC, index, hash2(ClassFile.TAG_CONSTANTDYNAMIC, bsmIndex, nameAndType.index()), + bsmIndex, nameAndType); + } + + @Override + public ConstantDynamicEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.constantDynamicEntry(bootstrap(), nameAndType()); + } + } + + public static final class MethodHandleEntryImpl extends AbstractPoolEntry + implements MethodHandleEntry { + + private final int refKind; + private final AbstractPoolEntry.AbstractMemberRefEntry reference; + + MethodHandleEntryImpl(ConstantPool cpm, int index, int hash, int refKind, AbstractPoolEntry.AbstractMemberRefEntry + reference) { + super(cpm, ClassFile.TAG_METHODHANDLE, index, hash); + this.refKind = refKind; + this.reference = reference; + } + + MethodHandleEntryImpl(ConstantPool cpm, int index, int refKind, AbstractPoolEntry.AbstractMemberRefEntry + reference) { + super(cpm, ClassFile.TAG_METHODHANDLE, index, hash2(ClassFile.TAG_METHODHANDLE, refKind, reference.index())); + this.refKind = refKind; + this.reference = reference; + } + + @Override + public int kind() { + return refKind; + } + + @Override + public AbstractPoolEntry.AbstractMemberRefEntry reference() { + return reference; + } + + @Override + public DirectMethodHandleDesc asSymbol() { + return MethodHandleDesc.of( + DirectMethodHandleDesc.Kind.valueOf(kind(), reference() instanceof InterfaceMethodRefEntry), + ((MemberRefEntry) reference()).owner().asSymbol(), + ((MemberRefEntry) reference()).nameAndType().name().stringValue(), + ((MemberRefEntry) reference()).nameAndType().type().stringValue()); + } + + @Override + public void writeTo(BufWriter pool) { + pool.writeU1(tag); + pool.writeU1(refKind); + pool.writeU2(reference.index()); + } + + @Override + public MethodHandleEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.methodHandleEntry(refKind, reference); + } + + @Override + public String toString() { + return tag() + " " + kind() + ":" + ((MemberRefEntry) reference()).owner().asInternalName() + "." + ((MemberRefEntry) reference()).nameAndType().name().stringValue() + + "-" + ((MemberRefEntry) reference()).nameAndType().type().stringValue(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof MethodHandleEntryImpl m) { + return kind() == m.kind() + && reference.equals(m.reference()); + } + return false; + } + } + + public static final class MethodTypeEntryImpl + extends AbstractRefEntry + implements MethodTypeEntry { + + public MethodTypeDesc sym = null; + + MethodTypeEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl descriptor) { + super(cpm, ClassFile.TAG_METHODTYPE, index, descriptor); + } + + @Override + public Utf8Entry descriptor() { + return ref1; + } + + @Override + public MethodTypeEntry clone(ConstantPoolBuilder cp) { + if (cp.canWriteDirect(constantPool)) { + return this; + } else { + var ret = (MethodTypeEntryImpl)cp.methodTypeEntry(ref1); + ret.sym = sym; + return ret; + } + } + + @Override + public MethodTypeDesc asSymbol() { + var sym = this.sym; + if (sym != null) { + return sym; + } + return this.sym = MethodTypeDesc.ofDescriptor(descriptor().stringValue()); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (o instanceof MethodTypeEntryImpl m) { + return descriptor().equals(m.descriptor()); + } + return false; + } + } + + public static final class StringEntryImpl + extends AbstractRefEntry + implements StringEntry { + + StringEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl utf8) { + super(cpm, ClassFile.TAG_STRING, index, utf8); + } + + @Override + public Utf8EntryImpl utf8() { + return ref1; + } + + @Override + public String stringValue() { + return ref1.toString(); + } + + @Override + public ConstantDesc constantValue() { + return stringValue(); + } + + @Override + public StringEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.stringEntry(ref1); + } + + @Override + public String toString() { + return tag() + " \"" + stringValue() + "\""; + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (o instanceof StringEntryImpl s) { + // check utf8 rather allocating a string + return utf8().equals(s.utf8()); + } + return false; + } + + + } + + abstract static sealed class PrimitiveEntry + extends AbstractPoolEntry { + protected final T val; + + public PrimitiveEntry(ConstantPool constantPool, int tag, int index, T val) { + super(constantPool, tag, index, hash1(tag, val.hashCode())); + this.val = val; + } + + public T value() { + return val; + } + + public ConstantDesc constantValue() { + return value(); + } + + @Override + public String toString() { + return "" + tag() + value(); + } + } + + public static final class IntegerEntryImpl extends PrimitiveEntry + implements IntegerEntry { + + IntegerEntryImpl(ConstantPool cpm, int index, int i) { + super(cpm, ClassFile.TAG_INTEGER, index, i); + } + + @Override + public void writeTo(BufWriter pool) { + pool.writeU1(tag); + pool.writeInt(val); + } + + @Override + public IntegerEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.intEntry(val); + } + + @Override + public int intValue() { + return value(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof IntegerEntryImpl e) { + return intValue() == e.intValue(); + } + return false; + } + } + + public static final class FloatEntryImpl extends PrimitiveEntry + implements FloatEntry { + + FloatEntryImpl(ConstantPool cpm, int index, float f) { + super(cpm, ClassFile.TAG_FLOAT, index, f); + } + + @Override + public void writeTo(BufWriter pool) { + pool.writeU1(tag); + pool.writeFloat(val); + } + + @Override + public FloatEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.floatEntry(val); + } + + @Override + public float floatValue() { + return value(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof FloatEntryImpl e) { + return floatValue() == e.floatValue(); + } + return false; + } + } + + public static final class LongEntryImpl extends PrimitiveEntry implements LongEntry { + + LongEntryImpl(ConstantPool cpm, int index, long l) { + super(cpm, ClassFile.TAG_LONG, index, l); + } + + @Override + public void writeTo(BufWriter pool) { + pool.writeU1(tag); + pool.writeLong(val); + } + + @Override + public LongEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.longEntry(val); + } + + @Override + public long longValue() { + return value(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof LongEntryImpl e) { + return longValue() == e.longValue(); + } + return false; + } + } + + public static final class DoubleEntryImpl extends PrimitiveEntry implements DoubleEntry { + + DoubleEntryImpl(ConstantPool cpm, int index, double d) { + super(cpm, ClassFile.TAG_DOUBLE, index, d); + } + + @Override + public void writeTo(BufWriter pool) { + pool.writeU1(tag); + pool.writeDouble(val); + } + + @Override + public DoubleEntry clone(ConstantPoolBuilder cp) { + return cp.canWriteDirect(constantPool) ? this : cp.doubleEntry(val); + } + + @Override + public double doubleValue() { + return value(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof DoubleEntryImpl e) { + return doubleValue() == e.doubleValue(); + } + return false; + } + } + + static class CpException extends RuntimeException { + static final long serialVersionUID = 32L; + + CpException(String s) { + super(s); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$AbstractLocalPseudo.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$AbstractLocalPseudo.class new file mode 100644 index 0000000000000000000000000000000000000000..945e42dd1adbdbbe122992c323314b0610647737 GIT binary patch literal 2576 zcmb_dZBrXn6n<{r7Luj4B`AncT2Ygb62%rs@8lPq-GWtZ7(wEY{7 z-}Qqp)u}Uf#^B(Lj<2Iu{X>4}_}shUEiOz){j%rmx%a%>bDnd~-Fshu3t$>=CJ{kY zLrg~;34xQ>YS#;vd)8BM$Iic{A*Nw%XI`2 zXDr9^Ck3LJY`GI1=+uzZk%BHz{8u)IH@(fcRl^Qk3dHKR>kEjY^l?DPK|DaAW2~A2 z`I&3R+eX1QoRuAsS6#+wIR2XJ+J!}b`P6yG_ij!|{lhxCrGBzz)~lYi=DVI0_vm;K z4^d1#&o5QoH5%^^H9lihOk3IN)A6uW>M)&}Qc2+v3}_hCaRfsGx%-bzAjQmD&Pv&^ z8+4t{WOq0(siO%E#{{zbWp=8uyyRJ|WRbN?;wXl7Jch>wbX!I}?Xt=@n9IC0zfaZG z8(X(0lFUy=<|ivKuq&=@tOQ9(VFY;%$90UNAdtCV7tFhgZ^50aS^|Ta9dB>=*bkbWvP8y$FrEAe|1!JYUT}rLb(53 zsG29V0#s$oGN9)q@Pl3`3cQ;shCX4JiEUv1=et4rL(K$7*)ktJ?bZmbgEN+6&NWsm zrng{JY)THRb}Jj6CI4H(n19u(3tZk8C!78HkLeKB$xQR;9`M;CFRY7f^8o&v^;>WS zj)hlftJV|QD;yXVfg_94%7H-P1sTUo`^rqz=F^Qn=&6su#^>kP~0=;2kX*M>* zCW~-?#gUdPhFn^10!2B|73Bz5lv9~hgW&Dw`8~_O_o$s99m;(Lk?U_l%jKKs${law zP_8f5L^{_OZ=&}O??iBp-$7acK12*3p%WkD06yXFxP?A^%K82org%CT*yL7yfq%5F zViSs!(aDI1T0^?^((Uq*61U`x4r1GC>##CH!2u(}N2wckE@H zr=(rE>x(w!JE6)K7+Iivf>e4=(sS1a`UTo8Gp> zZCCy#RQW|*Y$^ZMs;e>b9geQ!(b;@%9Zzf^7r~@tpH%F4Y#{PJI(uS~4-k*u?uiZ5 z#^WOc8yJgVq$eKG;Ps~{A$Mp4id)ASbsCcui7H@>DfoR)K>one{zx$VgdBcG9=~7= zzv480rvXABCiuHV+6)a zlT1Sv%BA*W$P2u^gotSbEqN{U9XK$@VTMJ&-MxFn;hZ?43Wltu75(Yr+Y2KxR6 DTMK(9 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f556ffc5f010773569d2669cca8f7e22204d2185 GIT binary patch literal 3091 zcmcgu?^7E^7=AV+xe$(00;05~Hrf^lrKhx2Xebs!D%2FJp|O=#XOkRo^tfX#7nN^1 zD8{Dd!y2Eff(npC`byHeoRP+gp z6h$n%+;N4QS5yoLVUmPJtDeSd7*udd#c7;j$VgO8*D$qZ$$=C2r0o>VhR$$tBoJ}A zx~bRP{OCcEg0l=`$KWSGoKum-8w_cCZK-LRylPUwk;4OqFy_-Zj|&Pesu;!yW%sC^ zn>QQ+Ua;%>T+=Y?B9m!euP^MS^-3^kppsf;qlLFPKUzs4$8aVrUftjG8y6an6kK9B z*-DC+z7#GqB&NBwGt-43yrtr8OfbYPzD4vej|8*Zf)Xl|d+yq#S0!DzifanqQSmM& z8FH;)e`U(hMQ6gW)+^j>QsDkj;Idqz9A8IX!L*7SpaT=&;wey}tl7>McNwOFDfG=( z4;D(0ov)?fCh?9!ZXB9_hOdM1T4cSW5QzJ4mqLjzw9e;fh4xHT6hlwRu=J(oR#kUa zydut&>>4*K+%d$rFO0hzMuXvY>8MIQv~NZ9m^{PAf0c#sSrcUYy`+X07zV;rsonW> z3laL$ksEVZif4#mXW3Y{xZ89n&)@zpWRHtcP*JFJCx@tFPD$6O`g3Zq);Ql=>j`0BKG=RXe7!xToyBPSQ>HRqgQ|zAfuV z!2^cAhz3HPyKFa|ntqG!dWN%y9vInCD8iE7a2MTy@Z>O)cJ9!vz(xU$n%D(Xofe{6f9Lqhyo2?=fuVsK!8C0c*0Z(gx|B_h2 zJxQQKrRV|qhP1^#3};5;&oTC(LlFB7sm%EIRKzrY294nvt}v9JVoE^uipSfjwE)y% zKhVddGmh9xDsZOI>5413uHZiX*h_SKvP4U!V2oUTLPjyH;-MU4ctm5Gkcq?jDF*)p Di$4!@ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundCharacterRange.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundCharacterRange.class new file mode 100644 index 0000000000000000000000000000000000000000..e3b20fef90e991d6634c1a0da60112db06c3a325 GIT binary patch literal 1603 zcmbVMOHb5L6#nkK3PX7eFd!li6?LXOst{KY5*;-*j>HJgzSCZySX$Bt_*l4cisKfoVlJonB-VCYPuo1XhP-#Ono_dEUd`^QfJ6|CfuLRvvaMHV@Rn|t~mt|G?F6)x#(-t>{t6W7{`8+QnAn_#Q)U&GDRQogrN+*Lu-| zUIlp-eNY)5{8!AmCtlr;J-f1Nikv)nY!Ug9RH@vBsnn#wpd1BG#J7BgWvaQ0%+I_LHJ21F;q+emKY~fJn|>Tv z{2mPw!*s{`?bfB6t{O3MYDVGV{=t literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariable.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariable.class new file mode 100644 index 0000000000000000000000000000000000000000..8a464d8cffa0a5229812e95bac5adb9048237b0f GIT binary patch literal 2489 zcmbtV-E!MR6#mw+Emsk3a6*eoe?n;++i{|{P)KkSNYa$5xM{$NOB)Kv)}~caB#*R) z>1*&DT)+&IOzBJ?fIBYWf*ZIfJO;yA$*JtdHYr?4yIP&|o$vhaPk;aT1i&)BP?5lp zf~1BN(hSA}>r35s1@~Rk(Ho8#1Y5Slb$h$%=!^A0_+~?_1-xZ>hD%?qhOj;N%-)}h z*D#&vH$(ce?b>32;hVfsd0>8J>W=B&>i}(d1Yx?O>3NR6A+}~$T;V?~|8LofS?5k~ znCMrbb_f|9QlM%WhQ@IHzq!5P*1eW%g@$JfETTBHpMtj3Ww0 zG`x%~!}K6lS8Sg*#Ik4crIzhjoNSGl*7IC0=6l+=Ud&a3XW?yjuTV}X0yp%iyZ1?6XBK%9R#~fl~u~o zDGd{Nogoh- z1%qt10poLD$5OLVbA&mf?$uvVnfm<(7xz7D&Gad_ltl7bt$HoL!LQQHW;of`#~B%a zO7kiY#5FGv3O;4HG>Cj(CHHG7xASg)w!0`*h^3?I^Eq|!=v z5WR2EmqWWWty*!sG@VQ4QoCT^({}=^p=^TQztHgh6*pJDBb*poXr zojn`vCuzw}Mf>STxWFI}-lo?MW@GZ%(A%fT;ZK~!Uzo+y4oBu98Y7ExYLHRs$az{r zM~YLsD1S>QoniR7Lp$Ae;uguIi0=pph^9!}i#VLScrRuYg|ibU^^65glOD>;2UDgA z-$VK8!IWuM^-%ucV9In+^-#V(D0Xe1sVYASBYYco!gUjOY0ZW?*u-Z^dG~DMbL9R3 D4Z2sd literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariableType.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction$UnboundLocalVariableType.class new file mode 100644 index 0000000000000000000000000000000000000000..08684ee7d3f2318aa72d102239d645c484d916b4 GIT binary patch literal 2521 zcmbtV-Bue_6#h;~G9gSYhT1mLAFQn;Auy%d3Z|eysg0(H22xwBI!O+6>M)ZvbE2!S z;d6MQYq?-m*YW{;m0r{fZ}bA)dnS+|Nu+u)bIzRE-?#tw`E~E7UjQuO%OoNg&=A!T zLtLQvxc-%4IZAqtX&W`$^!-iCmWH+6u#JVPuROD+R(;v5yG4h-nl)v)&gK0-CAVhU z;ctQXP0O*=yui1aV(GE@wQ1O$EE5E@V3lJ*2LX zq?}#UF^1O!qCSxZYKzSLIx}AuIF~8*#wYNGfR-O~%xy{bB#_aOMUIliC!sD1VCE=8 zA%VQWiTs#vZ8@fDdU9@@38r)yxGFGsa4s-)2;c6Y9>qR{Yj{(`TRN_@DYwO`mQZf!6*u`!9dn>&)V}d7CD&YmOP$egYg=q?-eVE3 zkbS_w_jD{^k=Q6@<(kXYeZGf}VRtd;mX2ixC8@zZ6~Op7!>>C!iX62lhn){DYA6Xz zcXPdOff5DRzQD#6-wc67+~>h^+wC<=^r z6mC13VMqk7QLy`r)+3!v%}0$AuJ<5PjRdr0FiTp`XG>~%OY8=5h^z!QX& zvLjb%4IIf$?4s};opgrbSqD1aa^fDz#E5$sL_`y%iQTV25K9}i3yR~PUH{bJYhnX2;BAj0?YAXqo>kk(X?gAIHh<;!RT HUm*QA!6#*o literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractPseudoInstruction.class new file mode 100644 index 0000000000000000000000000000000000000000..904b0201b1d8e3ffaf7206f58c5146220df2b91a GIT binary patch literal 1149 zcmb_bT~8BH5IsY;ES4$?RHz7wf&wOPVq$#2nCObJS{fqQ_q)5Jy|}&G+`a3^&+^H{ z2Y-M+$~apf(X<-V_%dhbW6zyAnfdo)))Zq+b_iVv@jDy9i{j+1wRHjb@PX%MF> z&)?{j1Kl5_!Q&`*R>f{F^^t?jOl8N&U4`Trp2BFS1t*oxTc%=oAg zHjmYN6{O0%{pH<}Qi2y|2@~ep+Hj}nM{JK&luBg2oy98cDyvKXH0ZgW&Iu3N6E(I= z@IP4X_$VXX+xjcXQ*AkRWphsoohEE|x4VSeVOH3fpNWWswKD}r#=2V$Pnhj+?)JGH zD)(`j(3z<1jn^j13X}XU$fp7OSSGyqf1Ez95L%P*ooO*_@cAS@iP?Q7>aIV_^#b+9Z~y=4sBusoL1UH+5$ zgvD_wp&g?Ip)qzO+4IrPymk0;$b@rp)g{U?i=7oO5G29s&KJ< catchTypeEntry) { + this.catchTypeEntry = catchTypeEntry.orElse(null); + this.handler = handler; + this.tryStart = tryStart; + this.tryEnd = tryEnd; + } + + @Override + public Label tryStart() { + return tryStart; + } + + @Override + public Label handler() { + return handler; + } + + @Override + public Label tryEnd() { + return tryEnd; + } + + @Override + public Optional catchType() { + return Optional.ofNullable(catchTypeEntry); + } + + ClassEntry catchTypeEntry() { + return catchTypeEntry; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.addHandler(this); + } + + @Override + public String toString() { + return String.format("ExceptionCatch[catchType=%s]", catchTypeEntry == null ? "" : catchTypeEntry.name().stringValue()); + } + } + + public static final class UnboundCharacterRange + extends AbstractPseudoInstruction + implements CharacterRange { + + public final Label startScope; + public final Label endScope; + public final int characterRangeStart; + public final int characterRangeEnd; + public final int flags; + + public UnboundCharacterRange(Label startScope, Label endScope, int characterRangeStart, + int characterRangeEnd, int flags) { + this.startScope = startScope; + this.endScope = endScope; + this.characterRangeStart = characterRangeStart; + this.characterRangeEnd = characterRangeEnd; + this.flags = flags; + } + + @Override + public Label startScope() { + return startScope; + } + + @Override + public Label endScope() { + return endScope; + } + + @Override + public int characterRangeStart() { + return characterRangeStart; + } + + @Override + public int characterRangeEnd() { + return characterRangeEnd; + } + + @Override + public int flags() { + return flags; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.addCharacterRange(this); + } + + } + + private abstract static sealed class AbstractLocalPseudo extends AbstractPseudoInstruction { + protected final int slot; + protected final Utf8Entry name; + protected final Utf8Entry descriptor; + protected final Label startScope; + protected final Label endScope; + + public AbstractLocalPseudo(int slot, Utf8Entry name, Utf8Entry descriptor, Label startScope, Label endScope) { + this.slot = slot; + this.name = name; + this.descriptor = descriptor; + this.startScope = startScope; + this.endScope = endScope; + } + + public int slot() { + return slot; + } + + public Utf8Entry name() { + return name; + } + + public String nameString() { + return name.stringValue(); + } + + public Label startScope() { + return startScope; + } + + public Label endScope() { + return endScope; + } + + public boolean writeTo(BufWriter b) { + var lc = ((BufWriterImpl)b).labelContext(); + int startBci = lc.labelToBci(startScope()); + int endBci = lc.labelToBci(endScope()); + if (startBci == -1 || endBci == -1) { + return false; + } + int length = endBci - startBci; + b.writeU2(startBci); + b.writeU2(length); + b.writeIndex(name); + b.writeIndex(descriptor); + b.writeU2(slot()); + return true; + } + } + + public static final class UnboundLocalVariable extends AbstractLocalPseudo + implements LocalVariable { + + public UnboundLocalVariable(int slot, Utf8Entry name, Utf8Entry descriptor, Label startScope, Label endScope) { + super(slot, name, descriptor, startScope, endScope); + } + + @Override + public Utf8Entry type() { + return descriptor; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.addLocalVariable(this); + } + + @Override + public String toString() { + return "LocalVariable[Slot=" + slot() + + ", name=" + nameString() + + ", descriptor='" + type().stringValue() + + "']"; + } + } + + public static final class UnboundLocalVariableType extends AbstractLocalPseudo + implements LocalVariableType { + + public UnboundLocalVariableType(int slot, Utf8Entry name, Utf8Entry signature, Label startScope, Label endScope) { + super(slot, name, signature, startScope, endScope); + } + + @Override + public Utf8Entry signature() { + return descriptor; + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.addLocalVariableType(this); + } + + @Override + public String toString() { + return "LocalVariableType[Slot=" + slot() + + ", name=" + nameString() + + ", signature='" + signature().stringValue() + + "']"; + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.class b/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.class new file mode 100644 index 0000000000000000000000000000000000000000..d699314cf7ee97099186bdb76484d753d0f94f1f GIT binary patch literal 3542 zcmbVPZBr9h6n<_57LpYxRuHXD_v@>-&_@UE&>P)AjYqO)#@iZC69o+aJXon?k2lj)s4 z^rBBeQbh_X!)zy-?wJM4HA|aTNf->h!dF~l7|iYSCtPzK-OzG+&B>(Dj{yaPDqh17 zLw|gkK`C4IIxp@qj7>&l%dS~;bj#GTmRWNv!p@|3q^j3d9LF$uKpqKRVK_CJj)?iQ zTHagCNY75F7?o}%x#QS+!F5D!h!{Mj;tiZ;=%O(ZG8WSkg5R}8NiT9okQ-+)rr?~4 zahzuuX}A%CB*TbyiUPy+w(c}EzS!&`FkDb^5pObd^J>+2%5b*5fg1r$o_%Q*Q<$cp zR(O@+T3h^3;KlIL)fp9+p^-O^C8NkN6vOu-t6+}dv`2)&&D}`St=6el@D{`Qc3ZMm zr7ANhNJ#}($>(+(LtXW)41IZh*W`|C3x?y7;7hBPw%0Su8HOv(^ZxinhAvGldt%3; zq=Oi*r3+rs3g&@;-Xi)~G5QO0nr)tFg^bf?BVWcXoe{l<;X;Fdeey}GCE zb;irx4^G>iAtm*CCu)*;%e9L_^2sn-zs;g|&}Dga5G{9wUC|v!l=5!Dy97l|!AA^N zUsj82Zn-Szq?c8`=ITaC*c0B(rhtfA=tOiw7e=W`_G5;{PGmQQvuDMH=^kCPEQb=G zSN-MMARg0c7Y*>8!oDavne@Yf9`Gbxbp;h4;KM=rFLSBg-U#J^I0^4c;XM_b*c!wZ zO&la)prXK3VS%oa@y5Zdn@_9*q2;_ex}h8 zWazt}T3{MoxP(5;V2MV<{%*XDWg3xOfc8#oZAC75Yl|WBD)rXLIv@9OfSa271Te}y8yN>r?2 zj3~N51kMmqGN!(B^DTDCnH5@ppFU*8OyGBJFey(bGD~u*QS1BtJ7y(j!o&3G%trKg z;|}fuBuwXGi|`+q{jo`StyP#3*XKTuZEyEI>`>cF=H15wJi;e5k}0}RGoRu!6un*v gW$5^v*2amF`>^5A51(^b literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.java b/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.java new file mode 100644 index 00000000..6aa046eb --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/AbstractUnboundModel.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import java.lang.classfile.Attribute; +import java.lang.classfile.AttributedElement; +import java.lang.classfile.ClassFileElement; +import java.lang.classfile.CompoundElement; + +public abstract sealed class AbstractUnboundModel + extends AbstractElement + implements CompoundElement, AttributedElement + permits BufferedCodeBuilder.Model, BufferedFieldBuilder.Model, BufferedMethodBuilder.Model { + private final List elements; + private List> attributes; + + public AbstractUnboundModel(List elements) { + this.elements = elements; + } + + @Override + public void forEachElement(Consumer consumer) { + elements.forEach(consumer); + } + + @Override + public Stream elementStream() { + return elements.stream(); + } + + @Override + public List elementList() { + return elements; + } + + @Override + public List> attributes() { + if (attributes == null) + attributes = elements.stream() + .filter(e -> e instanceof Attribute) + .>map(e -> (Attribute) e) + .toList(); + return attributes; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AccessFlagsImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..ebf44ce1bd866f5b47f78a97ab379f4f7ae96e7c GIT binary patch literal 3067 zcmb_eYf~Fl7=BIyELj%PrhvB4(khf(fGyH$X()2ntz6X5Sc+9Q$tEl;yPeIZe)j+P zL1#o6XY{Kx{wT-y9G2`R$dbNXj$Q@RW zRMYkh*VZkyZ0YrS)wB%NJbrDd%cZ*K>Sb@;GL8+~W9V5hZPQz1h^I5f1bUH>AS>vD zaurg!Y}D%;mR_rCgv`)uIc4259h+ft^H6`ItCnupRM)6lM%h!BoA%?IzF}U*0Fn}} zDY%Xl!`&$5&pne!`l_68*I6;WI)j$(kZ3>BE}zl3=YtA{FwBq;99w$*h=FN+co#P% z+)^-tQHFluS%bu=1%u)jbE*vE=`g`g>5v@GXU;g!P4k@Mj)F1VW#|?Z49PYd8SmkJ z3F8VTaGzl`DvS)*k4fXM6GWCmGN0BWeGP)&u1`i983|bhIZQFkL?vU*bjih4URx^- z)2bLQ<-cxtq8u2y(psh{V}|3Y4C>WTTZVVwRD3KMvwY_V9f{a54J+6^dSB%5=|ts~geMHwf?S;yfQ$t^m9VJbV=Pg!g7+FVXN`wU zdZSwnV}~kem?9R+n{Po4vVv6!YYNt}(ZW&iT+^;m|5hFMSf@gq5BI{^+x+EKDO%IF zlJF_RSRgML86j_}EedAM*1d*nP)1wpb|EDFV!!7X^Z#S37OA{eoeGIaZko2S-8e28 z?yg?4XeGrbi&fNJlmGV@ySxLFDq(svstQA%@@Ynb$HKw;52t86h9iE_BIq<~1`^Gi zRg77UiXq+JeKc7Lo?brM(qH?!XWMN$h_dv(YkJ16!!SqUBF=$}4V>p9rP6sfKX}{i z3=cb@Y-x1CIoknK>#h#H3r_~Y)QL|mn;0_ZNx1SXW4ISx4>Uul3i!}qxD(wlG)z6` zyu$}uB=|kcAQzm5TQ)Z6XlEE~tKS*k%?yfW+lDK~v{9FE$S@JKc|^q$|M?kBqqvvu z7Yv^ujugKa(4`~A4@!E*_-RJ(H1YcxWc)yPkk4pklU7XH5vS)!_BXI>?gUacH+72s z6Wqws^PLmi{#k6?qVHka2;4^(CXt|%D1{7eA&YHVy?X|O9ehsz2vEpi;@23y5c0b5 zrBA!ZuS4`M8PJXrWk8i85@3qHr-^EY?jUN2CfTG(HffS5kU$=VA?*4zDm}S`?(8qP z@gx0+f&0-T7Uu+@a%SKI(n!H`vf`mBl0u=MHsAgWsVoPfk93NA6c)bv6Pd*Yxp{&W8(UMdBe0XJtDS zy6$FH9zkzviHiXA^Gxty flags; + + public AccessFlagsImpl(AccessFlag.Location location, AccessFlag... flags) { + this.location = location; + this.flagsMask = Util.flagsToBits(location, flags); + this.flags = Set.of(flags); + } + + public AccessFlagsImpl(AccessFlag.Location location, int mask) { + this.location = location; + this.flagsMask = mask; + } + + @Override + public int flagsMask() { + return flagsMask; + } + + @Override + public Set flags() { + if (flags == null) + flags = AccessFlag.maskToAccessFlags(flagsMask, location); + return flags; + } + + @Override + public void writeTo(DirectClassBuilder builder) { + builder.setFlags(flagsMask); + } + + @Override + public void writeTo(DirectMethodBuilder builder) { + builder.setFlags(flagsMask); + } + + @Override + public void writeTo(DirectFieldBuilder builder) { + builder.setFlags(flagsMask); + } + + @Override + public AccessFlag.Location location() { + return location; + } + + @Override + public boolean has(AccessFlag flag) { + return Util.has(location, flagsMask, flag); + } + + @Override + public String toString() { + return String.format("AccessFlags[flags=%d]", flagsMask); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$AnnotationElementImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$AnnotationElementImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..fb35665e197288664bc963d162967801036a5584 GIT binary patch literal 2418 zcmb_dZC4XV6nSW+ANm9Oqk4L0cg-%iAm`|Z?9ANEeeTzI$^*3D%hy=PVB z#e{)8CK)pOmeVJItEm97(U!Va&5>q7Ie&&>VXl;_bBxh36meF^dj{Ue48!>}e{21% zP0yxuFyww!o4V-o-x$ofH(Oe#7{l;NE#>BiD!_9L*N$=XXlP@&fQvdV8Tbg78Lp)H zcSMIl54>!;442bg97I$twF*R;Sp!$`F+*0m8`87IQ-&64z9kK+$x4K{Rb_3?KnZ2C zwr%;_OKz9yy!f$LZxg7aVcmg6&Qz60n)ogcJ!ct=)CPjq}j{5-iHQBN>5 z)9Y{yDHG=6t~pX=svNahn7w?%7JRM0*XCZ+YCDwALc{G?PRsIab&iC?a@(ea)ZV_Z zG*VW%+;+R`mPd_FtwFd$?fw?S#Z>2G!ZA!AqJG4SU=YuzSObAP(D4aiAAsG$M15#jovcolRs4>imQvFRXkUx?F|c9n_~CIUBTu4)H_0} zPVx-h(C{gpR@J*mYrgz9Sh?~7dU^f@#-Ec&!)Npzq3ggyd`{m>;Z=NrFX==|0krx* zAAoE4iuR)#iIoVXN;8_i%F>SnsL@)il>friOH6B^%?Fj2IIkhLHxbx)j2wQ#G@b-@ z&xVQvyG7i@*91F7Gy0nd{syhe6TN(ZE5IMLeLVmpyb=LT(a^1?s9ytqKb87*EJo^! zQE=IE&>z+5o}^fp)MPr%2kUN6yU*@EySMURe;@t{UL94mOhkSJ&|tXQOk5{%CMNYfxh@!(M3F)X z#H%o%l`%}C#Btuh1$^{@WS9FpFFcEaWZ*xk&GQ9@k#eKb8pB0g;<#*J7IO@9r-yK4 zzU?wxD-Vr#;Hq9}6{!eU4SbAi4B5cl3Ovi9s5i*+|Fc%FXnrHex^gsc;0A7zqg~$xldV5cHf_mj8$0rPTPv^cR?7lqKLk!o4 z*Ffu;N{b2|u`$uK9J$s%XiINfv~A+2*mOI>ZVAs)a(p-v>{^uN{WH~w?$J{j?7H1& z!V?FQI*%aJ?fwqK6^($T&6Boam@W?~aoFq)hLWE0fItRDEm_o{<5#Lrb+p8zMiO1b zEw}G=q?!i|Q^_lJZ||tOP+zS{KUj7BfMbcF`rkX4TIXnz6qa2#@B>fuB6j>N#wQqZ z6B#_o<2$T!Gz@%?ABd);8@#>~SO?OKQi?6fs(l2;@J?sNa^AT6(u@>Wh10dAKi_oS z{eG{mF%;h&?Ibqb{<$X~OTXh;y}$AG@-H!Wa$5kzNQXsXGcM z$0Nr&b$CLg2B*jIW`$?BzC9J!Lfa8<_%M&@FZnMaN^HNgC5%4l%zD zoJ?-Gc?Dm^=8JK1*=p?&w?1Sak)0jnk;T{eCX9O=^%%(vWg=gZb6OUoG0Z3y!(8uE x%~eGn;t{P`f{FTKnIx6>w?u57{)s$BlTI#%(nCDO40X{Oo@H{_z!sik<{xKdC&vH) literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfArrayImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfArrayImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..503b6662478fb19e40efed6b2cc513a70c51d505 GIT binary patch literal 2471 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfConstantImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfConstantImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..2dcbde85f0387c1279c3d7122de6d2476c3b829d GIT binary patch literal 1931 zcmbtV+foxj5Iqwj3uL(nh~Nzc)C80uau1*+fJ7sqii=ggZIVf{xa?A!jmlr?BR=>6 zew5|eNtT2vswDa{XL@(K`}Adce*OOO6F>^P5rojDA*|yD+69)63!mbq?Mc@*ta#os zDwU#X$+&rPYQ;Bf+wly~bnG<6iEJ_D*cH#PJzo@P^NbSLXe<>$2Rb!$>4-oVxPNSX zHsY3HmzpdltHlqlNk;7t5tYZXs1lInGmOyt9 zg5oMLemT;52I4_Po3fHmXt*cP*KnN89m~9@;eo((<7=aUjoK+EO~niHf8Yp=U7d)F zS|wsfEK<)t2vcg zS1LdO^P<2~ zOR8zklah36q?cPIygYw5 zd9mrEId4ii$b?dEij8kZ2zS9D&-Wxm9K}Pfk0>2d4iQJDCeI-R&Y^|i@4Nl|%@DpT zl`*b8XyaOhjuM7Z#yF*+nldKvm=ew437*ol@P}^Q#e$LnJ+OL9;2Y0|;9G6yU%*n< zbhX#(*20LYQ!z{`oWgVBAUZLP8O&l13s}MmRSY~q=Y2cBvHsmQ!u3=c2e9J$k*_YJT3MT1Y*~f)|tsu zU;5Jj(wR0h{h0F5AJ8Aw>0L=if&dffi&l5F=iI&Lo?ZR(@AlsSYIts;kKw`wf6HB; z%QtSz=V7?!`NFN4x5xBmqaOnn@(wH%7)t5l=c1*8HbZ{alb)Vq$W4@2im)+g!EtZ` zCmHTLgLhS%woo$pPcht@C?5?xh|@S@;jDvmIL~nXD47`s+ffB8-0zA=kNPkP zJ>uX~d`2Z{^+E@pe8aFf(LAOy)oejAUDYJH;9wLNDakqy*K4Xx`Dgz}l7`{@!oe6W zQ-{U(UG9erOUGx-v|)L5L$q|Y{K~==hUp^-QA=E5Ok&~M0Ub)66}4i=S`1TE!9I3B z&`jkOhW=R2p{6IrQg>@r1TQ)Hlwr83THIgZfoI}mvR|)zB-Qk>8%&36QRsEme#!&B zCFtxBT~2ed4V|zW!wMWMAJ}a6h->OaF#tRp?Z2KY{Zz{Ff z?Nl=YCc0;465z{s9Z?ryEATp61zAXRsb(hsd(Bo37l&y=dR`KTVk2C?uPHL3JwT4SKZkGdEzOLP!)(l80VCwI88q@ma@%)k(zu9aJj2L;g*HIv literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfEnumImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfEnumImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..2855064f52066455f98917bcd99f48bf5303f8cd GIT binary patch literal 2450 zcmbVNZC4vb6n-XwY?3Ywq!guE(3WblX<6~DwZUphslM0-k1N>1Q@9ZwwZB2p0hh%1F=05k{=RR}ipMMWu0jOa|LyF<@p7qo+9ZNhh z+m7Y?UEASiP0jApERPY4YRKr&kYyN;4?pB>*XuB37Hwh6I}GVkxtT*A=QQX##&DkD zi@naiX$#3cVL1tS`=IBTcZG1JC2d#K>2q$qyDa(#YRZrcB3ZKzIK%Zu>@yCq?FwI7 zLiSwOF}G#+*0PY^v#Rnxu46(u*N@I9oIGt@&@qXN6sWYG1mV`s;T^oIVOqx}y!RF= zmipaCo=qt*Xuqn-_5#C5sa|d>>&rT3Fw2k+w(6q8e`7F9C&#=&frl}dn?)+ehdQp{ zDnnMfo6@rdMfiYV&ca`{oNyn4Rh5ftIzGb33_qME-Lo5~>ZrgI2mS?N)XmLdD+Qi7sGuDvq+A5d3ZfC>tNWY{%0t*GWEZz$l7h0y^4an12oJL}uykY`T4~ z%~iW$xDeM?^@4d-ev<4O_vMP~OAR%piBn$-(&ka48eei<=}XV*g~a+qF9fUCcb}W#!4*q% z9PZCGTz9|Ut0t(7?rdTuGTeIB2!*0W-G>DD89s03Kio|{kP^lpZ^Rlh5yq-TKoj(K+#X^+2fUf;aB~CI$b2zMHEUE3QF@zw zm`8SyM;43tI*5A=cOoP+_y$H5Q^#d7I$(TasBz&m#-sQqAnIG(4aOzhqftpBR9~pQ n)f56F*7d3$D-84xJpWx8*7pL6@3d;89R|8M;ZpoV7_`WViy^Ece} zxqR)md>)3Yo-f>*nbm1#qaOnn@(wH%7)t5kXQHKoHbZ{Klb)Vs$W4@&i?A_h!Eta5 z#~E&|w>Ml*Y7t28XXw4nj_=M%sWjJ~k_|G)msab(;@Zp^3N0l=&823TYNkHZ3-AJxWCK;&)CUgzh3i5r`t!(ExoJ-q1ROVDG&Ij zpa(;2InAkH=vmbmPVK1WB>mB5gW+^Gylt5om@?N*BTu#%=60~{^Quxcd+JB3#_x;@ z{<-P~En%7j!^!lpNzpaqlS*1+ZW+@Q>l$^ zr;jysDa3zHtpo)d345J4hr7Xr0;s$l)e)M4+S3xCd zeh$=T3N*JcLF;9*W@+rB(XRZBTxIf46yKB8hYEf3bQ1Ullk`0kpTakoB8$#PYz)_E zKETKT9d>b@zJ_*+Mgz{3>hEaC^8Fg|Iq`PF$4u`}pf?k!UHJ<`|6rKm_gxIXWf<&) z;RLn(8wrCMjdQEAg)f0WcERI-;tN>Y@KJob2mBnc`~G{w$M9VOpP^`tqJ_%j7B23G zkM%5U>si1}d>`GLexeDJ8`-39|-rjGqC<0Dg#sx{W*0IE@(- w1<}QI^CMYCw0p==_GfVyk7#9#D$K?-<}pHbHjPHUNY(ZjO&S-lgr6|-5l#I(D*ylh literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfIntegerImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfIntegerImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..6f2b56c47938f3b67a15fa678b40c48dd24cc55d GIT binary patch literal 2314 zcmbtVU31e$6g?ZqmMs)w!e^ia2%(Lg1`(hw!GSgyXxy5Z7A6nv)5hK;N))Y;*39se znCW!N(2r>z`UCo-I=w5cEhQlt0x!DSk9+RD=bqjD_rINg0Mzk=g&~HEoBSnreIBg4 zZJ$Tcn&%6*uKym>pN(PUEfgGBC^D4O%|D8^3_A>k1uyW_eTLk0Wu*ig$1FGwMsS?r z&Sq!J^#UcrfcqJEZ@cTei$Ne2SDp+SG@NR!HE83y2=$1e*p@-0c%T^EW*Rk3vA^Dx z(szyPqd=CZsV&OpiM_ zj|;S<0sbvdF@M=2BMF$hOL{T<)v{9EGO5ondM2SmwjDjcBcIingj%ezI_lVg5*5)QvE-PAq(OK#Nj!#ob8d#c-2qc!%Z>7F1=0 zVK||5wCM$6xwpM4!smR|Cz8jSvd#S!9(sCgCWqCAM{M2w@GjF?dm_|^>^$Wm-xhR) z2rs8NiH8nao#E6jWg8(doX!?EpqYV5ooZUQSz=h+g>%69O4;nQAG4aAHwOEe?1gQi zFARp0>1N%c>pCXMa#=)bNk+=TU54uWcbvr6ziP@4q*Rd#c{iaZDq>`mp)^{+H#QdW zz(U=@Lp)-*lvWz{0_ANBH>ucolGkb*HWiLn6c1em^geZbuyt5b96%wV+d3D6eLUiSkMht zq<;(3G+&|7eX>Jj?do61RcHP{=?#sBP^E8yb^@<4L*FyWE_{wz8qxk3jo~`|=ZP0G z^n~CBeKqVXS?!!FH+~_L#rrkJbCP9)$Mh>;TyGm!yZR?a|Hc@@UWB(91lu5-pv!;G zAZV+DTh$$$1Ag0+KvGbWfHiQR7$lH&{{;J@zuSEhH%;^fs#Y^vtj_G<@s=y oXf5c}z2tq%a%v_!i@&vw18PN~E?1z9-wnGM-}mf6*vKp8x;= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfLongImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfLongImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..9ada7a08f6a400f9490abf0537c1205a7318b217 GIT binary patch literal 2285 zcmbVNT~icC6g|zt&h9wMieDj#sE7%>sH0J1WD&(x!{Q1?Egtl#*==B8=w4@ft@5|z zB`>~dl~zSl;lUr^kFvZyGs_GJ6!J3tbGLpL^nBsg%Qbs-vd2>BRFc|n1kau!BE+|SB9cbH<;&sM?@;j43NBo4t~T> z6pB_)bl}M)h6kgKed$rn1`?B1jf;~GhH#2pEc0-=rds5EeBUnWhVhJpVVtF$iWeR3 zhYXGV@@1r-TUZfIT`fPeaE{@|cS%r7>cEtRg_9^`xj)YX&#aTpUcKy*NZ0q7R(ehkgKp|@0HIJ&8Xlgvklb%tZv;5Ia7V9MM!jXODFnA*g)!&^$F>`EU=8b2=v`-$oV zO<_6%!;#e3p-aZ_J}a6hU#eB%#)i{ewtNweG?ZHHw5u5b z6WudA3GnHwwzw<8X5h883bK%>eP%Zjj_2Q!WW8^C=o@)+>Qagzq7+mhcD7L-np^DV zDSjdk7|y1Oq)ARwmGr56Ok-h|;arN?MH35;7>0H?r5wfr;xe`3Ui4rDzkmwT{12$X z6liW?l=jQCnxwIZM!WJKa+R?UD88pv4=VJ{lO^ys#^`%Iw!(Q_pcUCiY}Ddu-p6PG zGInu^zJ~S!jRu@6&Ag!@%lA*j=fuYeA2S_4fnFtR1GOt3(f>aN7~XDSc%5Oe6Nbao z>Mth@W;6^|WgR~N@3z3>fZ_{S8}K3gwhjDeVC((2hY#aQ0-vD!8$}D1v2~o@2_NfO z*wC|ptGE{3oBo^$lN+r`-^#xz?iNK~OjDYoJpBF*m}J}o7=5@N3H1kVMB_LnOcX>H t*Ue2@8PRSdN7r>`!b=;yRUA z{M6@u#ISs7z)T5N*SADlxz!&n++cWcA{OdK5?Ub^K4X|UtT?Hv;yMgu#c+q>KSb$A z3#q!sFr1J%+Vldk(%)GZ;S0X*6TM?i+2;Nl4?Vp$o5QN>5mWb1TV3j}WudyV^Nfdl zM^M`kT26723^iAsp%m#BNd?woxUf&+MiUGdv)S&k&cLLOJte~YVp!aVb3~)1~h)6BTNLiR?sJ*`cNQr|Rr}9Wj6{(Q-61JiO z&Wth?NAq}8qI>PJg(o(i;#-DmX{KR6P~MJkl8lWdS*;Ji7~W(_^MY4$TR6$VB_4Eq z5luCv-0t_>41tF6%#Ja9@wz7-i>MuXJtf1eNqo6xHw?zhcR{k=_ci}s-RwpXh%kl} zq?Yo&YxL~u#-LD1*EAWfr<9~sPHSbvWf>d`s|+_%lVe!1@B_od@kgnO35A%WYkC+% zn8K$ZN$U54F0um6ElksXl~xNh4$)Yuy+y7z^E--fXf=cyee-k@c#9eOUP?~kCT3|x z=VLU6TQnbGv;ZA;aGSmwc9uqMoU62cp&^U+SBz&TzYQKeBe-Ks?;6u`?GKFpi7|$s z4?_HtfhZe@bMyp!ZXo6igjL(c72wwc5hNKU5mYDe0-FBLTF)+&;st_UK}?)s|Lx5*FSSP3o~7$>2*_%2^0xqXji8dvZP&oTZ# DxU5DC literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfStringImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl$OfStringImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..604df986d8c5c4ff039ad8f593dc27578da6b322 GIT binary patch literal 2297 zcmbtVTXWM!6#h1jEn5-9giD*Y1PGyx9YD|<7^grm(71IHT4)~1)5hK;N))Y;)|p}Y zm-i&neZ?>pyw=c0G-cisYM;1>%+4CgoaHg|m$`J7AQe}h44Sl^T3UUoLN8d;8-`+A29e@{Vz}B$jiw&=?+J!8y9}GK z>SLt&xP#B|IYpgA$e&S)7|el`*&!!2y+j zNL^Ky8HSCRqb)BGi@mKC5kBK9KFK@Ql5OrU^U%}#el{7-X5$zL%D|*{EDbUF#4xw3IuGfnRJXp)v3{n>80@FA7q*3- z5Dcf&%Q_j?wM{C&MG>ia87T{QbT=J&5>S=(XG{5kl!{u5ca0KJ5hq3&N}~nbw=stY z78(v7;t|7zG}5paC~r%+CgKE1sFgk$!>g=lUa&1Ug=;R(^PuC4XsRXUX0Kb%2$-~3 z<|F|=d)XBaMbr+xu99IE5|7dBLBjETKS|d5uFf9h&1nXK2xCe?mEi0im?xK3`kzGW^IopA$Z&XMY0yHi6pJ*BE_+F^0ePF#M5WuoH$;G~xRU zHxmY{x`R)#4{ic74p;;D1j%K5&%(a|_WFM?d=g(L@L7shD_X41?BL>Ic%x@=pl1=^ zz(h{}(1giN;>cJ3Mrp4ISvT^AraVV^_--GVWIO^Gd3+!1d<(bZwT8Nmg6K@$%+gMa ob`Lqq{tr|+kLhHRD$GU=KVqEftcLkQiK?xMpJ{Dj5l=Aw9~0y}^Z)<= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f8fbaecad61b5761091de2f7071b48f2c7324f15 GIT binary patch literal 4042 zcmbtX`F9gl7`-n|J83!s1`1X!R214KEfEz2f&wi?0;L6uMZ|5IPTGO#OiU(7-FHRY z1zZrt6?f$vDOS(%c>K{n$>Vn4o1~N0ip}wt`QE&I>;3L~^X1n+fA|SNH_k;7LXC#7 zj#|_SEI4Q!Hj=jCj3oPq4w@NHpl+k(Sl-P7HEr#K^@yNeLsUltbb~E%XQLx6{uIg_ZefRKu2#7C@{;oPQf!AFXy^;@-{EK zuE+86g7BLc}%9T$tVn;7}oAlU&gZ#g4fMav#G^AW@a8iKwah@ur8k~*CNjg?9JW~uhU1|)H< zhSfT*!}XFdQ~dfb1R1HIf)5&Yk(60fE=-|P3Lq0$qhl>@Bn^yQ&UA(aI%mtIf^gGn zQtVo~}vQ1~i8&x=`g=Gnh}Txf?er$ zhnd9uUdu82iep1&ey=fPb0^m8W(<4K$XoKgv>EnBEnZE$Fz0;LGRsBl!oaiqB(9R22y3U9n_|0mQ-e$W-De1QbZmbHht!|NbnIHI_YK{Ff<{Q7uYrCq* z-KAmDH$Nk=xeD{(V3h8D=|wTtZoF4nLftjx#?a!7^h|-?oJTHp= zYz2!s0P?-WOMV;ZxRPngc#1p9xPlGJxZGc*I@K|z+@B44pk4!1IZHE81x}pef)Xk! z$7)WPAqb4}8I!X=|2@Ry{LHJjI7pMcAq7T*#%+{ZVmCnE~A$}?sN1+IggL)`JR@TkRUolluV zl2TgL#=nF1Ef*mbwoYv(RVd#{Z7CG%$8u`TG+sE<_=Z`G{S1n9ei--jDV^-0vk+xt zB0hm7lejztxoVlj)geeA{EX(Qg4ZL;F?119%DF6)hEpIk;t0m+R>&dDcQ5wPu9jM7 zenjj3So;MedP{*;2~6OIeKOXrj!CQ&cpK3~Y@^)dJO9r0bxxv7;4P%MxJBS+?A#De zG=(RzOJEYdgV=5w$h}+T9zW)MjUA9q&i?gF*>6)KF@d|n!}2)+V_za>N{zCZz=(t| ztg!FG0oWw(TnD{i~Nm^Et#ov)+d6XU+5&i?68d^2X`yF)}x_`sw zr3Cab{usjJc!IJ8^XcYkJd2|^#w1?Gt9TtJ@CI=^h0}Ns?^Ejmr4_*kWZu&}DIZck zOZgGyQOb`gk5PU?`6A_6%9klWrF@n0Gs@Q~Kc_rF`32=0lwVT5MfnxwDax-YPg8zV MSI@{1e2b>P0g8@kI{*Lx literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.java new file mode 100644 index 00000000..4fc2d5cf --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationImpl.java @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.*; +import java.lang.classfile.constantpool.*; + +import java.lang.constant.ConstantDesc; +import java.util.List; + +import static java.lang.classfile.ClassFile.*; + +public final class AnnotationImpl implements Annotation { + private final Utf8Entry className; + private final List elements; + + public AnnotationImpl(Utf8Entry className, + List elems) { + this.className = className; + this.elements = List.copyOf(elems); + } + + @Override + public Utf8Entry className() { + return className; + } + + @Override + public List elements() { + return elements; + } + + @Override + public void writeTo(BufWriter buf) { + buf.writeIndex(className()); + buf.writeList(elements()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("Annotation["); + sb.append(className().stringValue()); + List evps = elements(); + if (!evps.isEmpty()) + sb.append(" ["); + for (AnnotationElement evp : evps) { + sb.append(evp.name().stringValue()) + .append("=") + .append(evp.value().toString()) + .append(", "); + } + if (!evps.isEmpty()) { + sb.delete(sb.length()-1, sb.length()); + sb.append("]"); + } + sb.append("]"); + return sb.toString(); + } + + public record AnnotationElementImpl(Utf8Entry name, + AnnotationValue value) + implements AnnotationElement { + + @Override + public void writeTo(BufWriter buf) { + buf.writeIndex(name()); + value().writeTo(buf); + } + } + + public sealed interface OfConstantImpl extends AnnotationValue.OfConstant + permits AnnotationImpl.OfStringImpl, AnnotationImpl.OfDoubleImpl, + AnnotationImpl.OfFloatImpl, AnnotationImpl.OfLongImpl, + AnnotationImpl.OfIntegerImpl, AnnotationImpl.OfShortImpl, + AnnotationImpl.OfCharacterImpl, AnnotationImpl.OfByteImpl, + AnnotationImpl.OfBooleanImpl { + + @Override + default void writeTo(BufWriter buf) { + buf.writeU1(tag()); + buf.writeIndex(constant()); + } + + @Override + default ConstantDesc constantValue() { + return constant().constantValue(); + } + + } + + public record OfStringImpl(Utf8Entry constant) + implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfString { + + @Override + public char tag() { + return AEV_STRING; + } + + @Override + public String stringValue() { + return constant().stringValue(); + } + } + + public record OfDoubleImpl(DoubleEntry constant) + implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfDouble { + + @Override + public char tag() { + return AEV_DOUBLE; + } + + @Override + public double doubleValue() { + return constant().doubleValue(); + } + } + + public record OfFloatImpl(FloatEntry constant) + implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfFloat { + + @Override + public char tag() { + return AEV_FLOAT; + } + + @Override + public float floatValue() { + return constant().floatValue(); + } + } + + public record OfLongImpl(LongEntry constant) + implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfLong { + + @Override + public char tag() { + return AEV_LONG; + } + + @Override + public long longValue() { + return constant().longValue(); + } + } + + public record OfIntegerImpl(IntegerEntry constant) + implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfInteger { + + @Override + public char tag() { + return AEV_INT; + } + + @Override + public int intValue() { + return constant().intValue(); + } + } + + public record OfShortImpl(IntegerEntry constant) + implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfShort { + + @Override + public char tag() { + return AEV_SHORT; + } + + @Override + public short shortValue() { + return (short)constant().intValue(); + } + } + + public record OfCharacterImpl(IntegerEntry constant) + implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfCharacter { + + @Override + public char tag() { + return AEV_CHAR; + } + + @Override + public char charValue() { + return (char)constant().intValue(); + } + } + + public record OfByteImpl(IntegerEntry constant) + implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfByte { + + @Override + public char tag() { + return AEV_BYTE; + } + + @Override + public byte byteValue() { + return (byte)constant().intValue(); + } + } + + public record OfBooleanImpl(IntegerEntry constant) + implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfBoolean { + + @Override + public char tag() { + return AEV_BOOLEAN; + } + + @Override + public boolean booleanValue() { + return constant().intValue() == 1; + } + } + + public record OfArrayImpl(List values) + implements AnnotationValue.OfArray { + + public OfArrayImpl(List values) { + this.values = List.copyOf(values); + } + + @Override + public char tag() { + return AEV_ARRAY; + } + + @Override + public void writeTo(BufWriter buf) { + buf.writeU1(tag()); + buf.writeList(values); + } + + } + + public record OfEnumImpl(Utf8Entry className, Utf8Entry constantName) + implements AnnotationValue.OfEnum { + @Override + public char tag() { + return AEV_ENUM; + } + + @Override + public void writeTo(BufWriter buf) { + buf.writeU1(tag()); + buf.writeIndex(className); + buf.writeIndex(constantName); + } + + } + + public record OfAnnotationImpl(Annotation annotation) + implements AnnotationValue.OfAnnotation { + @Override + public char tag() { + return AEV_ANNOTATION; + } + + @Override + public void writeTo(BufWriter buf) { + buf.writeU1(tag()); + annotation.writeTo(buf); + } + + } + + public record OfClassImpl(Utf8Entry className) + implements AnnotationValue.OfClass { + @Override + public char tag() { + return AEV_CLASS; + } + + @Override + public void writeTo(BufWriter buf) { + buf.writeU1(tag()); + buf.writeIndex(className); + } + + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.class b/tests/test_data/std/jdk/internal/classfile/impl/AnnotationReader.class new file mode 100644 index 0000000000000000000000000000000000000000..b4033f0b628b3c3edbd2d9ac28c3a38c5608a452 GIT binary patch literal 15123 zcmcgz3w%`7ng70d9sYrww?@ zCl7fw%F#)qT&6;Ma7))tqdUfwQxgh@Vr!V(<%_lzP(BrCr0X<^CNrI44^M;LW(0bS zC}v0Tuyr|;r@V1dV?Gs9kw(QjO{Hl}OLq3`stko=Ml>AgcVHLVJU7-QHk7+?RD}bz7RI1Tzoyuqq z)7%uY0^Qxl;9zBYUm$Aqv>V+~BR0rX+H1r%K`>imq5k?ve?M3aO6$~ErZdWcwv#s& zknv_z7m%OkYBW!$Q)zxWV^1)dXGzYu?sgL$StR9pNU z0^XHPn1-eEX`xQ1i9VRpUZ&9^rn6EAu+<|?xQ&qY{FdOl{V_uxHCoKHG?P@jBjLeV zARHTrMEWZmp)|clv>_ae?iU1>>U26)GUbVis8*)6<&6&XmBuHqPqT&;(5-;4AV4$9 zX_*)X)OUGiMM#&0FilD1VXg-Uy-!nA>D)r2s$q-#oMy-4QVi7I(hB;0G#x{0acgtW?Vi`0$OB&2R; zs?37aqM2fJr)g_%o6iHU#APG zlWCHQCb8fu#TH@4IQ~6F@>>%VV9_0PkudV&>=?1|Od9xEtzPgK^*Et)uX(M1{snW`sb7Iw5Wp%~OBl!lm2%}l910op0Scb886 zv>UmH^4M&KP)N6_4CBNBUV&0kKBCirMEOFA@(qrKG(x5_F~6lk zq)G8*6cdVvn5J6j+QCs|vX^O|ZR?GQ^}T`qx@hl^5ZbV>+Zd40pG%0iXKW1{`v#B; z7(M=2px1xeg2B`Lp|IcPnWAQie;_jGuk|nJ$)}Id6&hWs(?{uJK)_xn8A_P6J;Kcv zh<0Xqy)z$5jsbhFrfW31R^SXX71?ksx5qR+)z++b%)E|1q0uLGx}H9jl0cd!jF=pZ zM0W>bpo!_UUhY,fzo|Jl>+~7=EK{*)PRITM!{!rH)H%(L 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 i^%JN^P)|cWirUYId5lW readAnnotations(ClassReader classReader, int p) { + int pos = p; + int numAnnotations = classReader.readU2(pos); + var annos = new Object[numAnnotations]; + pos += 2; + for (int i = 0; i < numAnnotations; ++i) { + annos[i] = readAnnotation(classReader, pos); + pos = skipAnnotation(classReader, pos); + } + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(annos); + } + + public static AnnotationValue readElementValue(ClassReader classReader, int p) { + char tag = (char) classReader.readU1(p); + ++p; + return switch (tag) { + case AEV_BYTE -> new AnnotationImpl.OfByteImpl(classReader.readEntry(p, IntegerEntry.class)); + case AEV_CHAR -> new AnnotationImpl.OfCharacterImpl(classReader.readEntry(p, IntegerEntry.class)); + case AEV_DOUBLE -> new AnnotationImpl.OfDoubleImpl(classReader.readEntry(p, DoubleEntry.class)); + case AEV_FLOAT -> new AnnotationImpl.OfFloatImpl(classReader.readEntry(p, FloatEntry.class)); + case AEV_INT -> new AnnotationImpl.OfIntegerImpl(classReader.readEntry(p, IntegerEntry.class)); + case AEV_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class)); + case AEV_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class)); + case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class)); + case AEV_STRING -> new AnnotationImpl.OfStringImpl(classReader.readUtf8Entry(p)); + case AEV_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readUtf8Entry(p), classReader.readUtf8Entry(p + 2)); + case AEV_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readUtf8Entry(p)); + case AEV_ANNOTATION -> new AnnotationImpl.OfAnnotationImpl(readAnnotation(classReader, p)); + case AEV_ARRAY -> { + int numValues = classReader.readU2(p); + p += 2; + var values = new Object[numValues]; + for (int i = 0; i < numValues; ++i) { + values[i] = readElementValue(classReader, p); + p = skipElementValue(classReader, p); + } + yield new AnnotationImpl.OfArrayImpl(SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(values)); + } + default -> throw new IllegalArgumentException( + "Unexpected tag '%s' in AnnotationValue, pos = %d".formatted(tag, p - 1)); + }; + } + + public static List readTypeAnnotations(ClassReader classReader, int p, LabelContext lc) { + int numTypeAnnotations = classReader.readU2(p); + p += 2; + var annotations = new Object[numTypeAnnotations]; + for (int i = 0; i < numTypeAnnotations; ++i) { + annotations[i] = readTypeAnnotation(classReader, p, lc); + p = skipTypeAnnotation(classReader, p); + } + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(annotations); + } + + public static List> readParameterAnnotations(ClassReader classReader, int p) { + int cnt = classReader.readU1(p++); + var pas = new Object[cnt]; + for (int i = 0; i < cnt; ++i) { + pas[i] = readAnnotations(classReader, p); + p = skipAnnotations(classReader, p); + } + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(pas); + } + + private static int skipElementValue(ClassReader classReader, int p) { + char tag = (char) classReader.readU1(p); + ++p; + return switch (tag) { + case 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's', 'c' -> p + 2; + case 'e' -> p + 4; + case '@' -> skipAnnotation(classReader, p); + case '[' -> { + int numValues = classReader.readU2(p); + p += 2; + for (int i = 0; i < numValues; ++i) { + p = skipElementValue(classReader, p); + } + yield p; + } + default -> throw new IllegalArgumentException( + "Unexpected tag '%s' in AnnotationValue, pos = %d".formatted(tag, p - 1)); + }; + } + + private static Annotation readAnnotation(ClassReader classReader, int p) { + Utf8Entry annotationClass = classReader.entryByIndex(classReader.readU2(p), Utf8Entry.class); + p += 2; + List elems = readAnnotationElementValuePairs(classReader, p); + return new AnnotationImpl(annotationClass, elems); + } + + private static int skipAnnotations(ClassReader classReader, int p) { + int numAnnotations = classReader.readU2(p); + p += 2; + for (int i = 0; i < numAnnotations; ++i) + p = skipAnnotation(classReader, p); + return p; + } + + private static int skipAnnotation(ClassReader classReader, int p) { + return skipElementValuePairs(classReader, p + 2); + } + + private static List readAnnotationElementValuePairs(ClassReader classReader, int p) { + int numElementValuePairs = classReader.readU2(p); + p += 2; + var annotationElements = new Object[numElementValuePairs]; + for (int i = 0; i < numElementValuePairs; ++i) { + Utf8Entry elementName = classReader.readUtf8Entry(p); + p += 2; + AnnotationValue value = readElementValue(classReader, p); + annotationElements[i] = new AnnotationImpl.AnnotationElementImpl(elementName, value); + p = skipElementValue(classReader, p); + } + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(annotationElements); + } + + private static int skipElementValuePairs(ClassReader classReader, int p) { + int numElementValuePairs = classReader.readU2(p); + p += 2; + for (int i = 0; i < numElementValuePairs; ++i) { + p = skipElementValue(classReader, p + 2); + } + return p; + } + + private static Label getLabel(LabelContext lc, int bciOffset, int targetType, int p) { + //helper method to avoid NPE + if (lc == null) throw new IllegalArgumentException("Unexpected targetType '%d' in TypeAnnotation outside of Code attribute, pos = %d".formatted(targetType, p - 1)); + return lc.getLabel(bciOffset); + } + + private static TypeAnnotation readTypeAnnotation(ClassReader classReader, int p, LabelContext lc) { + int targetType = classReader.readU1(p++); + var targetInfo = switch (targetType) { + case TAT_CLASS_TYPE_PARAMETER -> + ofClassTypeParameter(classReader.readU1(p)); + case TAT_METHOD_TYPE_PARAMETER -> + ofMethodTypeParameter(classReader.readU1(p)); + case TAT_CLASS_EXTENDS -> + ofClassExtends(classReader.readU2(p)); + case TAT_CLASS_TYPE_PARAMETER_BOUND -> + ofClassTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1)); + case TAT_METHOD_TYPE_PARAMETER_BOUND -> + ofMethodTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1)); + case TAT_FIELD -> + ofField(); + case TAT_METHOD_RETURN -> + ofMethodReturn(); + case TAT_METHOD_RECEIVER -> + ofMethodReceiver(); + case TAT_METHOD_FORMAL_PARAMETER -> + ofMethodFormalParameter(classReader.readU1(p)); + case TAT_THROWS -> + ofThrows(classReader.readU2(p)); + case TAT_LOCAL_VARIABLE -> + ofLocalVariable(readLocalVarEntries(classReader, p, lc, targetType)); + case TAT_RESOURCE_VARIABLE -> + ofResourceVariable(readLocalVarEntries(classReader, p, lc, targetType)); + case TAT_EXCEPTION_PARAMETER -> + ofExceptionParameter(classReader.readU2(p)); + case TAT_INSTANCEOF -> + ofInstanceofExpr(getLabel(lc, classReader.readU2(p), targetType, p)); + case TAT_NEW -> + ofNewExpr(getLabel(lc, classReader.readU2(p), targetType, p)); + case TAT_CONSTRUCTOR_REFERENCE -> + ofConstructorReference(getLabel(lc, classReader.readU2(p), targetType, p)); + case TAT_METHOD_REFERENCE -> + ofMethodReference(getLabel(lc, classReader.readU2(p), targetType, p)); + case TAT_CAST -> + ofCastExpr(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); + case TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -> + ofConstructorInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); + case TAT_METHOD_INVOCATION_TYPE_ARGUMENT -> + ofMethodInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); + case TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -> + ofConstructorReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); + case TAT_METHOD_REFERENCE_TYPE_ARGUMENT -> + ofMethodReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); + default -> + throw new IllegalArgumentException("Unexpected targetType '%d' in TypeAnnotation, pos = %d".formatted(targetType, p - 1)); + }; + p += targetInfo.size(); + int pathLength = classReader.readU1(p++); + TypeAnnotation.TypePathComponent[] typePath = new TypeAnnotation.TypePathComponent[pathLength]; + for (int i = 0; i < pathLength; ++i) { + int typePathKindTag = classReader.readU1(p++); + int typeArgumentIndex = classReader.readU1(p++); + typePath[i] = switch (typePathKindTag) { + case 0 -> TypeAnnotation.TypePathComponent.ARRAY; + case 1 -> TypeAnnotation.TypePathComponent.INNER_TYPE; + case 2 -> TypeAnnotation.TypePathComponent.WILDCARD; + case 3 -> new UnboundAttribute.TypePathComponentImpl(TypeAnnotation.TypePathComponent.Kind.TYPE_ARGUMENT, typeArgumentIndex); + default -> throw new IllegalArgumentException("Unknown type annotation path component kind: " + typePathKindTag); + }; + } + // the annotation info for this annotation + Utf8Entry type = classReader.readUtf8Entry(p); + p += 2; + return TypeAnnotation.of(targetInfo, List.of(typePath), type, + readAnnotationElementValuePairs(classReader, p)); + } + + private static List readLocalVarEntries(ClassReader classReader, int p, LabelContext lc, int targetType) { + int tableLength = classReader.readU2(p); + p += 2; + var entries = new Object[tableLength]; + for (int i = 0; i < tableLength; ++i) { + int startPc = classReader.readU2(p); + entries[i] = TypeAnnotation.LocalVarTargetInfo.of( + getLabel(lc, startPc, targetType, p), + getLabel(lc, startPc + classReader.readU2(p + 2), targetType, p - 2), + classReader.readU2(p + 4)); + p += 6; + } + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries); + } + + private static int skipTypeAnnotation(ClassReader classReader, int p) { + int targetType = classReader.readU1(p++); + p += switch (targetType) { + case 0x13, 0x14, 0x15 -> 0; + case 0x00, 0x01, 0x16 -> 1; + case 0x10, 0x11, 0x12, 0x17, 0x42, 0x43, 0x44, 0x45, 0x46 -> 2; + case 0x47, 0x48, 0x49, 0x4A, 0x4B -> 3; + case 0x40, 0x41 -> 2 + classReader.readU2(p) * 6; + default -> throw new IllegalArgumentException( + "Unexpected targetType '%d' in TypeAnnotation, pos = %d".formatted(targetType, p - 1)); + }; + int pathLength = classReader.readU1(p++); + p += pathLength * 2; + + // the annotation info for this annotation + p += 2; + p = skipElementValuePairs(classReader, p); + return p; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.class b/tests/test_data/std/jdk/internal/classfile/impl/AttributeHolder.class new file mode 100644 index 0000000000000000000000000000000000000000..a843194e39a038da4838da5fce1887e3c2558270 GIT binary patch literal 3213 zcmbVOZBr9h6n<_JTnUQ=RIDwaA}UFMSZhTMrXux)HlQttihbK83oL})bh81m{Ui2s zM`t?Dbew7HU}rl0)|pQKM8EV$I8NS+c&CsRxvg1y2eJ< zDtl3A2)CjQx`uWgyU-z!TrRAnEZZ|(+bE{;MWb9^u!?5NS}k#>=ebs{;+a>RV!?C; zqDFP4OdQ#I4Cy}IhE8;8*sWs^_6qdYan}9TTncp5oJ|>}l5~G;Fs^+1$!)Po88Xm5 zyrE&gjyLg^z~QEWs?OVuV$oTjsuVq|R5X36=A$H|S4STX2(((|Ypz)~ZSpxdxGfxU z-@zdr{W#1bxaO*}M$g;bJ=caKII7{8jzPo)cD=|aAsU5(z}`kMs^aPRyxg1AF@#}( zNZGopGMa2d3dc3Pt>XmVc|{E_R2FWy7E3Omt;?6|C+K5vGVTLff(|n{@>G8!4#kqLxTHKG(&6<&uuexWWLQS!RHXTkon#Fi=yVIX}0Bik(Pc8@?3Y@=cTYR39nz0sb!>hO~&dGoMEo03UHkQbwGijzW z;S{*LBWu~_bY(SXy0b=3%C{@)D_BH-$25Dcnyrmi~ucW(X zLAnKmA#k915_BChRt1hUHw)@OoxPaTMyZ-te{%gu1D%qN#x^8(`G!Gh}_7hBQ+g6J2HLMA@qiC$=3dVpE z_`q?2%iD^UZVsOZ6}!faQ*ra=CH58m^)(f#rZOT=4K|Ytj^mX**C zffac|7j+b1#$azpne*ILisDPS8p=96RJg0&AS`>$Sus;tKU;<}7K}X4xDA1})yCN$ zjoAmA6tXLZT_~F6fvn@KR7#Ec&#+tCi;XKUY@DT@|KCRyviaV|&KZQAV8@%`Db9aG zpR{e$osjL_ENi&KfAS?xwn|UKU4g#lrtEx*3mjsxLOh3gI?3Aw$0^Q2nC8Vp$jb|# zSGkfwm~TKV@fafUGqhWe(fT8zk9_NEe99{i*j6JrjF0%HD|>v58O{V|ah(>@*Y_O5 z97mGBA@V4>i5Q~}ZK7M?8wMEq2|f3)Q;r7{KOjnjfe>!UND;_LeZ&SF(yiP;3Mg!Yq;Ne?ZM`$;ithw04NC;|n zQgL!x;2!pooO1%dqH}tfY>bES;Q3#5KDvB2r&zsF0zA#Tz?m8cL*z4rHB_)oohI%&CZH*stNtQ}l4ks}_;UoWBbYkGu@Arvaj0(ByrzL>@kP{%2V7 zq6*i|a)CFGUYuj;GKg~=;sv8xuwH_xf*q-W9q|jMz{-LtD+yMX^(G7^AYtnWKSPwT z`<~KD)hx$1-t_pC_-}KRBJGs;lTUCF*u-R@t*~D@rQ!+1SSATeDWtOorn3QzQn*}^ z5LCc?EGkbv&Sk)>LBN<2dE!2_$OA-tN>n^0m5GK}F+Tz~6NA#MOs)l?UFX@Nu)s+O ai&)|)0XST> attributes = new ArrayList<>(); + + public > void withAttribute(Attribute a) { + if (a == null) + return; + + @SuppressWarnings("unchecked") + AttributeMapper am = (AttributeMapper) a.attributeMapper(); + if (!am.allowMultiple() && isPresent(am)) { + remove(am); + } + attributes.add(a); + } + + public int size() { + return attributes.size(); + } + + public void writeTo(BufWriter buf) { + buf.writeU2(attributes.size()); + for (Attribute a : attributes) + a.writeTo(buf); + } + + boolean isPresent(AttributeMapper am) { + for (Attribute a : attributes) + if (a.attributeMapper() == am) + return true; + return false; + } + + private void remove(AttributeMapper am) { + attributes.removeIf(a -> a.attributeMapper() == am); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..8eb8cd0f1b3bf98d4ca0915c1469b93b334432d1 GIT binary patch literal 4018 zcmb7HYj+dZ72VgCJhD8-#s!MOfCGlul8X!>2}R}+JCHb7CaH}bLy~4JUF^Z58D%u$ zk)}=hNYeNFMZfeTYjyQQ+l8SdYc=$1e@XvDAN!03X>4St)mqY>d*_~W_Bm&tbFcpK z?@#^)U=qJgqYdo_5+;)9P&j_Qw3@TsK>M!cA%x zL!r~xR&m8zapCh!_#DEB;v|9>A(%6p!1_n($g@X#) zLyWb+c5;`NuIpk@RoLe1cWSn;nShy^Lu^Olfv#`M$I(Vh28I;+TR9zC79Wn7cslf9 zi9ua$ERUGTAj{NNEML2U!c#5Xilru>rnWDcIEoyd3%ts-SF{NAf8oTGAUP(o$C=S^ zcEZH7cuq7$j8ix^y%kmFo@8de3n%eq1E);nF|LsNKjjs=iZy?(;Y$1PNQmu>iL-)q z`(tbc>sIJ()xZl1*;WC!o2<-*QJ%B>WgQ4XCr!MF^9qTZcCex_6VGk40w<*wFR&KR zJG#u2tjl+cZBcdR4ZO6D_*0Ifmn~;DumXMlR#8`^P*RvuI65WeeN8jrMLlS{gDgJF z8N6Znw$$2S)$xMCvgKOKA%HY4;G(pRX@#9}%(H=SyUVQfKDL+{6PNHRYb3Z`(X;fh zNEZ*sx5uzIn@WCaWXix-6m~a*S+FSFfSkr_m=p7t6*6&sk@*;3=T?00rno>%1{Ub) zRz#Rwv20hDV$|-$JWd$6vM!EI*s+Gwg+;t!;!V88((x)qI;60FlSXnWe9yXh8KidTBo@~yIF_hGEl zvtG?FYH4*myjsQfsPKle6P_3FthXw4CDon|{4k9l;l~DkB5miV3J04M^J{Kkmvye* zgc`E6_)*+D+r8nf>Resr%a&VmbaiOj^Hyt>e9WyUyUaR4@il)nw!g(89SKY_*0Xk? znIv<{b+tb!on8}H??&eh{F2SH>C!rr>#-X6H9ODNTbYNtV>rh8Zi9jc1ATI-Vdw6X zdrCO+g21s&?rY)5t5!JjxDH1ih8#`GC-Dw{ea=3VdnLzQCi?&?lURe1XLd?xnV zA@0}h<#|0A=e_VWEu4+n8;$I}8}3))a~DdHpE-^KDoGp0ANkN0YU~IXCt_NX4b)$2 z2v0=9-4yQr9gM_XB-%wu9ade*g_x4=7?dR1y3Q%u<0X)Kga`j*+$51YyT~Lj6xz>> z?)wA<;168nXP`b%1~|g+34UMt6t68R^#HSEBEM>ucd+(q61uP|8`d1_5#fhJ3w3u{jB-8c#V9$Ay%S~s7*&b2oQ^gT*+ zaF33>lBYVSB-DG+@h|!BvRxhQ?C$#y$?8eRr zf1E_XC$dhih&hBSkxTY@~i5oGWr$le#^l1?Q;>Ss6#VLLO- z-1Yl#HYym3Dd>z4eJr77UG_>AzZ=H%d-y&_X(2!0T8h`qllU1|`l#Jw-hSTEiC^GX I_zn913)61Vpa1{> literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java new file mode 100644 index 00000000..66e974b4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.Label; +import java.lang.classfile.TypeKind; +import java.lang.classfile.instruction.LabelTarget; + +import java.util.Objects; +import java.lang.classfile.Instruction; + +public final class BlockCodeBuilderImpl + extends NonterminalCodeBuilder + implements CodeBuilder.BlockCodeBuilder { + private final Label startLabel, endLabel, breakLabel; + private boolean reachable = true; + private boolean hasInstructions = false; + private int topLocal; + private int terminalMaxLocals; + + public BlockCodeBuilderImpl(CodeBuilder parent, Label breakLabel) { + super(parent); + this.startLabel = parent.newLabel(); + this.endLabel = parent.newLabel(); + this.breakLabel = Objects.requireNonNull(breakLabel); + } + + public void start() { + topLocal = topLocal(parent); + terminalMaxLocals = terminal.curTopLocal(); + parent.with((LabelTarget) startLabel); + } + + public void end() { + parent.with((LabelTarget) endLabel); + if (terminalMaxLocals != terminal.curTopLocal()) { + throw new IllegalStateException("Interference in local variable slot management"); + } + } + + public boolean reachable() { + return reachable; + } + + public boolean isEmpty() { + return !hasInstructions; + } + + private int topLocal(CodeBuilder parent) { + return switch (parent) { + case BlockCodeBuilderImpl b -> b.topLocal; + case ChainedCodeBuilder b -> b.terminal.curTopLocal(); + case TerminalCodeBuilder b -> b.curTopLocal(); + }; + } + + @Override + public CodeBuilder with(CodeElement element) { + parent.with(element); + + hasInstructions |= element instanceof Instruction; + + if (reachable) { + if (element instanceof Instruction i && i.opcode().isUnconditionalBranch()) + reachable = false; + } + else if (element instanceof LabelTarget) { + reachable = true; + } + return this; + } + + @Override + public Label startLabel() { + return startLabel; + } + + @Override + public Label endLabel() { + return endLabel; + } + + @Override + public int allocateLocal(TypeKind typeKind) { + int retVal = topLocal; + topLocal += typeKind.slotSize(); + return retVal; + } + + @Override + public Label breakLabel() { + return breakLabel; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..da954d191f3ac658a81c6aa742262ff5d538db4a GIT binary patch literal 3300 zcmd5;-BTM?6#w0Pun-oADM8T|khYqSw##Q~4I(8{NgE0k1gvfCCRxbRWj7`pl{a5~ z^1-M61&%X5=uA=LgQMe{f0X07cQ+q|g{ecG@n!GH%{}M*&hK~b$6tT{`Wt`@c0%yM zFCic!h%Sckp8A=p7^=CetmgN$g3Zu1r<=Mx&)|>6H+#^H9tj~Cy^tAZ_KHsw-L$oe zsTxYbP^;A)-Ov<$zicRrmStD%idtUL?2=VnGVRJimi}M}>Sj^=1*?3py2B8QIiSUV z8Otz;Qr$As@wRF1BEXKy7{lufJ!)mQwy&9Xl?3TrDB&W7^$Z{+MF{FK3Qw=IG>N3>UbLsefj$7e$ zOfWw;r$D=y+YK0 zmwPdfcO@*yxQRuE3tnU`)^@fkI_)Bc(C6I9I{QOu=jH@?_}&nWnT~JrgbGi%B;yv| zr|uEac!Nc@!E6zjHAlC^VNM<$DyO~56X=kfBrw%IfKHS*U82PJ*`EKh|G{{_%t{589>lY zLMkRa`_xMzQpa!Q_qgz_?daTh^jF`ytrniFsAabi1`5`Gxn^t2&68o9WIN^Jd)`~* zSdV5I?sQDfCEFmLa0HyZ`@Z>4fSv_YoNAQBskC7+jC=Qg^E?#Wwo5FhvvJguiq>K} zJ=d*TrJ&uSHwYcIUefc;d5w!s&x@>SYLyIswD5y5dhC|sYcWY@st*K}9!O#S>Y;-@ z%pWW?M)*5LjP%G5Bi-M$cA0D+vgn~Ph}&e}A?rIDyJ)-D7|G@ZD zOeBBD_{xu_g(Ha>se27g!da5Z&3R~DFBp=bLAbc|mbU)xeK6WeIrje@@36Caz!c-|)$6E}K zBk3<&i5;R>MWP{RHGkWZ7jHzT@mfmqnFo~6q2eJ~Yq(C|P9-Itpk2vz4?gJ@^mOj) zbl&oGeuPil%=g?nqe&`ru8wzn;8v!N_k7?@?;z arguments; + + BootstrapMethodEntryImpl(ConstantPool constantPool, int bsmIndex, int hash, + MethodHandleEntryImpl handle, + List arguments) { + this.index = bsmIndex; + this.hash = hash; + this.constantPool = constantPool; + this.handle = handle; + this.arguments = List.copyOf(arguments); + } + + @Override + public ConstantPool constantPool() { + return constantPool; + } + + @Override + public MethodHandleEntry bootstrapMethod() { + return handle; + } + + @Override + public List arguments() { + return arguments; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof BootstrapMethodEntry e + && e.bootstrapMethod().equals(handle) + && e.arguments().equals(arguments); + } + + static int computeHashCode(MethodHandleEntryImpl handle, + List arguments) { + return (31 * handle.hashCode() + arguments.hashCode()) | AbstractPoolEntry.NON_ZERO; + } + + @Override + public int bsmIndex() { return index; } + + @Override + public int hashCode() { + return hash; + } + + @Override + public void writeTo(BufWriter writer) { + writer.writeIndex(bootstrapMethod()); + writer.writeListIndices(arguments()); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$1.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$1.class new file mode 100644 index 0000000000000000000000000000000000000000..26a08d4086f7c10787f51bbdcde0f85e6b0ce3a0 GIT binary patch literal 2788 zcmb_eYf~Fl7=F$Y$c3d%Lv2OH8jChJNLvwWgII!KV?#hFLBy(?WT8u!vzg7=0^=WX z#!r6nHjd-HgU(bx`=cD+-7LEcT^Mv^hMco!-^=qp@8#@YfB*Ivzzmc)B=kfPkW0llWdJ3`^2Z5VoSMQq%d<-*)6B@jbAiiC`Q$P7teb)m7PHU&f9q{cNd#n6+< z*86b=XQN2UIENHN&KLI)hI?Y@?+{+TSyyz6P@d0Z12~tRSEVSm+1;kvwl@h3BHoXScshz98PDKZhGAdV2UNB;R!xnVWJv7Tn+k8Ky9~ul z0D&)l2>&9{)n&>Kei+Y3aY@DtNHdIu`BDy&Qe5E=xUs{%EK!cgvQW9`Fhnxh^|Foq zvWyYDMDJW+M0g}qv3*^{6&V?14?vgqgi4ydne}qE9!DO9C`M(Bp~x^12F3F{ue6E0 z5$}0fC=E^5#2!O*rFN&buv%ld5z2+9bF2-jAPLuGT*oU6XPhWJC5EMNioJ}KLcJ=- zl32>tZGW%In80fc1E#9@eZcTZxH}I}YgSjcDFfkdXY3|hB8#e7ssyXkuZx!w_&+cJF+}Eg7#;X5j zhLp%lcYwrI-qei_^(r-EXo8+3ltF54Fr-7pgT&GtX&VHNRcP0+Nas?hj$a~#%ch;- zYN+4|DIra}&h5>?>jSPCXX zg-%Gt6qQ$E*|5x}I!D(S!{FgN%o(Os;Ijv%*QF&2N>T3gWh~kXf6BS9;H|?9KIOlFk?$mJJR<(|xsADy?BW@cVDnq%#xoSGyV2|>Ymr-vb)6F8$ zjZEVhESa>w1nA=+M*sb|Nv9>+jgy2#Ya*Bb1uXXn(I4nZ!X*9nkqq!D-k@LE*(WfC zH|dGt7E+!CYCk$l~{>VJ;GCe9MS*W(a&{d zTm*I;(w`vzS8qt4)&> z`SwV7-v#KAJc1Xn=xUC+nvoxoJ4)?O0o_PfH#tqgze_l}>FpsLPI?P}V)$2F^`ksK zy-TDKr>aQOngkh~z_M%bI%UDhRW4s3bK^$=1*;|I24kBWAQWA5&f1H+bSPm3b!T10 ed$dNdhIM@CoUGv^T2mxrm#6)gr!xNd*3dsx2Hvg! literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundAnnotationDefaultAttr.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundAnnotationDefaultAttr.class new file mode 100644 index 0000000000000000000000000000000000000000..b2fa13edc200e4c67518f5f8550acdc00a824fce GIT binary patch literal 1728 zcmb_cT~8B16g{(BSz4A40jq$hCE)Hj$3bd&LcmR)m^0m_b60?VQAZxuG(REzEV2jZ@A-edEB*WPj7!I zcvS?2M2F5jG=tsXXP(cihl&S^ffX~z z;;MyfHfAu(u-5P3-44Jukcog8-uFaZNEPQ+ytp34+(7wTxX$n}skpqY1LrrSF3Mwx zr1tzOkv(2=r8o%dMnH&1nFbp4vrh4W#>89I7DMio{o*?nep5L&rMSaHr!yLVaZiUpX^_rSAjq|js zAw>@`oL^m={|xql<|b~?SGRPSd06HuZqhm*`Qa88Xhl148+Yg|JzK<*_NLigOw;~l zn%kX!EA%f%7K6@USj8HBb?h>E>iu*1kFdUDGEd_uy_dh>$|qRb`ksDAaK>na=@6Vv pWX-J>q$tE(3~9aP%d&(sinalVOa?ZI2R$0NM`MO!YF6%J<`*<<09pV5 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundBootstrapMethodsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundBootstrapMethodsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..70feb2d0ffaa5e71f2f634ec4dfce274e29ecca0 GIT binary patch literal 3109 zcmcIm%W@k<6g@qXJh3v4jT1XI*dYNMWZ91Lbij&D9LK>*WGBRl$%BVS(j=Nho>7fP zRD}&2SnwAV8#Y-$L7V^u#f~a|fCaE%!~0PbD_8_h&&aYQ4? zxcAYg0A^uCp&+CptRaFnf%x^@jf82rhGXf4M7E%pN>|N-kuX<_g~V~YY~^NL*D*6? z*AQqsYFef{EpRH9zOKKbCkncCt>)0IJbup5bB2=)+)&lEpcjkWlp0xX#}>4!h-%mh zO(4}eo*@t3aocuFuA>(h3^#A*N>vjA(aic>0p-Ek$%JsKXv;{rX>s?XQFZsiJwcU0gA zK?KGvYg;8(x7?y_7ZRHeCRGdz%r#Xjs;aX`aC91=Lx3}z6c5|=<{)?O{L z2wh|o4Z8DX5FsPO#)lX}f zL{dPpuL=yuuGHkpnap(~>n1Ddv*C`4DdtsB_Uh|>g>B|POSpZ>yk_Zc*&*Ra8!EUm zZ|Fe{%DezM-ecBk#EURc&0Q_d^Gu$wp8HBL8Wv%Ww6 zPd_3Aui6bqU{4Km8$GwCv&hY>UXLWvft#y+uF^`G>_wZ1d+WWqSzPyMr4=>7oVE}u zkK#9iv$fW*2MvNZiolLcLq;umy|k-Q%-F{^Wh|M`dreVbu4(jJt#GEE?p$MN!g)3i zwseyfl;M1|wtzO$ATWb@tjK%Ur>|OG!Qraw4ryKhGOyRW#704M@LtH?VET9|uY$x) zZ=xgELLfw0WN$TPtiE1?RkxOFfoasrQN9Y6?6Q+JPV$w*OQjytUfHMwwk#SYcixt_ zj+U}4!|^iMV90hge{-nF^7(LI*8*?jz^f4Zc^4{R+vC3?A4eQd^9`rq8D8alBXAs| zjL$gAj&b%H!u$dK@zJrtI}mYk8)`iM0XhcP@X&4Se9t>F!~br%QTYn0@+CCoYxF7K z;5g-RUjZMACpe=j%;6-B$kDTyry)5?(Rc`_IF_LNwbNYl;iV~Cz+V0z<644WxhFy# zJ8yBIKmur!Lgib}sIMeaF)FZ#GrmXSAljjFcbSLP&ry&%KEWeteg`8fQ=#cWDR~>G z`RN!~!|u;8G#QQ$L{`@D#AIYZ?T>tjI62C%tW5QX`y+Rem}nav{22Q#$s>b3ZBlv% zhnHRtiFf{aKR$XFPf6Bj?_C-WdtfKfL9pMEt?$vP{D5BNN9#+kop&5yzrTJuLQ;6?6J@Dg73z6w_O R?WRN~n9g_(A%h(H{{=p3m$U!? literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCharacterRangeTableAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCharacterRangeTableAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..7994616141b44ddda23728acfbb640e0ed9a273c GIT binary patch literal 2468 zcmb_eTW=dx5dOxu^=0E+8kd%kwt<#7PFjZ+00U$U*b9h7D|Fmq)oF$$Ik?( zz_gwr6UQ(tFdNoG*SG4+p%sJzsibinFBmvs;v`-aOdb^J9>s({Agmu<6vXnCiHd=j z1k=4zU_HxLu^X6*x8^GcPMJ8ZtQ$&S#S1eS!I+7c@roeguL&;aE9#l(nZJXymohkq zR}G9SZFxafySIz6;9UN0htk`tn|3WM?bz8BD;X#Vt{f$_y*W=UJL{emwgOh{^*x!M z?eIY7Sr_|(Va=5YdfBg2TYuH@?8VmBsvT&ff}yHkv)nsY;HbjeVaCD@rzu!Guyne6 z>-n`zFCsPOXRK!g9rZ%N#FlO^Lf%t&w?B5eP!MhSboh98Fb^Bg0;(NG&C#IkPFhKU z{N?|1sr*MjcqK8d`F(ZCmT9U^{-7p^+g@F*dv2GVP9N;Pb8dKbo>+6ObwVr-!S<@2 zAZfeymhFXPUh3?NLslhKHCUGot-X(yYxkK=jjDmNV18c&N5e(k7dk879-)elW@29n z^sKUf>&-o<1?gqK71Zo`PA_JryS*-``-GS;+RgB$-{f^{Ry@xRblccW!Ps+W30~uj zh(IvGZ$u3%u9KXp5lm@5$0^tIRSz%ED@HsNhNU)r!Yq<1s8*Ohg6z?e}Z>O#W}1$#Z^**6L^4Y{Ermji1cxtyeP)8 zjvJ&@J|FL-XP)#KM7OCVVIWDr-xKB$f8y>o4f8!oiFQ(M@?@K;;1;? Lrd?H6i#YiY8Y-)V literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCodeAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCodeAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..65331423b901a917827ebeedb29ebd11cc1a5b7f GIT binary patch literal 2410 zcmcgt-E!MR6#h1nBgYkKh?ADTl7^(M?KCx%wiKMCBqk*)P6%}xm|+H@SWBW-mW(Vj z%^UC-JOCFkgI!vn!v!~R!3~eVdoY}{afFkqnfitcd(ZBk^X+%eetY!CKaU;*DC3h1 z2A~TSbn6YTxD>Q}XEBOGce@oyfx$V~ccTS? zTe-?z`zyQX+5S#XP?^JTOWToQDbXRuTD2Pua!E8=x}^+;anituiRUpYFw;k@fDuyOmLCb|IV*2*T4N^0aY`Ul zBaRj6??k%-!ZPrJz(i90R%NssIIHCCar{drUdAf|C#7HWf~M>5>^lfdCRVp6yu|UZ znwa48hxq(zWQP&2PMUa)R}EfW_8nfEHgS&EvhsdSHX=9hS8U($WVjwQxhfY-Wuiz2^nCqljf_<4rEt6#*@mxA@R& zCf>qzqR)pe?M1Rl1ag*@|8&W~JA6M05{yqP9udZu$&!tw<1Bl!F8wH3xII!yc8GEQ zQ#L7qIne!8TwkuW>f18hu(v&08Lb30+uO85m*?F@J=%3C#T&b23%2NDJ!aE{37K$8Cj#FYt9A^5~aJUsa~Q zRt;KVP2QyM1+|XD%Dlvnlk!@V&1fZPQd`Wf%dqZ7k#wr9?HYe6WYfSMf$3xWEWIFZ z&eTXO-823K<)ilgpxf<;m@AnR2;mDwQlfymqPY{0^L%fgUcOU{q9IM nfAv6RyHKfaZ9c@h^8N_7)i{7EjXE8&flab9WU=%<)`$KD&1!yp literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCompilationIDAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundCompilationIDAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..b02ac40b513215afbf62ad31fa2aaf895316b895 GIT binary patch literal 1565 zcmb_c-EI;=6#mYFEYPj3tyXKTT5Xk|mW_!qCNxbHZHmEOi1yBlfnDm>Wp=X+CfxcM zK7}Sm6EA!KpGl2pfD%X$3o(S9nKR!x^PS%xzrTG4P=cL?ftZQ7g>y&{awpDP+mp(T zr10&!FIugJ=exGo41N1?(3Z|4r6RA^RxTm2>q$@T5uRl#C*qy3eIbvBluBCtg)1C4 zDvkvVY&{oY$e?oeD1{_aCejw>U=jAu&S$eruM{*x&lk!IWckU!K4GrwOOFg;r!vXz z5brYkUDTY;TUfv%!3ssk4}?=yB2ok@r?G@(6BjL9!U`cjg<-;c#L;=B8V{dJ6?F)9 zrkoucsd^w=N=Ow3fo~5KiYBfQ?vIPTI8BrNw}`|`fx}5$sCd#nY&UCe^itG(mMm3* zy6}%gg5DC}gH8GQx)` zvOY7_*#b^TSA%v`clUWr5tc_wu%KImkUVr->L6%w!&+r2-Kbk&E*Ht#grR|Z-1i0u zmw8m`l_w;xt9)u8&OacT%WtoL1%2Xu3|IN9=PBqXO!|d2KIeKkT*Eq_SOeE_gKg>E zO>Ag1?`~m{^>6du8r*I2-4;s>++o>WWcaJ!e!vo~Z{|<>Gu=*&S1wh eqKE6h9q(JqGAC^{kL~ViV29Tfgc5Pg$`I7tm{QYe&CpwL1-+L{U^4z4O7qH0j65J9 z;8%czK;nQn^EcqYuRx49A4)_N(h6Dj?yTR8-kX`7@4vr%1yICJ3K2v##B`iNoRB|m zyf$oCT7fGZqwa`yyJ6n8~*q@!xx}sO~+_n_1tO}=N4dWB$l$IVD z!d7`&+!5X-)@_EI&gq!P0zvmh*YQN7B1IqxRML85nP=9wTf_1P>+kTagg;J*K)eE~D!Yq`aIZ%efCFJi_958*Yc!gOhM* zwdH}==BuxlT-ORzlUdv-D^tb~c6fqBKv?FX8?HQSd0kME zJ13+b`T%{Xs$*0BDuZZ*EO}>UXU5-rGvi;sfBXbc$6N_H9Ds83F z!goDiL{Ufi(pBBicQ=Drx8GZ9R4cZU(6_F%vKxdiOU*;^UAVr``*(usN%&VO+S1fA z9d2@Mi7;fR#`3O%BBB0t6bmV+4>B~;6IR~Bb5J6zWx*2H6}TB;ghD-Nb8(fX(sDcQ zwxszcT0UEbn}H|%U13zB|1}oufrD3g&5*VBoy?Zmmzmleyf_c zFg%-Es&4UGtzue+YF1rKed^Th^12Y7S*iCo!R55;qvql3!hzmb&8#(;;;+q@0Q$jh8GE zQ#P!jozjt^i)O?&H_CU4VL2*a-jt^LcNHWyoH9ilESR=YtXE5hw->}u7aW~i``k1A zabq$e4$T_ryQ5gz+oH1!HHMg8VVDe6S8sKhtaGDbsJ*JPD;TCDjZZfZL)>+UY^FUC z+V4g(ue*U+i8T6mWwljGt$)`%u(_yvRN?pG{ftgAGSsQG{(}#lCe&X>^FWZrWl*zS z=vdkYLME-WAc8Z6O5DU~S0=-Y$c5+}I(DZl=Z7=ME;>e6`xdzkU3gLh?>co)H=fZA z!7$w32Md0OGV~RVn%Ht`bW$pL+crE|T7z^t-toM~5*@iQFx;ejDo$^@o@hKxqY4uA z1Nw5abK_sYK1qvP^z<(?#4||7M{t|Qxxfxt%+QEDXl9nM{I5C8`_}ZefFX*Y(znuD zTcoumnu*~K&E3U4dit@KX~y?ga-Wf;|G5)f_$clC_`UvGd`!j;u#`q@hWpaj$5@m3 z0GTF6&ztnf2}XZlDk@PBL7@wRx?nePre#{kwwwtfD}I6x z0f~pif-Mpsg}CFSQ6DB0R9W_n@7%|kb00r{eftie3OfS>i4>A1u3>_~I%*%=(o-Vz zxNAEu?{*KQD{R>bT>G)#^V+*gg|gLCf?;A?dQ$B$JS#Ph_#1A!+&esFRMqA$1aFJ5 z600!s^_&L*Db>sSX-p!WLdL`tOor;^@vKDfYHuA8DCv9Mk#mNO7)crO11LQuUArN> zs-igDs!QkZ4fierPH z5NF3?OgH7B$5k&RVjrFJx*f}&Lzh(CQ-SZhcEojrt+G>LNLKweIm$JpC-!=smIz<+ zmP?YEhVO89pNCTa4~0qfT6P&~jVoZAf*Z~O!(uGv(fy+zZ}KrxcjV5D`9BtDY#09k8&WBx0c#XckTkpv0crtdVZFqV)q z7GN67xI;2)V1T=rr#~{qJuFZFy}OS^a;$et$dm0d?RD_M*$SNvV62jC3J-=Lnxv_9 ziqiJOls5A)d8JmlcMAN(6QgvP{4=1MAp` QRs#=d%}`*?)h6bC12b^Te*gdg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundInnerClassesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundInnerClassesAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..2734764f9f578b2f183c0f0e4268ce0ab8405dd3 GIT binary patch literal 2819 zcmcIm-EZ4e6#rd2iIdd*AYDg4Hb%$B(zIPh2W2E(=^DB&BTL8Hj|(N4RbFfFkD}U*GffJ0JJ_{?AXp0LbCv zI3&mlLMpW-zE>5{3{>lMS)(?+#srWfsoRlerBjUfxNy9bFbit^*S+229MLz}@dc-l$WQOU&QQCdp zjY8h4*j)K5D$d|lhCVJ!n7(AW&Mw0xk{KABl5N#p&2nqDZKm5CSp{dg0|D_qgoCR; zr{X+bXXxkZh2|Bf*f33og=F5RUg*hoVbE=|O2{F5l00vZvuE9{ToDX$q%f&qO2srT zG9(12NQaf0YuJ?c3~{@{t<$zlO7o;YyH~b$^pbmEVFz2b2V=OT;tf!!B)h`!g`cz3 zDyBnlYSu`nOkcJhm`7#eL#!?Ku<(;zZ{jTlv)r_|DFxad^8#QvpM2mG7~r9(69w-u zTn@rHNO4E?#a4}NOLH3zp}FAmh|8VxsqVs;`7D(|&MuRr{(@oY#YS~Ych@^2o%5+zGHv&UUNGfVoN}s7fXF6)L)iVg4aK+TNDLTxcIF&5k)oTn<-PEhP<b$fMX)OqW3Lj%fshVtmzZI3@i$ z%@hoSomF>{_ZEV*sMp;aHg8O7`yS(0_vqm_Jax7xO)?Bu=#lvBKx>9Z90^&mPty&p zbF@=Ih<-pcH92+q8Q2d*%eYGad=`TA7ZmAl%+q_yJBN3%KySo>Ygi{xJ;-~y**&r%MrXcC{RrhZd`?R*JumHHXpXPp&8uTSW2`98 zhK538-{3w!aB2^yGhso6HxuJ~co82-fKCzl91+UyS4gdfE literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLineNumberTableAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundLineNumberTableAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..7ae631262bc68a27783f7fb88a1d39060404e231 GIT binary patch literal 2253 zcmb_dTW=dx5dOxuP2x>j+PD{jX$vjbj?<+948>_^6I!yB8>$8>A%w`rUbmZWcCGaq zsqgt6Jn+IRNL(r;ctzrszkmb}Eq5Wr1K~TniQ^=0f2X9&{uHCgD$hzIFw%}mwP$zU;qvo{3sxmyL;{Xm)H3~fTTrgGJ&xxKO zO_CJh9MW+Z;{v^9-F1Ddu@qWCC=jxJ1V=R-({UV+3nm`{m~;oE@~vq>s$dpP4NnNl z{b;wgGQ_~P$S}R8pTz{8)NukQ1qr_?m@b%Rv2S7?22su8DLk#=w1PP!7>n$8NfewZ zywd~t#>%Q)538Ftx@uJo&k8Do`o24n!%NOB&k8#MOYq{ZG|u!`->%+=hBI3woAZ8y zNC&pbiVO-4)%?2U-n0ToRnq2SD!lEme6H?W6FVDa|H7mPi8_;Us;}og)kVe3TGS_` zxvz4!*f-lrkZk#M_Q=ja?zXmqd2bMy!71IDsH!4&{r|Zc{(}#^Q<%!ao*EQrZPk|7 z>w=N(tASnWkTrpp7 z&kmxBw@G<^-}@ZrcwZ+Vc!pm>Jr*1beA5yrM(cdeIF`8LBgG#uTAD29zkrnFGiaZ1 zA&E);k8uQkfQIi0@*~QemEr@K!dcFE6b7E70VSQoG=Y`$JjQwU1{F5H^4JWJx_d`@i;DELJ+TM4^3OE?zo!c3Zxjr z6s8qijAI6~f~B6GwF5J`4iop`WkDoe%oG*8Bv|bQ(8+!bDa?7gny0R)kRHl9Vb)W? zAQq8UkcmUZlHi=LtY(@7A$w0SpZ>T-QFqD*dd1CUI#aqLxYA9U+KGy@y#=#l>|2`K zaH#gpzoBomIPk1c{sFjX?b*3}PVh`Jh${1_<(LzOuKGa`+~);)OB*eWLKE%RM+FJTu`ou zehZ;8x*l#~A9or-xMnlTv33R?)`FfPD4z!AOcH2sM!p!n`d`KH-@IjIvKUVqsNY`6 zUn1R6bnH9^>8)7oLH&B5W}aMQ!S?6?o$Z5~ks9S#D_B+bS$4I`17^>sQ9(ga=&*gJ z2%9DO#q%9&%I8cLIx^l>Q`%`-5y^<{*bS$m-{5sD7;P`WRjbBF3ik5c3%q-qYgcjY*tb8>#}BZpehcLnY;hRn_xyL5+?f0k zDR1F?^j>~?awK;D-g+dw9-U4`KF8E@GWry$kGMTN{RA)XJPOAiMdiz*-_+&rvEao= zz^{oM#HJ#~*yf?g0!C#K5=IZv-tUdPuNOBAEX^FP=G zJs)Sh@1Q{MXUN$Nu7!CGs(9CrnQ{z&>;}@r?4&_woJ{h*Iq%u?@to(JcmMe7=U)M=U^{{U zf(k+^!srqt4vUYHhUMtCrJ2cssZ}cbhN&lwqq3P?E>*4KlH=IMUe(bBU1`HIoQz;S zoERLV{7_MjU*3L+|cp$fJ-k7v>gFJCHX z=B{QN+McQ3e_Yn@yPLWrL63Q&Q4tK(qN+NEnamp%C#B$=V6vUhl~Pg95ezrZ0Tpi` zD(EXv*x=%7z7q>6*TkDDVi*$idQjJ}63n$X@CsHp63@=CiVGMKsAcW3S<;F-j%GUo z$whDxV+t;*7{_J7Oxwts4YR;Di}%UAAQaC{=M=mpm~UsmzXB0VVAAE+74nNrX~VEn zbX_L&VhV8u(<%~}5uEcFRxgzxP}&ztgXF6z2Ky#Tgy5pxZ_7r?Uc>Q*Ar*Q zIIuLQYLof*{^23r5X7sdX=6NR?Uz!Sl;Cs!)~U0pm^Jky-E#aJ=-+f0tLefl=+7IL zzF9rm(`~Ow1kq*?+|Hr4^Uz?gY_~03^JwU(6`6dGZWYW@#jp+pQ@#+k;=sZeSojHF z^+r5M-y?6VkR`s#b=xP?M-VKRnCVb63a2wfu-}Q9GgF~?KzXG2{(mLKe~*~mO7ffz z*81ormeF`iGjb{!gt}mHK6UFgc2n~v8@bJ7@E6vsS9G z5^Bz}bldA6oz>{5gK>j5SO9`q{zl!qkna=$_u{7Pnzv7S=V4sudV`WL5#mJv3?*jg zVxeb{ggk|knE4HTPtpG!PlA}|ZrMWn9W3A$y}7&h z@IJk`yW2?7j=M`^gqH4b@5WR+%kZog-3OE{V(BEdKhebxu$%Y+%J10VGRW`wA2FI9 z{RI=Q;C%Q&W^8mI^6R|B@kh5i%?_mUS=Z45Lc$`d(%(VGJU} z_qGv6KFoaYBFpHmQFt1}iEXY|$?ulzk;h|g|-Y-)(jg~NpRyl>8X&U2pg@#c@efB6l-96pI5gs_5$ ziYVFyiQVG!q+z+bV`*lxU~1*^mSO5iW3OZ;AJ`SEc;9s$W3%Gwg0>mMGTd3g<9K#g z`&vtynzbFcH0NDk)wQDTq#7!m+FH~~B`Re`H#*Rc4h1n4olpgt*T-|shqtJ^J9cqJ zbF@93QItIHpCxjAS$-)`J;erH&i}t=i`YX2$yW4y;vW~ ze(5Bd{Og!$k=RZ^GHPTjzm`Z7@DCpu?EIel-{lZhQAb9w% z5L!%)H{$%HeA`0#w&6Y}0tuJ7~74`Iqb=WEaP4o_@E_y=?)#>R(!h9u-A zlplEz#$EpJ<_gI{krh73YnbL)qIv=Mkm8P4F@q22z>{Y2Aq{)dN4UVd_bGeMtKU7~ zcU2g3JnO{ARS+^pi|y1g5bgGTs**XgkEUKIIUJ+>3DJMO3~&`ZF%;^Rt<2H z@F1Tuz|YVtpQB%%VpyJGM7}^$zQnYAg|y_6LCMG zFiOrJQHt_6z!PLB3Hp)6V=OS(VQOZ5Vn#^SA|;P|;0kY6r6*YBX$U#2`D+O4Tx0a>)xZV@{sD^K*M9&2 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..233fed31fa3a7a2d15704405329cc1663a2f5003 GIT binary patch literal 6219 zcmcgwTXPi089m+F-4W6Nx>&-B1cq1+LLe`av5Z-9kwCHqVkHm=+c-p{)ks>j+F8%e z0)jaBBHsvhY_KuJvANhrw&PGqRf3f`NhMFIPw&PkEI7$=*R0I)XXg)kT8IC6{-ArnUa4eyv(_`_3 z9*$3?65%c*lN{}|EHgfmv2=z|M?4v~wlM5$>N~6*(ZUHWIqq7tT`b?LYoodu@tu&v z+O4HhG^uyZ&?1y#k%BT6TfJNkj>oL-$E=96KhH8kE=9YFhp>@hQQ9&yF)L#dKuOb@AqAUAR6lpt zvYzi~WUuX5y~!~{L5GMPpBV6HGPgIO#w{wgVw+aquR6FZDu$BEvD!8atqOJqb-uJ2ahOtREXHiuq1C; z5ta=1H63&*z{ip@dKK(qxZh9dh1}gTw1uIB;&-cvqMy=%@X`S-HmQy4PC&F3<)ZF2 z(wFwA*o#4i#R5@6+54!@!R2#~*!zAJLpVTzla3#^-LAJBJMp;C#}f=@5!Uj^;Fv2< z;&^?5x7=DS5d}{&tSd&B{ge`gCd+XUhlIf2VMzU-1kQ4kxLT1xI$)<~J4j=cn)1HZ zX`0%!FjN^vpo;=Xks@;0knoZT6>%IU=M*-TG3fZn`kYY<)a!|+{0j2+VI+j6ri#;) zYpERtcWPJHo=H;%RiI)F+nG&oloJQz<4MiViQ5Zg=x{}5J~b4&mMb?#wnP}Z7KDl5<{99 z7ky_iU`@p7{L*>bgM{~V=6f034g{+vy}m)qP5y$tW57PR@CYb9AHP znKDSmTCe=msq7wxih(K4xpLgnD^B<)ANOwlH`J6U=m0V$51dhLip;sb$v^RW{K;Ks z$ph^5Jqc|*y<1C9QW3F7hIBJchaA#q7Swx&Vc6mO!e50R3G$^|xMGzDMpjl5f{vWA zNwTfuf!+Tx$)9JwJm8gCkQIkhkO{gLD2^u=bQTHX(VZ(f3*{|TFNOJl#VLSdNjm$K z>Ir>HPg)d9ZSGT0ak-XI^yDaod5YXI?CbZQ?Rbt6baAmSLDCzk4A{N&J}M!t#mVBb zlMsRymKov>jYGUChTz028*35nZMLZUZM}>G)i%0Fx zXi^D|(sKnAlH?&Md_7d&ib~#wTK)j)`39`y8*z;0G~1w<#&PNqJWk-dL@ZiQ<9kFd zS|_oRFrT5e5YT@2EWNY0`W%ftj~RLjLEC9u%u$99j0uDGB8;MO|EXiU7hp%Jxrv)gTE|euXlo#<5aS2Hx4oYPfMIn^6a|joT)8hiF zbb#!wy-Z@1;}r*R7xjc#6$GgKfz*E;4~nM1vsJ!?e!+K<%KK2xqb}SE2ltem%gP@+GLq6I2uu93+A#iQv%u1g{c7jW0oUo}jvr zAVvhEL@+i#!D~ctw=Y3$o}jjnV3G(DM39`H;0I)0`bI)DH3f*eqFgc}3}P zN7j2PLc$3*H~a<pS0{v9H7 z=p3A3p_w3?z4@o+mN|5b5VlvX-aNxNLGO%~vsU#3U>W-H2DLaE=o88rss|-#L>Jzqu>ej{C3*|z zXx=&cWcoIZg>Z>J(w?V;tx#%zM4|*>;0XuiD1FK~gA0W66|McDT>CYxeMhWiCA9WO za_wJoYrn{?{Zg)d7bPr%d+{DFBFIjnju=&1tJ7CGA#;F5@tDoVhA=>Emqm7DvrZ-~ zWfyUU<}q1VM1ip-ejkd%FIqOPMf(w%vmd25Nhu);QN|Q}z!>lkwBICggU;B8a;V2W obTvD)EjMdc4s9gWr3jYeBYZ4>Kf#aXFNdf$q6CWq{}a^x8_W>6=l}o! literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleHashesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleHashesAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..7b9b5d9c132c52789376782ac23b744cfde1d1b8 GIT binary patch literal 2621 zcmcIm-%}e^7(HJSvi#VV+BUTmu~MmqK#8=7l_1g}EvW&twD^DzEXe{(m)*=}qvEJz z9mc=GXJ35PnTj1}^igO0iyR-U=WasS=)$BA4ny|l?)}bpzVrRK`Qz`Oe+4jy54sUU zTth-f2aC%He4py*MN22?DM&7F;WyXLX#z zd4XOr_H5TEulR=N3#8DE3wU0`MIC*(Bp7)HV8JPm5Tg*Zx0k>Clyo$7-OX21Be6vcP=|W+6E#HI7$mkfss37KU3f7}5ttIj>{#rg- zs^j9z^UCBt4dJWG9VY$p6| zi|XGwvGQBTzzJMaRb;+#y3vQJP z>jlR#y`b*Y+`M%BC5Um}bTJ67^FOApS3W2BD~58R034St^H6S50Uc6diSxXHat-2iW5ir;989Ht4XR&Qa3z-sk2&eL|5YvsKD z?iSzGY2>*#hj;j?NKA5HozXLoN#rq}J3#7tevbtllIop!f$ut&-tf(99P>Oy47tLP zG}<_{*M5h22-UHEfd1+JUvPO*A#3Y1@ySFg(f=)`)RBP$3{G_ftKj5hazCCJO(pv3 zd#U6Bu0Fx=%0Mc)KC_>Y@1Fja8GV9lREb8KVp&&ek}*R*rc$3EC40R4KgFPYhKziU z3HbuE@+Icv5mx0Zta0CveOU5!5Y+;iPw-~EjXO-uEc&rP^^zE(o&~NFNZ~&2a>cY` z8SkRVs0Vp!F;JONHxyYSpNoh;rD=zTPSLO|RPQfL{~7pDn!ZQ8dKTWty+Gv^qN_JC OJm9mNUR3$4qVFG+N9DZ$ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleMainClassAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleMainClassAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..e1947927c803bf0a1bfb1d57725d71ae39dd732f GIT binary patch literal 1580 zcmb_cNpI6Y6#iZkvemSug+hS>g%+~3HC%d0RS6J?2Ar?@y{%NZl(&hOwi zfP_HezzGiUqY!VLg+wx;p~&(qZ{G5~^~cZ8UjUS0W)VX?g@l1~ND>MstyiWkmE}v} zm`z7?yKURCOuOSb<|8+dt%pkab|X+0A-QKuTkR8`=Bg*+wJ;qakH>_{TKt(MT9#jm zWEknH3D0AuO8zK=G%_h<4a~tH9Go7{MhLIwwgShh30sENM-~Wkp*MXvgzf4y&11+b z?0HF}nm4e3MS|gpp5uyET?tk1t>zKbKN-10+>_)|33{z$PIVy>=+u~F%RBdS;2AziGKNk&$DN9wiDV!tW z+xk8rCe%y2%lV!fyvZ_|o|Y0J)@&2jBV8U#12ZN&VU-XzBbi639uyNH?zs$hWzvzJ zH+1I3Y1HgRGW|WWrF}-6soTd=sKDoVzWF~rat1uyT@0x+Yz=~$o2}9aZ)ZsS8Ib;K z%n8}L8~9D@3C}FT@?<6M=pG@Y53Q~`aJ$^QMny`?539`LN?DsaLGXZwKn#S-JUR8w z1C#evzO|9y4@eh^TWg;{@A(|ZRbKUY1${+|zTq0*3w=IZ#~R;Q0yl7zb?MVBtZQyQ z-Nquz-{G?{dfVW)O{Tco*_%`$_#q-$UDdUBM#5>*ogoD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModulePackagesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModulePackagesAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..643fcfa8db489057b1fcd5c46c900a079088aa5d GIT binary patch literal 1636 zcmb_c?@!Y}7=EssjE%yODGmh{1>FkL_`y#jB)IrvW)R~HA5D(#m}RAH+N;Sv`)~M1 zXjDkl@YTdW%J^Pa$bbrHNYmc+z4ym+&pr44`u%MmKpkcQ8ZtR#bzH&_gR$N2nzk!N z;Bv>b93F;Swj)e?$9K%fUgWk{r3~!NND79bW!tso3d4&^bDO{8ro-LNKu}$UzY@GH zf?BG>VXigq`{dN9ZsakHd=3R2BhVS1ogdF!3~$YAM~-;OtuF6~@UQ^Gu%Fl%#`|C* zX**`q4rNUh9n(?7ID_ug<&+H-8^w+&{J^?rAniEJXsEt z43ErDvW~Ozr!N5&i!|pxZ*{SUDj;k|~MT>Jn4Qxz`7@8mGwOAxjT1YAh_y?135VD{`O6kim8O zj?oBh7dh=SbZrke$Y%5dFpU}dqfp$$Eh?a9w=qkJ)$9(&DfTYSRq_7X9If?X%#&>d z_Yx2-@>D)$;|p>>Q8WyijPBwxVNs@!v^I$6JK_0(lC~e?>E|yec<#r(tdtb05ZHdn XDgjpvEMPGnH9VlPK!p`oOPKltV~X0E literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleResolutionAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundModuleResolutionAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..886f9d0b9387db1c014449282a208a3f9a578b00 GIT binary patch literal 1498 zcmb_c+iuf95IyUdI7tmHy+MGs6k5ootpyM8kg5_ysxYK|XrRw*;!SXIY|CCF^#k}1 zK7bb_1QHK?03U^zb(l#k)H@mosN(_Sf$pKLONX6`&zwKsRv(S%%7q^WJiO zDI%YHR@>uo+;Kf&xxLV{o(GBVJd-kVTZt45*NeZ$Qvk_n1RV)pC8Xg3hy9r5>Fh7IPenb2L3Pv!%Uh^9}mNJ zW18y`=r*NZQ?Ra?n8h4}8S+yv;7(KWNHQ?HfO#w!STwPOWrpen921EV5%lIUgI==B zwt<@rPbZPd&v>_{q^Q>ehYB;>aD8!@^jac%&08Kx<{Lqqd&fL-)p;P)CVF9V3ig=!rQdwt*IU1BIxD%%X7E>P9WfcR%Z84ArHiP~bH z9vFs&@kZNGGr*8L6tR2}#58B7?fW81dq_~0tJB9Fk7!~wFx;SbPObF3(ORTa2Ri+L zT&23T@*V68?K8MVU-cM5TZEx4;WnKseLdX43Z2LTt5_pnYIhgwN}G1~Fh}Shi zHt24XBpM!&>>*0@Rk5FtMA@5_uQ2F;^&75#PW4p$th&>RY3#l)a}Zk}cq41 zZO7A6dBU~pt_Z`X<4W6U2d@3Z?|6;JS}SM2qa`7|?s$&gAZ+EU2jZQuUE#Hk7?q9r zODP&sm0}eJzP3dWuu^4tFN+amGssyOg+JsdHWjU6py6=TrcslTX*B%&@GPp{35J$Z@%#wWqA*r(8;1o_&9Z&9b+WS)NihY+Q zQ&qn%+&!TjbM6aM`i&D3o(<*gczFy-M~RTAHwg=|u^yqH71QmgGzd$v%7Ya5D~ON` zd`3ERJc@2`7|H9?xLJ=?`Uj__4ThVoIW14bdA9a%+^bf_^Q4NZOLB$G zojfjZpF2JQ!WEv8X64by>nxv|NbwICDXgr{e+7NweG+s0HG>rN6B+u2YkV&B^l%;X zd}0gSz)kjLcDJx#w0UMBYRizSv2nszARB_!TPH}P8mc2pBf&aiy z0SSS`fgivL4*VU&tn(m|Ow?2;ig$N*9^cG-JKukQ{RW@{D~AM<22v(2AWbNqw%%Bd zRCXYRYc*XFhHb~SEvMtV)+4VgTZc*oPNS=ALVDkkjyfPb%hyiDTVc6Eo{Sk)wD}8L zwCtc9t1$BQT=+gKRSU;iWRNwGGcgB~aCmk+TM@h?J5*1-P>oy@=AtzEI0(D7X)ebg zS2^XfhBI$s0gD9F7d_V#t-2C{B2YDlB`h1bY~l)52&EYu6XpXhOcd_1R6&n$KVL1x zR;lU9PzkAg&vUK67G(q12v%I-#jrUJ7-@KQ8fmMqo0rf`o% z;OO%}m{PBukWiUgwMk<9qY-67qS+>_$0j*ecvehzB0>~D1)eX3U@BYs_I1dnhI)scIu%CI6pN&j}_cOHkJP2p5 zE+JR>O?*yy$Z&q2RVnQtB9g7i5I+y_fS+^%gsVIN^~!UP*Hu2X zk>VeaDVBEDzJNaRK8fr6)l(Am0|x!X4L%q9dbo)-KCuOE;WqoyyE|Cd+PvGqBHM5B z-W=U+@!d8{61dBFi#^>ze9|(Y31v+c95yh5Q3k{3+pfnuEy)APz#4fv95YbF8HPeYU-Cf6U|Yp86f2GD{$x7F z8SZ3p!FOo0vJnopoDIQc6cDd>_obcBB(Lp>P;w!C&vUJq>KI&Yp~jG_dmTzN(sYEq z5-B#G@HLk#V@OD2)PkpJHvFQbFYD^ zJQ(_XkARNv{fKRU=R=+zCrvh+hxaEY^~K4k{6Fi{-C!6Jf8HeGP1KDNpEK7j)-E&x4bB5+ekfFJYn%4egn!^aFwqN* z7hY@PN8*LICjKbnd)h(xXmCc-wCD8we9rqm=l%8j`wsxCu#3pSC?Id*42Br2?e2~( zJtabqySC%?8YSuSKFpQA`iY7*3GPDNAGn>GBBEp_jN_5+CCxI`b{VWU>%5qfA zP)@xw_`Yi=ZAd^imKzNDRliGt zN-gP$^|;p&;WOTGNixy$9qw-MQ0o7_Ft47=h++Ly8$l>?&L%@O6Z}Ei5XpK8HyGwJ zjrW_|rx1e?_ylm+0*5P|f;n zUO8rzo%$qVefS5CWJe#kz?nT9(3_#y_T$hI4{5N`l|4Mw7WGAC7+x2VdgSXnZ8kkm zgb67H5v%&wF@rlaA#z|iPj61oF*8IZEH!zERLE#e# z3|yq|IIS>VqhP#(X}rNDl3A$(E@OuN$Q4&`l@jRPHB>3E-d#tTd~eWRCr@>=q)TDU zk!%z<`ykq6scojL&nWyv$+BoO_7!Idixzz(-9bEW3C}xJjQ0tiH2zc{&#lCkRr-l) b1U5}sC*ZmQ^H@mM9B$KEq{O;bi786B+(OVLKgTKIEV7w5Ynb|J0WmA?5vzdM0dFMUnJm)#jdEY<& zee^qk3f|2jgRBZgLm&DDh4tD-(RM>Ca1EzuI!2?hW;<5VuKP~$oY!<~i(weptIg07 z^e@=19hL=`^VN0ZrcrbZ_eRR75}9AKjG7gcx^8Iux?=b~H|eu0gBZY|ikyZaXo54n zpv9I0*>I+dDE zYGOaTHH>0Rp!vov$1`fnp%H`v(R0{?msCt>*o&71hhM-kNe)QhhsOmzrD_H_+2QL3Yj4cl*5 zdC7Aqg&`coAr*NIvnU8g;$+$t5oElzDAdO(#k{w=Zkb_ec5C%i%&}0tu+hdK7+kh* zxJK9vsNf4*JT9byJ{AAA)RxL6)~4ds=x#^VcCD+;`l=OtV5~Y^*BN7_-^^j9 z7dO4p*^V7k`RVgT_Wy*YbXl+bGa_RL+oZ#E*~UbRABzF?RqgSkPb zV?C%iE4cJb+}^nB=+&6N+b^K1-eRQd)0O(I{qfX5kX!befoWajCBoyNQ`ASJ&Lyc= ztwy-yHOQ}~yRH?)%C)GzvDB&5c8X&>voqj1$|nyv~b^W05N!6#jtW z!r{58Umykf8S0N*$l?wDk8p&14pnaRuK9wFfkI+{<9L&AG{rnlFhDdriMQxDnw`QJ zZBKI^1y8=c&2I^e64!>X&;s!n;q-COO5rD{k8y>=FrQryFupMP8z!TLU47Tf*^|n+ zGWk7b=Ejv@G4)ZjkD#ZQWk~&0UPj zJxs`#n3k`Qm#=Y3zCnd^UB1Qp@?D(iJW=h(A-uy}6y98A{>F%Wf_a_6S)!jN3yX24 zMBifM9OF$O`-G-_Dh5QQUo!9y4*m_bmH&DAOPIKTi`<{VB`n2b20F(aqeLaVjJ^K> D3L|gw literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleAnnotationsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..a1ff16e343e155dd7cab3c56ad6a33d7e1178a74 GIT binary patch literal 1662 zcmb7E-A@xi5dUqja_w<^SQJGNQ9)?=I6>5h5)vRW)KngT^nGa$TsZccyFDTg>c6Ck zAH)Y=P5h&bv)9ssp0zw|r#m}0^PBn2%+Funz6036a|M~-2)dpwgdyzPG%r4@}KBjmovm0M#NY#@u2@SL&;RZ%0jVdEx- z8G7T=H&S4jFLy$7A=?sFEB15S#t7~(*mZvD`MkEHc%T?q$-)@!ni#in4-*V?ogBA$ zJqI!nP*K}zqI>!O43wG;(azMw1BUgaF5%~W=5$xj?2b5)Tt$J)u=GbkSCXl3HEVIT z$S~Cn{t82S!>>_{fwGY9R&>1Q2D_YEpCMQFtK6&bKeqw$Xx`7OPc`IGQlRKZyHWdtg)Em_!8iXeH<-d%&D&&_dE$D$Ar6)(IS@UDTOCkj%5Z>>aF literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleParameterAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleParameterAnnotationsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..0a3245919797171e8f6f9e87c312ab3ff4b00430 GIT binary patch literal 1826 zcmb_dT~8B16g{`CEtFLd5J5#nL7{xC8skd|36c;il^8I*88fs43~pyPyR#(x6#s=L zCK?}nHvTB%ooy)~n*xn#wsU9Zex7?~=J%f;KLM=ZNf8-j3&=URf;^$LU;pSTZDgp0 z=hi$CMLWuqu4)9H`_hkfec6~$ZO29u@{39gfQ31 z@o{QLiHwGfT3YIa=jUTxnQ5XO8|ArG6`67YqlC4z9*LuNx|c*Qx8m2C1N~K{<$B!M zmf<_WcoPPzeoc5=B2;$XTFjX}6%jsk1o$++y69(_kg4quCQ{jUqJONIZzP-}OrqW$bUMY8maOBsr7#+$)}ny z9HbmXCd>30t`b(yEVfc=6FNP`<8#E&Sa5z_f^O+9yKhY@(%rfv6gT}itjSfrj0r=h zPs)Nl*o2;S8JSmp#P^R=(OQNH;U$yy+2yZBJmuRh1Hw&yC+x`21CL`o+d+9Q zZu}eQ3(HyD;(z;?AiIY`R^c|!OHDo8!8p&@0(WtbeOc)~Cag9~4=}*?4_S8Fdy~93 z#VZ*+;!rzw>%n^?_Z RJ{dDu;IYW|wrUq+e*ycoH*Ej_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleTypeAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeInvisibleTypeAnnotationsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..ecb528d66714022126d31b8d70c1217c06c39dc7 GIT binary patch literal 2384 zcmcgtTTc@~6#k|cme%DWD2g{gL`nhIyGRj5BC%LW1VW4tCPO>o=yta5PL2K)e}S)> zXf&D-ef7nEB%a-t(!!>K5+8QwcIM1?zWL6aAHTk=1DM535)niV#7xA|!jOJecy39h zg{!!20!)E&$(Vq#1i)E!{ zQDoIi>B&`FEWa*^8KoS}wRDtM!^dFSb;lA2~!wXBAyPAPzlQ@cA1IJ7p#|eh9X6Uv8+yv6?(j{$+o#FAH zZ#COAf(9B!DheoTX5PF>40B<+;hPe(c7H!F!ok*VuyDr~MWJ-K5bL-OH>mm9 zQYu4i)+taLbmXKG3+3XfaF;oWh@mUzlTl7=uF+6I@+rKC^!;lav zZ#$k;YYfB9^RC7ULnQx%VIb7Jo*l~iVvwv1L!rjonPP~R916LokrPU^Dlg7%+)RZU z?OiCDX(FhN(kB0$ZZbe%-~z=Gro&n&n=~1?#LyRJT1SzAD-45SMm2vG5z$R8$u-4w z*(J?<{jUPvM?UG%riYDhy_%%|)Q)UtnAkBH4x;fL3NCDY59t!_^skh%Uz%e`E;(g4 zFXpI}GITfQ_c>oG46O^o({~+@o^vy+lyCz{3Cf)DJ(Vh4pn4Ml!%6zO{JKbm-XF)& zM{Pfiejsld^2gI2dqM*=GYS7|ANYvgPK*Q-HJl0zRtXZiy==mI6>5h5+afqYbp;w`o6RaE*yK!-JXg6f2VYJ6ql~lH(t_4n9`@#Tc6R2QZ)W!AuW#Q0Y~Z1T6f7HQ7Z=dOFn+*aa?j^# z->djMiuR;0ymhTZxf^Q{F^q(<((*`@Wh8ffv9460xt4*Vv+0@HQpfwxd95bGf`bgQ zHXIkda2fIk)k9AzEkecpQ(@&%&G#M$v8px!F!ZcSCG{G^vzfNBHVo=5!K)OftwGaQ z159zYoJBtdYz(@%h#bRK_jo1~cw7IXq#27LBh{YIwWu--)^WvJ`d&#!x?tj8a&Z~M z47~~M^#m9eN}aHr%C$&bC4R2D7{N6Lx5i)j0k3Xr9%=?wbTEeNHpX4tzy!m5C&#U- zo&XsLiPDyuioNoG{)>%vXk}{S7Q>@#I)My(c{5o;lRKHpRv8%js4psqGy)CeD}NbvMdPP)WZK^0dFoD;Yn%PK zd@wlMK^#`Z6MEVhhR&8_(ex%w>!yhG(;%YBaf?ccFd^8yf74w~JeFvvGoXUeN|}d+ z?`b#iQTl(ku9v($XahOL;H!kC1#PQojISw zJozzyH1~<;1uT*@p37uy&PMZ}(f0$nJjo$iSB^3I1${>QfsQShQ2oZW^%l1E4#U>_ pB%E8n-U#O9da=8XUV literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleParameterAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleParameterAnnotationsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..cabdedb152ef787da2d1befe4535795617c323cd GIT binary patch literal 1810 zcmb_dT~8B16g{`CEtFLd5J5#nL7{vsCdQW%5+otk6k@31L1N6%4mh}--R#bq@Jsv~ znwV&O@X05Cl=05C6p#&2Vw&yTnYkb5o_lBJ_n#j>0jy%Nhzzm?1Cvd~lUE zGStFz>z;_BUFAtvH3QFm?#H^ZVoa!ZVj~IpC8d>FCcK=k?u(DY^@QF#X0&R}H>GIE zu$-#U@wG03fR!pUTfOK(ZvjOIeQ*fd7soT1z}t+qQBAp}BDLemS0WTm$=R%E?Hgf~ zucJ;-LSK?#3n5{?dRDMw$yAt(vITn0K|clvP9P3EUo>h)goZ$sA_g&3z_5cG7$MA^ z<@gBNA&}9KIZK01czQn5m6;aTu~D8|RgozdFiNPTRY)8b)9s44+^XN;`uA6rmK$+% zM~1HjvrQPR`gP%LiBQ>jdogF;tBCOSOnOiDR@b#G6EgK(!bEDH9jhHH=9@{k5vEd= zJN?maNDKyH)iQ$0#pJGIyb)M?~&fJf(tiLuoD>Y~xoU0${x{nE~&C&x5u>C`pozC7Q z?@jSa29J2{F{W9vv7hm1?VZwB6!^RP9oIi6dNzLE?q%O4v0J{JcI=j~8OGC+N|;To S<}ja(87%NvWP6*ni?P3S-!OXs literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleTypeAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundRuntimeVisibleTypeAnnotationsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..5499f796e9d59d16ad1d8de27a3d17b03c5e2d25 GIT binary patch literal 2368 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 VV^UsA*be6ec6iRQor<=MwZDVX$Aka? literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceIDAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSourceIDAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..6767873aa11bce232959545927b0b85d8be534f4 GIT binary patch literal 1520 zcmb_c+iuf95Iy6BI7uB^S|}7KP-r2SHWn`kDOIHsKp2HS5U6Y|Gvt<$-_T zQ$Ru>@xTZ0QHWV5jS|UJO@%D)Wp-xv%*@&O{paT|08N-hXvpZu8n}QQp?Yk8FkN3d zkuN;6>xnq-xt?RX{m?U?1OwmRmojoY1L+WQyRPrbJ;KX!>sWjgrYHQPDWj$`f9(j{ zi5jU26JM`H7_yR8IV>QLf{vnr1sH_=v*X!J;I)H6)OD<<6W4@=B#aRb!cOZnms5}} z4!NP=Tr{wVC4v!(p%)0dEkz^=WEHWD6&;riT)`@#Hiu(EDdNPumA%K$d>IW1X4$Hw zCaD|vu@t@xgTON<1`Qq8*eEUS;-o@mN;0y|z~<5|wp`yi81y?%^hR_%mMph|uJ8^; z;w6FLyKQk5sA9kYgz2?IvCIvc?- zJc;7nS={WVDxH$c#vVg0wA~|L$U(#z{Pcfb!Fho2!y)A35%+CEy*w9}2%qPu@Oc2v zom@h3#NOxJeh4eGB&#dlbHoQuEMEjMzedCIeJ4tIH6_pE_%mAjvsx#{t| z#=9P}`~mrDZF~I(=qs-?xXz<$k0i*tIwR<`Gfv+eJGFh#@y~HQ_a?y&Y>yo*{D9qSxz8*N7%WFEo!wj%a%E7)3b9|-MUk~5(K_gt_PB^f5vjGV3u$_ zUD^;2Ma~w^{m`L;I(|!vs`T@b20OkMh3BzRaeTE0-RLopGI0PVVZL)bV;bH{ASw^o z-EC2}<&J-XAsxmoYlOZAlzL#2ZD#0Tze2S#m4F=F*>!)@hiNa4nna7{!;WJI)jCMV}8L%ok&G zX=5;?8XakTRiVG2l>ZeArlp3DLN)LWVLD0+qSchS7U{e7-?L)fcSKP4xo-=*BF{uB zWv@@oWzku4^Rsz^$7I9|i&m#ZcYc_%$mlz*`*Ac7lFBI;wq!YSslHj3zD|?L(iL76 zzNOl}`7s%+TU_*oSeWfIEpCQz%1I?;!s%F#JBbq#m9>BC!!QA=Y4rdkoa%@SZdcFc z)CSwre(beUzuSqMPRrgdC0+Yp{?FR~XPkVU5PI7>f-twIuR8VLF8`lnMbIv*P9yAL zIM6=uv%ELmaE42`%>S`lT)|Zi zu2uzHTxHeesrA>Xi*w@BlihT905ZNmLQ+fuq2y~M~GI2N(Q WTL~=VhJGh-liw*uqiDZ{V;=yB?C0YE literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSyntheticAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundSyntheticAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..60c2a32c37ed7a8680495e669cc84b43c6908c3e GIT binary patch literal 1178 zcmb_c-A)rx5dNlJ+gd9q|DZ)lFwsI>xGo`~HO89Cg*7Bxo^DU!;P&ih_pC{8cnIHw zD-$nx0Nw!}#W=ey4aAkSXg1k1GiScpnQvzH;@8h}0Cl`9B7yz+(c51vi$fH20ji1GOl2og&&9OAf8AZ&aNZ3ltN?aFU|A``4b+5yvO*fU6 z`%$kggD;}(vSp^}Il?^B)n_>d%{&h#_1B)Qkl9*B@^FE_#(VYbsmv0 zq?M5MJx-GvgoWE>^!@8n4#x?#lj?LAqt#t5>|skCXSAD}aqvncU9{viODjJ(2QmMQ~3OktWeM&Jpaa;#XI!EEAP rz#Qfozrfbg=x&kkme`WPGRGK5D|nVzo}-+c8LaYIWK5jt3oQQzqq1hE literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundUnknownAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute$BoundUnknownAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..6d3cc577a6c4b6b67c4595d6ecd26f1f5de3b638 GIT binary patch literal 1162 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.java b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.java new file mode 100644 index 00000000..6fea4e44 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/BoundAttribute.java @@ -0,0 +1,1066 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.classfile.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +import java.lang.classfile.*; +import java.lang.classfile.attribute.*; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPool; +import java.lang.classfile.constantpool.ConstantValueEntry; +import java.lang.classfile.constantpool.LoadableConstantEntry; +import java.lang.classfile.constantpool.ModuleEntry; +import java.lang.classfile.constantpool.NameAndTypeEntry; +import java.lang.classfile.constantpool.PackageEntry; +import java.lang.classfile.constantpool.Utf8Entry; +import jdk.internal.access.SharedSecrets; + +import static java.lang.classfile.Attributes.*; + +public abstract sealed class BoundAttribute> + extends AbstractElement + implements Attribute { + + static final int NAME_AND_LENGTH_PREFIX = 6; + private final AttributeMapper mapper; + final ClassReaderImpl classReader; + final int payloadStart; + + BoundAttribute(ClassReader classReader, AttributeMapper mapper, int payloadStart) { + this.mapper = mapper; + this.classReader = (ClassReaderImpl)classReader; + this.payloadStart = payloadStart; + } + + public int payloadLen() { + return classReader.readInt(payloadStart - 4); + } + + @Override + public String attributeName() { + return mapper.name(); + } + + @Override + public AttributeMapper attributeMapper() { + return mapper; + } + + public byte[] contents() { + return classReader.readBytes(payloadStart, payloadLen()); + } + + @Override + public void writeTo(DirectClassBuilder builder) { + builder.writeAttribute(this); + } + + @Override + public void writeTo(DirectCodeBuilder builder) { + builder.writeAttribute(this); + } + + @Override + public void writeTo(DirectMethodBuilder builder) { + builder.writeAttribute(this); + } + + @Override + public void writeTo(DirectFieldBuilder builder) { + builder.writeAttribute(this); + } + + @Override + @SuppressWarnings("unchecked") + public void writeTo(BufWriter buf) { + if (!buf.canWriteDirect(classReader)) + attributeMapper().writeAttribute(buf, (T) this); + else + classReader.copyBytesTo(buf, payloadStart - NAME_AND_LENGTH_PREFIX, payloadLen() + NAME_AND_LENGTH_PREFIX); + } + + public ConstantPool constantPool() { + return classReader; + } + + @Override + public String toString() { + return String.format("Attribute[name=%s]", mapper.name()); + } + + List readEntryList(int p) { + int cnt = classReader.readU2(p); + p += 2; + var entries = new Object[cnt]; + int end = p + (cnt * 2); + for (int i = 0; p < end; i++, p += 2) { + entries[i] = classReader.readEntry(p); + } + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries); + } + + public static List> readAttributes(AttributedElement enclosing, ClassReader reader, int pos, + Function> customAttributes) { + int size = reader.readU2(pos); + var filled = new ArrayList>(size); + int p = pos + 2; + int cfLen = reader.classfileLength(); + var apo = ((ClassReaderImpl)reader).context().attributesProcessingOption(); + for (int i = 0; i < size; ++i) { + Utf8Entry name = reader.readUtf8Entry(p); + int len = reader.readInt(p + 2); + p += 6; + if (len < 0 || len > cfLen - p) { + throw new IllegalArgumentException("attribute " + name.stringValue() + " too big to handle"); + } + + var mapper = standardAttribute(name); + if (mapper == null) { + mapper = customAttributes.apply(name); + } + if (mapper != null) { + filled.add((Attribute)mapper.readAttribute(enclosing, reader, p)); + } else { + AttributeMapper fakeMapper = new AttributeMapper<>() { + @Override + public String name() { + return name.stringValue(); + } + + @Override + public UnknownAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { + // Will never get called + throw new UnsupportedOperationException(); + } + + @Override + public void writeAttribute(BufWriter buf, UnknownAttribute attr) { + buf.writeIndex(name); + var cont = attr.contents(); + buf.writeInt(cont.length); + buf.writeBytes(cont); + } + + @Override + public boolean allowMultiple() { + return true; + } + + @Override + public AttributeMapper.AttributeStability stability() { + return AttributeStability.UNKNOWN; + } + }; + filled.add(new BoundUnknownAttribute(reader, fakeMapper, p)); + } + p += len; + } + return Collections.unmodifiableList(filled); + } + + public static final class BoundUnknownAttribute extends BoundAttribute + implements UnknownAttribute { + public BoundUnknownAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + } + + public static final class BoundStackMapTableAttribute + extends BoundAttribute + implements StackMapTableAttribute { + final MethodModel method; + final LabelContext ctx; + List entries = null; + + public BoundStackMapTableAttribute(CodeImpl code, ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + method = code.parent().orElseThrow(); + ctx = code; + } + + @Override + public List entries() { + if (entries == null) { + entries = new StackMapDecoder(classReader, payloadStart, ctx, StackMapDecoder.initFrameLocals(method)).entries(); + } + return entries; + } + } + + public static final class BoundSyntheticAttribute extends BoundAttribute + implements SyntheticAttribute { + public BoundSyntheticAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + } + + public static final class BoundLineNumberTableAttribute + extends BoundAttribute + implements LineNumberTableAttribute { + private List lineNumbers = null; + + public BoundLineNumberTableAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List lineNumbers() { + if (lineNumbers == null) { + int nLn = classReader.readU2(payloadStart); + LineNumberInfo[] elements = new LineNumberInfo[nLn]; + int p = payloadStart + 2; + int pEnd = p + (nLn * 4); + for (int i = 0; p < pEnd; p += 4, i++) { + int startPc = classReader.readU2(p); + int lineNumber = classReader.readU2(p + 2); + elements[i] = LineNumberInfo.of(startPc, lineNumber); + } + lineNumbers = List.of(elements); + } + return lineNumbers; + } + } + + public static final class BoundCharacterRangeTableAttribute extends BoundAttribute implements CharacterRangeTableAttribute { + private List characterRangeTable = null; + + public BoundCharacterRangeTableAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List characterRangeTable() { + if (characterRangeTable == null) { + int nLn = classReader.readU2(payloadStart); + CharacterRangeInfo[] elements = new CharacterRangeInfo[nLn]; + int p = payloadStart + 2; + int pEnd = p + (nLn * 14); + for (int i = 0; p < pEnd; p += 14, i++) { + int startPc = classReader.readU2(p); + int endPc = classReader.readU2(p + 2); + int characterRangeStart = classReader.readInt(p + 4); + int characterRangeEnd = classReader.readInt(p + 8); + int flags = classReader.readU2(p + 12); + elements[i] = CharacterRangeInfo.of(startPc, endPc, characterRangeStart, characterRangeEnd, flags); + } + characterRangeTable = List.of(elements); + } + return characterRangeTable; + } + } + + public static final class BoundLocalVariableTableAttribute + extends BoundAttribute + implements LocalVariableTableAttribute { + private final CodeImpl codeAttribute; + private List localVars = null; + + public BoundLocalVariableTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + codeAttribute = (CodeImpl) enclosing; + } + + @Override + public List localVariables() { + if (localVars == null) { + int cnt = classReader.readU2(payloadStart); + BoundLocalVariable[] elements = new BoundLocalVariable[cnt]; + int p = payloadStart + 2; + int pEnd = p + (cnt * 10); + for (int i = 0; p < pEnd; p += 10, i++) { + elements[i] = new BoundLocalVariable(codeAttribute, p); + } + localVars = List.of(elements); + } + return localVars; + } + } + + public static final class BoundLocalVariableTypeTableAttribute + extends BoundAttribute + implements LocalVariableTypeTableAttribute { + private final CodeImpl codeAttribute; + private List localVars = null; + + public BoundLocalVariableTypeTableAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + this.codeAttribute = (CodeImpl) enclosing; + } + + @Override + public List localVariableTypes() { + if (localVars == null) { + final int cnt = classReader.readU2(payloadStart); + BoundLocalVariableType[] elements = new BoundLocalVariableType[cnt]; + int p = payloadStart + 2; + int pEnd = p + (cnt * 10); + for (int i = 0; p < pEnd; p += 10, i++) { + elements[i] = new BoundLocalVariableType(codeAttribute, p); + } + localVars = List.of(elements); + } + return localVars; + } + } + + public static final class BoundMethodParametersAttribute extends BoundAttribute + implements MethodParametersAttribute { + private List parameters = null; + + public BoundMethodParametersAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List parameters() { + if (parameters == null) { + final int cnt = classReader.readU1(payloadStart); + MethodParameterInfo[] elements = new MethodParameterInfo[cnt]; + int p = payloadStart + 1; + int pEnd = p + (cnt * 4); + for (int i = 0; p < pEnd; p += 4, i++) { + Utf8Entry name = classReader.readUtf8EntryOrNull(p); + int accessFlags = classReader.readU2(p + 2); + elements[i] = MethodParameterInfo.of(Optional.ofNullable(name), accessFlags); + } + parameters = List.of(elements); + } + return parameters; + } + } + + public static final class BoundModuleHashesAttribute extends BoundAttribute + implements ModuleHashesAttribute { + private List hashes = null; + + public BoundModuleHashesAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public Utf8Entry algorithm() { + return classReader.readUtf8Entry(payloadStart); + } + + @Override + public List hashes() { + if (hashes == null) { + final int cnt = classReader.readU2(payloadStart + 2); + ModuleHashInfo[] elements = new ModuleHashInfo[cnt]; + int p = payloadStart + 4; + //System.err.printf("%5d: ModuleHashesAttr alg = %s, cnt = %d%n", pos, algorithm(), cnt); + for (int i = 0; i < cnt; ++i) { + ModuleEntry module = classReader.readModuleEntry(p); + int hashLength = classReader.readU2(p + 2); + //System.err.printf("%5d: [%d] module = %s, hashLength = %d%n", p, i, module, hashLength); + p += 4; + elements[i] = ModuleHashInfo.of(module, classReader.readBytes(p, hashLength)); + p += hashLength; + } + hashes = List.of(elements); + } + return hashes; + } + } + + public static final class BoundRecordAttribute extends BoundAttribute + implements RecordAttribute { + private List components = null; + + public BoundRecordAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List components() { + if (components == null) { + final int cnt = classReader.readU2(payloadStart); + RecordComponentInfo[] elements = new RecordComponentInfo[cnt]; + int p = payloadStart + 2; + for (int i = 0; i < cnt; i++) { + elements[i] = new BoundRecordComponentInfo(classReader, p); + p = classReader.skipAttributeHolder(p + 4); + } + components = List.of(elements); + } + return components; + } + } + + public static final class BoundDeprecatedAttribute extends BoundAttribute + implements DeprecatedAttribute { + public BoundDeprecatedAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + } + + public static final class BoundSignatureAttribute extends BoundAttribute + implements SignatureAttribute { + public BoundSignatureAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public Utf8Entry signature() { + return classReader.readUtf8Entry(payloadStart); + } + } + + public static final class BoundSourceFileAttribute extends BoundAttribute + implements SourceFileAttribute { + public BoundSourceFileAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public Utf8Entry sourceFile() { + return classReader.readUtf8Entry(payloadStart); + } + + } + + public static final class BoundModuleMainClassAttribute extends BoundAttribute implements ModuleMainClassAttribute { + public BoundModuleMainClassAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public ClassEntry mainClass() { + return classReader.readClassEntry(payloadStart); + } + } + + public static final class BoundNestHostAttribute extends BoundAttribute + implements NestHostAttribute { + public BoundNestHostAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public ClassEntry nestHost() { + return classReader.readClassEntry(payloadStart); + } + } + + public static final class BoundSourceDebugExtensionAttribute extends BoundAttribute + implements SourceDebugExtensionAttribute { + public BoundSourceDebugExtensionAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + } + + public static final class BoundConstantValueAttribute extends BoundAttribute + implements ConstantValueAttribute { + public BoundConstantValueAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public ConstantValueEntry constant() { + return classReader.readEntry(payloadStart, ConstantValueEntry.class); + } + + } + + public static final class BoundModuleTargetAttribute extends BoundAttribute + implements ModuleTargetAttribute { + public BoundModuleTargetAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public Utf8Entry targetPlatform() { + return classReader.readUtf8Entry(payloadStart); + } + } + + public static final class BoundCompilationIDAttribute extends BoundAttribute + implements CompilationIDAttribute { + public BoundCompilationIDAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public Utf8Entry compilationId() { + return classReader.readUtf8Entry(payloadStart); + } + } + + public static final class BoundSourceIDAttribute extends BoundAttribute + implements SourceIDAttribute { + public BoundSourceIDAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public Utf8Entry sourceId() { + return classReader.readUtf8Entry(payloadStart); + } + } + + public static final class BoundModuleResolutionAttribute extends BoundAttribute + implements ModuleResolutionAttribute { + public BoundModuleResolutionAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public int resolutionFlags() { + return classReader.readU2(payloadStart); + } + } + + public static final class BoundExceptionsAttribute extends BoundAttribute + implements ExceptionsAttribute { + private List exceptions = null; + + public BoundExceptionsAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List exceptions() { + if (exceptions == null) { + exceptions = readEntryList(payloadStart); + } + return exceptions; + } + } + + public static final class BoundModuleAttribute extends BoundAttribute + implements ModuleAttribute { + private List requires = null; + private List exports = null; + private List opens = null; + private List uses = null; + private List provides = null; + + public BoundModuleAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public ModuleEntry moduleName() { + return classReader.readModuleEntry(payloadStart); + } + + @Override + public int moduleFlagsMask() { + return classReader.readU2(payloadStart + 2); + } + + @Override + public Optional moduleVersion() { + return Optional.ofNullable(classReader.readUtf8EntryOrNull(payloadStart + 4)); + } + + @Override + public List requires() { + if (requires == null) { + structure(); + } + return requires; + } + + @Override + public List exports() { + if (exports == null) { + structure(); + } + return exports; + } + + @Override + public List opens() { + if (opens == null) { + structure(); + } + return opens; + } + + @Override + public List uses() { + if (uses == null) { + structure(); + } + return uses; + } + + @Override + public List provides() { + if (provides == null) { + structure(); + } + return provides; + } + + private void structure() { + int p = payloadStart + 8; + + { + int cnt = classReader.readU2(payloadStart + 6); + ModuleRequireInfo[] elements = new ModuleRequireInfo[cnt]; + int end = p + (cnt * 6); + for (int i = 0; p < end; p += 6, i++) { + elements[i] = ModuleRequireInfo.of(classReader.readModuleEntry(p), + classReader.readU2(p + 2), + classReader.readEntryOrNull(p + 4, Utf8Entry.class)); + } + requires = List.of(elements); + } + + { + int cnt = classReader.readU2(p); + p += 2; + ModuleExportInfo[] elements = new ModuleExportInfo[cnt]; + for (int i = 0; i < cnt; i++) { + PackageEntry pe = classReader.readPackageEntry(p); + int exportFlags = classReader.readU2(p + 2); + p += 4; + List exportsTo = readEntryList(p); + p += 2 + exportsTo.size() * 2; + elements[i] = ModuleExportInfo.of(pe, exportFlags, exportsTo); + } + exports = List.of(elements); + } + + { + int cnt = classReader.readU2(p); + p += 2; + ModuleOpenInfo[] elements = new ModuleOpenInfo[cnt]; + for (int i = 0; i < cnt; i++) { + PackageEntry po = classReader.readPackageEntry(p); + int opensFlags = classReader.readU2(p + 2); + p += 4; + List opensTo = readEntryList(p); + p += 2 + opensTo.size() * 2; + elements[i] = ModuleOpenInfo.of(po, opensFlags, opensTo); + } + opens = List.of(elements); + } + + { + uses = readEntryList(p); + p += 2 + uses.size() * 2; + int cnt = classReader.readU2(p); + p += 2; + ModuleProvideInfo[] elements = new ModuleProvideInfo[cnt]; + provides = new ArrayList<>(cnt); + for (int i = 0; i < cnt; i++) { + ClassEntry c = classReader.readClassEntry(p); + p += 2; + List providesWith = readEntryList(p); + p += 2 + providesWith.size() * 2; + elements[i] = ModuleProvideInfo.of(c, providesWith); + } + provides = List.of(elements); + } + } + } + + public static final class BoundModulePackagesAttribute extends BoundAttribute + implements ModulePackagesAttribute { + private List packages = null; + + public BoundModulePackagesAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List packages() { + if (packages == null) { + packages = readEntryList(payloadStart); + } + return packages; + } + } + + public static final class BoundNestMembersAttribute extends BoundAttribute + implements NestMembersAttribute { + + private List members = null; + + public BoundNestMembersAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List nestMembers() { + if (members == null) { + members = readEntryList(payloadStart); + } + return members; + } + } + + public static final class BoundBootstrapMethodsAttribute extends BoundAttribute + implements BootstrapMethodsAttribute { + + private List bootstraps = null; + private final int size; + + public BoundBootstrapMethodsAttribute(ClassReader reader, AttributeMapper mapper, int pos) { + super(reader, mapper, pos); + size = classReader.readU2(pos); + } + + @Override + public int bootstrapMethodsSize() { + return size; + } + + @Override + public List bootstrapMethods() { + if (bootstraps == null) { + BootstrapMethodEntry[] bs = new BootstrapMethodEntry[size]; + int p = payloadStart + 2; + for (int i = 0; i < size; ++i) { + final AbstractPoolEntry.MethodHandleEntryImpl handle + = (AbstractPoolEntry.MethodHandleEntryImpl) classReader.readMethodHandleEntry(p); + final List args = readEntryList(p + 2); + p += 4 + args.size() * 2; + int hash = BootstrapMethodEntryImpl.computeHashCode(handle, args); + bs[i] = new BootstrapMethodEntryImpl(classReader, i, hash, handle, args); + } + bootstraps = List.of(bs); + } + return bootstraps; + } + } + + public static final class BoundInnerClassesAttribute extends BoundAttribute + implements InnerClassesAttribute { + private List classes; + + public BoundInnerClassesAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List classes() { + if (classes == null) { + final int cnt = classReader.readU2(payloadStart); + int p = payloadStart + 2; + InnerClassInfo[] elements = new InnerClassInfo[cnt]; + for (int i = 0; i < cnt; i++) { + ClassEntry innerClass = classReader.readClassEntry(p); + var outerClass = classReader.readEntryOrNull(p + 2, ClassEntry.class); + var innerName = classReader.readEntryOrNull(p + 4, Utf8Entry.class); + int flags = classReader.readU2(p + 6); + p += 8; + elements[i] = InnerClassInfo.of(innerClass, Optional.ofNullable(outerClass), Optional.ofNullable(innerName), flags); + } + classes = List.of(elements); + } + return classes; + } + } + + public static final class BoundEnclosingMethodAttribute extends BoundAttribute + implements EnclosingMethodAttribute { + public BoundEnclosingMethodAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public ClassEntry enclosingClass() { + return classReader.readClassEntry(payloadStart); + } + + @Override + public Optional enclosingMethod() { + return Optional.ofNullable(classReader.readEntryOrNull(payloadStart + 2, NameAndTypeEntry.class)); + } + } + + public static final class BoundAnnotationDefaultAttr + extends BoundAttribute + implements AnnotationDefaultAttribute { + private AnnotationValue annotationValue; + + public BoundAnnotationDefaultAttr(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public AnnotationValue defaultValue() { + if (annotationValue == null) + annotationValue = AnnotationReader.readElementValue(classReader, payloadStart); + return annotationValue; + } + } + + public static final class BoundRuntimeVisibleTypeAnnotationsAttribute extends BoundAttribute + implements RuntimeVisibleTypeAnnotationsAttribute { + + private final LabelContext labelContext; + + public BoundRuntimeVisibleTypeAnnotationsAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + this.labelContext = (enclosing instanceof LabelContext lc) ? lc : null; + } + + @Override + public List annotations() { + return AnnotationReader.readTypeAnnotations(classReader, payloadStart, labelContext); + } + } + + public static final class BoundRuntimeInvisibleTypeAnnotationsAttribute + extends BoundAttribute + implements RuntimeInvisibleTypeAnnotationsAttribute { + public BoundRuntimeInvisibleTypeAnnotationsAttribute(AttributedElement enclosing, ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + this.labelContext = (enclosing instanceof LabelContext lc) ? lc : null; + } + + private final LabelContext labelContext; + + @Override + public List annotations() { + return AnnotationReader.readTypeAnnotations(classReader, payloadStart, labelContext); + } + } + + public static final class BoundRuntimeVisibleParameterAnnotationsAttribute + extends BoundAttribute + implements RuntimeVisibleParameterAnnotationsAttribute { + + public BoundRuntimeVisibleParameterAnnotationsAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List> parameterAnnotations() { + return AnnotationReader.readParameterAnnotations(classReader, payloadStart); + } + } + + public static final class BoundRuntimeInvisibleParameterAnnotationsAttribute + extends BoundAttribute + implements RuntimeInvisibleParameterAnnotationsAttribute { + + public BoundRuntimeInvisibleParameterAnnotationsAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List> parameterAnnotations() { + return AnnotationReader.readParameterAnnotations(classReader, payloadStart); + } + } + + public static final class BoundRuntimeInvisibleAnnotationsAttribute + extends BoundAttribute + implements RuntimeInvisibleAnnotationsAttribute { + private List inflated; + + public BoundRuntimeInvisibleAnnotationsAttribute(ClassReader cf, + int payloadStart) { + super(cf, Attributes.runtimeInvisibleAnnotations(), payloadStart); + } + + @Override + public List annotations() { + if (inflated == null) + inflated = AnnotationReader.readAnnotations(classReader, payloadStart); + return inflated; + } + } + + public static final class BoundRuntimeVisibleAnnotationsAttribute + extends BoundAttribute + implements RuntimeVisibleAnnotationsAttribute { + private List inflated; + + public BoundRuntimeVisibleAnnotationsAttribute(ClassReader cf, + int payloadStart) { + super(cf, Attributes.runtimeVisibleAnnotations(), payloadStart); + } + + @Override + public List annotations() { + if (inflated == null) + inflated = AnnotationReader.readAnnotations(classReader, payloadStart); + return inflated; + } + } + + public static final class BoundPermittedSubclassesAttribute extends BoundAttribute + implements PermittedSubclassesAttribute { + private List permittedSubclasses = null; + + public BoundPermittedSubclassesAttribute(ClassReader cf, AttributeMapper mapper, int pos) { + super(cf, mapper, pos); + } + + @Override + public List permittedSubclasses() { + if (permittedSubclasses == null) { + permittedSubclasses = readEntryList(payloadStart); + } + return permittedSubclasses; + } + } + + public abstract static sealed class BoundCodeAttribute + extends BoundAttribute + implements CodeAttribute + permits CodeImpl { + protected final int codeStart; + protected final int codeLength; + protected final int codeEnd; + protected final int attributePos; + protected final int exceptionHandlerPos; + protected final int exceptionHandlerCnt; + protected final MethodModel enclosingMethod; + + public BoundCodeAttribute(AttributedElement enclosing, + ClassReader reader, + AttributeMapper mapper, + int payloadStart) { + super(reader, mapper, payloadStart); + this.codeLength = classReader.readInt(payloadStart + 4); + this.enclosingMethod = (MethodModel) enclosing; + this.codeStart = payloadStart + 8; + this.codeEnd = codeStart + codeLength; + this.exceptionHandlerPos = codeEnd; + this.exceptionHandlerCnt = classReader.readU2(exceptionHandlerPos); + this.attributePos = exceptionHandlerPos + 2 + exceptionHandlerCnt * 8; + } + + // CodeAttribute + + @Override + public int maxStack() { + return classReader.readU2(payloadStart); + } + + @Override + public int maxLocals() { + return classReader.readU2(payloadStart + 2); + } + + @Override + public int codeLength() { + return codeLength; + } + + @Override + public byte[] codeArray() { + return classReader.readBytes(payloadStart + 8, codeLength()); + } + } + + /** + * {@return the attribute mapper for a standard attribute} + * + * @param name the name of the attribute to find + */ + public static AttributeMapper standardAttribute(Utf8Entry name) { + // critical bootstrap path, so no lambdas nor method handles here + return switch (name.hashCode()) { + case 0x46699ff2 -> + name.equalsString(NAME_ANNOTATION_DEFAULT) ? annotationDefault() : null; + case 0x5208e184 -> + name.equalsString(NAME_BOOTSTRAP_METHODS) ? bootstrapMethods() : null; + case 0xcb60907a -> + name.equalsString(NAME_CHARACTER_RANGE_TABLE) ? characterRangeTable() : null; + case 0x4020220d -> + name.equalsString(NAME_CODE) ? code() : null; + case 0xc20dd1fe -> + name.equalsString(NAME_COMPILATION_ID) ? compilationId() : null; + case 0xcab1940d -> + name.equalsString(NAME_CONSTANT_VALUE) ? constantValue() : null; + case 0x558641d3 -> + name.equalsString(NAME_DEPRECATED) ? deprecated() : null; + case 0x51d443cd -> + name.equalsString(NAME_ENCLOSING_METHOD) ? enclosingMethod() : null; + case 0x687c1624 -> + name.equalsString(NAME_EXCEPTIONS) ? exceptions() : null; + case 0x7adb2910 -> + name.equalsString(NAME_INNER_CLASSES) ? innerClasses() : null; + case 0x653f0551 -> + name.equalsString(NAME_LINE_NUMBER_TABLE) ? lineNumberTable() : null; + case 0x64c75927 -> + name.equalsString(NAME_LOCAL_VARIABLE_TABLE) ? localVariableTable() : null; + case 0x6697f98d -> + name.equalsString(NAME_LOCAL_VARIABLE_TYPE_TABLE) ? localVariableTypeTable() : null; + case 0xdbb0cdcb -> + name.equalsString(NAME_METHOD_PARAMETERS) ? methodParameters() : null; + case 0xc9b0928c -> + name.equalsString(NAME_MODULE) ? module() : null; + case 0x41cd27e8 -> + name.equalsString(NAME_MODULE_HASHES) ? moduleHashes() : null; + case 0x7deb0a13 -> + name.equalsString(NAME_MODULE_MAIN_CLASS) ? moduleMainClass() : null; + case 0x6706ff99 -> + name.equalsString(NAME_MODULE_PACKAGES) ? modulePackages() : null; + case 0x60272858 -> + name.equalsString(NAME_MODULE_RESOLUTION) ? moduleResolution() : null; + case 0x5646d73d -> + name.equalsString(NAME_MODULE_TARGET) ? moduleTarget() : null; + case 0x50336c40 -> + name.equalsString(NAME_NEST_HOST) ? nestHost() : null; + case 0x4735ab81 -> + name.equalsString(NAME_NEST_MEMBERS) ? nestMembers() : null; + case 0x7100d9fe -> + name.equalsString(NAME_PERMITTED_SUBCLASSES) ? permittedSubclasses() : null; + case 0xd1ab5871 -> + name.equalsString(NAME_RECORD) ? record() : null; + case 0x7588550f -> + name.equalsString(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) ? runtimeInvisibleAnnotations() : null; + case 0xcc74da30 -> + name.equalsString(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) ? runtimeInvisibleParameterAnnotations() : null; + case 0xf67697f5 -> + name.equalsString(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) ? runtimeInvisibleTypeAnnotations() : null; + case 0xe0837d2a -> + name.equalsString(NAME_RUNTIME_VISIBLE_ANNOTATIONS) ? runtimeVisibleAnnotations() : null; + case 0xc945a075 -> + name.equalsString(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) ? runtimeVisibleParameterAnnotations() : null; + case 0x611a3a90 -> + name.equalsString(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) ? runtimeVisibleTypeAnnotations() : null; + case 0xf76fb898 -> + name.equalsString(NAME_SIGNATURE) ? signature() : null; + case 0x6b41b047 -> + name.equalsString(NAME_SOURCE_DEBUG_EXTENSION) ? sourceDebugExtension() : null; + case 0x748c2857 -> + name.equalsString(NAME_SOURCE_FILE) ? sourceFile() : null; + case 0x6bf13a96 -> + name.equalsString(NAME_SOURCE_ID) ? sourceId() : null; + case 0xfa85ee5a -> + name.equalsString(NAME_STACK_MAP_TABLE) ? stackMapTable() : null; + case 0xf2670725 -> + name.equalsString(NAME_SYNTHETIC) ? synthetic() : null; + default -> null; + }; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundCharacterRange.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundCharacterRange.class new file mode 100644 index 0000000000000000000000000000000000000000..9b3fcf6a149850a71e950a7caa81dded895af4d5 GIT binary patch literal 2350 zcma)8ZFdtz6n-X6vS}F7CSXMctV&Cg7D9_uO4=fQL8Gy)O^L>eve``1t=nDBW`lpq z4|)z%j_2qP@JDgDGubA)G%kLb*|~G)xzBw~{(be=KL9qMrxC-LhB!w8Nrt(j)-NT~ z_JnKeR>`pRZnte(qGTRFwMq|~UC-4GZ_5(L!uA-FE2eFFYYb!gLVX-5jB7}9oC9Yl zMIo&_J-fAWs7o~A?&)?%FvJa~McZsO>g5LMRESJjn#*uZV3K$^?RHlXAyyej4i_|B z7LMA!ezJ-%|HgFud0ZoaS88fc%S0~Tz*RgH^Og;xl1-5Et2#3 zN}(d5u5x@RaWr{TvAs0;`4Pv*_=IF#Pj|gtLj|0)bC}_n#dU^MM|f4eDJ+Jogj7A! zpXnuw;u^@Ix-Uz-0!LBeC4}ADHPV>J4GlLrO1MSdM}=(DbcNx`B&_#LOGPWIx6Y*U zc77xS)20II8J_9brEvDkg?b7UhGtlNpd79l&Qq~E)199tzQcnNs-Kz+jZzBBx9paZ zwk^HWU7cw?*6=CA$-ga{_c+S(S?ZLX#9HN8lOetk zW}{f9@i`u7Sm)G$n+(|@7s|Kj$P(0^=~hqdv>B$t>GU;J8Xt0eA#G&CHppYipu+K$ zO0x1ijViv;u+6c9-H`t^&o%81m15g*k9BIIn12UHTUKxGgE!?(2N8sL{Glr-u9)pnanFCs=Xr1+?Pj7dZb1 ziDGy}YYuT*XKB5TapaLf0d*HK-0+bVajAw!pQfhFo`E4fNlkVvOW-#jTr%?5zv)48QmEP zMBV2Dt@w;`0Y;OlQAqa!NVx$e>eMJCKFYcKBavu=`AAECu({+^Ji+t{uKoT-q&EW? ze87grnU8VT_bcOLTpLPO!c*V z1k%R=ek2Tr$N0&|IwWnG`=#7M>Tld`j1lCWS|d)|a;=e|ZRI8I*BVLs+EQQA_b=tw gOME@_Kcfn_M#a33Md|}t%>9a68hG$C$zpi&8Vz?B>Hq)$ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundCharacterRange.java b/tests/test_data/std/jdk/internal/classfile/impl/BoundCharacterRange.java new file mode 100644 index 00000000..374ba5bc --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/BoundCharacterRange.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.classfile.impl; + +import java.lang.classfile.Label; +import java.lang.classfile.instruction.CharacterRange; + +public final class BoundCharacterRange + extends AbstractElement + implements CharacterRange { + + private final CodeImpl code; + private final int offset; + + public BoundCharacterRange(CodeImpl code, int offset) { + this.code = code; + this.offset = offset; + } + + int startPc() { + return code.classReader.readU2(offset); + } + + int endPc() { + return code.classReader.readU2(offset + 2); + } + + @Override + public int characterRangeStart() { + return code.classReader.readInt(offset + 4); + } + + @Override + public int characterRangeEnd() { + return code.classReader.readInt(offset + 8); + } + + @Override + public int flags() { + return code.classReader.readU2(offset + 12); + } + + @Override + public Label startScope() { + return code.getLabel(startPc()); + } + + @Override + public Label endScope() { + return code.getLabel(endPc() + 1); + } + + @Override + public void writeTo(DirectCodeBuilder builder) { + builder.addCharacterRange(this); + } + + @Override + public String toString() { + return String.format("CharacterRange[startScope=%s, endScope=%s, characterRangeStart=%s, characterRangeEnd=%s, flags=%d]", + startScope(), endScope(), characterRangeStart(), characterRangeEnd(), flags()); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariable.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariable.class new file mode 100644 index 0000000000000000000000000000000000000000..b8cabb950d7d2247d1f68fd1e7d63eb10966b4d9 GIT binary patch literal 1804 zcma)6X;afs6g`in!4g(kTu|!*v``43vRFV_wOZjru`>+ghcrzwnC3CbD-QokzbHDR zKfoX5cwbW5rp1oane^r5-gD1AclrJ2$1ea|*pH$O?Fu?nbRxpAcvASNS&lGWN4GV@ z);+Ii*`{WdPHk-??+I5o#3nC0g$y@zJEyyrp0`bg$g1U7Vx3_so@s@##S3Pdz*6Z% zE{ZN(QxH|r4V7WGmETn{dp*6_P z;HHXOxXmzD2VWtmZArzqP0wIZc~Kr*>r`-;VS#k5rd9zAW!nTn`Q5=?1@~0MaGznO zmA>1SYZ^jUXR~bC1(PE7>xITDhe*_Q2g&P}4PkLd3-v`Rk?X=khIr`q$k9vY+PIgD zc{Ueo(nu0kM z^H^XQsNtlkrH^G&%9$+Cevx4$p03xgVnL!k!BYi`DwePu;u45XtzP7ANvDu2SCr(a zu1W#2%Fvgw9CNQ+ z%A4*%FtCH6l2k4`#0Se`m}@!0&7+v2IEEi*qNQhb_(?=wEP5u1$kGf^S^n&KDbH<& zSZH)EN4GW^6ioT#TEaZw!Bn)^SWR6`4N0+mcWMT$CEI3ahAzP`+aQ|dW!ErwX+1KG zHj6SVD@BdiMH{vaD@f78?F5s1mY!?$mPR}M0A*@=>>Jn@I<{e*o^mMzlVljjb2`NW zGrYhCy^#YpX?HXKw2d9IrV2x?z-sg_zjaQ1h4PsW0jP`$Bz-_>D%k{p47+$qH)PyrP5xkaY?vGl)zR%2;DwixhatM;HmLs(D558gG08 z84Opja=vIpeDFc!CmtQP6Xb+XEPL2N=fnkOvWGI)fNu5zj~n@>>i8zBeBTnoHthWc Ds>jjO literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariable.java b/tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariable.java new file mode 100644 index 00000000..a5953c86 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariable.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.classfile.impl; + +import java.lang.constant.ClassDesc; +import java.lang.classfile.attribute.LocalVariableInfo; +import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.classfile.instruction.LocalVariable; + +public final class BoundLocalVariable + extends AbstractBoundLocalVariable + implements LocalVariableInfo, + LocalVariable { + + public BoundLocalVariable(CodeImpl code, int offset) { + super(code, offset); + } + + @Override + public Utf8Entry type() { + return secondaryEntry(); + } + + @Override + public ClassDesc typeSymbol() { + return ClassDesc.ofDescriptor(type().stringValue()); + } + + @Override + public void writeTo(DirectCodeBuilder writer) { + writer.addLocalVariable(this); + } + + @Override + public String toString() { + return String.format("LocalVariable[name=%s, slot=%d, type=%s]", name().stringValue(), slot(), type().stringValue()); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariableType.class b/tests/test_data/std/jdk/internal/classfile/impl/BoundLocalVariableType.class new file mode 100644 index 0000000000000000000000000000000000000000..53e4c9e8f21339e9565f206a8bfcab8cb5c95100 GIT binary patch literal 1617 zcmaJ>Yg5xe6g^8zQ%d9|;sX?XfNd#+mk1V6o=#>u@}bxnhVjF;O=~bsm}G;)ztS&? z&gc*DM>*bYY9F+d=}fxW+&uzVYsU7hmznV_M{LiQX<=4vE__#Re^4;NFw!DCE}oN4 z>Fzxh_ocN_i7<#sOeuJ%;t{5)P_2YkoqM~)Fi65pyISCuPo|G|c$}|)A}8Z`tl|lt z5}y>x5J{%=1ZFX(;JJzW&7-!!Z>kga>Hl7Yi_9339Ft?<<~;lyOSB>!uem~MBee;l5s?r z6vJfigD%P{P?N;zuIs}pUeMJS1(P=(JzvtBjtKn#B|Sg&9qcPD`>;Vzc|C$UIEFcF z(rP9M!z*OzjS{ehZ32<29lWM!Cfl?DtI@yw)}Q_cwq$p0vdn}Z?H={ zQqvAaOY+z}W#76fNu!*lI>JN{)sz&&9$oB`_yE%ltO7+#p3Kv#rDX2JPsMD<|6<;Q@g+v!fmduxc@|mvfu+X(jdu#MxX~LrT z!LKI%DC4=Mdoh;an(V%v^E}Tv_niCd_xB$F8raMrfuw|#j0sFKHP!%Az!H}Y->oZZl*CJ3`KW|3o<^10^mH?GgXn&KcY z4Gn9Z^w%W3MUK7%mWfZYOhkD?1xBGl3ourl{-q52HI6Ajn zN8O1gwG3|IwuF+5JGjfBT$ueKI73zhIb2f;KbB)-9GV#0w%MgCtHqj)-%)cc%zs6X zhZH73LWN;H?pCxxF4WkvN$**Qj>ZGeq{Acon z6Ss> attributes; + + public BoundRecordComponentInfo(ClassReader reader, int startPos) { + this.reader = reader; + this.startPos = startPos; + attributesPos = startPos + 4; + } + + @Override + public Utf8Entry name() { + return reader.readUtf8Entry(startPos); + } + + @Override + public Utf8Entry descriptor() { + return reader.readUtf8Entry(startPos + 2); + } + + @Override + public List> attributes() { + if (attributes == null) { + attributes = BoundAttribute.readAttributes(null, reader, attributesPos, reader.customAttributes()); + } + return attributes; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufWriterImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/BufWriterImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..3938c931cc710fd15de956755f9b12b5c14af323 GIT binary patch literal 6886 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 b?3;7gyU8IV|2&%W$sXr_@zuW-`~Un8L-1UA literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufWriterImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/BufWriterImpl.java new file mode 100644 index 00000000..87161588 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/BufWriterImpl.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; + +import java.lang.classfile.BufWriter; +import java.lang.classfile.WritableElement; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPool; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.PoolEntry; + +public final class BufWriterImpl implements BufWriter { + + private final ConstantPoolBuilder constantPool; + private final ClassFileImpl context; + private LabelContext labelContext; + private final ClassEntry thisClass; + private final int majorVersion; + byte[] elems; + int offset = 0; + + public BufWriterImpl(ConstantPoolBuilder constantPool, ClassFileImpl context) { + this(constantPool, context, 64, null, 0); + } + + public BufWriterImpl(ConstantPoolBuilder constantPool, ClassFileImpl context, int initialSize) { + this(constantPool, context, initialSize, null, 0); + } + + public BufWriterImpl(ConstantPoolBuilder constantPool, ClassFileImpl context, int initialSize, ClassEntry thisClass, int majorVersion) { + this.constantPool = constantPool; + this.context = context; + elems = new byte[initialSize]; + this.thisClass = thisClass; + this.majorVersion = majorVersion; + } + + @Override + public ConstantPoolBuilder constantPool() { + return constantPool; + } + + public LabelContext labelContext() { + return labelContext; + } + + public void setLabelContext(LabelContext labelContext) { + this.labelContext = labelContext; + } + @Override + public boolean canWriteDirect(ConstantPool other) { + return constantPool.canWriteDirect(other); + } + + public ClassEntry thisClass() { + return thisClass; + } + + public int getMajorVersion() { + return majorVersion; + } + + public ClassFileImpl context() { + return context; + } + + @Override + public void writeU1(int x) { + writeIntBytes(1, x); + } + + @Override + public void writeU2(int x) { + writeIntBytes(2, x); + } + + @Override + public void writeInt(int x) { + writeIntBytes(4, x); + } + + @Override + public void writeFloat(float x) { + writeInt(Float.floatToIntBits(x)); + } + + @Override + public void writeLong(long x) { + writeIntBytes(8, x); + } + + @Override + public void writeDouble(double x) { + writeLong(Double.doubleToLongBits(x)); + } + + @Override + public void writeBytes(byte[] arr) { + writeBytes(arr, 0, arr.length); + } + + @Override + public void writeBytes(BufWriter other) { + BufWriterImpl o = (BufWriterImpl) other; + writeBytes(o.elems, 0, o.offset); + } + + @Override + public void writeBytes(byte[] arr, int start, int length) { + reserveSpace(length); + System.arraycopy(arr, start, elems, offset, length); + offset += length; + } + + @Override + public void patchInt(int offset, int size, int value) { + int prevOffset = this.offset; + this.offset = offset; + writeIntBytes(size, value); + this.offset = prevOffset; + } + + @Override + public void writeIntBytes(int intSize, long intValue) { + reserveSpace(intSize); + for (int i = 0; i < intSize; i++) { + elems[offset++] = (byte) ((intValue >> 8 * (intSize - i - 1)) & 0xFF); + } + } + + @Override + public void reserveSpace(int freeBytes) { + if (offset + freeBytes > elems.length) { + int newsize = elems.length * 2; + while (offset + freeBytes > newsize) { + newsize *= 2; + } + elems = Arrays.copyOf(elems, newsize); + } + } + + @Override + public int size() { + return offset; + } + + public ByteBuffer asByteBuffer() { + return ByteBuffer.wrap(elems, 0, offset).slice(); + } + + @Override + public void copyTo(byte[] array, int bufferOffset) { + System.arraycopy(elems, 0, array, bufferOffset, size()); + } + + // writeIndex methods ensure that any CP info written + // is relative to the correct constant pool + + @Override + public void writeIndex(PoolEntry entry) { + int idx = AbstractPoolEntry.maybeClone(constantPool, entry).index(); + if (idx < 1 || idx > Character.MAX_VALUE) + throw new IllegalArgumentException(idx + " is not a valid index. Entry: " + entry); + writeU2(idx); + } + + @Override + public void writeIndexOrZero(PoolEntry entry) { + if (entry == null || entry.index() == 0) + writeU2(0); + else + writeIndex(entry); + } + + @Override + public> void writeList(List list) { + writeU2(list.size()); + for (T t : list) { + t.writeTo(this); + } + } + + @Override + public void writeListIndices(List list) { + writeU2(list.size()); + for (PoolEntry info : list) { + writeIndex(info); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder$Model$1.class b/tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder$Model$1.class new file mode 100644 index 0000000000000000000000000000000000000000..2331c43d7c86897151b699ea9cff8b9d5c607e36 GIT binary patch literal 1338 zcmbW1U2oGc6oy~7U9)CkD}{~0fDI_n4_FuI=@GKH^0G<4!Y8hI-B*W7+WT0kuhLe zn1jWTJ>u`V?Q+$zUpJ406VMXdQpupgkSr7%Cg!nVAZy_~atu$VT9jeF?dckKx;0ny zgrY^(3iWv9Fp#d@4wVx~PuW#Z`C(7!tzyH#MTXU(x?zw;;$l)*mn>YuGRfwSBaR83 zAE4t+jhz6TrtsIJ3{e4^8*7mgZ-cBX0Tof~;98e*r6fh4G2L61YZfnq~q&ah=+wz86-B89io9qoh)Q zhTJ}8$(gF3+6cQdz-CIH!OAB%H>5@<1^7+6{)~__XXFfS;uh)MAzYq(Biy4iT=@qs zoM3T?8x?8Af=^MW(z2uww~3O#9o&s=0Y$PYx=~8FACIi#0ofe+%wruJbjL(0>G=n` CLRfzQ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder$Model.class b/tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder$Model.class new file mode 100644 index 0000000000000000000000000000000000000000..e2897a218577bdbd8fe30183eb04355a72816b4a GIT binary patch literal 5918 zcmbVQ2Y3_b8Ge7+&e`$-!T}P25PxMwP>mV|K^3)71;WphU!Yn~=tH_`rv*aYd$oO9 zIAa@$aJP}R+k%*iX$nFrrlU?^Q90qO`_gtwi`kpaJ}YC!vz{$COv7F&aN+!7;Z41@ zn1PuJW~sOc7Yj@+)XuO_qOJ`ITr$7O$L*emqt2IYbN{DyUa+1+EmhD6hCcHZ5TKm`#Bj{N|UCSk69y1{L$rC{U#( zlZg?5xup&4^elDko3Ek?%>oreT2kQplKOKD6RVf5wyIcwg%W0#Osha$fqo~|G8c;!1P(odTwTQ?tnZb;k?`}(r zNAl0IQrcBk?HYlaA#J$ZifIX=UPNlK3Y{umgf7~aPFSwV&ha`GH=>&%u}6~njfNTb zp{q#sCXa$uvmP51Y*g`LDe=-$c4mnwSt^Vgx9CAcu}Q&Z6}{M!tp-O&k7f@zKo};3 z=0_q;5e3_1IZhIQC{w8WB2bI1=#(Gp6zmdMIvIb&jHR63P#|L`Iu+~|xH`|i*-U4W zNh@XR@eN4{9hTeL;h3J3H`VB)@#csT#LbAyR-y~c^ziKX$4WNLJ#9_BLF~bR0z<`K z3>Ls@gCj~~udLFCk~V9o5SiKUi68ch>&i8%3Hxxv;vf>Rq=l@wWwh}B>E@0bDWnzH zDl*tNNl#v5qzL;S-5#*w-c%qa_8azq#JfOy$-?ij81W%J)#ep`5flr=IU{0N#RzT@ z2o5=#B4)oOP~JmVh@@nX4dCS}UV&G#iD)sISb^U1>=TALYqK+Ea;-Gyku1~ORJ;nW z7EojK)7DITqh&Gm;j$TtCKHA&#bg;A$6ur3wRj!75k=Wf+i58)r9%$wP7dt|XEsau z4S1u1J5;<0Zx&ck4iRo9ebb#-?UQp};Mww_@nLIMbZ^# zjAt`e^!;j^b=#M5=ILAUHU$S%+=;gfT$b+)`SzWoW-j)pIAJysfmeFyE|N^_Y>_0y zcW*V`$;~8Z%MK&HVqSWef_L*Yug9GpLA)0S72KubeRzMt_tBBGt+O+Pj5v24!yf6< z(q4rXv?6Z`HARB>AU>qv!zw<4j|xoBtBMdud*n_~Yg=9Vu-m+3M~nE2(d%hJ+>Lt_ z+^ga~e7w*ir|HQR!%7Wltf%aX;l#pY-{DJ4)->OdMZ*)cZf`zOe6E<+qF<>6kUGceB_y;6k0v~I)H*Jp>aLaC^meSZ1^%R9o*Rw;bOEcpM z=d31b>@hVvlcFJOvKvcoMPBa9#`(mrZ6!4e!`bvFnchX~3;C8zs;qe8lj+(?nM#d$ zGAiDSfxs0dMaXP<`xvRGL~SiL*rO%A^i*@ha*l}bq?TgQNre0N)a=ME9YQxbZu^lj zn*>uO#;AiS#p%GZTFbv$mEz~t(wFJyHd@mCe24Jn16cGZ>h)RdhK?{bVIjg4Q7)5Kzo4q`BT6sUwi!I=l`XvvOKRJ z!Jgy}Es=pU>&jgK`2>9^gp;56N>>@bhl+-h(N) z7svQC%jLjvJj^FaBP9!*;C+<lmEWo>~ zGCcbbUUMcfI&XQs2ybtWnPvtV6AAtDSVpTyU@tHM;L|! zn8UkA`E5P!z+?1UX8gDpyfeI?iK^!?MZwbN(5_&`l5=Q0=Va|O*?3ZTg%k7ODcroR zPCJ3vV`OwQC6f;dmPWXl33|c>K8rz8NgOOBm87d2MSniaF7M+$-b#8C8MEd*$zU=8*NnJ7qGwR+^ z`3T;%t)h7p?-|7hqNDg&aZH}^#bkynH58D&)sxjutDRW5HY&956Mp;L$e#7tHZ^D4 zRD6XI5}}~%>z=$YuhO=v=F>P@Y|Ig#F;zHA41vs?DC3yV;HZSJ9~pYK+s?Hb-{G~MX!{-ie;41!v(DX*@Du#px%&lvh2P?@q?$vD0N>RA#vYO2v;6mW K{1gAi?EeAZW5`DU literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..f22a3de16b5c4e32289599dde76af0e347b62237 GIT binary patch literal 5627 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder.java new file mode 100644 index 00000000..8603c77a --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/BufferedCodeBuilder.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.BufWriter; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeModel; +import java.lang.classfile.TypeKind; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.Label; +import java.lang.classfile.MethodModel; +import java.lang.classfile.instruction.ExceptionCatch; +import java.lang.classfile.instruction.IncrementInstruction; +import java.lang.classfile.instruction.LoadInstruction; +import java.lang.classfile.instruction.StoreInstruction; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +public final class BufferedCodeBuilder + implements TerminalCodeBuilder { + private final SplitConstantPool constantPool; + private final ClassFileImpl context; + private final List elements = new ArrayList<>(); + private final LabelImpl startLabel, endLabel; + private final CodeModel original; + private final MethodInfo methodInfo; + private boolean finished; + private int maxLocals; + + public BufferedCodeBuilder(MethodInfo methodInfo, + SplitConstantPool constantPool, + ClassFileImpl context, + CodeModel original) { + this.constantPool = constantPool; + this.context = context; + this.startLabel = new LabelImpl(this, -1); + this.endLabel = new LabelImpl(this, -1); + this.original = original; + this.methodInfo = methodInfo; + this.maxLocals = Util.maxLocals(methodInfo.methodFlags(), methodInfo.methodTypeSymbol()); + if (original != null) + this.maxLocals = Math.max(this.maxLocals, original.maxLocals()); + + elements.add(startLabel); + } + + @Override + public Optional original() { + return Optional.ofNullable(original); + } + + @Override + public Label newLabel() { + return new LabelImpl(this, -1); + } + + @Override + public Label startLabel() { + return startLabel; + } + + @Override + public Label endLabel() { + return endLabel; + } + + @Override + public int receiverSlot() { + return methodInfo.receiverSlot(); + } + + @Override + public int parameterSlot(int paramNo) { + return methodInfo.parameterSlot(paramNo); + } + + public int curTopLocal() { + return maxLocals; + } + + @Override + public int allocateLocal(TypeKind typeKind) { + int retVal = maxLocals; + maxLocals += typeKind.slotSize(); + return retVal; + } + + @Override + public Label getLabel(int bci) { + throw new UnsupportedOperationException("Lookup by BCI not supported by BufferedCodeBuilder"); + } + + @Override + public int labelToBci(Label label) { + throw new UnsupportedOperationException("Label mapping not supported by BufferedCodeBuilder"); + } + + @Override + public void setLabelTarget(Label label, int bci) { + throw new UnsupportedOperationException("Label mapping not supported by BufferedCodeBuilder"); + } + + @Override + public ConstantPoolBuilder constantPool() { + return constantPool; + } + + @Override + public CodeBuilder with(CodeElement element) { + if (finished) + throw new IllegalStateException("Can't add elements after traversal"); + elements.add(element); + return this; + } + + @Override + public String toString() { + return String.format("CodeModel[id=%d]", System.identityHashCode(this)); + } + + public BufferedCodeBuilder run(Consumer handler) { + handler.accept(this); + return this; + } + + public CodeModel toModel() { + if (!finished) { + elements.add(endLabel); + finished = true; + } + return new Model(); + } + + public final class Model + extends AbstractUnboundModel + implements CodeModel { + + private Model() { + super(elements); + } + + @Override + public List exceptionHandlers() { + return elements.stream() + .filter(x -> x instanceof ExceptionCatch) + .map(x -> (ExceptionCatch) x) + .toList(); + } + + @Override + public int maxLocals() { + for (CodeElement element : elements) { + if (element instanceof LoadInstruction i) + maxLocals = Math.max(maxLocals, i.slot() + i.typeKind().slotSize()); + else if (element instanceof StoreInstruction i) + maxLocals = Math.max(maxLocals, i.slot() + i.typeKind().slotSize()); + else if (element instanceof IncrementInstruction i) + maxLocals = Math.max(maxLocals, i.slot() + 1); + } + return maxLocals; + } + + @Override + public int maxStack() { + throw new UnsupportedOperationException("nyi"); + } + + @Override + public Optional parent() { + return Optional.empty(); + } + + @Override + public void writeTo(DirectMethodBuilder builder) { + builder.withCode(new Consumer<>() { + @Override + public void accept(CodeBuilder cb) { + forEachElement(cb); + } + }); + } + + public void writeTo(BufWriter buf) { + DirectCodeBuilder.build(methodInfo, cb -> elements.forEach(cb), constantPool, context, null).writeTo(buf); + } + + @Override + public String toString() { + return String.format("CodeModel[id=%s]", Integer.toHexString(System.identityHashCode(this))); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedFieldBuilder$Model$1.class b/tests/test_data/std/jdk/internal/classfile/impl/BufferedFieldBuilder$Model$1.class new file mode 100644 index 0000000000000000000000000000000000000000..49ddbe60875774034f2c5259b36417f4f3b24d73 GIT binary patch literal 1491 zcmbVMTTc@~6#k|Zwp&)%BA|#D#H!FL%S91cLLwC+NkJ0`@5^=ygVR~E7kKqAnV?1= zjL-fk!7B91~Kt-1(8yC1hOuHm+UJGjd*@b@u;*7W>!$30}2 zn9AI3M#>F^r>vT%f~duPdwNg91X*=5+9_?ennhB>q=5%0Q(7F?<;RrthbeYaiHq+g z4jwU#cNqRdg25)BuH;4V4EY)pckpm0lp!K|5pvFR(=VI`u`!cRhxM z%S-oK`1C$&al1(SLK0zNn+M?=FCY;an@Vv%vEY=)-lT0{g7j7ZNes+1;|@eksfYgk zcuXf#G+U)HM`N*4{RCF|0_`KMa+s!XAKe53ROma}wn7z8Xhrr38pBhX_mbHMlZ;8% z^o?ORQ`l1F4D1Zo&Tzf@6=OMc(BroNoWR6s#zX0khZ1IB5${(7J4?1P>_Q5wSE@g7 z?=$Xq;Id?mgt(qUol`W4Ddq?zhj~JZ$7gs>W1bq_B3>pt!&s(qh|UJ6_1M(cm} z;@v;sFYv3LgFxlz@tf!P-GAfp_|EL6yA4aE_MCP)v-4i&eV+H3`SYJ&egiOu?_!9c zNkX%X7PK;)ST3xjG{aFXL(x-tU9s(=rmHEfT+ve(s>Pyesf7tm)e9G@nqE+?-YK)7 z>I|*Ul4kb~GmK=m>LMLO6fp^L8EudmhPUc~A*$+XSv4G+p)<3rtSYIhqv@%PW;^LP z+R-7QQ^t05{fGDSIoq+6ymQ6KnN_1uJKGt}(42D&JNoOL56s6Y`JFOez%EL|w6u~& zm1Ee|KM>eEQ*ktt)+w2nuv@~*GG0M9LzkaxZ3~ssw8nK?WjN@C(-otXn#nDzc_;08 z4K7L8%dl5?63aen0w{3^9ycLlAJ4KyEmxeiHtfLx8NGa^wW3&5J&wac8HdnMn~J(p zqH^wYPf_Rid_J$*_5|M|&>NJI#1KQXp_D1{p-`i|Y1ocpI2F^>Q&*hg=(yonYr_7B zjFhl1sCHh$QHIg2lE5Wm@6kAhag1aADnptI_`mp^=D41~NeQDePT@4ekw%U#Y8GKL z#=FI93x?P&%~=uvFnk{b(ue061=&jR0vsz=jXY;rYK-b!EvwchuJ}=dX{IHdd9Jes zTb|S8oQ&7-I)hw0!z_WykZM@(Y(>``o*icaHxSrgkV%IwGDzggQExj8$%bA;{u3lh zlcY)1P-#qXxZhy-t1;Y9hu=b+t%Fk6GPOe0u|L$W-?v1>HcaBOgg0emFvZaBO9q!W zs#}rtLdh>NBs`i4?F*p;aXO6|8MAnc%x+nlqt2NO`@`8uYJZh)As)>~ktOBy(^@R@ zD`1+M{cN8-ln}GIwTd_6vT(Mqa9zR`(qmtkTnTH#Ra}#>Ambe@G7S3PeU63~i=mC= zSu;xWie4p|*;&(AQR=Mtly1Xy+>mfn#(Pj0dcxcX2u`vK+UwSO9RZHU9kH9;#B<0*U7PVf(+J~4Em2*|%XHRG`{MP0`c3QQaOD2~~dD1XcOVB|j9<~Th;3z$V z+rj8f#5z0qQKx-Aw5Le~jf?#^(1DwQfC(>P2c=)dD#f@(7BV7#^S9@oafu#-w`nDUHTrf4 zAJAVOe}qQL3Q->a0s43x_i#LEpdez%?jA1&!-x2YRzmCt>g}~q`#aCFKU{Bbgxb&I zV=w+36_?kqJLw)^z#R@h!SKT1BaA%6@vA;yZtZM(h_3}|*S!H&H$K5#^33>s=|#8) zNx(e%1nC9W`&oB5zd0m(gz+hNNg7(mr3i+S4>9dW??N+WdIx=!{Rl-mNwGL(60ZM^ zEJpDu?osqU?7(NZPv>L!9E)B)1tJtj=5*KFt-oS!p~=f)9i;Nvg=Tkp*qgSv)4p}Q y%kUVv>|-p|*Z6**#;3h3nmx9BfiEdm1YhB6F-GwXja{@7p=SA(*fvaa`uP{anfh7) literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedFieldBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/BufferedFieldBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..093100595d7ec9a6c4dd3e45453d0faf08fcccf5 GIT binary patch literal 3265 zcmbtW>sAw27~LlqhJ;Zt-bzJON);yRC@Nxuv_M5^30_dF+S`y!U~n?YnoMkcl)gpV z)l{vkUG3lg@9T7RpEDB@Af(!|7IV%_zRUjhcRAG|YtH(<^?b>x1!-uAr_cvo!#*AR z(Jydev-s3>yukK7%QXwGRjZX8*EXGU)ivkprIPL2#RbQ9i*t3yE!w_7ukG4p+Y4%h zvea@TJ>;bI13EG|D4-WAUM;Y^;7+CD3YbgXT&+}HCzx+jP^J#+ID(@B8chZEw~RE~ z)yllYzd-zpgs&_N>UbB&1QMQAwgt|HfE9VIV4Faz1ZqAAN>ewyz<;jvkLws#`bE1| z&~Q>{w%AE?0+Zd! zwo`|UDtgkG#mBN^ZwOo=(zk50ob2P9%tEIMQc1WGc43+wx2WS2e99vK#tAkA7TSqv zRZ6>7llL8sphTiZ&uPg2%Y3+R`(;@y?P>z46=&VEg1XO?Uk)>_(kpW}-Btm6Ae+ev z{MDVX-NT|Qzw_IsLPrF9Oo0C_tC$JfWqg$hnrG(-^e;J{y<9J^+5Y{oH8M+;g5|DS zz9ZkGkBMNzVFyoi4X#rKlEFmqyh=|~W1XkQws>VfH0N|P`2t6ps@r?B&E~crx@0zt zU*=VmIPs$6LtvyMz1zxEVBbn$6`tm;YD7xhuX_S_qY_sTb~U!F?zinX0^6{>qASP3 z@etS^#!1cgY?0{*+*~)s>2rI>+oWBR^sH-aZ)WAc5fD^Vs+gH(?mNwgFr5O+oyW{p zw?zYLk5RKF)(oAuiM$jpJz31B&_}PN~P`>Y*O5e5u!m&Mikr$Um&$E36&?bhY3K$nTXk!pq;w>s8Z#cZ1W#silt-NHYm6rvz z@^VGlW$t6R&3~TB>N`(at{Q(!;trp8`Sv5?=;1nPynrxXLwocBsRq(Uwt)fTYy*dk za}B&>3?>>FGUC7D#7mrN;EXYtY#{psHDkEP=V_$)oIrxU`gtfH!etEN3NJ8|7{yhX znBv&l%T3PkP%FB_jxN(Mg>Dfd!2`x53({kb;%-bg>B^$|6B?C~k>lxa^w9j2Xh z_7$$g@G$!aM!v(o?C%)KOCHY{(t2ExwO>i!WKwTo2#d elements = new ArrayList<>(); + private AccessFlags flags; + private final FieldModel original; + + public BufferedFieldBuilder(SplitConstantPool constantPool, + ClassFileImpl context, + Utf8Entry name, + Utf8Entry type, + FieldModel original) { + this.constantPool = constantPool; + this.context = context; + this.name = name; + this.desc = type; + this.flags = AccessFlags.ofField(); + this.original = original; + } + + @Override + public ConstantPoolBuilder constantPool() { + return constantPool; + } + + @Override + public Optional original() { + return Optional.ofNullable(original); + } + + @Override + public FieldBuilder with(FieldElement element) { + elements.add(element); + if (element instanceof AccessFlags f) this.flags = f; + return this; + } + + public BufferedFieldBuilder run(Consumer handler) { + handler.accept(this); + return this; + } + + public FieldModel toModel() { + return new Model(); + } + + public final class Model + extends AbstractUnboundModel + implements FieldModel { + public Model() { + super(elements); + } + + @Override + public Optional parent() { + FieldModel fm = original().orElse(null); + return fm == null? Optional.empty() : fm.parent(); + } + + @Override + public AccessFlags flags() { + return flags; + } + + @Override + public Utf8Entry fieldName() { + return name; + } + + @Override + public Utf8Entry fieldType() { + return desc; + } + + @Override + public void writeTo(DirectClassBuilder builder) { + builder.withField(name, desc, new Consumer() { + @Override + public void accept(FieldBuilder fieldBuilder) { + elements.forEach(fieldBuilder); + } + }); + } + + @Override + public void writeTo(BufWriter buf) { + DirectFieldBuilder fb = new DirectFieldBuilder(constantPool, context, name, desc, null); + elements.forEach(fb); + fb.writeTo(buf); + } + + @Override + public String toString() { + return String.format("FieldModel[fieldName=%s, fieldType=%s, flags=%d]", name.stringValue(), desc.stringValue(), flags.flagsMask()); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder$Model$1.class b/tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder$Model$1.class new file mode 100644 index 0000000000000000000000000000000000000000..0d00ee4c2e2a724473f05e301146201d526e5850 GIT binary patch literal 1359 zcmbW1-)|B@5XZj@v@|CL`s%-A zqBZfs_-NF>$vAh=f{7)OOW4_4=05Y?nVtRd`^#4VRXoWcfuw`6LlrSueXKrvL;*DgEWk>NK)TF&W zMjE;YA%pQw%RtmU zhONm}dnPp<^=j06!yb$Gm_8DI@WS&012#kXzw6Fmy;Mr*7%V97GjZo)g^p+%3^%}X zx#$+4iy=wBIV{sZH)*y@HbK@bmOg8>K1a^f3N%L8y&*PJ{0LS$#ibE7Y8&7u>H0NB&YY7oxQA8JyGOVJ`9`>{b6n{g zuAE|Fgc}!W#e&aJXVP+{5ci3az#1OJb{!jJQ*^}?@hD!|#AC8~^2uToWx8}CmGt}p DYr$d> literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder$Model.class b/tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder$Model.class new file mode 100644 index 0000000000000000000000000000000000000000..186b745823cac6233776261fce00b9eb3838096d GIT binary patch literal 4853 zcmbVQ`*#~h75+xCv$njBRi_Emg(hw7)-R%_EqPc@AaNX`#*a`X4ki>>Nh@dL)vnlG zIWf-yZFxg^Ln#m* zWA5ZH|9$0E028>@i4?YJXw%V-?E(icl^3&?6PTW3*x8b8_&7j|3XTfw z9Bc+3nv>e!u45N=3$#~kV}Ux{t+v^Qvk;^4SgB$Dlx)V^mFn(L}>buHy%W6VzPS&YlY@hbEoC zTMqp`tYajUFPnZzlJYhk`;es@t6`j-U9Oph z{SDl6j$g0UTrV)ovo+H*q#q`)l+4h39XLW*XW2?)4DXOJ_)dXc5!<0!g}}3%h1}3w zn%Q_%FoW_i_YgS;KcKv@PBsBlscvM3{$61^c*w+f_gyor~U_vqxRU%S$*$OVIU=VmF z&TylW-GZ^LL~TBnpc{!Y!CjYW70qclFOYqG>y#;xc{11Lb-WiB1oU+) z&M=<{)spi<&9(xmo=iX~5T@N@I^K^DumBJ$Ft0GOM_QtU2At$wkmpsv(lQ4_y1Xdx z@76BA`S>lIvlX{&WpCudCMPMr!;;Tv>_Qo)hKh~_Tol;RD4+6Dk)_l1CXEt*+8c#h zc;h5Q1oL_hmvk(G&eAS>R$!iW1@1|XQ0CfsxrL!L*8zu>Ii}ZzYFHFyRX8%>kM31d zncU$tEM!Lp%8zMaNzXJY)NJt*)1?a@d<}t)I+g^68^6C^g0NulUSyS;GweFc{Oy|x zQdGdwxPoO3AJ*{^d{p4J27I0|wqSa+eo4yDR^&yOkEcqsgOT-dd_u$HIzEX{Z8AX} z!cK#{R}DJgaGbwLg$uDLP&RK$$Y_^_CvI^s#HiNrl)!zhvQ%x(I~6+fKETD8S zFO&&3Py#(umSfJ;t3}g0YZPs+^iH`Y!=5udOU|RkHrZy;^p-i4c$jL`cyDEt+Gp19 zHNxGy$(xN>i1#Zbo>w6|EZ&y|Yr!#sx<@S!t&4`izus7k$K23>3u}l(MzvTrh-FmxMsPiL z;j)ox%>EibJrYt!pE8`XZTkIFuDe*T#c7X& zffo=xs^=ZY^uoL~Str`Vh|sXYR{SPzlFZbwDsWfptt>2x6SnOszSL6m=aUebjC_*v z*`tG32|mO1&vNz%#}vmM!y_+443DfpTSND6xst-?L#4+Qsn=s5-5aFx2^N7IAuZDH zof72ERUBvrcr^r2uI}7$btk@tuZQP#+MA|@f(<%SM0q<4ewLKfEtG6v0@D$oK|yf^g2o@jE=0rYG}}lHe&r9 zL-+>{;Gf9hU!f*@)fpR_jN`jZAi;e*nMBW0Z-MV)DbmSi@<{f^daK+20C#>{q{(%B zNT4v^7HJes+tqYu=<{p1T)2jhHR4Al>uc!2f2h%GG1kW-ZQAiP&r0D3_+dC+#gD?V n13%^{bMSd;{}ViiUqD*g$61Q3{f;H$H0Sc)@9{F$aL4}uUSw8e literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..07c2b6a4fb9a54bc8deeae8fe845e6ab6aec8668 GIT binary patch literal 5968 zcmb_g`F9i78NE-o8CxE}5#T`B35zY+RviK%h=$k(iWA$A7@QKiWGs!$z-S~!BbK%# zDNWL}>5{hTLiZ(Ux;JTK1EFcjPdTT5K>wVc-uGrk(#W#nB?Tr$$O;moB^%$_&1p1_JjmScI32(IQ>@|Ht4ty8wJ`OqhJaQ_zo-d zYSD&{mgs2uw3k0{)bZS_N`AABElNITma`hR32dt2@0xj=2}qA*vnK7@##}dc;C>A| zb?m}!fvvTF7sNpd(LzXkq)Zqy}^h zVo3VqT5}f3u#}+h?PM`$+L>;A0>c^}(6JW}3apBffpj!-Ie~S3bsqSX&GbJV$9_Dd z;ed{ZaZn&plRZ)LtfKNDUd&HbY}=T%nYzAaYJAO#=b@Ma;gF6`f(6l0IKsRM++XKH znC-M5%Bia*Q%=fgcvN6_E0X#G<4(TVjl&q#S)E5%1O-(eQqT0&!mQ-_uD(dF0$Mj3 zjI&sd>G%|m3&d+m1csvG)v63VZ{TS+9>e1rCUi_>=}V?0!!xgKGZ5FrN4eR=%0}e7j!r%GDmL35jYuSUR7wm;$&rM zr^m>fO2KqxM{5yO6G$@B#6=x0m}Si?D$C?#gtxWcSaVLMy`tk1E^{roY7VJwH9V`~IUUdA%K{r~J#!JX+!PpGl}cPPoAzIB6TZU2Tn_w^V0S9SkCNqrIfcs7L}deEmaqDW^=gAQ!BN0VZPFnsW@V;5+?jfbl)ena3F3JAQyuOKmegU|e`z;Qx;5>R&@ z?A4tIbTx;^UiHj_ta|3zfOp7~Ag@wa2foScxA^oov|$DB`;#{zl6Rn;xrwfM#FMFc z^dtx7u{Jq4kM+q7?eo}_Y(SC1dzDue<3fsK1>)ug0TTixF(V zC_fsEVJD6tjicCyV|Z1~QWo(Ye3wtOts)X?Bx8!H(f1fln;N~wQM($+h&t#wx37W! z1ex|7~ zPx^uI%K`ES8A0X)49h?!2j0iw8(24R7l$X3Ovi}8JTh-$O)|NFqqo7u`xZ{{l@yW| z{jBs7eeevbA&>Pu+3bQvw%E#pUfNlYmG~KcPRqc-AP||8cEol`KJ#=Nc=aIfa#oxM z_T0v4fj{x7J~J2V;)+*6`2~I%Xqcr>k_DTo;mij}NY6jZzh`d2n8z9UcH@v#T2H7; zbp0|5@=DcZDhQOz(Xa4pst;(?%i(YEI<3eI7Afl6yMwtiN$T(6-&%1KR%!wE0!j<; zYEUIqDO_Ufkmy{DpUr9Ca?L`02G(p8Y7XF2CCfFVRinj=! zz}xITzWHM`FEL0gGT+F`SL%XIRP7{KS<;T+nfvbnuG73ron5KqZG0()x+WmMB!lfh zqq0{yk`&{_s=6*B6~#`zd57wK?B+RgvB0auZm$Z4@^^6k4BO}njXuAojQB|ijP#7K zhux%EUqRq$k}d12LAL8DJG58<%ZQza$o5Dg-sVFL@8S;c63OfM2jo}tgc^6_U$}>F H)W81$ri*N= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder.java new file mode 100644 index 00000000..c6cf9d8e --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/BufferedMethodBuilder.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.constant.MethodTypeDesc; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +import java.lang.classfile.AccessFlags; + +import java.lang.classfile.BufWriter; +import java.lang.classfile.ClassModel; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeModel; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.MethodBuilder; +import java.lang.classfile.MethodElement; +import java.lang.classfile.MethodModel; +import java.lang.classfile.constantpool.Utf8Entry; + +public final class BufferedMethodBuilder + implements TerminalMethodBuilder, MethodInfo { + private final List elements; + private final SplitConstantPool constantPool; + private final ClassFileImpl context; + private final Utf8Entry name; + private final Utf8Entry desc; + private AccessFlags flags; + private final MethodModel original; + private int[] parameterSlots; + MethodTypeDesc mDesc; + + public BufferedMethodBuilder(SplitConstantPool constantPool, + ClassFileImpl context, + Utf8Entry nameInfo, + Utf8Entry typeInfo, + MethodModel original) { + this.elements = new ArrayList<>(); + this.constantPool = constantPool; + this.context = context; + this.name = nameInfo; + this.desc = typeInfo; + this.flags = AccessFlags.ofMethod(); + this.original = original; + } + + @Override + public MethodBuilder with(MethodElement element) { + elements.add(element); + if (element instanceof AccessFlags f) this.flags = f; + return this; + } + + @Override + public ConstantPoolBuilder constantPool() { + return constantPool; + } + + @Override + public Optional original() { + return Optional.ofNullable(original); + } + + @Override + public Utf8Entry methodName() { + return name; + } + + @Override + public Utf8Entry methodType() { + return desc; + } + + @Override + public MethodTypeDesc methodTypeSymbol() { + if (mDesc == null) { + if (original instanceof MethodInfo mi) { + mDesc = mi.methodTypeSymbol(); + } else { + mDesc = MethodTypeDesc.ofDescriptor(methodType().stringValue()); + } + } + return mDesc; + } + + @Override + public int methodFlags() { + return flags.flagsMask(); + } + + @Override + public int parameterSlot(int paramNo) { + if (parameterSlots == null) + parameterSlots = Util.parseParameterSlots(methodFlags(), methodTypeSymbol()); + return parameterSlots[paramNo]; + } + + @Override + public MethodBuilder withCode(Consumer handler) { + return with(new BufferedCodeBuilder(this, constantPool, context, null) + .run(handler) + .toModel()); + } + + @Override + public MethodBuilder transformCode(CodeModel code, CodeTransform transform) { + BufferedCodeBuilder builder = new BufferedCodeBuilder(this, constantPool, context, code); + builder.transform(code, transform); + return with(builder.toModel()); + } + + @Override + public BufferedCodeBuilder bufferedCodeBuilder(CodeModel original) { + return new BufferedCodeBuilder(this, constantPool, context, original); + } + + public BufferedMethodBuilder run(Consumer handler) { + handler.accept(this); + return this; + } + + public MethodModel toModel() { + return new Model(); + } + + public final class Model + extends AbstractUnboundModel + implements MethodModel, MethodInfo { + public Model() { + super(elements); + } + + @Override + public AccessFlags flags() { + return flags; + } + + @Override + public Optional parent() { + return original().flatMap(MethodModel::parent); + } + + @Override + public Utf8Entry methodName() { + return name; + } + + @Override + public Utf8Entry methodType() { + return desc; + } + + @Override + public MethodTypeDesc methodTypeSymbol() { + return BufferedMethodBuilder.this.methodTypeSymbol(); + } + + @Override + public int methodFlags() { + return flags.flagsMask(); + } + + @Override + public int parameterSlot(int paramNo) { + return BufferedMethodBuilder.this.parameterSlot(paramNo); + } + + @Override + public Optional code() { + throw new UnsupportedOperationException("nyi"); + } + + @Override + public void writeTo(DirectClassBuilder builder) { + builder.withMethod(methodName(), methodType(), methodFlags(), new Consumer<>() { + @Override + public void accept(MethodBuilder mb) { + forEachElement(mb); + } + }); + } + + @Override + public void writeTo(BufWriter buf) { + DirectMethodBuilder mb = new DirectMethodBuilder(constantPool, context, name, desc, methodFlags(), null); + elements.forEach(mb); + mb.writeTo(buf); + } + + @Override + public String toString() { + return String.format("MethodModel[methodName=%s, methodType=%s, flags=%d]", + name.stringValue(), desc.stringValue(), flags.flagsMask()); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/BytecodeHelpers$1.class b/tests/test_data/std/jdk/internal/classfile/impl/BytecodeHelpers$1.class new file mode 100644 index 0000000000000000000000000000000000000000..fe9af9b3c77a3b5613d9aab19f2a47e7c14e2edf GIT binary patch literal 2412 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 switch (slot) { + case 0 -> Opcode.ILOAD_0; + case 1 -> Opcode.ILOAD_1; + case 2 -> Opcode.ILOAD_2; + case 3 -> Opcode.ILOAD_3; + default -> (slot < 256) ? Opcode.ILOAD : Opcode.ILOAD_W; + }; + case LongType -> switch (slot) { + case 0 -> Opcode.LLOAD_0; + case 1 -> Opcode.LLOAD_1; + case 2 -> Opcode.LLOAD_2; + case 3 -> Opcode.LLOAD_3; + default -> (slot < 256) ? Opcode.LLOAD : Opcode.LLOAD_W; + }; + case DoubleType -> switch (slot) { + case 0 -> Opcode.DLOAD_0; + case 1 -> Opcode.DLOAD_1; + case 2 -> Opcode.DLOAD_2; + case 3 -> Opcode.DLOAD_3; + default -> (slot < 256) ? Opcode.DLOAD : Opcode.DLOAD_W; + }; + case FloatType -> switch (slot) { + case 0 -> Opcode.FLOAD_0; + case 1 -> Opcode.FLOAD_1; + case 2 -> Opcode.FLOAD_2; + case 3 -> Opcode.FLOAD_3; + default -> (slot < 256) ? Opcode.FLOAD : Opcode.FLOAD_W; + }; + case ReferenceType -> switch (slot) { + case 0 -> Opcode.ALOAD_0; + case 1 -> Opcode.ALOAD_1; + case 2 -> Opcode.ALOAD_2; + case 3 -> Opcode.ALOAD_3; + default -> (slot < 256) ? Opcode.ALOAD : Opcode.ALOAD_W; + }; + case VoidType -> throw new IllegalArgumentException("void"); + }; + } + + public static Opcode storeOpcode(TypeKind tk, int slot) { + return switch (tk) { + case IntType, ShortType, ByteType, CharType, BooleanType -> switch (slot) { + case 0 -> Opcode.ISTORE_0; + case 1 -> Opcode.ISTORE_1; + case 2 -> Opcode.ISTORE_2; + case 3 -> Opcode.ISTORE_3; + default -> (slot < 256) ? Opcode.ISTORE : Opcode.ISTORE_W; + }; + case LongType -> switch (slot) { + case 0 -> Opcode.LSTORE_0; + case 1 -> Opcode.LSTORE_1; + case 2 -> Opcode.LSTORE_2; + case 3 -> Opcode.LSTORE_3; + default -> (slot < 256) ? Opcode.LSTORE : Opcode.LSTORE_W; + }; + case DoubleType -> switch (slot) { + case 0 -> Opcode.DSTORE_0; + case 1 -> Opcode.DSTORE_1; + case 2 -> Opcode.DSTORE_2; + case 3 -> Opcode.DSTORE_3; + default -> (slot < 256) ? Opcode.DSTORE : Opcode.DSTORE_W; + }; + case FloatType -> switch (slot) { + case 0 -> Opcode.FSTORE_0; + case 1 -> Opcode.FSTORE_1; + case 2 -> Opcode.FSTORE_2; + case 3 -> Opcode.FSTORE_3; + default -> (slot < 256) ? Opcode.FSTORE : Opcode.FSTORE_W; + }; + case ReferenceType -> switch (slot) { + case 0 -> Opcode.ASTORE_0; + case 1 -> Opcode.ASTORE_1; + case 2 -> Opcode.ASTORE_2; + case 3 -> Opcode.ASTORE_3; + default -> (slot < 256) ? Opcode.ASTORE : Opcode.ASTORE_W; + }; + case VoidType -> throw new IllegalArgumentException("void"); + }; + } + + public static Opcode returnOpcode(TypeKind tk) { + return switch (tk) { + case ByteType, ShortType, IntType, CharType, BooleanType -> Opcode.IRETURN; + case FloatType -> Opcode.FRETURN; + case LongType -> Opcode.LRETURN; + case DoubleType -> Opcode.DRETURN; + case ReferenceType -> Opcode.ARETURN; + case VoidType -> Opcode.RETURN; + }; + } + + public static Opcode arrayLoadOpcode(TypeKind tk) { + return switch (tk) { + case ByteType, BooleanType -> Opcode.BALOAD; + case ShortType -> Opcode.SALOAD; + case IntType -> Opcode.IALOAD; + case FloatType -> Opcode.FALOAD; + case LongType -> Opcode.LALOAD; + case DoubleType -> Opcode.DALOAD; + case ReferenceType -> Opcode.AALOAD; + case CharType -> Opcode.CALOAD; + case VoidType -> throw new IllegalArgumentException("void not an allowable array type"); + }; + } + + public static Opcode arrayStoreOpcode(TypeKind tk) { + return switch (tk) { + case ByteType, BooleanType -> Opcode.BASTORE; + case ShortType -> Opcode.SASTORE; + case IntType -> Opcode.IASTORE; + case FloatType -> Opcode.FASTORE; + case LongType -> Opcode.LASTORE; + case DoubleType -> Opcode.DASTORE; + case ReferenceType -> Opcode.AASTORE; + case CharType -> Opcode.CASTORE; + case VoidType -> throw new IllegalArgumentException("void not an allowable array type"); + }; + } + + public static Opcode reverseBranchOpcode(Opcode op) { + return switch (op) { + case IFEQ -> Opcode.IFNE; + case IFNE -> Opcode.IFEQ; + case IFLT -> Opcode.IFGE; + case IFGE -> Opcode.IFLT; + case IFGT -> Opcode.IFLE; + case IFLE -> Opcode.IFGT; + case IF_ICMPEQ -> Opcode.IF_ICMPNE; + case IF_ICMPNE -> Opcode.IF_ICMPEQ; + case IF_ICMPLT -> Opcode.IF_ICMPGE; + case IF_ICMPGE -> Opcode.IF_ICMPLT; + case IF_ICMPGT -> Opcode.IF_ICMPLE; + case IF_ICMPLE -> Opcode.IF_ICMPGT; + case IF_ACMPEQ -> Opcode.IF_ACMPNE; + case IF_ACMPNE -> Opcode.IF_ACMPEQ; + case IFNULL -> Opcode.IFNONNULL; + case IFNONNULL -> Opcode.IFNULL; + default -> throw new IllegalArgumentException("Unknown branch instruction: " + op); + }; + } + + public static Opcode convertOpcode(TypeKind from, TypeKind to) { + return switch (from) { + case IntType -> + switch (to) { + case LongType -> Opcode.I2L; + case FloatType -> Opcode.I2F; + case DoubleType -> Opcode.I2D; + case ByteType -> Opcode.I2B; + case CharType -> Opcode.I2C; + case ShortType -> Opcode.I2S; + default -> throw new IllegalArgumentException(String.format("convert %s -> %s", from, to)); + }; + case LongType -> + switch (to) { + case FloatType -> Opcode.L2F; + case DoubleType -> Opcode.L2D; + case IntType -> Opcode.L2I; + default -> throw new IllegalArgumentException(String.format("convert %s -> %s", from, to)); + }; + case DoubleType -> + switch (to) { + case FloatType -> Opcode.D2F; + case LongType -> Opcode.D2L; + case IntType -> Opcode.D2I; + default -> throw new IllegalArgumentException(String.format("convert %s -> %s", from, to)); + }; + case FloatType -> + switch (to) { + case LongType -> Opcode.F2L; + case DoubleType -> Opcode.F2D; + case IntType -> Opcode.F2I; + default -> throw new IllegalArgumentException(String.format("convert %s -> %s", from, to)); + }; + default -> throw new IllegalArgumentException(String.format("convert %s -> %s", from, to)); + }; + } + + static void validateSIPUSH(ConstantDesc d) { + if (d instanceof Integer iVal && Short.MIN_VALUE <= iVal && iVal <= Short.MAX_VALUE) + return; + + if (d instanceof Long lVal && Short.MIN_VALUE <= lVal && Short.MAX_VALUE <= lVal) + return; + + throw new IllegalArgumentException("SIPUSH: value must be within: Short.MIN_VALUE <= value <= Short.MAX_VALUE" + + ", found: " + d); + } + + static void validateBIPUSH(ConstantDesc d) { + if (d instanceof Integer iVal && Byte.MIN_VALUE <= iVal && iVal <= Byte.MAX_VALUE) + return; + + if (d instanceof Long lVal && Byte.MIN_VALUE <= lVal && Byte.MAX_VALUE <= lVal) + return; + + throw new IllegalArgumentException("BIPUSH: value must be within: Byte.MIN_VALUE <= value <= Byte.MAX_VALUE" + + ", found: " + d); + } + + public static MethodHandleEntry handleDescToHandleInfo(ConstantPoolBuilder constantPool, DirectMethodHandleDesc bootstrapMethod) { + ClassEntry bsOwner = constantPool.classEntry(bootstrapMethod.owner()); + NameAndTypeEntry bsNameAndType = constantPool.nameAndTypeEntry(constantPool.utf8Entry(bootstrapMethod.methodName()), + constantPool.utf8Entry(bootstrapMethod.lookupDescriptor())); + int bsRefKind = bootstrapMethod.refKind(); + MemberRefEntry bsReference = toBootstrapMemberRef(constantPool, bsRefKind, bsOwner, bsNameAndType, bootstrapMethod.isOwnerInterface()); + + return constantPool.methodHandleEntry(bsRefKind, bsReference); + } + + static MemberRefEntry toBootstrapMemberRef(ConstantPoolBuilder constantPool, int bsRefKind, ClassEntry owner, NameAndTypeEntry nat, boolean isOwnerInterface) { + return isOwnerInterface + ? constantPool.interfaceMethodRefEntry(owner, nat) + : bsRefKind <= MethodHandleInfo.REF_putStatic + ? constantPool.fieldRefEntry(owner, nat) + : constantPool.methodRefEntry(owner, nat); + } + + static ConstantDynamicEntry handleConstantDescToHandleInfo(ConstantPoolBuilder constantPool, DynamicConstantDesc desc) { + ConstantDesc[] bootstrapArgs = desc.bootstrapArgs(); + List staticArgs = new ArrayList<>(bootstrapArgs.length); + for (ConstantDesc bootstrapArg : bootstrapArgs) + staticArgs.add(constantPool.loadableConstantEntry(bootstrapArg)); + + var bootstrapDesc = desc.bootstrapMethod(); + ClassEntry bsOwner = constantPool.classEntry(bootstrapDesc.owner()); + NameAndTypeEntry bsNameAndType = constantPool.nameAndTypeEntry(bootstrapDesc.methodName(), + bootstrapDesc.invocationType()); + int bsRefKind = bootstrapDesc.refKind(); + + MemberRefEntry memberRefEntry = toBootstrapMemberRef(constantPool, bsRefKind, bsOwner, bsNameAndType, bootstrapDesc.isOwnerInterface()); + MethodHandleEntry methodHandleEntry = constantPool.methodHandleEntry(bsRefKind, memberRefEntry); + BootstrapMethodEntry bme = constantPool.bsmEntry(methodHandleEntry, staticArgs); + return constantPool.constantDynamicEntry(bme, + constantPool.nameAndTypeEntry(desc.constantName(), + desc.constantType())); + } + + public static void validateValue(Opcode opcode, ConstantDesc v) { + switch (opcode) { + case ACONST_NULL -> { + if (v != null && v != ConstantDescs.NULL) + throw new IllegalArgumentException("value must be null or ConstantDescs.NULL with opcode ACONST_NULL"); + } + case SIPUSH -> + validateSIPUSH(v); + case BIPUSH -> + validateBIPUSH(v); + case LDC, LDC_W, LDC2_W -> { + if (v == null) + throw new IllegalArgumentException("`null` must use ACONST_NULL"); + } + default -> { + var exp = opcode.constantValue(); + if (exp == null) + throw new IllegalArgumentException("Can not use Opcode: " + opcode + " with constant()"); + if (v == null || !(v.equals(exp) || (exp instanceof Long l && v.equals(l.intValue())))) { + var t = (exp instanceof Long) ? "L" : (exp instanceof Float) ? "f" : (exp instanceof Double) ? "d" : ""; + throw new IllegalArgumentException("value must be " + exp + t + " with opcode " + opcode.name()); + } + } + } + } + + public static LoadableConstantEntry constantEntry(ConstantPoolBuilder constantPool, + ConstantDesc constantValue) { + // this method is invoked during JVM bootstrap - cannot use pattern switch + if (constantValue instanceof Integer value) { + return constantPool.intEntry(value); + } + if (constantValue instanceof String value) { + return constantPool.stringEntry(value); + } + if (constantValue instanceof ClassDesc value && !value.isPrimitive()) { + return constantPool.classEntry(value); + } + if (constantValue instanceof Long value) { + return constantPool.longEntry(value); + } + if (constantValue instanceof Float value) { + return constantPool.floatEntry(value); + } + if (constantValue instanceof Double value) { + return constantPool.doubleEntry(value); + } + if (constantValue instanceof MethodTypeDesc value) { + return constantPool.methodTypeEntry(value); + } + if (constantValue instanceof DirectMethodHandleDesc value) { + return handleDescToHandleInfo(constantPool, value); + } if (constantValue instanceof DynamicConstantDesc value) { + return handleConstantDescToHandleInfo(constantPool, value); + } + throw new UnsupportedOperationException("not yet: " + constantValue); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CatchBuilderImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/CatchBuilderImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..5ab534dbd64a7f90de7f184091ae5dcd4559c654 GIT binary patch literal 4893 zcmb_gYgb%X8GiQ6Fb9SM0ZP)4gk)NCfdMixRa=>alu(*r2^gUuq^%x?0~{F6kTYj$ zFkY*+RqL(wR<+hk74J4RKxo!d>xXu&{s6!FKe}4uv-g?HnM=V`*GkUbv-f*>_WM5X zzVPP1U;Qh90o;rrfS`tujv9monih@6jd;qi=i{R@i)PXl2%oZS%k2{gc63hEp%!%- zB0B1!3v@5eF2ya|H67bX#gi!`lbN$pX53m{NyP^YH@R>&Yo%sQXNUs=Vn*Pu;i8M8 z!a#b~%!wwXk47E4&?HdnI;&?>>Ex2Y$>HssDIuQ~=}=i}(QyY_1?p)@AsV!21@>1( zF>K73sf30-0?i6#*0oac^G0T2%yc8zjiAKVreh!W3q+D~f#a(yW=3F_XHY3nI8l#w z9Mo_~M-+DnG#1SbTNy?*ke(B0>FD&S$qA+RKB;tA;BbczrI(IGg+hdgj_Npu4uJ-R z$g<}zWK*ss@Mz9}LZ!_6+|6a}q-&+^_(0muWS31RZ(C)*YHAMqQ<{h%hAs`=I(l%t zBw`*`My1g)FJ~>s97)?F*%TRY^xc=_Bb`dz2_5g36!5~V@*BZD_<)8F>i7`u6*zIb zgb=86Oe48q%%n`k=jl3p7`+-2I!@uVz`knS99>D0odThAqvN9j2Yg8>M#&Rm`p)2f z4gEUKVnEIU7V^{{crO4d8h=8_WWJb&@u9O|oF^Z2eJT?aeTJu)@`PA?+2F@1@ zQqDDOH$EV@j0en2vL54jSi^*lNqn44E_!7(F;~Vct9G|PM)`u6)-Ww_chUGzDrL?a zseWgkthU|3D@k)j5?#Y10(TbW#$1P`lG}A6xP)LWK0#IuUST0}CaS6_IwQ9quWx3e zX5LyfJr{LZ`@K=AYUr3jlIb*7R!q6U^!TBAo=WPg#5qgp5=?1=n?i|Zev!WXS86Wk zu&^jM%d|IHo`szM2&Ryd8~t)wD0B0j6SBb4I#%RS5ac@KZ%1mdme2TCR3xa6%?TgM zqCk$N%63-AJyf;;u@; z&+GUCzR10(kS4Wb^~G z&{OiTJ!{#sEH#0??P9TWoHcw`-bMPc*~58rL#`be2|YcZqfr~FSO$_A*`t(+cup687KL)(fwi?w&cZohmE$p9Qd#- zAL8Y{mTymi=XkwnlFvy#NSoxVPqlorsg^G-%6yOg0KU&Jp9K8YaI6MD;P;38brnH` z*dB^)Ld3e(p~bq_(GcrdM|12Zc28~M&UNg)Mv(xX=XW2%{2r%L9CbK>Mw-0?CvlLc z-;X#G^UUGL_z8c}u!1L4PXY|6o`e`AgctBrjz}O+@^_GJYpm-H)ZM^=HE3NoaCi3x zj=aqAkn$d;4sfsX6!qi_o?7uDex~MI@pJrwc7I7(y)g0;M}EbT0|-2%q4t(^$X3He zjpuYgb=z~{`ZcxqEcCDix)?AG5XT6pbFy20V%HIW0|(hOY~bYcgnb>_E4YtM^A`Go znC#lZ0|FyGTR1O>J;BZefxqKoZ-_#B+d^9y3veNaZenWcCN443kG4Fvfls!DHZZ$^ z`AsbSZSB@SC>(zsM`W`B+iR*iWV-H|;=IQH&6~KqjyQXS=Z<*omEI6RU6p9|awOi< zCXvvpyMfP5uHilpa&JvrO%C)?*~_60m#VadH}J&d+O2U0wZ{aPoftvhL`!Oxj~87Fo8Gu zviTRL@eVGDW{_SWzlNe1>jdfY%7 zzg0wh4RiP%dm%-cJxsflTEp)P@_F(^QQQ4C!WxE7zlA`@JLuQ&2mX5-8pqz^%Dj5} z6E*+LHF)G6C)XtLBQX-Yi;SL>1r=13mVZS8{nue$twnifwDJWM!8MXu_{c0rUgC)7 z=@s_=!lLx*`4L)^CDJa_@j4x<1WVc|T5RE40r;G^sA^q=h9y?=GHb(DAiSz+&w-Ft f!)k4$?d$9Yu#OG3E$ltVtZs(un5i>(HC*=}N^5Dt literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CatchBuilderImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/CatchBuilderImpl.java new file mode 100644 index 00000000..5d262c39 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/CatchBuilderImpl.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.Label; +import java.lang.classfile.Opcode; + +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDesc; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; + +public final class CatchBuilderImpl implements CodeBuilder.CatchBuilder { + final CodeBuilder b; + final BlockCodeBuilderImpl tryBlock; + final Label tryCatchEnd; + final Set catchTypes; + BlockCodeBuilderImpl catchBlock; + + public CatchBuilderImpl(CodeBuilder b, BlockCodeBuilderImpl tryBlock, Label tryCatchEnd) { + this.b = b; + this.tryBlock = tryBlock; + this.tryCatchEnd = tryCatchEnd; + this.catchTypes = new HashSet<>(); + } + + @Override + public CodeBuilder.CatchBuilder catching(ClassDesc exceptionType, Consumer catchHandler) { + return catchingMulti(exceptionType == null ? List.of() : List.of(exceptionType), catchHandler); + } + + @Override + public CodeBuilder.CatchBuilder catchingMulti(List exceptionTypes, Consumer catchHandler) { + Objects.requireNonNull(exceptionTypes); + Objects.requireNonNull(catchHandler); + + if (catchBlock == null) { + if (tryBlock.reachable()) { + b.branch(Opcode.GOTO, tryCatchEnd); + } + } + + for (var exceptionType : exceptionTypes) { + if (!catchTypes.add(exceptionType)) { + throw new IllegalArgumentException("Existing catch block catches exception of type: " + exceptionType); + } + } + + // Finish prior catch block + if (catchBlock != null) { + catchBlock.end(); + if (catchBlock.reachable()) { + b.branch(Opcode.GOTO, tryCatchEnd); + } + } + + catchBlock = new BlockCodeBuilderImpl(b, tryCatchEnd); + Label tryStart = tryBlock.startLabel(); + Label tryEnd = tryBlock.endLabel(); + if (exceptionTypes.isEmpty()) { + catchBlock.exceptionCatchAll(tryStart, tryEnd, catchBlock.startLabel()); + } + else { + for (var exceptionType : exceptionTypes) { + catchBlock.exceptionCatch(tryStart, tryEnd, catchBlock.startLabel(), exceptionType); + } + } + catchBlock.start(); + catchHandler.accept(catchBlock); + + return this; + } + + @Override + public void catchingAll(Consumer catchAllHandler) { + catchingMulti(List.of(), catchAllHandler); + } + + public void finish() { + if (catchBlock != null) { + catchBlock.end(); + } + b.labelBinding(tryCatchEnd); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ChainedClassBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/ChainedClassBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..04977791414ef68fc500b18b7ffb3b9076d36957 GIT binary patch literal 6243 zcmds5X>;4w6+Mrl1c^doMU9oHu^o9yDv^@uC3RKPc4N_2tXQJuNOs~_Nehvn1PKHf z5cJZ0P11c!m!wO&r)}DqcE(ZaWG40Jes6zH)AIn31SJroE;E^_G$etCi~G(!_q_X- zzy0&AcL3z^#}pFiQjk>9jUIu4HSL;~H8pD`dtrG^FS-IfCk)GQPYHC5j$Q6UFZvXu zRP;j?$gY*vvxepBj-{E|qN&wtWy937Mx|7~4EovIsVNp}Q#i?&s(SLEgH zS+BFYYna(`-730i*@7FQkny0&cUIiK0xD)!((l0-r)1}POdG#f|p8Ae}p z+wdvaD{%1Nd#NA$aX`UCDjvoM1RiK{y(KTygI1K03hWFA=O=}6q%eXp6=`G`hwT_E zejG!iK_a|#U+|dH%$$M=#u$fos$MSZj$WEJbh8x5sE>VQRUE=$0aXgh)hu`3w#ipE zmam1XX}D5ijTds#)ln6X;DZ7RUAg)VhL(x-;_*FAozGC_6zVuWB=bEf@OM%YGa|Nj zA8X#;Pe?b#=0Ix%UuE#wOKy4ctmQg4!y5a~Y(2K;?2>MJDILdg6*-(>5pe33z{Mc- z9mXzG9m7IYMm-i!srU#UWgcAH>snx6Lp9!rZiNzp*N-XW6`WCV7SjTITEjBRT%fNk zg;dZgI)_OI_Z?W3U7b@gBm42)EV6jW{GV4bi#fKsj%L-$wo?(94-bzPmb_i5+I6dR z*3>Jykw%G8;G$^6mU`M^9g}}{J-eakFX`s0v4q} zF9|&HzmR4dfz)OJPfBe*C9uDPWWs>@@ieX~SW@wfl*)rqk__2%5~_F!lcJRGepJQB zY76~!E`2|2`xld}@ zr55yB(J`v7&2_V~s#zsduArxUFVT2TOhoqKan!&gnS19wVQYKnwoz8N4QNifLH<{x zBl4d5is{TuXu^#&+LX@jvRqBDu0rY3lV|6kzxpUD)3N@O{-slqubK4@4J!C&|I)->E9;E zd}u4zdbJQunKyLhqPj8R#84v5S`G(%aPykO;?2D|Ra*}QAMAZYEgeMfTSO0Q&xgr0tZVkVp7mXx^QNKNfmz#LuUEqxnXM-sZ7<3NZSHD_uEya( zs3~|MubJk8;p&WBov|$4@sg<56#R|?Y~gS7-wsT{>uuY@C{vzl_)*|6*S`t=uk%PG zfkAm5!_%TcdE5no3a=Be(8ud;*u1U+Vwl$opDd-{gh-FS0VSQe@)z9oWTER=a$;xl zExZqSod*2d#ZSV!0uNjGGCz;Jjr*<$@g|1aiqB?&0wB;(5Engt2hWpdL*KAjHCvaSC`piopJQ=$r7%yP5v$6 zI&OIVFL}`=aFeYvO8KmxQ6}(lUgyyLF78FQf?fsd3ik7xRhzd(es~zxJIBwvM8$K& zzyt~JawH(^6LiWQ1;0rb&d{->KuzC*lDUn238eqT`-B&sJdgyAAcdn|C_}z&6Sj&^ z;#2g*!!-u(C4koQ9_XdVT^kr}dF%1oCp}MoXuW|aKb4>6^UvV3fuEO1S(1Lz64~1r zzastJ!a@J%NM@WlIySL^4{zXP3wM`?dx%5>C$XFR#1TA7`JBWkPJ2D4eXq?J()b)c z?;%U$3%rsMr}0IS-xW%NZ21yfe5B9Q{sp|qZ^_}eNVh~f8G-UPPV)roHXh?Q@fIdB z;~RKfhD7Kg+&-g$-PeCh{V6zJR@0!~t9+s7oFoscX7z0?IUr%ruG2 zkeqK5khGJOCPS3UmhZ5|r}Vo7{Sv;nmC`MMZ{vzb>9ZcC^FF0oKxrs~Fr`nE(yJtB ziRhmprO$St^!xZhlhPkHDSg?a^blSN&~1|V@@9z_J@0K2A2`iH_oE;sNBJvd)|bxQ zfxdy2%?|d39P|YQ|Cldyb6^d~+T(Nf6a18o3A~D*@i#?uKj&R9CI4D*|6BYXf57m+ E0H38RbN~PV literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ChainedClassBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/ChainedClassBuilder.java new file mode 100644 index 00000000..b33d192f --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/ChainedClassBuilder.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.util.Optional; +import java.util.function.Consumer; + +import java.lang.classfile.*; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.Utf8Entry; + +public final class ChainedClassBuilder + implements ClassBuilder, Consumer { + private final DirectClassBuilder terminal; + private final Consumer consumer; + + public ChainedClassBuilder(ClassBuilder downstream, + Consumer consumer) { + this.consumer = consumer; + this.terminal = switch (downstream) { + case ChainedClassBuilder cb -> cb.terminal; + case DirectClassBuilder db -> db; + }; + } + + @Override + public ClassBuilder with(ClassElement element) { + consumer.accept(element); + return this; + } + + @Override + public Optional original() { + return terminal.original(); + } + + @Override + public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer handler) { + consumer.accept(new BufferedFieldBuilder(terminal.constantPool, terminal.context, + name, descriptor, null) + .run(handler) + .toModel()); + return this; + } + + @Override + public ClassBuilder transformField(FieldModel field, FieldTransform transform) { + BufferedFieldBuilder builder = new BufferedFieldBuilder(terminal.constantPool, terminal.context, + field.fieldName(), field.fieldType(), + field); + builder.transform(field, transform); + consumer.accept(builder.toModel()); + return this; + } + + @Override + public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags, + Consumer handler) { + consumer.accept(new BufferedMethodBuilder(terminal.constantPool, terminal.context, + name, descriptor, null) + .run(handler) + .toModel()); + return this; + } + + @Override + public ClassBuilder transformMethod(MethodModel method, MethodTransform transform) { + BufferedMethodBuilder builder = new BufferedMethodBuilder(terminal.constantPool, terminal.context, + method.methodName(), method.methodType(), method); + builder.transform(method, transform); + consumer.accept(builder.toModel()); + return this; + } + + @Override + public ConstantPoolBuilder constantPool() { + return terminal.constantPool(); + } + +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ChainedCodeBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/ChainedCodeBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..bd507a6f330044717c3fe33dc4122ae3b0214514 GIT binary patch literal 1935 zcmbtVTT|0O7(E*B)J&bLREzW25 zlSm+`Ler6g&M?=Bu~6o=E36m*L&B`O^+rV!kA`#&-*$|HhHLtE)inyybY2o&(9w@H zZE6ZcKkjGH>OS}UA}%#aYxP{?n{;b=hRyR; zMHeUEiG=*11f@cT{vut1okpc3yggoWC^8Tn&_4HUIgWzee%Y=w%y+Es)*D4yHLH5; z)_qU#3d7K^*mTwrzV&|@{f%uh>4YDZ7sFUvr%%g|K^0+Dbh-`ALt)rCCjr^zo=}%- zt~{q&n#-EU$B=$5{BqTL$vs{X)M3bdZMWL+Od;VIhFjg9lQ#qlRK*IY+UYkS`yjpN zsUa&g(@WnySfuYIikPxL(>s;TeFn?UeuVm-hFw^u=Y?P@L(8+!ki%VyO@zyF5BF(A z8}R_61S!8Hk%ATamV{wsfg&OGLyA#@qo*WZrng+9Wj~ consumer; + + public ChainedCodeBuilder(CodeBuilder downstream, + Consumer consumer) { + super(downstream); + this.consumer = consumer; + } + + @Override + public Label startLabel() { + return terminal.startLabel(); + } + + @Override + public Label endLabel() { + return terminal.endLabel(); + } + + @Override + public int allocateLocal(TypeKind typeKind) { + return parent.allocateLocal(typeKind); + } + + @Override + public CodeBuilder with(CodeElement element) { + consumer.accept(element); + return this; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ChainedFieldBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/ChainedFieldBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..8e5b7517ea36a871ab0f6e98094eb47d30f9078d GIT binary patch literal 2603 zcmbtWT~`}b6x}yKhJkpEGUKn-^#s9otHv6A2AT9bM1`(nrPPv}t?NwGAs>u#8G& z-?U`fES0Tv_RuhGSzI=yRa~r^R#CbFodw6PR7+}jebryA>X}x0ziJme)3MXp@N*`K zi|E$SqvH~K1uoTX17H<_i>~~pYPvG#*tx1@35<*eAtU%RW9MJ>lKN#GedrfRdf%00 z{>1bOhiCljY@!S@D`P7ft_obOE460Od+FPPEGr60T*2E)&T9gxD4@LOn)X2^f@ky4 zbxw>uOJ)LPuj?4XI~0k6mP|@2FumGJ;?2;m0ilL>1@8V=w=N9hrjA>v2qInAC9x zX@P6?jGwCxR;5u;dJFVLB@Rl1YHFAg7_O(N4%(M$$&w{$dr4OFJstP)zCb%`fF-aT z4cFYOp`^~3)R=2{&}#kD?U2Zu2e#o=T`928YCp_H%I3_PA(_m4Mqsf8{2I1a%TPK> zk#&m1)4j^=o2!=gq`Rq#RG@d&DHzt4;hJh5zKj+21g2V+X_HPstTB&{?cSlut(+`6 zCoDNv8YO`n|ID?}!98w}2mMz~3ORm_GtW_!PYE|As5uLOjR7 zACs@qIomPN@e2ljKo@7jv+;rWGYtMryLQa+KIE@8%GnqaNMVuPc>@#p3X|AjhyGAS zB%;UUF^`Wp+Tw~IlSiCicCo;B>bFbJtiS%Q&n|{Xe5+WhZ(U>=!xG0CbiBc3bZF?* zFr#6dcLBj^ffvu*&NW_dh>Cw#LKDRN;czI}GK2E`;+=949Nqa$rpWRoZV3FuS1TJXd&EksdLkN{3D?+W1SPVo24|sQ+Lf zt|X%=S^ERqQwep7yaLg)z=)snn~HdkPvw consumer; + + public ChainedFieldBuilder(FieldBuilder downstream, + Consumer consumer) { + this.consumer = consumer; + this.terminal = switch (downstream) { + case ChainedFieldBuilder cb -> cb.terminal; + case TerminalFieldBuilder tb -> tb; + }; + } + + @Override + public ConstantPoolBuilder constantPool() { + return terminal.constantPool(); + } + + @Override + public Optional original() { + return terminal.original(); + } + + @Override + public FieldBuilder with(FieldElement element) { + consumer.accept(element); + return this; + } + +} + diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ChainedMethodBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/ChainedMethodBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..59ed8d7f180dedc2b30521cdafff97c1e56a7a64 GIT binary patch literal 3842 zcmbtXYgZFj6x}x@41`e-6-80;4MB|fsv6Xqh=mGBh5D%UF-Zn8Fqw&yiRd5bU+IT_ zY1i^m?OLs$`=e_2otb1N5K?Wk)=ci5Irp4>_Br?5Gk^X4?hgPtyhtL34h3-)33Lkd zt!dA+w5eIE>3jJ#z2FLTP8ycs-Vo>*8GX==E_5qMs_20#aBi)*o;EC3cP!0J7fh{M zT`^2OZIml!I#<#ROE1ppZpkiYYld0W9f7WbZB=V!IXpD$S*y8*nO><`1=p~xbS`+E zNn$5@74)gtg?@oup{$RrDzMYhpVkaVpSP{~nrRB08u3*|9LS7rebi6i_o2fD6Z zqM|Qu7;d2?a5}m^bf?LM%*^PFg8c&fL$2mDE}wc{&@0l1B=+HeB=n#_DynhObqs4Y z69KeTa_kK)Z|WJJ+e0c2;|N(IrDcPp3S5|NNAgl2*9=j?QGtn1Ue|-;IHBOAic>f( za4@8NOL&+UT0#0Nus7zU(D%@SA$kZqHh{|(m#6&GI?lEjOBI5h1xt?{Jqc)%69@%BYyc zbpciGP*=0u1>0u+UD*a@U8+JUZ`anB1Od*-47jP{bKGJ++m5m7=kq{apU3V!Z^vk6 zMnR5@gj*^E?5B3%Q<4Q}O2r*~ArR-T<))o(okvZ}nySEN)pfuMX4*n%WN!DOv1(~< z&Cvz2?TXlBWUFtsS`X5Vj6klP3w3zy3^9b{Lv9^`-dUF2`C2)zJ4>>(2=vd|1d{75lsDYMyfyx`^fk(R=t zz3t*DB|?*of4<(IOtjq*tqvW5t1U}fyX^DXkg=NIhO&B~%futDN={y?SESw%2Qw=n=KGJ8D|E#6ppI5{Y-c)rdR_ z7UVS3Tr^yr^r|zKr8^!?dR0M9;ADuuNq;ji1sei~+l#UX^1Z+WPo)@m6!G3CJ2*C& zeX>R7voAT0;Vu-86PV?A4iJMJD}1w@dIOO<^9o98?D22d@o>K5a(sMm{2g`!KU09e zAzm?W1U6<|%d$z_n zJA-ca6j_|b0@8TIKIsY3-;)}NXqtX3;46+E(Bggi(aATf z&rA8PhhE0;kWVs5e83(g6m%(=R&bnm0l{g37u)BqIbI)#ir*fA2x8uFI3Vm1&G3}x zopj+g6-x@#)JrI1Z*eS!)GwUJJon^B3~&iaT=rZU@MRmYRXoNw)FkNaGT%v!4mv!k zA*qqqka&xc7{*@X%xjzvEp&Jm21to?tCuZOKdy5pWN-jCBG!f))`sw{M@dMHeDWQw z`>F6fM?XO0UE*+wBhLR}iGiLG!~FOdF`slnNA@*tZ&q|FqNqE7VsJr%*!n=v);Nh_ W9j1p>pv+kp8K?$x7tin consumer; + + public ChainedMethodBuilder(MethodBuilder downstream, + Consumer consumer) { + this.consumer = consumer; + this.terminal = switch (downstream) { + case ChainedMethodBuilder cb -> cb.terminal; + case TerminalMethodBuilder tb -> tb; + }; + } + + @Override + public MethodBuilder with(MethodElement element) { + consumer.accept(element); + return this; + } + + @Override + public MethodBuilder withCode(Consumer handler) { + consumer.accept(terminal.bufferedCodeBuilder(null) + .run(handler) + .toModel()); + return this; + } + + @Override + public MethodBuilder transformCode(CodeModel code, CodeTransform transform) { + BufferedCodeBuilder builder = terminal.bufferedCodeBuilder(code); + builder.transform(code, transform); + consumer.accept(builder.toModel()); + return this; + } + + @Override + public ConstantPoolBuilder constantPool() { + return terminal.constantPool(); + } + + @Override + public Optional original() { + return terminal.original(); + } + +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$1.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..5f091b1b966636701615e56b60dd0e9028a4fd7d GIT binary patch literal 1144 zcmb_bTWb?R6#gccZnH*>RqLf*+FGPZ)kOpm5(*)EHgCbAYbt)8c8KQKhTlk+RTDLc^}N^)t)xtsS6jE98{~g zj4KQ~li`UcwGpA_%9}gO=}dVY%e7Bj2c&I1XDIX8Or0|Hw!0UP*sSM*+s1@)5F2qw zq#|rOs4=W1w6T%O8^zi;GSJ?BwqYoBf}voz+Lc-y#nXWZ-}8YY%St!!x$5&!T0JwC z%(09Zo_7Bs#U=wgVR({zOQk2rnwvPJtMvbWXoHJ2PI-Z0D)B zd)ik)B=tDW!odbZ{lXn&SUwVwc@sqRPO1l5i!g~IBCONk7eEo{nHA}$*G1Yj+Ib|I zwKTqgeW6VOE412UppEOaR#O0O;3jFzz8ykY=a-}vNEX;F;38RZ%|ld3Ah6#{!*Fa}4n#!%9`{GPf8;iU-D#k+lq23Hb#s>&hahGIi*P zBf-$696iU7?w;*b8B!NJZ#S%R3Fzq3(5<5fNrq%I-{$TCH$8^-1tEpE#1I`%?`Y^_ zm~O@ArEthCfVkodtIQn@R~W`x`2^OAe*(Q2)NvI<44p3bHXTtBR5XTx@erFDv|M^8 zfqq=qF^n4wJ!Ye@MJ_AeegL?jBHq$*8zZ%dCGnoGQ7;%`)hM7 z%UgzHR5@Kw${a6=iZndmA%xm)ZGag@FJ{~507EHcRG-kA=KuXz2$}yg7LAxogfUUF zeaGZ#Lr~4~jj2($Wm0sSRfh0BA#P8&@5twWP$>yJoNhm30c*p literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$AttributeMapperOptionImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$AttributeMapperOptionImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..b2511a21c6eca3ade7484a30fb1ac192bf906850 GIT binary patch literal 2317 zcmcIl+foxr82&myCWL4LDvGP(0hNSZN7mz-h=&M5RXmg^Rk~N5q=A8)z5uA>aUK~ASQso|2w8^G2H)nk z%jKH=LbR0MX2{kY>F7Czf$8$fFmf2SkS|~a1%~=Yd((EL7QW=J-Ew<U9i+oh{F` z>xNt)a*3#^2U`11Gt}Y<_dMZ0^R%O+xnU^sy>|?!8<8KOc3gWklr6(+FC?4l7`cA9 zfFeo^IjxpSv0P(#J>56}cdF&sc7#E!Ix;v`z!4lJgX=t4udB9TSUezuOD3T40*>PZ z!7bi~+zlAs9E|p^Xr47UL`zr8Z!DZ-xR$0mOKrTxw4#*M6l}Z_i8ZzpM7-{h?xNmAUF%mEkPmVv2O1;wY~$4958>HXJFQhFeYH zzvNAqJRWPP7I#;;?-)8c9MtO$;XQvK)x$8p*Ty?<*G}n)(Ce!GocnxBP|J|b?Y^=6 zCI}5eN2hy~dDP-d4960$q88{B4FgjK!L)3WD~8EkZTsYeA?(lbn<8b%FRRdR2{VPr z_fB=2xpTz?LjC+y1bR^g+QKYD`IjdMb?WYfEIm|82ioUeoZ%pcks^at%;HuaxABjK zI|WoxBcxLF{7`CVOV}}ri6k{xb5|L|r|v{Ja$9W*J7!$uvh9jss-e_o=ymr`GP1hT zlnB10N_-@OmhX64`Q0KBEZql*j(>kv(rtaur0mo}VM$8iM=AwX_{0xgoX&j<_i50l zc%(z3lO`&~p5hkj3>Q<;KG0a0XE@WJl~Nhwh*^5xG9a(%8#7NFt$)yP&fpZikBq+4 z7{D1ic}`~;TJx3v!74NV!TLnh04C|5B~IWy&eDH8=E6CgCyMwJtruu-w8tl>Xg5Xs zAx76oOkTt&y>XZ5${3ub)v#NY9UKBa(l+yxwOFH-SR17m>v9kAQQ*Tbi66&wB3?_v z%~fW0aBM&MIM`e#*c{5JM1GH8hBTNs?1-jNE1zNYi()8I6XX9UVgFa;^c7NJV!w*N sX)Teuy?MGurv`_cl#Lv&;|A{1$;pViiaE;d1n%KMb{G%w2n(3_4l!+e3jhEB literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$ClassHierarchyResolverOptionImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl$ClassHierarchyResolverOptionImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..4d793b671456e264990225fd8cf0a76962b4f938 GIT binary patch literal 1979 zcmb_c+fvg|6kVs#rY+Gzfic$Xq7I1Y6xIKc3rFQ(~{2GXP^DKmVDKjDMS z=s3fJAK*th?vsQzOrh}5hvuApy7$^=t$p_X`|tP)pW%NO2c(+&CS9H_mwy7G5W~h$yMK`#j*Xo9{ zD$KWJ7Rj3NtTmn6s;yNIH@RaO2i)GMySilx2ZmuUzRiVUuGG3!E63S@g*5THDkFt{ zhPZ2OxwdZZGJMXIx_8$?HgqFDgO@ig;~EAjZ&h`wt5$_GY;-qoQP3NfF@oz<8UD4Q z8V-Zn)g&Qq8|6K&xrOXU31bY4=axZKxnqSH6uM*cZCzN!><&Y(uVAXAn|!@dD|35W zEgPh1x@2jpv7_3$u!F;1x2lsArEZp)`r$oyt5)TMYO6I)&zv$0X3nU-*BwQMp)kv) zdJN1G*KP?A{KYVT3hhE&7?N97!`8S^oFKg>IO(x@flse*ojdND<+u{&7_ygs_Vl1m zdcJ?fvRuct)w<8$iK8#YAf;k>kiTRToa#UA?b^mvYm!MQFif;$(VAn?i}Wiu-U&qljoaB4LI`I08RmB30?+6%1>6aEGoTf>X_EFrR^Kr74X^qgD%>4$-<$pmsA}fLk`o_o;_=ZXP z4*Oo1!Zcar@1Zf=qos4-_9?z*#qgcdJEP)qziPsqY58Cb%YXATM literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..48f595908583e58d9d2b876fa5faf5d35dc5b76e GIT binary patch literal 11519 zcmb_i34C0~S^tl&w^}{xv}`{gv17}&w2~~_@s(ZI(H+TN9oAu6aawh?dY0B+?JB#g zIPL+om=p>z@e zZ|3cr@BZeSZ@$r|Ub}M_K$m#jjUp6lDA7@hGJ)!=fhPlP;Xq`jZNv;lW77gNzUx3MI)`+$ z;jln`+B3K&<}(D27a)*!3Okt3jiY!-!!aGlae|JlR@Ooy6mA=ux@ra!aVkA#KCuvr znS;^D;6j)y@<5}Flr_!QwDzZ3Mv7B99)?%IowzY?j$RKXg0li1JG|2Zwshv}Z|c`@ zT3}mdxeo-0q35ZfsX~DpKAe#e=#dBo3yVNwC7x3n%l5YuV7!`OZKYUuL_7&ph<}ogP?1CtA6>{7hudzFz zlao1kOd*gp-ckr4Ez}xMDFnH$mlOib^^ijIv%O;@v$KM*ZIwGIIiFV)qLo&j-6K>4 zxg@Z^U=kw}7&k8BG3h^-1r9e}?(`RgN~J!e?ZGA2!*H3n6rwqpk(@>C}!;f8C$F~ zSwm2u*=b2;0Vw+^^cpC}p?o^%<~9{fD2OEc8fFUUZFD{yO4tQ=V;Ui8v8w{_rqc50 zd<`tMm1nwQENxy#zg7XODWlz!GCjO5;A^yR>KSvUrD(8gEh~Ry!qSHu zI^H7F%!<*zj**`3$>E_Pe+Ax#w`=$o9p8#?6F64b`nEhXX;Oir=oNuWcFA(M8(@kU z-iSBaB}h5E+f<&VZ?Pl+e_Trc69PvI3Xnvn%&q8Z_(_4indRRf4x2N9a7S#00W6Y8 zr}!Fvia{(hPpR-mPb?OVx$z8sM#qP-$enJ+Obqal9GD^ho3l)rJPWw-EIuOF*GF@L zV)DBTus@Gq(C~|L>HiXsJ(&P2IhJa%d3q|8I_dLy9ZUEa10T;jv({OL$EdN!%QkrB zhF4_GLz!7_3Ju9)4|SEtnbOnM;;)6kvW{C=5pX42j^B_aANO#_=;&m3Pv`if<>G*9`vr#|$ z`v-d_2ge6Gdqzgf(Th*%__VCQ)Tyr>e*a|0*w{#a=lEC;zn{hL>iDdzY*h93Uz!~4 z8yXp#JUc!x%x`}DzK%bTRf?+Nj>BFsDaRoGP{$w1szY6GN56k^XwdrV z@96CDk81d1fwLPnSl(bKy`lntiqC8KGaY{}L!KwIdUCvOP4FP^)8>`HLO78sU%2rS z{!%WRFYq91UjT(rsVwFpTzkI{I8V?CF~Nc%qgUc)~M>{?gna-}obvKCZT<~TPd zixUF1{%9}|zQ9_Xd{6#Zl9&x~=~NGxiP`A%a3B_#Gg&+3PeswFfM7ddTPiuGvBwqx zEviZ;5$#w>o(2@?pQ>3i7J5xRF ztQDoVRE~Rw*vm&lGm$`IAx5|Ri1X4;smnSXW;FS~)7$@@Y37CGo5x%$ZxvW@=3B{{ zCw00nxfC*6t}J;dos%aF#uZ0R*vQl8BIb4V!ys2J{eFFj3=M&E1qI7Zsq6)2TbAUL zrrw;%=rSo7S(6DL3#BTZ%4Ti7e2mCi9gyWC&ifyhBpnZ;kI8_S2?WVKp6PT}1{ai$ zmy;`{VoI`hPqvO1gmEgju_#y&E)%3P)J_+KO7CWC3vV)Gwr5?A0_NU>$nsGkpqxtD zM(E@gTB*sC1?i+^%c_eB^xa2}o4zn~ke*DqP6xxu3q<#5bRiZrt(~)0ttB~@nSrWR zGt(Y4iPXEd6KGhEDDJ7?S_jtG1D{ zca`iqNbdcYZ#w%zO1@?lGnF#dOB9g}l+tSVg9OF*rvu7Wviv<38B-`_ z5>%BF^?00ch-vhLH4%#!%IP(`CLYmYWX7`2O>lK?IiGo0cAQ~mnj1xU9jdrq$CK%% zX?Eh%>Amd3+Q^}U)<2b@&LJ^O( z_xN`VweoKnc*j{Q|FS^!{96Fk^9En_yk%EC@4{8jJ8aeS{#o_BH Gb=e#8^uc}$ z@$6&(q$MPqih+wJchQ62R(*s z8T&m(`7)Y3hI<*U&l5utzRG7Av4eE~na_C(GyX- zkV1y3h+-F&O?8U%o{vKt;A7JuA2r?*KI^@ud>Y;|K6iOFJ|FbD_}uR;=d;P{=CjpX z(d^X?{qBiP#V0E3E9*Bsi?14bedSSal~FZu8%HjBtBX(67}fPPcW@H;C>h|tQ&y+M z=;U~a?QyoNY)`R0&GtdIXW5=(ySobCgb*uu!zYaD7t!vmHEIVI@pk#r>8&&B1{X0e zU%I`Ujm_SYMNG-JUT?iYF%~f<-}<~;j4j@>MfA$Iv)--7R+m zRIFf3GF_~EV@mn$Ia=0FTMf{w2kDJNRQoXY;ykT7fcD@HehIb+AO4g2DCHH#aeR|HD8pXS zM!EKoQln_Xf79PxI3)JrHEO0D$HXqYPJegv4<5F15gkT_kZWlORj;E5RT^BHDALfb zp;JS*hF%SQ8qR9)YZ%lptYL%`B+P3tG*Qg|;+tqM*Y!=-zgOXYl?(}4uC-PL7itLw z0Nks%IMK`)F(J)qU+S|;G07`ByPL z(efg$c$!x*>n)-8ynt&(FiLLWiHzISs-O_13g)S>C#ay9qIt~1mZo_?Xu?H`q#(-a z9Fp$?qC)6Y{5DjIO`;MdLdFF>Ijcg@C^Rx9609bQILss@o?BR0!c!lH zn@qoT5oNdW4#tEQqhu8~Cp^uqD|q@AzAKm8>on6-sKE_7)>~}cHm1346!k)eV$z^F zW!RUaIy!VQVQQ5GCCb1WifU-lw{bGd;Ynq7ahe3FY9@!@^8(&SUEjtBa;@_&n{}$v zw5u%INy!a~SZq%sP7tvS$J;%g=3DroTllf(23GOxM9VGw^a_6VHh%6o#dSF)e1IKp1) zNAujl$F1OJcRXv4u}rBYk=Njkc)$VtHduVm_FHH0yIklN_0!~9D%j;|zJp(058m>7 zS6Vg~z9#l4zAMCoNlb0(9gus7mTMq88>LA!%*4cA2jEQ`1FjSM9Dr*!2E0`?H~`mg z44C)24#397fOm`i4#2xM2E31(fMqwkwjbOW@Ii6V0eJt$fO&)H0Nk`O;5O0d0NlC( z;OY)6ag(qj>*1uYmdPdiTt4Wsq>IT!sg#SWnhq{J+kSd|9S~!WI=yVh`H6 zou4ERO4emF8MWu9f0i39d?S zxpe|3i2XG2wDWqVo3|}}yixHp$r#3n=w#G)iNoTkct{)*$HfV8Qk)VG3$O5re!{+! zx@gBeakkwc^gVHoeK&hQ`(E|~?EBacvOmjyh`pcvF#AFF=h+XlA1Nzm8goyKmX$M+ ixF^Q=ev|m+zn93tI1Ebd5*OINZ2c@QiV1NU#{U4HpV_Sd literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl.java new file mode 100644 index 00000000..8bffbd6d --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/ClassFileImpl.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.classfile.impl; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Consumer; + +import java.lang.classfile.AttributeMapper; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassFile.*; +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassHierarchyResolver; +import java.lang.classfile.ClassModel; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.Utf8Entry; +import jdk.internal.classfile.impl.verifier.VerifierImpl; + +public record ClassFileImpl(StackMapsOption stackMapsOption, + DebugElementsOption debugElementsOption, + LineNumbersOption lineNumbersOption, + AttributesProcessingOption attributesProcessingOption, + ConstantPoolSharingOption constantPoolSharingOption, + ShortJumpsOption shortJumpsOption, + DeadCodeOption deadCodeOption, + DeadLabelsOption deadLabelsOption, + ClassHierarchyResolverOption classHierarchyResolverOption, + AttributeMapperOption attributeMapperOption) implements ClassFile { + + public static final ClassFileImpl DEFAULT_CONTEXT = new ClassFileImpl( + StackMapsOption.STACK_MAPS_WHEN_REQUIRED, + DebugElementsOption.PASS_DEBUG, + LineNumbersOption.PASS_LINE_NUMBERS, + AttributesProcessingOption.PASS_ALL_ATTRIBUTES, + ConstantPoolSharingOption.SHARED_POOL, + ShortJumpsOption.FIX_SHORT_JUMPS, + DeadCodeOption.PATCH_DEAD_CODE, + DeadLabelsOption.FAIL_ON_DEAD_LABELS, + new ClassHierarchyResolverOptionImpl(ClassHierarchyResolver.defaultResolver()), + new AttributeMapperOptionImpl(new Function<>() { + @Override + public AttributeMapper apply(Utf8Entry k) { + return null; + } + })); + + @SuppressWarnings("unchecked") + @Override + public ClassFileImpl withOptions(Option... options) { + var smo = stackMapsOption; + var deo = debugElementsOption; + var lno = lineNumbersOption; + var apo = attributesProcessingOption; + var cpso = constantPoolSharingOption; + var sjo = shortJumpsOption; + var dco = deadCodeOption; + var dlo = deadLabelsOption; + var chro = classHierarchyResolverOption; + var amo = attributeMapperOption; + for (var o : options) { + switch (o) { + case StackMapsOption oo -> smo = oo; + case DebugElementsOption oo -> deo = oo; + case LineNumbersOption oo -> lno = oo; + case AttributesProcessingOption oo -> apo = oo; + case ConstantPoolSharingOption oo -> cpso = oo; + case ShortJumpsOption oo -> sjo = oo; + case DeadCodeOption oo -> dco = oo; + case DeadLabelsOption oo -> dlo = oo; + case ClassHierarchyResolverOption oo -> chro = oo; + case AttributeMapperOption oo -> amo = oo; + } + } + return new ClassFileImpl(smo, deo, lno, apo, cpso, sjo, dco, dlo, chro, amo); + } + + @Override + public ClassModel parse(byte[] bytes) { + return new ClassImpl(bytes, this); + } + + @Override + public byte[] build(ClassEntry thisClassEntry, + ConstantPoolBuilder constantPool, + Consumer handler) { + thisClassEntry = AbstractPoolEntry.maybeClone(constantPool, thisClassEntry); + DirectClassBuilder builder = new DirectClassBuilder((SplitConstantPool)constantPool, this, thisClassEntry); + handler.accept(builder); + return builder.build(); + } + + @Override + public byte[] transform(ClassModel model, ClassEntry newClassName, ClassTransform transform) { + ConstantPoolBuilder constantPool = constantPoolSharingOption() == ConstantPoolSharingOption.SHARED_POOL + ? ConstantPoolBuilder.of(model) + : ConstantPoolBuilder.of(); + return build(newClassName, constantPool, + new Consumer() { + @Override + public void accept(ClassBuilder builder) { + ((DirectClassBuilder) builder).setOriginal((ClassImpl)model); + ((DirectClassBuilder) builder).setSizeHint(((ClassImpl)model).classfileLength()); + builder.transform((ClassImpl)model, transform); + } + }); + } + + @Override + public List verify(ClassModel model) { + return VerifierImpl.verify(model, classHierarchyResolverOption().classHierarchyResolver(), null); + } + + @Override + public List verify(byte[] bytes) { + try { + return verify(parse(bytes)); + } catch (IllegalArgumentException parsingError) { + return List.of(new VerifyError(parsingError.getMessage())); + } + } + + public record AttributeMapperOptionImpl(Function> attributeMapper) + implements AttributeMapperOption { + } + + public record ClassHierarchyResolverOptionImpl(ClassHierarchyResolver classHierarchyResolver) + implements ClassHierarchyResolverOption { + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassFileVersionImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassFileVersionImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..87994c33dff188461531e9e7101731b4d55670fe GIT binary patch literal 1310 zcmb7ETTc@~6#k~SEoDog0*W9aP~8^nBB0S!O|)X%q>%?mlZN=PZ3mpX7qi{spYlNy zQDUM$z#nBivs>C)nkGE#nVB=^eBZgv{`vd!H-Iu8r4T_>K}pJ z=?%+lw~vLzbzy(B^cVHE@0ksM&*CO1f|QC$s0>@6GhE$vTJ)XE`82M@v*BQ2l13MZF=~=G1xiT0ADc&hqV3=;1r>1V1&WXNXZxLMz zi&#={OT{v7GtBhw4Jz)5j6pdytq$KmW|-HEeC3iwDTO;&Rj{UF9l8HF4t!5ICshAq z*RxG(#1n16KfEm+4XDDPN`ow2D+Tu$*8AlBmJgSLAy#&qoFP*Y4u9LR>)bmu>lSIU z6}MqpRnrsl+*QW>_o7WDt&D5VFo_(5QZP>jRp^r^e17OM>`;DV2J>=@OZh7K*Dw0L zbyatUr0-soc~%=yI2xh@x8pUq9Ak!sQJEBFUGadXI0A;dB(w5y(96rpp{6xX`Z(rD zYILf}$4G0Y@B^%{cm}1gbcXa-Qbmv_nMI7`D#(6C@9 zi6s3b?ssW)TIF55@D0jm+JxYVK$#B!)zF{|NIf6voE~;Aj&v?UGRg$^D9#A2=?zIu zU-~5gp>Z#*G`6UkGWcz>3L)PFH3XKk^YLG}QHx6CbKE?r#U#Gm Vonz(8P?nDe0$uK9xf@tL{0EFvDop?Y literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassFileVersionImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/ClassFileVersionImpl.java new file mode 100644 index 00000000..ba260529 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/ClassFileVersionImpl.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.ClassFileVersion; + +public final class ClassFileVersionImpl + extends AbstractElement + implements ClassFileVersion { + private final int majorVersion, minorVersion; + + public ClassFileVersionImpl(int majorVersion, int minorVersion) { + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + } + + @Override + public int majorVersion() { + return majorVersion; + } + + @Override + public int minorVersion() { + return minorVersion; + } + + @Override + public void writeTo(DirectClassBuilder builder) { + builder.setVersion(majorVersion, minorVersion); + } + + @Override + public String toString() { + return String.format("ClassFileVersion[majorVersion=%d, minorVersion=%d]", majorVersion, minorVersion); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$CachedClassHierarchyResolver$1.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$CachedClassHierarchyResolver$1.class new file mode 100644 index 0000000000000000000000000000000000000000..e426b05e6011319cce1a8066aec1982f72a3db89 GIT binary patch literal 1969 zcmb_dTTc@~6#j;`EL#?-h?JX(S`kWNLA;;~sHqT$6o?pJ&9EKH!m>+twXdMi$$ zT|r92X>>4TkHnACsPBowEQuiGEjpVn!;_(CoUY>s+zBe_KM=lY3`g0AHL7nsQ%jZ( z3>BR?tDs9m8r=*JPq63=@#U4(IflFc8KZ(;hW=|# z$?bLSS@K*Z#)B=(XIMGOkTVko0aqH%j8ngzq-ipoDu`gqEv|Bp?+WT-ie5D(LM3h) z&PVHY>_SOD<_YSnwzYtpI|aTM)dcb4=UyEvHnu z4mrVYGR#J65Z+2STWihynVwZ>hndn%gy?Nq7Jjhc`hkMm3}cNo5>2^9#}QuWP7pBq z|24d+BWmN4g9`)H@+}}7fu&ON#h^zdMqg{lxk$TN`JT|4%;r9TWj{fAOQ$AWqJJ}K z0?%=o{#`^PDP(YkR=FF*RpJlPUM1GE6hJPR953{jrgy5Q)7kf6BcIXMghK8+)OR@Z z8u8p45{ZR=3?oZM=~=-Dx=A`m@*0|c%BehhkG|A>a;y_a zI-aCeT2!+m-_Y|BebUwOlr%C)LRB|1kpvMaj|9d;g$Y~>*GXKbHBOJf4crPTQ@BHG WFU8r3DH!Mp{SgVH^r}ratG@v!vNdM_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$CachedClassHierarchyResolver.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$CachedClassHierarchyResolver.class new file mode 100644 index 0000000000000000000000000000000000000000..94016b010e6ea29810a5d74714135a7db3c1891e GIT binary patch literal 2407 zcmcImU2oG?7=BI?>Lw&B3(!*N2kXk#q@m^;MoL=*Cs#?I3}; z0Pc1%{=shHmQPh1(zNUSCWLs7ofexQSXqgbbB^D0eBS4M-Y@_A_OHJI)G(Dp3TX|Q zJa(Z?V9%;?+t6*pS=O&Eu1YfyXdAU0D;N_<50w_OXh&8D*AeKAQL)sN>YLlu-RQyr4c&Ph#3AySpp875?%H}Ikkd;S7k%l_r!|`T zfuoyvL$X^nlv>Yg=oPr|{+iDjIheG4+F5c{H1+3k7~ctG=C1xSDKH*W^aVFEM!pxA z+^!#!kxFDLT5}k{5fvLh2n@stGhN3I3@3;p{Ic}T>W$KZh9QCSf9FFWJ8vyJM$qu2 zfD>~tV|_GEL#w*@?pD$z`Q1#bkI-Hnt1{YS3S0dB_0^9h2>px=@z_*_ptQhvskwFX z)-hu_a;~wqD7|aOqD@J0#x)Il!SF2g+!SVl70YMw*wG9ZXy43Kfyy>~Li#(CDDSLq zBK_lk5c9R&rg+aU%OH$2mB0cw6L4E2HC{NrB%hfj;cF_(1p4A6w<=?g@+8Y!VLmX- zTa1*Z_uEHJyV=BY^KQd4q#s;y{XoM-fsyUi6OuITIMNGm zmkhg}Pxrmz2QWfnJ6nYcAC9wTrXcVm(yaC@o$TX9)r~1Dah*b$&+H>x&%-<^SjH;c zJIWJ2*J;jO1gRc?LQ%8nOlsz+jkMtE`*08wk(kj%hjE_g8I4nD$1^F^g(D zV+)UaR`p$pL<7Hx+*PT>3|YTk6JB`AaJt+K!ji5Za5spYJr=%IP$3*NkV6;40oyMr z^i^&N2DaQom+CQa2!|Q;KrRNJ?Y?1nIaJ=4Knuf(&?4sr1=(xhD2@?imHXAAtWYeo z`vzH32*(Yaz)32Gcw6U=&+ux${3mWSzp^H*pfJ3gr4*l5j5xz^j({4RXi<*kh!kfH zoWpsl$o$0YWO3Mws;X%^2!H%6QSP;H+Hig%M90d)74EGZF|L=pLJ*r5qY`bEv zzOf>_CBEWNje5$`;?8sK*=ipP+k>i2`JLV;#!yQ=6+u;2o^g+F2;wR^KRnceNMVDO z7>*iG0xE2?D|5Yk#h_h{W^1LJj~(|CNvZc zJjNu$ndbGqx*OOV!i>@oyJg6%Y$GvzOlHz{H|4r8BgGl+Rvh6El%-s+*9wWO#$BC| z#D+`nYC_E)&#nd1OPYk)OA2BiFLyghqVE_cjba)l*NrEkAg1*GR+@NXY9ONIo5`^L z(ig;>-HtSr83vn9_Q;TiIhxCRt5Uh6bmA(Fj}#aN(1srMP^hV_1~#q7)R>@EqjQ=s zq<4XKPt_|#YcBs4EI;xETK?o0bbcgJ3K!{{CUxKjhUnWLsbUy;+L2KRq0Vz5ND3qL zKa(P{5&_-xAY38`3h64XN>$5mksKfB?`{MmQi&0|X}Di*VSWU7|4-&8FdCbW6IhCD z^!&&c`u=3!8|gGIsKdk+@<7uyj9=Zu4EI1s{xh__ZqX6DVU&t%aTrPC&b{uiZLH&Z zSOSGSh<5q{o!_9pU~OM<>J$1^rC6d;V^rK5BuiloH^cQ7?$COWBoQGZI@}Fq^iYsf g9R=LOeN2(;IMrCkElg9E1~7x!bOuj|CiCd~1wL6X3;+NC literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ClassLoadingClassHierarchyResolver$1.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ClassLoadingClassHierarchyResolver$1.class new file mode 100644 index 0000000000000000000000000000000000000000..018724685ad1d40e10269a733ba9d31d5e15a515 GIT binary patch literal 1693 zcmcIkTTc@~6#k|Kmev+3f`}j@A{J0qE{akhQG`HJ>ZQViZ^L$gh3#y!J0OREWqZnASZbIy0ZbIzRk^7G>-0LxfPB8IqumK0ji#*o?Phun0y z+%;cp?+Z&Yv@O`uR!a==?ATTk?MN6%rf>-X$> zmF+O3l>5w<+&eDtvS66b=FePMuJjd`%3Ri#&xLR0#v;c><=JvKmqZ6T4P;Wdj4ph;X~nW8i8Ey|~8Ec@CGs*m1oY>%}PRkk;D> z(0VH;qz5&sEgLLN(_S$%_jL^NEa2i4mNltq@O6-yOOJ_NAb;GG@A?KOXPSoYF2B= zy2OVf>e~&W_T17-?opRfJ5t)L2;WezCTU)rg@}5S@FJ%{wKYG@Fj;h~o+VbP>lu3M zua&-allneT#aE=|xIW#y8c_p}8D9PKx-zsEgs;|IUl|~FlNa+quhqJg!VAI>l*8d* zrC*po_6&xoD`Q}|O%H0EetJh~cZXIc%}h(iKY+cXMGT`f>SN$5?$Vg5DIkk6+A-bO zq@|5*0@HAv6Q?lZr%0dT%E<;h2@L4*MIRk&xQ;;W8%e$+jUNH*5XsU6G>!=x2_$r& zSNCwAFeXV#MDhmVn6!@JLFOsBp99kUC8J&e1 j>I`NB!-sf8a|`BZd=g0Ju|RVdd6~mJ7Kz6o?dkgk0cp~e literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ClassLoadingClassHierarchyResolver.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ClassLoadingClassHierarchyResolver.class new file mode 100644 index 0000000000000000000000000000000000000000..87758c31988ed81642d23261d1b1385d96f8a8c4 GIT binary patch literal 2309 zcmb_dTT>%N6#hCPOfIv)hRfbqL>5;Pkcf9pz{LO(4Fs4N1y^yHOkmjAnK(1S;-{>C zz}MAPc2}#ceY46xV3j{WebCZUtJVk0@^mL51E%n{^Dy0gy8E2(eCO-#FaP-Ta{yVW zQ3Mc_&>6kACETny z_MTDZa+Hw}N>lgkjv&TTd+8mdDSwEZ=#z<6H91q>3K z`nxsNr2YM4zD;#U>BL41LwHESu#AT>!Z7W_aY$}^;_BSC=(Z|0gJf64YKBdJxHcFQ zJ~W~LqK^MK6y-RIMQKVG|6;Z_mo;ycLZAuy+^zYh-tq5 zSsBmad4|(v(v4$m=~uzs zB)rU!Y?VzAb%LzuOew~;rFu1oxLK|1p#8DW_(al1%)VJsh)i-OJ(H$m-OyWmr|CqA zp(AUTDSCI_u=M5H^)1~gs-jl$ysfEbNp%c9ZWuef9fQuYl7HYV6WW2J5%;UjsKpc0 z_)pyM)MZk%perZtj(}EX2xulr_c)&fuJ5>wb4;f~@l@^Fl3HyL6wYX7Z`Gg0*z>2!}|*Ld6c>(cNlM#dTSV=Kachm?dCq0$M514!}|!a zo8up$_b$!_a06j>2N!Q9KZZo}mjbwl#L~nUe9^=K#%~~U2a_M5mj+K9;F$xwa1UL4 z2YKueh?9f|_@2=IK)8OS=kX^D;%6lB3nuX^-Lv;Gjo&Df`y!j+I-0|5mZ9J*VNKHe zP{eD5wwYJmQX>Q)^FpbTgY-wnLx-F m0bf(xb!r3Hz?-7IinpmfPxdgbVw0*kMAdw!GeWnQ`2GY)+kW=| literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ResourceParsingClassHierarchyResolver$1.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ResourceParsingClassHierarchyResolver$1.class new file mode 100644 index 0000000000000000000000000000000000000000..84e21cd9e2063f348542bdedddad39639cd6a8a1 GIT binary patch literal 1657 zcmcIkTTc^F5dKbE*tRZG%T44WDqsuJ6%cQ&AXEuWDqf02AD8W+EN*w3-BS{Nhl#&K zUkcI0`0S4|&R&o$Akhb!^jzl5d^7XS%>MlK^*ewfib+Hel@OEBflh|huDYixhHBQ7 zms`7B6AYaN-PFY*Lo}1!Od^higrtm1kQw@p)r*GeIAu$%a+{&I#zke{5xm|e9?WFR zXIkVXTxJ+Jeya#uH)|_R-5|Uqx)4p`3epmKWb~qsVQjbhLD5aYZBsQA&2_%58(h)r z4MTY=bc5ltuu6f#x?1N9bD5BL%`zRKnnLj+e8wFu9}dnBAn&>!kZ~1*M1$9_7TqgtHGV}@bK%cDs(R<@g_CUnbGR)YgW ztY}rK*4<^@F_7-h=R~C5?ty97duv!c&3)7?x)}r6}@JvqG?l-)sUkA#+RH;S0SW+MiKni6E#?* zD3TSg6<2BEXl&c7?e;^?EfE#rxv3eJ+Yo-#5}q(@Tm;oLPV3weYnCGtM`u literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ResourceParsingClassHierarchyResolver.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassHierarchyImpl$ResourceParsingClassHierarchyResolver.class new file mode 100644 index 0000000000000000000000000000000000000000..0bacb28173489e11d9c3f46d5fe760d7354fe6b3 GIT binary patch literal 3692 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 accepting instances of ClassHierarchyInfoResolver to resolve individual class streams. + * @param classHierarchyResolver ClassHierarchyInfoResolver instance + */ + public ClassHierarchyImpl(ClassHierarchyResolver classHierarchyResolver) { + requireNonNull(classHierarchyResolver); + this.resolver = classHierarchyResolver instanceof CachedClassHierarchyResolver + ? classHierarchyResolver + : classHierarchyResolver.cached(); + } + + private ClassHierarchyInfoImpl resolve(ClassDesc classDesc) { + var res = resolver.getClassInfo(classDesc); + if (res != null) return (ClassHierarchyInfoImpl) res; + throw new IllegalArgumentException("Could not resolve class " + classDesc.displayName()); + } + + /** + * Method answering question whether given class is an interface, + * responding without the class stream resolution and parsing is preferred in case the interface status is known from previous activities. + * @param classDesc class path in form of <package>/<class_name>.class + * @return true if the given class name represents an interface + */ + public boolean isInterface(ClassDesc classDesc) { + return resolve(classDesc).isInterface(); + } + + /** + * Method resolving common ancestor of two classes + * @param symbol1 first class descriptor + * @param symbol2 second class descriptor + * @return common ancestor class name or null if it could not be identified + */ + public ClassDesc commonAncestor(ClassDesc symbol1, ClassDesc symbol2) { + //calculation of common ancestor is a robust (yet fast) way to decide about assignability in incompletely resolved class hierarchy + //exact order of symbol loops is critical for performance of the above isAssignableFrom method, so standard situations are resolved in linear time + //this method returns null if common ancestor could not be identified + if (isInterface(symbol1) || isInterface(symbol2)) return CD_Object; + for (var s1 = symbol1; s1 != null; s1 = resolve(s1).superClass()) { + for (var s2 = symbol2; s2 != null; s2 = resolve(s2).superClass()) { + if (s1.equals(s2)) return s1; + } + } + return null; + } + + public boolean isAssignableFrom(ClassDesc thisClass, ClassDesc fromClass) { + //extra check if fromClass is an interface is necessary to handle situation when thisClass might not been fully resolved and so it is potentially an unidentified interface + //this special corner-case handling has been added based on better success rate of constructing stack maps with simulated broken resolution of classes and interfaces + if (isInterface(fromClass)) return resolve(thisClass).superClass() == null; + //regular calculation of assignability is based on common ancestor calculation + var anc = commonAncestor(thisClass, fromClass); + //if common ancestor does not exist (as the class hierarchy could not be fully resolved) we optimistically assume the classes might be accessible + //if common ancestor is equal to thisClass then the classes are clearly accessible + //if other common ancestor is calculated (which works even when their grandparents could not be resolved) then it is clear that thisClass could not be assigned from fromClass + return anc == null || thisClass.equals(anc); + } + + public static final class CachedClassHierarchyResolver implements ClassHierarchyResolver { + // this instance should not leak out, appears only in cache in order to utilize Map.computeIfAbsent + // is already an invalid combination, so it can be compared with equals or as value class safely + private static final ClassHierarchyResolver.ClassHierarchyInfo NOPE = + new ClassHierarchyInfoImpl(null, true); + + private final Map resolvedCache; + private final Function delegateFunction; + + public CachedClassHierarchyResolver(ClassHierarchyResolver delegate, Map resolvedCache) { + this.resolvedCache = resolvedCache; + this.delegateFunction = new Function<>() { + @Override + public ClassHierarchyInfo apply(ClassDesc classDesc) { + var ret = delegate.getClassInfo(classDesc); + return ret == null ? NOPE : ret; + } + }; + } + + @Override + public ClassHierarchyInfo getClassInfo(ClassDesc classDesc) { + var ret = resolvedCache.computeIfAbsent(classDesc, delegateFunction); + return ret == NOPE ? null : ret; + } + } + + public static final class ResourceParsingClassHierarchyResolver implements ClassHierarchyResolver { + public static final Function SYSTEM_STREAM_PROVIDER = new Function<>() { + @Override + public InputStream apply(ClassDesc cd) { + return ClassLoader.getSystemClassLoader().getResourceAsStream(Util.toInternalName(cd) + ".class"); + } + }; + private final Function streamProvider; + + public ResourceParsingClassHierarchyResolver(Function classStreamProvider) { + this.streamProvider = classStreamProvider; + } + + // resolve method looks for the class file using ClassStreamResolver instance and tries to briefly scan it just for minimal information necessary + // minimal information includes: identification of the class as interface, obtaining its superclass name and identification of all potential interfaces (to avoid unnecessary future resolutions of them) + // empty ClInfo is stored in case of an exception to avoid repeated scanning failures + @Override + public ClassHierarchyResolver.ClassHierarchyInfo getClassInfo(ClassDesc classDesc) { + var ci = streamProvider.apply(classDesc); + if (ci == null) return null; + try (var in = new DataInputStream(new BufferedInputStream(ci))) { + in.skipBytes(8); + int cpLength = in.readUnsignedShort(); + String[] cpStrings = new String[cpLength]; + int[] cpClasses = new int[cpLength]; + for (int i = 1; i < cpLength; i++) { + int tag; + switch (tag = in.readUnsignedByte()) { + case TAG_UTF8 -> cpStrings[i] = in.readUTF(); + case TAG_CLASS -> cpClasses[i] = in.readUnsignedShort(); + case TAG_STRING, TAG_METHODTYPE, TAG_MODULE, TAG_PACKAGE -> in.skipBytes(2); + case TAG_METHODHANDLE -> in.skipBytes(3); + case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, TAG_INTERFACEMETHODREF, + TAG_NAMEANDTYPE, TAG_CONSTANTDYNAMIC, TAG_INVOKEDYNAMIC -> in.skipBytes(4); + case TAG_LONG, TAG_DOUBLE -> { + in.skipBytes(8); + i++; + } + default -> throw new IllegalStateException("Bad tag (" + tag + ") at index (" + i + ")"); + } + } + boolean isInterface = (in.readUnsignedShort() & ACC_INTERFACE) != 0; + in.skipBytes(2); + int superIndex = in.readUnsignedShort(); + var superClass = superIndex > 0 ? ClassDesc.ofInternalName(cpStrings[cpClasses[superIndex]]) : null; + return new ClassHierarchyInfoImpl(superClass, isInterface); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + } + + public static final class StaticClassHierarchyResolver implements ClassHierarchyResolver { + + private final Map map; + + public StaticClassHierarchyResolver(Collection interfaceNames, Map classToSuperClass) { + map = HashMap.newHashMap(interfaceNames.size() + classToSuperClass.size() + 1); + map.put(CD_Object, ClassHierarchyInfoImpl.OBJECT_INFO); + for (var e : classToSuperClass.entrySet()) + map.put(e.getKey(), ClassHierarchyInfo.ofClass(e.getValue())); + for (var i : interfaceNames) + map.put(i, ClassHierarchyInfo.ofInterface()); + } + + @Override + public ClassHierarchyInfo getClassInfo(ClassDesc classDesc) { + return map.get(classDesc); + } + } + + public static final class ClassLoadingClassHierarchyResolver implements ClassHierarchyResolver { + public static final Function> SYSTEM_CLASS_PROVIDER = new Function<>() { + @Override + public Class apply(ClassDesc cd) { + try { + return Class.forName(Util.toBinaryName(cd), false, ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException ex) { + return null; + } + } + }; + private final Function> classProvider; + + public ClassLoadingClassHierarchyResolver(Function> classProvider) { + this.classProvider = classProvider; + } + + @Override + public ClassHierarchyInfo getClassInfo(ClassDesc cd) { + if (!cd.isClassOrInterface()) + return null; + + if (cd.equals(CD_Object)) + return ClassHierarchyInfo.ofClass(null); + + var cl = classProvider.apply(cd); + if (cl == null) { + return null; + } + + return cl.isInterface() ? ClassHierarchyInfo.ofInterface() + : ClassHierarchyInfo.ofClass(cl.getSuperclass().describeConstable().orElseThrow()); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassImpl$1.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..cea07d698b8d8068180c766dd38062d0cdf3bd8c GIT binary patch literal 1391 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 methods; + private final List fields; + private List> attributes; + private List interfaces; + + public ClassImpl(byte[] cfbytes, ClassFileImpl context) { + this.reader = new ClassReaderImpl(cfbytes, context); + int p = reader.interfacesPos; + int icnt = reader.readU2(p); + p += 2 + icnt * 2; + int fcnt = reader.readU2(p); + FieldImpl[] fields = new FieldImpl[fcnt]; + p += 2; + for (int i = 0; i < fcnt; ++i) { + int startPos = p; + int attrStart = p + 6; + p = reader.skipAttributeHolder(attrStart); + fields[i] = new FieldImpl(reader, startPos, p, attrStart); + } + this.fields = List.of(fields); + int mcnt = reader.readU2(p); + MethodImpl[] methods = new MethodImpl[mcnt]; + p += 2; + for (int i = 0; i < mcnt; ++i) { + int startPos = p; + int attrStart = p + 6; + p = reader.skipAttributeHolder(attrStart); + methods[i] = new MethodImpl(reader, startPos, p, attrStart); + } + this.methods = List.of(methods); + this.attributesPos = p; + reader.setContainedClass(this); + } + + public int classfileLength() { + return reader.classfileLength(); + } + + @Override + public AccessFlags flags() { + return AccessFlags.ofClass(reader.flags()); + } + + @Override + public int majorVersion() { + return reader.readU2(6); + } + + @Override + public int minorVersion() { + return reader.readU2(4); + } + + @Override + public ConstantPool constantPool() { + return reader; + } + + @Override + public ClassEntry thisClass() { + return reader.thisClassEntry(); + } + + @Override + public Optional superclass() { + return reader.superclassEntry(); + } + + @Override + public List interfaces() { + if (interfaces == null) { + int pos = reader.thisClassPos() + 4; + int cnt = reader.readU2(pos); + pos += 2; + var arr = new Object[cnt]; + for (int i = 0; i < cnt; ++i) { + arr[i] = reader.readClassEntry(pos); + pos += 2; + } + this.interfaces = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(arr); + } + return interfaces; + } + + @Override + public List> attributes() { + if (attributes == null) { + attributes = BoundAttribute.readAttributes(this, reader, attributesPos, reader.customAttributes()); + } + return attributes; + } + + // ClassModel + + @Override + public void forEachElement(Consumer consumer) { + consumer.accept(flags()); + consumer.accept(ClassFileVersion.of(majorVersion(), minorVersion())); + superclass().ifPresent(new Consumer() { + @Override + public void accept(ClassEntry entry) { + consumer.accept(Superclass.of(entry)); + } + }); + consumer.accept(Interfaces.of(interfaces())); + fields().forEach(consumer); + methods().forEach(consumer); + for (Attribute attr : attributes()) { + if (attr instanceof ClassElement e) + consumer.accept(e); + } + } + + @Override + public List fields() { + return fields; + } + + @Override + public List methods() { + return methods; + } + + @Override + public boolean isModuleInfo() { + AccessFlags flags = flags(); + // move to where? + return flags.has(AccessFlag.MODULE) + && majorVersion() >= ClassFile.JAVA_9_VERSION + && thisClass().asInternalName().equals("module-info") + && (superclass().isEmpty()) + && interfaces().isEmpty() + && fields().isEmpty() + && methods().isEmpty() + && verifyModuleAttributes(); + } + + @Override + public String toString() { + return String.format("ClassModel[thisClass=%s, flags=%d]", thisClass().name().stringValue(), flags().flagsMask()); + } + + private boolean verifyModuleAttributes() { + if (findAttribute(Attributes.module()).isEmpty()) + return false; + + return attributes().stream().allMatch(a -> + a instanceof ModuleAttribute + || a instanceof ModulePackagesAttribute + || a instanceof ModuleHashesAttribute + || a instanceof ModuleMainClassAttribute + || a instanceof ModuleResolutionAttribute + || a instanceof ModuleTargetAttribute + || a instanceof InnerClassesAttribute + || a instanceof SourceFileAttribute + || a instanceof SourceDebugExtensionAttribute + || a instanceof RuntimeVisibleAnnotationsAttribute + || a instanceof RuntimeInvisibleAnnotationsAttribute + || a instanceof CustomAttribute); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$1.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..d09d9e1b7de0cc869d826cbace89e2ebd6d5266f GIT binary patch literal 1304 zcmb_bYfscb6g{)M(A}lLiXabPDCMO{1pyxzBSIId-7ayvn8*k0b_XbwcGGq-{vtoC zi803T1N=pPGTy1k5~C(0HtpOw=T2wNnVI|b`{yG7%UH}Kg|vi>j5f40Jl(SoZPl~= z9o6ydDB5;CuG(=Ny0vD^)kBZl(CvJ_!hIWer97*@_^IJK$gXg|ATbfdt~p<7yMYo%O$VrUG;|J(s_Y&|m0 zqnAMn!n#Y&8PXGzx`Yc1L#@p=gG$rcExO#RYhf6KLg0XmK_M`o2rL@qB}>p3Wn2=p zoY1;yX{*|Ek+>q`sz~ILgi$tE1$#}#^%iSZ4MVVsj8Va6ld)ELU6A84CIs1^kX2JR zbxU6|^q1PombIo=B-~&qv_zL{d)$d>l827x`fmIv@wUN`Sq|!)q1$kMZZ;2UJhbeZ zM@)|qIJUQ8hpxcKWaqErJI47+&ID|Ee)M&c9b#VVG)Rl4_Y121GT89x*pD zMe!D)Z%9)QXnq1a`jYAiS6KjK`b{1%yK3G64>)`CL>+gtE5L8%3Y31(Yxgka&+ z=rMtR4u1y;IrO3*eHg$9#wdq(G2T7Fk6UwGBuRaV?9oC~G+C@cImZ|yCunYsK`lPDM$KJ)}^8wJq*p3 zDXjAP*9vFItsZ5)CMe)mF-O()s^~*MLq>R!lwmEudZ~-YB~YK`epqlDtNoO%`H(Zd|>F!8-|g%iu+jDU`Ry;wXfPP ze^cGv$3>4bgvEYsOAeOvOeFeS=1r8$4eMiUfYb5Zt6?@Zs^<%BSD+Lb?}{~<69 zhHh$19lVLkn0Fi@@fAbMnpgEL{(=BY)+fD@ zU19HXJ*q8^L62m!7M5W@*&f^7^LDr%DMqg`7+v+eooc0+=wb|lgd{eU?{0|)mTy;t z=O<0VHYNqJkB_IFB%>dDSoI01hU;=abjfM_*^>)I!3&04M{PK#ECnkJ*Und^fki#Q zByE}odVMKcK(y$H%E{Ffp0tv}lhzQOQZJ30^gBwN6LLVm_7hASIDn!J9-vJdIzU$I zOC6wdpR^iqi+-EHh@8f4qNm9RS>X=ybV^D_rF)`eT$xM1T!v^2DH%J30?{2QQUxi= z6hXU@M6~uaGL{M5qf@$3v_o74z7u&mdK5{Cqj%6M8#}{%0Qhzx^AU{4<}(ybrk>Hp z4l(>M`<_UrUVH|3F%jn7T2Dj|c_6L*fO1|M>DUdUmei_98n<1{ICrLT_F~4}_4X$t zcb?b$TH0yoVUH(ia&lBt1PwWQIc1fo8VDsF0q_A)IqJ>~0V;!sc#J1_iX#2DOL+sy Orm#dFmhln>`u+mI!@qC< literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$LeafNodeImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$LeafNodeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..2c569886bd1965eedb3cedd400a8eb5e1041e941 GIT binary patch literal 2342 zcmbtVU3c3=5WVBtmYpbdYWfulZQ7=gIBC^Fffk1VbsOU1e9+|Np*(HuO`=5B8c7a^ z|HK15haNb2;0N%dILxkOTS=Xik_TzDqnSIicV>3~{^#&705xokAcJ!jvNm$a6UO(% zfp9$G?>H}HQw1$Te%|%nXn}BUdSdJtJl<>VJFXwez!#p=^h6kLyPkC1 zcE@vSdbt*u-*r|@HKf>HQ7x$#gsd;xl5n#z2-#GA7zsaeYRSh_88)jr=6M?>9WZww zysjL@1(YqkXX7F+5v~}7ZsdAS7zI+aopmD!8MRHgJDm!#y0s^pQFSI(z3EdeGcQ+c zT*U;T5Gh7-{T;$8gZ$sU_M#bDV?Yz;nvD}yz+ zxz`wb#i|TG;&-0Sfkk}G@5$H{)0p8EI~i#GzhuBOsPK0&!)mPpyUt=RiRAD~o8~Hi zV*EG$NaH^@_;zfN;NLYi_xJ|83hk`ZeUN}yl|x(xj>E)h#xPa_bAhjp`$OE{2Yx-4 z#c=mY6IDl_=bSSv3zgYJTtCVGa%|IQsen)LsmXg350gX&Wc&{6v|Z#97-Bw$IgkAp z=NvvWJN+DA82JcavOLdu#;p-IM%CyD-yqBFGmiy)jqg}@%d8(^2^0KX$M^Xn8Z1{> KuHpx*W8z;@=1c+r literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$ListNodeImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$ListNodeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..8edb98921ace00e3b7e3175c06290964b4e6e714 GIT binary patch literal 4066 zcmcgv-**#57`>CWS(+|wY)c_lK}x|k{76NL&>*%Hk!o71DMb*_O|osb-Ry?!rchKo zNB<39ee*%j5u`kLeD?S^dAzf`X?9~Nr02-X&g|^W_ucP)cV@o*>z`+T0GP&i3B=H* zpj|}=;sOJ!+PaphxrUjUDmZRcE4n$uaRuTR49jpY3bc)kE_PxMIu#^TbU_t3zgk+$ z7?!J7EzQgnP0ewZ3{%e-<%*e^map?w@AC`?hNZnZyQIq(fey#rFm-`5xt5IN<*Ka2 z(XFBfNr84tE7Q*5oEL$qS<9KCZ8@%HxtZypb6Iza*)H^=PeH$meHakf--wv;>RLII z_Zo)m+J5Z4Bcr}mj~6-Sc|M>bh1VH^#b_LXWb-8H=?xWc;-EmxUJ^Jt5<+*au&Ni` zY}j-JKsLeX-coTGL&V~L5*UnNi7x16N{3Y(#W8}?Diw1>;80}#Qq3y5hHYi81Ral! z5f!6I3n)vb=FVyrfpY;+FW~Rsr5$JB@&(BudvQD4-MrHyNo)iMI6`U0q3n^qvt3|t9u`S(lorq$GrBb^vhI1;; zV}desjE9sNcfpLz&jpF%eSz_)yT%^a$!=D`2ULD5aO#^!pfhhQTbf&|63yihjdI3? zkj!2Z%Ehd}J?5#Eo$PPIu&-@5TnJoKju*-2Gzk{y$r+YDS1T9v>Vj5~2SRVoE^6kY zRyE{%Fxc*{7~E;u)^OHIlP3qr zcCymdkFUhlu9-MeKS_7ETd3#znz<%$tv=a1K_jx?6##*=(qikolQ)53mGlP!Vun}L ztnRMZrFpH&%aZps_tN(vVTZ5$UBUEi`2@Z2XsvHcZplR6u2qZr6;=&Ax|>UeQ}Toq z*fXa)?p51y72Fay(Fz#?ee-&?Y`Cso%GV0snW#Go?g+F-DsRVn?J~@wW?ggjdKi8^ zle}cxF7vHbe5#!!z7jY_Y0JVYd>3tVJ@s^=(1mdnRb0bR5+tL3cfKU265I|YMNb^d z39P_Su&QDWEWm~uzzl2MUehxUSnY+ka-!`gM@U_6v z2FOTeqA6AIt-!&Zr?T?%^Uui4LTn0#`=nB>UR7N%L^?7mmaG(GH literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$MapNodeImpl$PrivateListNodeImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$MapNodeImpl$PrivateListNodeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..4a8e233d609f09e978703dd830ef668f4ca07288 GIT binary patch literal 1445 zcmcIkTWb?h5dJ1jvP~LWn^-m8Yf{av-P-z~L_~>*g&2iOKm_4rdulgs&W7ESLLU_0 z{WU&S6#N1HC~?lFl2im;(OuZNoS8Xu`F6g3`}74s3!4@aghF5J3wxwp&%Pf7;-Kw@ zdJajXETnU=FiV)9n3z*S!rvvVR9>{B15c<|_LE*;I=WdMtD89fkhQ5+YhsSzaHYxH<2+0<6goU=NWM?$!$>5pjd92B| zeMfj*5x7P^QYQ7D8xlJIv?WbKDl`)!+>94^JXbD4i2-{r|8~LzQiRRF=oLeK+aCpv ze8?arEd7koHS@m^W;-&}kNi+uC=(iSP)f*cDJ6p_vg9u3rg3ATLfD8CuN-xUdmB*; zb;7M!{!>UM%pH>ozd*JHo3K7v8-E5u3pWV$7+ySW1755n&kMyogm=7BPBC3#=_S&< z;(&au-uMi9zWNa}hsYe_#0S literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$MapNodeImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl$MapNodeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..8954cb8f24c597270e5224ea8248e3c9cfb161e7 GIT binary patch literal 6224 zcmcIo{dW{s8Gi15O+F?eq(Hl1fwn1-P0CVAY0V-n1Tc{h(1lQ1zb3nruw-{;yE_}2 z)>^dHS}T5_qP1$Zt)dpSC|?0fsajO5$6u-*J^tcfDpnOB08do3A7wCMvY|Nu!fVn2M?JUMsWvmfrw=kh;vI{)%1*Ql^w%!lHLBrHnW^bX=oL= z(Uqz=xqPxOXN{QI9;1AahBaUz!V-3|jwQH}-WH6azyc4|m8Vpy5pgWluuR8$aB~2y z?37HSkW9OSK*$~vxMPiClo!ubyMh>)lWL&$6*^Yp76yIP$XCp=z)fq^3Eg%+&!psR ziiKAg^1&+5Lgz#2`X+S720(q(807A#bSO;U`0TFsA9QVlRNwi zHxPH|Sc{~9Hk3CUMu&Xx9d_e2eUj=*&;%LRJ9VtbU9_3$%NS(dE)^{(KVuMQQ*k#o zYPd(oy?C!cQ#D|&>5+2oQPPMc?`_20Na@&w_tCdpd3&MgFd}^OpnP+mj{C7ippj-e zM$RhlH2HRMtyH`6-8!~O`KAf^0hwBfv_r@H(L>~6liseXg)p5z8a^PfPT~4w(PivH z(Y8#>DF;fgP1c--K7rNMS^KPVrC78}j+xzEG)so0)b>X*W>H==U?;-Tz}-6b;DgM_ zh&h&)HZBaXf{#erH1=xPr(*#78HQ?9t288y7gVf*oy`s9jKRF=LakJjE0NU9$$M$Q z3JL$9j)(AJfh8(N6jP9FcU3G=}1||*@CU1sN-Qt)8=Xh`|8Vj%yTFb=jJ&g1CG< z&bC-Bp_*<;1D=ou9T9k1)mu|q<;5JWPO7f;Qrvx5&cZk+Lz&%4ZmB`gSXPNz#!k}5&D;twQ zYoDDl@&iW6ZB+ilh;uN<%ITUP@0Hr5Gm*naenepRL~C(Z$iSKw2;KyqqK1Sa+<$EqQjFR-gZqnFH$*h3H+=G^zV%ocluj!qvg1*4C>M|CXJ$KI^55QHe zn234XcDW!1z-yYOW@fJ1r8|+sIfu)fz27fF)|}G)-3`JFLRCFWjY7#>>i`UqYV#NY(5QXyHd)SJ9xU{E~{IHTsc~; zl|{_mOut!ndhD{J;iN$4eA)t)ZnbTP9myzq+RH8ISx}Ex<<97oj-y!Jf?rlQ<=)8YH3uDXi*YP*emKAm$+ zQcCZ&EVJb1Snk*w6(Vc6#I`)2#J0KnFSa3f)bNHtM>WFN?CK=AT#yBBsIkA~@yNGL z!xf6SxWP_B#coH@@CSk0tBM1`4rWQi9|e}rF3M%bODXQ;?j{6*ClN-g{3^l2Y^(e- z;Ep`X^WA579l~d^h}Tg(&HvBw$wAHtb6lD@2a)JF11-^c22F{JSa{$ZZa9NQr`&nZ z@P7&CfjAMO)DxkZ2yr}v&-3X@4+YQS3%nzqYlU#Hq#e>ao-2H9 z7$D|8Jn91Ko`4T1Wa&{#n!KH=N(>h@8ShQGE8DQ zh~0Xgqoaw)8(99mmH79J{ZB>2 ziT@o*$jEqnSjAQfyv?@!7dF$sVjcd*^ZeiWx$GaifaGCtACc%H>4XTzJ| zmc*;42`wC5Onw}!W!$G`1DkFf*Q_5AF@zuEC+_$Pe#%i6$7v?wXZSgOfs1_7#lY6# t75s`JdyV7k_s6;QyNqAQbuS6 zuIF>htH1TFl2A88XFLv?q4C^o(KNzBo=n0L4ut1dzIFmtTp4 zOD0V8GU$_)$M(w=hhgD$H{b^Pk<`&^VgM;BwCXnk&XCUL?0xsZwR|_IS>^40UX2O{ z(iqe+WMUXs82bJ=tOTt()pFqaEneQGTCyF{lAc1xffEr|wL)hG0U+^5OkBk%Lr>8Q zyl9DGs1vFkxt^=Up&3NONE`_v$4rc4LeL>=XfiBjb6pWaseePLrN$0%(QkVJ-)Pmh zdHBNJ_UUBpA2m@o7aoxUL&|PcUBBXno`7!StASgmG^z8PF(jY!Xs@xe>4xM(^GL0# z(Vj;l;dr&cjangvD%o6xrlwf++cd6rU8I1U!_;oZ8alHZ9N6S5DJLD$5zMQvgX?2_QKlHi0Y}>64fs zzgwh@lN6V62;&p_PSO8?G=|&s?2)#ok|M%LvHS@xpMnYh*ctyUotVG8 zkVBrdDY`WZdoNsRaG^-BS&|Bw^!(K5F)|QqfOv^9Y70 f^DIGXyN-L9C0h)0xG&{A9*`7^NB=Y|E@yrM_oXu( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..c8552508f7f2c235d74d535768c7eb77176cb99b GIT binary patch literal 68936 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 IJ)kQ87f3~>0{{R3 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl.java new file mode 100644 index 00000000..fac2eba9 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/ClassPrinterImpl.java @@ -0,0 +1,1084 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.constant.ConstantDesc; +import java.lang.constant.DirectMethodHandleDesc; +import java.lang.reflect.AccessFlag; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import java.lang.classfile.Annotation; + +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.AnnotationValue.*; +import java.lang.classfile.Attribute; +import java.lang.classfile.ClassModel; +import java.lang.classfile.components.ClassPrinter.*; +import java.lang.classfile.CodeModel; +import java.lang.classfile.Instruction; +import java.lang.classfile.MethodModel; +import java.lang.classfile.TypeAnnotation; +import java.lang.classfile.attribute.*; +import java.lang.classfile.attribute.StackMapFrameInfo.*; +import java.lang.classfile.constantpool.*; +import java.lang.classfile.instruction.*; + +import static java.lang.classfile.ClassFile.*; +import java.lang.classfile.CompoundElement; +import java.lang.classfile.FieldModel; +import static jdk.internal.classfile.impl.ClassPrinterImpl.Style.*; + +public final class ClassPrinterImpl { + + public enum Style { BLOCK, FLOW } + + public record LeafNodeImpl(ConstantDesc name, ConstantDesc value) implements LeafNode { + + @Override + public Stream walk() { + return Stream.of(this); + } + } + + public static sealed class ListNodeImpl extends AbstractList implements ListNode { + + private final Style style; + private final ConstantDesc name; + protected final List nodes; + + public ListNodeImpl(Style style, ConstantDesc name, Stream nodes) { + this.style = style; + this.name = name; + this.nodes = nodes.toList(); + } + + protected ListNodeImpl(Style style, ConstantDesc name, List nodes) { + this.style = style; + this.name = name; + this.nodes = nodes; + } + + @Override + public ConstantDesc name() { + return name; + } + + @Override + public Stream walk() { + return Stream.concat(Stream.of(this), stream().flatMap(Node::walk)); + } + + public Style style() { + return style; + } + + @Override + public Node get(int index) { + return nodes.get(index); + } + + @Override + public int size() { + return nodes.size(); + } + } + + public static final class MapNodeImpl implements MapNode { + + private static final class PrivateListNodeImpl extends ListNodeImpl { + PrivateListNodeImpl(Style style, ConstantDesc name, Node... n) { + super(style, name, new ArrayList<>(List.of(n))); + } + } + + private final Style style; + private final ConstantDesc name; + private final Map map; + + public MapNodeImpl(Style style, ConstantDesc name) { + this.style = style; + this.name = name; + this.map = new LinkedHashMap<>(); + } + + @Override + public ConstantDesc name() { + return name; + } + + @Override + public Stream walk() { + return Stream.concat(Stream.of(this), values().stream().flatMap(Node::walk)); + } + + public Style style() { + return style; + } + + @Override + public int size() { + return map.size(); + } + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + @Override + public boolean containsKey(Object key) { + return map.containsKey(key); + } + @Override + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + @Override + public Node get(Object key) { + return map.get(key); + } + + @Override + public Node put(ConstantDesc key, Node value) { + throw new UnsupportedOperationException(); + } + + @Override + public Node remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(Map m) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Set keySet() { + return Collections.unmodifiableSet(map.keySet()); + } + + @Override + public Collection values() { + return Collections.unmodifiableCollection(map.values()); + } + + @Override + public Set> entrySet() { + return Collections.unmodifiableSet(map.entrySet()); + } + + + MapNodeImpl with(Node... nodes) { + for (var n : nodes) { + if (n != null) { + var prev = map.putIfAbsent(n.name(), n); + if (prev != null) { + //nodes with duplicite keys are joined into a list + if (prev instanceof PrivateListNodeImpl list) { + list.nodes.add(n); + } else { + map.put(n.name(), new PrivateListNodeImpl(style, n.name(), prev, n)); + } + } + } + } + return this; + } + } + + private static Node leaf(ConstantDesc name, ConstantDesc value) { + return new LeafNodeImpl(name, value); + } + + private static Node[] leafs(ConstantDesc... namesAndValues) { + if ((namesAndValues.length & 1) > 0) + throw new AssertionError("Odd number of arguments: " + Arrays.toString(namesAndValues)); + var nodes = new Node[namesAndValues.length >> 1]; + for (int i = 0, j = 0; i < nodes.length; i ++) { + nodes[i] = leaf(namesAndValues[j++], namesAndValues[j++]); + } + return nodes; + } + + private static Node list(ConstantDesc listName, ConstantDesc itemsName, Stream values) { + return new ListNodeImpl(FLOW, listName, values.map(v -> leaf(itemsName, v))); + } + + private static Node map(ConstantDesc mapName, ConstantDesc... keysAndValues) { + return new MapNodeImpl(FLOW, mapName).with(leafs(keysAndValues)); + } + + private static final String NL = System.lineSeparator(); + + private static final char[] DIGITS = "0123456789ABCDEF".toCharArray(); + + private static void escape(int c, StringBuilder sb) { + switch (c) { + case '\\' -> sb.append('\\').append('\\'); + case '"' -> sb.append('\\').append('"'); + case '\b' -> sb.append('\\').append('b'); + case '\n' -> sb.append('\\').append('n'); + case '\t' -> sb.append('\\').append('t'); + case '\f' -> sb.append('\\').append('f'); + case '\r' -> sb.append('\\').append('r'); + default -> { + if (c >= 0x20 && c < 0x7f) { + sb.append((char)c); + } else { + sb.append('\\').append('u').append(DIGITS[(c >> 12) & 0xf]) + .append(DIGITS[(c >> 8) & 0xf]).append(DIGITS[(c >> 4) & 0xf]).append(DIGITS[(c) & 0xf]); + } + } + } + } + + public static void toYaml(Node node, Consumer out) { + toYaml(0, false, new ListNodeImpl(BLOCK, null, Stream.of(node)), out); + out.accept(NL); + } + + private static void toYaml(int indent, boolean skipFirstIndent, Node node, Consumer out) { + switch (node) { + case LeafNode leaf -> { + out.accept(quoteAndEscapeYaml(leaf.value())); + } + case ListNodeImpl list -> { + switch (list.style()) { + case FLOW -> { + out.accept("["); + boolean first = true; + for (var n : list) { + if (first) first = false; + else out.accept(", "); + toYaml(0, false, n, out); + } + out.accept("]"); + } + case BLOCK -> { + for (var n : list) { + out.accept(NL + " ".repeat(indent) + " - "); + toYaml(indent + 1, true, n, out); + } + } + } + } + case MapNodeImpl map -> { + switch (map.style()) { + case FLOW -> { + out.accept("{"); + boolean first = true; + for (var n : map.values()) { + if (first) first = false; + else out.accept(", "); + out.accept(quoteAndEscapeYaml(n.name()) + ": "); + toYaml(0, false, n, out); + } + out.accept("}"); + } + case BLOCK -> { + for (var n : map.values()) { + if (skipFirstIndent) { + skipFirstIndent = false; + } else { + out.accept(NL + " ".repeat(indent)); + } + out.accept(quoteAndEscapeYaml(n.name()) + ": "); + toYaml(n instanceof ListNodeImpl pl && pl.style() == BLOCK ? indent : indent + 1, false, n, out); + } + } + } + } + } + } + + private static String quoteAndEscapeYaml(ConstantDesc value) { + String s = String.valueOf(value); + if (value instanceof Number) return s; + if (s.length() == 0) return "''"; + var sb = new StringBuilder(s.length() << 1); + s.chars().forEach(c -> { + switch (c) { + case '\'' -> sb.append("''"); + default -> escape(c, sb); + }}); + String esc = sb.toString(); + if (esc.length() != s.length()) return "'" + esc + "'"; + switch (esc.charAt(0)) { + case '-', '?', ':', ',', '[', ']', '{', '}', '#', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`': + return "'" + esc + "'"; + } + for (int i = 1; i < esc.length(); i++) { + switch (esc.charAt(i)) { + case ',', '[', ']', '{', '}': + return "'" + esc + "'"; + } + } + return esc; + } + + public static void toJson(Node node, Consumer out) { + toJson(1, true, node, out); + out.accept(NL); + } + + private static void toJson(int indent, boolean skipFirstIndent, Node node, Consumer out) { + switch (node) { + case LeafNode leaf -> { + out.accept(quoteAndEscapeJson(leaf.value())); + } + case ListNodeImpl list -> { + out.accept("["); + boolean first = true; + switch (list.style()) { + case FLOW -> { + for (var n : list) { + if (first) first = false; + else out.accept(", "); + toJson(0, false, n, out); + } + } + case BLOCK -> { + for (var n : list) { + if (first) first = false; + else out.accept(","); + out.accept(NL + " ".repeat(indent)); + toJson(indent + 1, true, n, out); + } + } + } + out.accept("]"); + } + case MapNodeImpl map -> { + switch (map.style()) { + case FLOW -> { + out.accept("{"); + boolean first = true; + for (var n : map.values()) { + if (first) first = false; + else out.accept(", "); + out.accept(quoteAndEscapeJson(n.name().toString()) + ": "); + toJson(0, false, n, out); + } + } + case BLOCK -> { + if (skipFirstIndent) out.accept(" { "); + else out.accept("{"); + boolean first = true; + for (var n : map.values()) { + if (first) first = false; + else out.accept(","); + if (skipFirstIndent) skipFirstIndent = false; + else out.accept(NL + " ".repeat(indent)); + out.accept(quoteAndEscapeJson(n.name().toString()) + ": "); + toJson(indent + 1, false, n, out); + } + } + } + out.accept("}"); + } + } + } + + private static String quoteAndEscapeJson(ConstantDesc value) { + String s = String.valueOf(value); + if (value instanceof Number) return s; + var sb = new StringBuilder(s.length() << 1); + sb.append('"'); + s.chars().forEach(c -> escape(c, sb)); + sb.append('"'); + return sb.toString(); + } + + public static void toXml(Node node, Consumer out) { + out.accept(""); + toXml(0, false, node, out); + out.accept(NL); + } + + private static void toXml(int indent, boolean skipFirstIndent, Node node, Consumer out) { + var name = toXmlName(node.name().toString()); + switch (node) { + case LeafNode leaf -> { + out.accept("<" + name + ">"); + out.accept(xmlEscape(leaf.value())); + } + case ListNodeImpl list -> { + switch (list.style()) { + case FLOW -> { + out.accept("<" + name + ">"); + for (var n : list) { + toXml(0, false, n, out); + } + } + case BLOCK -> { + if (!skipFirstIndent) + out.accept(NL + " ".repeat(indent)); + out.accept("<" + name + ">"); + for (var n : list) { + out.accept(NL + " ".repeat(indent + 1)); + toXml(indent + 1, true, n, out); + } + } + } + } + case MapNodeImpl map -> { + switch (map.style()) { + case FLOW -> { + out.accept("<" + name + ">"); + for (var n : map.values()) { + toXml(0, false, n, out); + } + } + case BLOCK -> { + if (!skipFirstIndent) + out.accept(NL + " ".repeat(indent)); + out.accept("<" + name + ">"); + for (var n : map.values()) { + out.accept(NL + " ".repeat(indent + 1)); + toXml(indent + 1, true, n, out); + } + } + } + } + } + out.accept(""); + } + + private static String xmlEscape(ConstantDesc value) { + var s = String.valueOf(value); + var sb = new StringBuilder(s.length() << 1); + s.chars().forEach(c -> { + switch (c) { + case '<' -> sb.append("<"); + case '>' -> sb.append(">"); + case '"' -> sb.append("""); + case '&' -> sb.append("&"); + case '\'' -> sb.append("'"); + default -> escape(c, sb); + }}); + return sb.toString(); + } + + private static String toXmlName(String name) { + if (Character.isDigit(name.charAt(0))) + name = "_" + name; + return name.replaceAll("[^A-Za-z_0-9]", "_"); + } + + private static Node[] elementValueToTree(AnnotationValue v) { + return switch (v) { + case OfString cv -> leafs("string", String.valueOf(cv.constantValue())); + case OfDouble cv -> leafs("double", String.valueOf(cv.constantValue())); + case OfFloat cv -> leafs("float", String.valueOf(cv.constantValue())); + case OfLong cv -> leafs("long", String.valueOf(cv.constantValue())); + case OfInteger cv -> leafs("int", String.valueOf(cv.constantValue())); + case OfShort cv -> leafs("short", String.valueOf(cv.constantValue())); + case OfCharacter cv -> leafs("char", String.valueOf(cv.constantValue())); + case OfByte cv -> leafs("byte", String.valueOf(cv.constantValue())); + case OfBoolean cv -> leafs("boolean", String.valueOf((int)cv.constantValue() != 0)); + case OfClass clv -> leafs("class", clv.className().stringValue()); + case OfEnum ev -> leafs("enum class", ev.className().stringValue(), + "constant name", ev.constantName().stringValue()); + case OfAnnotation av -> leafs("annotation class", av.annotation().className().stringValue()); + case OfArray av -> new Node[]{new ListNodeImpl(FLOW, "array", av.values().stream().map( + ev -> new MapNodeImpl(FLOW, "value").with(elementValueToTree(ev))))}; + }; + } + + private static Node elementValuePairsToTree(List evps) { + return new ListNodeImpl(FLOW, "values", evps.stream().map(evp -> new MapNodeImpl(FLOW, "pair").with( + leaf("name", evp.name().stringValue()), + new MapNodeImpl(FLOW, "value").with(elementValueToTree(evp.value()))))); + } + + private static Stream convertVTIs(CodeAttribute lr, List vtis) { + return vtis.stream().mapMulti((vti, ret) -> { + switch (vti) { + case SimpleVerificationTypeInfo s -> { + switch (s) { + case ITEM_DOUBLE -> { + ret.accept("double"); + ret.accept("double2"); + } + case ITEM_FLOAT -> + ret.accept("float"); + case ITEM_INTEGER -> + ret.accept("int"); + case ITEM_LONG -> { + ret.accept("long"); + ret.accept("long2"); + } + case ITEM_NULL -> ret.accept("null"); + case ITEM_TOP -> ret.accept("?"); + case ITEM_UNINITIALIZED_THIS -> ret.accept("THIS"); + } + } + case ObjectVerificationTypeInfo o -> + ret.accept(o.className().name().stringValue()); + case UninitializedVerificationTypeInfo u -> + ret.accept("UNINITIALIZED @" + lr.labelToBci(u.newTarget())); + } + }); + } + + private record ExceptionHandler(int start, int end, int handler, String catchType) {} + + public static MapNode modelToTree(CompoundElement model, Verbosity verbosity) { + return switch(model) { + case ClassModel cm -> classToTree(cm, verbosity); + case FieldModel fm -> fieldToTree(fm, verbosity); + case MethodModel mm -> methodToTree(mm, verbosity); + case CodeModel com -> codeToTree((CodeAttribute)com, verbosity); + }; + } + + private static MapNode classToTree(ClassModel clm, Verbosity verbosity) { + return new MapNodeImpl(BLOCK, "class") + .with(leaf("class name", clm.thisClass().asInternalName()), + leaf("version", clm.majorVersion() + "." + clm.minorVersion()), + list("flags", "flag", clm.flags().flags().stream().map(AccessFlag::name)), + leaf("superclass", clm.superclass().map(ClassEntry::asInternalName).orElse("")), + list("interfaces", "interface", clm.interfaces().stream().map(ClassEntry::asInternalName)), + list("attributes", "attribute", clm.attributes().stream().map(Attribute::attributeName))) + .with(constantPoolToTree(clm.constantPool(), verbosity)) + .with(attributesToTree(clm.attributes(), verbosity)) + .with(new ListNodeImpl(BLOCK, "fields", clm.fields().stream().map(f -> + fieldToTree(f, verbosity)))) + .with(new ListNodeImpl(BLOCK, "methods", clm.methods().stream().map(mm -> + methodToTree(mm, verbosity)))); + } + + private static Node[] constantPoolToTree(ConstantPool cp, Verbosity verbosity) { + if (verbosity == Verbosity.TRACE_ALL) { + var cpNode = new MapNodeImpl(BLOCK, "constant pool"); + for (PoolEntry e : cp) { + cpNode.with(new MapNodeImpl(FLOW, e.index()) + .with(leaf("tag", switch (e.tag()) { + case TAG_UTF8 -> "Utf8"; + case TAG_INTEGER -> "Integer"; + case TAG_FLOAT -> "Float"; + case TAG_LONG -> "Long"; + case TAG_DOUBLE -> "Double"; + case TAG_CLASS -> "Class"; + case TAG_STRING -> "String"; + case TAG_FIELDREF -> "Fieldref"; + case TAG_METHODREF -> "Methodref"; + case TAG_INTERFACEMETHODREF -> "InterfaceMethodref"; + case TAG_NAMEANDTYPE -> "NameAndType"; + case TAG_METHODHANDLE -> "MethodHandle"; + case TAG_METHODTYPE -> "MethodType"; + case TAG_CONSTANTDYNAMIC -> "Dynamic"; + case TAG_INVOKEDYNAMIC -> "InvokeDynamic"; + case TAG_MODULE -> "Module"; + case TAG_PACKAGE -> "Package"; + default -> throw new AssertionError("Unknown CP tag: " + e.tag()); + })) + .with(switch (e) { + case ClassEntry ce -> leafs( + "class name index", ce.name().index(), + "class internal name", ce.asInternalName()); + case ModuleEntry me -> leafs( + "module name index", me.name().index(), + "module name", me.name().stringValue()); + case PackageEntry pe -> leafs( + "package name index", pe.name().index(), + "package name", pe.name().stringValue()); + case StringEntry se -> leafs( + "value index", se.utf8().index(), + "value", se.stringValue()); + case MemberRefEntry mre -> leafs( + "owner index", mre.owner().index(), + "name and type index", mre.nameAndType().index(), + "owner", mre.owner().name().stringValue(), + "name", mre.name().stringValue(), + "type", mre.type().stringValue()); + case NameAndTypeEntry nte -> leafs( + "name index", nte.name().index(), + "type index", nte.type().index(), + "name", nte.name().stringValue(), + "type", nte.type().stringValue()); + case MethodHandleEntry mhe -> leafs( + "reference kind", DirectMethodHandleDesc.Kind.valueOf(mhe.kind()).name(), + "reference index", mhe.reference().index(), + "owner", mhe.reference().owner().asInternalName(), + "name", mhe.reference().name().stringValue(), + "type", mhe.reference().type().stringValue()); + case MethodTypeEntry mte -> leafs( + "descriptor index", mte.descriptor().index(), + "descriptor", mte.descriptor().stringValue()); + case DynamicConstantPoolEntry dcpe -> new Node[] { + leaf("bootstrap method handle index", dcpe.bootstrap().bootstrapMethod().index()), + list("bootstrap method arguments indexes", + "index", dcpe.bootstrap().arguments().stream().map(en -> en.index())), + leaf("name and type index", dcpe.nameAndType().index()), + leaf("name", dcpe.name().stringValue()), + leaf("type", dcpe.type().stringValue())}; + case AnnotationConstantValueEntry ve -> leafs( + "value", String.valueOf(ve.constantValue()) + ); + })); + } + return new Node[]{cpNode}; + } else { + return new Node[0]; + } + } + + private static Node frameToTree(ConstantDesc name, CodeAttribute lr, StackMapFrameInfo f) { + return new MapNodeImpl(FLOW, name).with( + list("locals", "item", convertVTIs(lr, f.locals())), + list("stack", "item", convertVTIs(lr, f.stack()))); + } + + private static MapNode fieldToTree(FieldModel f, Verbosity verbosity) { + return new MapNodeImpl(BLOCK, "field") + .with(leaf("field name", f.fieldName().stringValue()), + list("flags", + "flag", f.flags().flags().stream().map(AccessFlag::name)), + leaf("field type", f.fieldType().stringValue()), + list("attributes", + "attribute", f.attributes().stream().map(Attribute::attributeName))) + .with(attributesToTree(f.attributes(), verbosity)); + } + + public static MapNode methodToTree(MethodModel m, Verbosity verbosity) { + return new MapNodeImpl(BLOCK, "method") + .with(leaf("method name", m.methodName().stringValue()), + list("flags", + "flag", m.flags().flags().stream().map(AccessFlag::name)), + leaf("method type", m.methodType().stringValue()), + list("attributes", + "attribute", m.attributes().stream().map(Attribute::attributeName))) + .with(attributesToTree(m.attributes(), verbosity)) + .with(codeToTree((CodeAttribute)m.code().orElse(null), verbosity)); + } + + private static MapNode codeToTree(CodeAttribute com, Verbosity verbosity) { + if (verbosity != Verbosity.MEMBERS_ONLY && com != null) { + var codeNode = new MapNodeImpl(BLOCK, "code"); + codeNode.with(leaf("max stack", com.maxStack())); + codeNode.with(leaf("max locals", com.maxLocals())); + codeNode.with(list("attributes", + "attribute", com.attributes().stream().map(Attribute::attributeName))); + var stackMap = new MapNodeImpl(BLOCK, "stack map frames"); + var visibleTypeAnnos = new LinkedHashMap>(); + var invisibleTypeAnnos = new LinkedHashMap>(); + List locals = List.of(); + for (var attr : com.attributes()) { + if (attr instanceof StackMapTableAttribute smta) { + codeNode.with(stackMap); + for (var smf : smta.entries()) { + stackMap.with(frameToTree(com.labelToBci(smf.target()), com, smf)); + } + } else if (verbosity == Verbosity.TRACE_ALL && attr != null) switch (attr) { + case LocalVariableTableAttribute lvta -> { + locals = lvta.localVariables(); + codeNode.with(new ListNodeImpl(BLOCK, "local variables", + IntStream.range(0, locals.size()).mapToObj(i -> { + var lv = lvta.localVariables().get(i); + return map(i + 1, + "start", lv.startPc(), + "end", lv.startPc() + lv.length(), + "slot", lv.slot(), + "name", lv.name().stringValue(), + "type", lv.type().stringValue()); + }))); + } + case LocalVariableTypeTableAttribute lvtta -> { + codeNode.with(new ListNodeImpl(BLOCK, "local variable types", + IntStream.range(0, lvtta.localVariableTypes().size()).mapToObj(i -> { + var lvt = lvtta.localVariableTypes().get(i); + return map(i + 1, + "start", lvt.startPc(), + "end", lvt.startPc() + lvt.length(), + "slot", lvt.slot(), + "name", lvt.name().stringValue(), + "signature", lvt.signature().stringValue()); + }))); + } + case LineNumberTableAttribute lnta -> { + codeNode.with(new ListNodeImpl(BLOCK, "line numbers", + IntStream.range(0, lnta.lineNumbers().size()).mapToObj(i -> { + var ln = lnta.lineNumbers().get(i); + return map(i + 1, + "start", ln.startPc(), + "line number", ln.lineNumber()); + }))); + } + case CharacterRangeTableAttribute crta -> { + codeNode.with(new ListNodeImpl(BLOCK, "character ranges", + IntStream.range(0, crta.characterRangeTable().size()).mapToObj(i -> { + var cr = crta.characterRangeTable().get(i); + return map(i + 1, + "start", cr.startPc(), + "end", cr.endPc(), + "range start", cr.characterRangeStart(), + "range end", cr.characterRangeEnd(), + "flags", cr.flags()); + }))); + } + case RuntimeVisibleTypeAnnotationsAttribute rvtaa -> + rvtaa.annotations().forEach(a -> forEachOffset(a, com, (off, an) -> + visibleTypeAnnos.computeIfAbsent(off, o -> new LinkedList<>()).add(an))); + case RuntimeInvisibleTypeAnnotationsAttribute ritaa -> + ritaa.annotations().forEach(a -> forEachOffset(a, com, (off, an) -> + invisibleTypeAnnos.computeIfAbsent(off, o -> new LinkedList<>()).add(an))); + case Object o -> {} + } + } + codeNode.with(attributesToTree(com.attributes(), verbosity)); + if (!stackMap.containsKey(0)) { + codeNode.with(new MapNodeImpl(FLOW, "//stack map frame @0").with( + list("locals", "item", convertVTIs(com, StackMapDecoder.initFrameLocals(com.parent().get()))), + list("stack", "item", Stream.of()))); + } + var excHandlers = com.exceptionHandlers().stream().map(exc -> new ExceptionHandler( + com.labelToBci(exc.tryStart()), + com.labelToBci(exc.tryEnd()), + com.labelToBci(exc.handler()), + exc.catchType().map(ct -> ct.name().stringValue()).orElse(null))).toList(); + int bci = 0; + for (var coe : com) { + if (coe instanceof Instruction ins) { + var frame = stackMap.get(bci); + if (frame != null) { + codeNode.with(new MapNodeImpl(FLOW, "//stack map frame @" + bci) + .with(((MapNodeImpl)frame).values().toArray(new Node[2]))); + } + var annos = invisibleTypeAnnos.get(bci); + if (annos != null) { + codeNode.with(typeAnnotationsToTree(FLOW, "//invisible type annotations @" + bci, annos)); + } + annos = visibleTypeAnnos.get(bci); + if (annos != null) { + codeNode.with(typeAnnotationsToTree(FLOW, "//visible type annotations @" + bci, annos)); + } + for (int i = 0; i < excHandlers.size(); i++) { + var exc = excHandlers.get(i); + if (exc.start() == bci) { + codeNode.with(map("//try block " + (i + 1) + " start", + "start", exc.start(), + "end", exc.end(), + "handler", exc.handler(), + "catch type", exc.catchType())); + } + if (exc.end() == bci) { + codeNode.with(map("//try block " + (i + 1) + " end", + "start", exc.start(), + "end", exc.end(), + "handler", exc.handler(), + "catch type", exc.catchType())); + } + if (exc.handler() == bci) { + codeNode.with(map("//exception handler " + (i + 1) + " start", + "start", exc.start(), + "end", exc.end(), + "handler", exc.handler(), + "catch type", exc.catchType())); + } + } + var in = new MapNodeImpl(FLOW, bci).with(leaf("opcode", ins.opcode().name())); + codeNode.with(in); + switch (coe) { + case IncrementInstruction inc -> in.with(leafs( + "slot", inc.slot(), + "const", inc.constant())) + .with(localInfoToTree(locals, inc.slot(), bci)); + case LoadInstruction lv -> in.with(leaf( + "slot", lv.slot())) + .with(localInfoToTree(locals, lv.slot(), bci)); + case StoreInstruction lv -> in.with(leaf( + "slot", lv.slot())) + .with(localInfoToTree(locals, lv.slot(), bci)); + case FieldInstruction fa -> in.with(leafs( + "owner", fa.owner().name().stringValue(), + "field name", fa.name().stringValue(), + "field type", fa.type().stringValue())); + case InvokeInstruction inv -> in.with(leafs( + "owner", inv.owner().name().stringValue(), + "method name", inv.name().stringValue(), + "method type", inv.type().stringValue())); + case InvokeDynamicInstruction invd -> { + in.with(leafs( + "name", invd.name().stringValue(), + "descriptor", invd.type().stringValue(), + "bootstrap method", invd.bootstrapMethod().kind().name() + + " " + Util.toInternalName(invd.bootstrapMethod().owner()) + + "::" + invd.bootstrapMethod().methodName())); + in.with(list("arguments", "arg", invd.bootstrapArgs().stream())); + } + case NewObjectInstruction newo -> in.with(leaf( + "type", newo.className().name().stringValue())); + case NewPrimitiveArrayInstruction newa -> in.with(leafs( + "dimensions", 1, + "descriptor", newa.typeKind().typeName())); + case NewReferenceArrayInstruction newa -> in.with(leafs( + "dimensions", 1, + "descriptor", newa.componentType().name().stringValue())); + case NewMultiArrayInstruction newa -> in.with(leafs( + "dimensions", newa.dimensions(), + "descriptor", newa.arrayType().name().stringValue())); + case TypeCheckInstruction tch -> in.with(leaf( + "type", tch.type().name().stringValue())); + case ConstantInstruction cons -> in.with(leaf( + "constant value", cons.constantValue())); + case BranchInstruction br -> in.with(leaf( + "target", com.labelToBci(br.target()))); + case LookupSwitchInstruction si -> in.with(list( + "targets", "target", Stream.concat(Stream.of(si.defaultTarget()) + .map(com::labelToBci), si.cases().stream() + .map(sc -> com.labelToBci(sc.target()))))); + case TableSwitchInstruction si -> in.with(list( + "targets", "target", Stream.concat(Stream.of(si.defaultTarget()) + .map(com::labelToBci), si.cases().stream() + .map(sc -> com.labelToBci(sc.target()))))); + case DiscontinuedInstruction.JsrInstruction jsr -> in.with(leaf( + "target", com.labelToBci(jsr.target()))); + case DiscontinuedInstruction.RetInstruction ret -> in.with(leaf( + "slot", ret.slot())); + default -> {} + } + bci += ins.sizeInBytes(); + } + } + if (!excHandlers.isEmpty()) { + var handlersNode = new MapNodeImpl(BLOCK, "exception handlers"); + codeNode.with(handlersNode); + for (int i = 0; i < excHandlers.size(); i++) { + var exc = excHandlers.get(i); + handlersNode.with(map("handler " + (i + 1), + "start", exc.start(), + "end", exc.end(), + "handler", exc.handler(), + "type", exc.catchType())); + } + } + return codeNode; + } + return null; + } + + private static Node[] attributesToTree(List> attributes, Verbosity verbosity) { + var nodes = new LinkedList(); + if (verbosity != Verbosity.MEMBERS_ONLY) for (var attr : attributes) { + switch (attr) { + case BootstrapMethodsAttribute bma -> + nodes.add(new ListNodeImpl(BLOCK, "bootstrap methods", bma.bootstrapMethods().stream().map( + bm -> { + var mh = bm.bootstrapMethod(); + var mref = mh.reference(); + var bmNode = new MapNodeImpl(FLOW, "bm"); + bmNode.with(leafs( + "index", bm.bsmIndex(), + "kind", DirectMethodHandleDesc.Kind.valueOf(mh.kind(), + mref instanceof InterfaceMethodRefEntry).name(), + "owner", mref.owner().asInternalName(), + "name", mref.nameAndType().name().stringValue())); + bmNode.with(list("args", "arg", bm.arguments().stream().map(LoadableConstantEntry::constantValue))); + return bmNode; + }))); + case ConstantValueAttribute cva -> + nodes.add(leaf("constant value", cva.constant().constantValue())); + case NestHostAttribute nha -> + nodes.add(leaf("nest host", nha.nestHost().name().stringValue())); + case NestMembersAttribute nma -> + nodes.add(list("nest members", "member", nma.nestMembers().stream() + .map(mp -> mp.name().stringValue()))); + case PermittedSubclassesAttribute psa -> + nodes.add(list("permitted subclasses", "subclass", psa.permittedSubclasses().stream() + .map(e -> e.name().stringValue()))); + default -> {} + } + if (verbosity == Verbosity.TRACE_ALL) switch (attr) { + case EnclosingMethodAttribute ema -> + nodes.add(map("enclosing method", + "class", ema.enclosingClass().name().stringValue(), + "method name", ema.enclosingMethodName() + .map(Utf8Entry::stringValue).orElse("null"), + "method type", ema.enclosingMethodType() + .map(Utf8Entry::stringValue).orElse("null"))); + case ExceptionsAttribute exa -> + nodes.add(list("exceptions", "exc", exa.exceptions().stream() + .map(e -> e.name().stringValue()))); + case InnerClassesAttribute ica -> + nodes.add(new ListNodeImpl(BLOCK, "inner classes", ica.classes().stream() + .map(ic -> new MapNodeImpl(FLOW, "cls").with( + leaf("inner class", ic.innerClass().name().stringValue()), + leaf("outer class", ic.outerClass() + .map(cle -> cle.name().stringValue()).orElse("null")), + leaf("inner name", ic.innerName().map(Utf8Entry::stringValue).orElse("null")), + list("flags", "flag", ic.flags().stream().map(AccessFlag::name)))))); + case MethodParametersAttribute mpa -> { + var n = new MapNodeImpl(BLOCK, "method parameters"); + for (int i = 0; i < mpa.parameters().size(); i++) { + var p = mpa.parameters().get(i); + n.with(new MapNodeImpl(FLOW, i + 1).with( + leaf("name", p.name().map(Utf8Entry::stringValue).orElse("null")), + list("flags", "flag", p.flags().stream().map(AccessFlag::name)))); + } + } + case ModuleAttribute ma -> + nodes.add(new MapNodeImpl(BLOCK, "module") + .with(leaf("name", ma.moduleName().name().stringValue()), + list("flags","flag", ma.moduleFlags().stream().map(AccessFlag::name)), + leaf("version", ma.moduleVersion().map(Utf8Entry::stringValue).orElse("null")), + list("uses", "class", ma.uses().stream().map(ce -> ce.name().stringValue())), + new ListNodeImpl(BLOCK, "requires", ma.requires().stream().map(req -> + new MapNodeImpl(FLOW, "req").with( + leaf("name", req.requires().name().stringValue()), + list("flags", "flag", req.requiresFlags().stream() + .map(AccessFlag::name)), + leaf("version", req.requiresVersion() + .map(Utf8Entry::stringValue).orElse(null))))), + new ListNodeImpl(BLOCK, "exports", ma.exports().stream().map(exp -> + new MapNodeImpl(FLOW, "exp").with( + leaf("package", exp.exportedPackage().asSymbol().name()), + list("flags", "flag", exp.exportsFlags().stream() + .map(AccessFlag::name)), + list("to", "module", exp.exportsTo().stream() + .map(me -> me.name().stringValue()))))), + new ListNodeImpl(BLOCK, "opens", ma.opens().stream().map(opn -> + new MapNodeImpl(FLOW, "opn").with( + leaf("package", opn.openedPackage().asSymbol().name()), + list("flags", "flag", opn.opensFlags().stream() + .map(AccessFlag::name)), + list("to", "module", opn.opensTo().stream() + .map(me -> me.name().stringValue()))))), + new ListNodeImpl(BLOCK, "provides", ma.provides().stream() + .map(prov -> new MapNodeImpl(FLOW, "prov").with( + leaf("class", prov.provides().name().stringValue()), + list("with", "cls", prov.providesWith().stream() + .map(ce -> ce.name().stringValue()))))))); + case ModulePackagesAttribute mopa -> + nodes.add(list("module packages", "subclass", mopa.packages().stream() + .map(mp -> mp.asSymbol().name()))); + case ModuleMainClassAttribute mmca -> + nodes.add(leaf("module main class", mmca.mainClass().name().stringValue())); + case RecordAttribute ra -> + nodes.add(new ListNodeImpl(BLOCK, "record components", ra.components().stream() + .map(rc -> new MapNodeImpl(BLOCK, "component") + .with(leafs( + "name", rc.name().stringValue(), + "type", rc.descriptor().stringValue())) + .with(list("attributes", "attribute", rc.attributes().stream() + .map(Attribute::attributeName))) + .with(attributesToTree(rc.attributes(), verbosity))))); + case AnnotationDefaultAttribute ada -> + nodes.add(new MapNodeImpl(FLOW, "annotation default").with(elementValueToTree(ada.defaultValue()))); + case RuntimeInvisibleAnnotationsAttribute aa -> + nodes.add(annotationsToTree("invisible annotations", aa.annotations())); + case RuntimeVisibleAnnotationsAttribute aa -> + nodes.add(annotationsToTree("visible annotations", aa.annotations())); + case RuntimeInvisibleParameterAnnotationsAttribute aa -> + nodes.add(parameterAnnotationsToTree("invisible parameter annotations", aa.parameterAnnotations())); + case RuntimeVisibleParameterAnnotationsAttribute aa -> + nodes.add(parameterAnnotationsToTree("visible parameter annotations", aa.parameterAnnotations())); + case RuntimeInvisibleTypeAnnotationsAttribute aa -> + nodes.add(typeAnnotationsToTree(BLOCK, "invisible type annotations", aa.annotations())); + case RuntimeVisibleTypeAnnotationsAttribute aa -> + nodes.add(typeAnnotationsToTree(BLOCK, "visible type annotations", aa.annotations())); + case SignatureAttribute sa -> + nodes.add(leaf("signature", sa.signature().stringValue())); + case SourceFileAttribute sfa -> + nodes.add(leaf("source file", sfa.sourceFile().stringValue())); + default -> {} + } + } + return nodes.toArray(Node[]::new); + } + + private static Node annotationsToTree(String name, List annos) { + return new ListNodeImpl(BLOCK, name, annos.stream().map(a -> + new MapNodeImpl(FLOW, "anno") + .with(leaf("annotation class", a.className().stringValue())) + .with(elementValuePairsToTree(a.elements())))); + + } + + private static Node typeAnnotationsToTree(Style style, String name, List annos) { + return new ListNodeImpl(style, name, annos.stream().map(a -> + new MapNodeImpl(FLOW, "anno") + .with(leaf("annotation class", a.className().stringValue()), + leaf("target info", a.targetInfo().targetType().name())) + .with(elementValuePairsToTree(a.elements())))); + + } + + private static MapNodeImpl parameterAnnotationsToTree(String name, List> paramAnnotations) { + var node = new MapNodeImpl(BLOCK, name); + for (int i = 0; i < paramAnnotations.size(); i++) { + var annos = paramAnnotations.get(i); + if (!annos.isEmpty()) { + node.with(new ListNodeImpl(FLOW, "parameter " + (i + 1), annos.stream().map(a -> + new MapNodeImpl(FLOW, "anno") + .with(leaf("annotation class", a.className().stringValue())) + .with(elementValuePairsToTree(a.elements()))))); + } + } + return node; + } + + private static Node[] localInfoToTree(List locals, int slot, int bci) { + if (locals != null) { + for (var l : locals) { + if (l.slot() == slot && l.startPc() <= bci && l.length() + l.startPc() >= bci) { + return leafs("type", l.type().stringValue(), + "variable name", l.name().stringValue()); + } + } + } + return new Node[0]; + } + + private static void forEachOffset(TypeAnnotation ta, CodeAttribute lr, BiConsumer consumer) { + switch (ta.targetInfo()) { + case TypeAnnotation.OffsetTarget ot -> + consumer.accept(lr.labelToBci(ot.target()), ta); + case TypeAnnotation.TypeArgumentTarget tat -> + consumer.accept(lr.labelToBci(tat.target()), ta); + case TypeAnnotation.LocalVarTarget lvt -> + lvt.table().forEach(lvti -> consumer.accept(lr.labelToBci(lvti.startLabel()), ta)); + default -> {} + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassReaderImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassReaderImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..60ca47d0d310f7468a284561e0176c7c837d95ad GIT binary patch literal 18596 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 PU4eEf+T&=Kd5ZrR=@(91 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassReaderImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/ClassReaderImpl.java new file mode 100644 index 00000000..b8a262ce --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.classfile.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +import java.lang.classfile.*; +import java.lang.classfile.attribute.BootstrapMethodsAttribute; +import java.lang.classfile.constantpool.*; + +import static java.lang.classfile.ClassFile.TAG_CLASS; +import static java.lang.classfile.ClassFile.TAG_CONSTANTDYNAMIC; +import static java.lang.classfile.ClassFile.TAG_DOUBLE; +import static java.lang.classfile.ClassFile.TAG_FIELDREF; +import static java.lang.classfile.ClassFile.TAG_FLOAT; +import static java.lang.classfile.ClassFile.TAG_INTEGER; +import static java.lang.classfile.ClassFile.TAG_INTERFACEMETHODREF; +import static java.lang.classfile.ClassFile.TAG_INVOKEDYNAMIC; +import static java.lang.classfile.ClassFile.TAG_LONG; +import static java.lang.classfile.ClassFile.TAG_METHODHANDLE; +import static java.lang.classfile.ClassFile.TAG_METHODREF; +import static java.lang.classfile.ClassFile.TAG_METHODTYPE; +import static java.lang.classfile.ClassFile.TAG_MODULE; +import static java.lang.classfile.ClassFile.TAG_NAMEANDTYPE; +import static java.lang.classfile.ClassFile.TAG_PACKAGE; +import static java.lang.classfile.ClassFile.TAG_STRING; +import static java.lang.classfile.ClassFile.TAG_UTF8; + +public final class ClassReaderImpl + implements ClassReader { + static final int CP_ITEM_START = 10; + + private final byte[] buffer; + private final int metadataStart; + private final int classfileLength; + private final Function> attributeMapper; + private final int flags; + private final int thisClassPos; + private ClassEntry thisClass; + private Optional superclass; + private final int constantPoolCount; + private final int[] cpOffset; + + final ClassFileImpl context; + final int interfacesPos; + final PoolEntry[] cp; + + private ClassModel containedClass; + private List bsmEntries; + private BootstrapMethodsAttribute bootstrapMethodsAttribute; + + ClassReaderImpl(byte[] classfileBytes, + ClassFileImpl context) { + this.buffer = classfileBytes; + this.classfileLength = classfileBytes.length; + this.context = context; + this.attributeMapper = this.context.attributeMapperOption().attributeMapper(); + if (classfileLength < 4 || readInt(0) != 0xCAFEBABE) { + throw new IllegalArgumentException("Bad magic number"); + } + if (readU2(6) > ClassFile.latestMajorVersion()) { + throw new IllegalArgumentException("Unsupported class file version: " + readU2(6)); + } + int constantPoolCount = readU2(8); + int[] cpOffset = new int[constantPoolCount]; + int p = CP_ITEM_START; + for (int i = 1; i < cpOffset.length; ++i) { + cpOffset[i] = p; + int tag = readU1(p); + ++p; + switch (tag) { + // 2 + case TAG_CLASS, TAG_METHODTYPE, TAG_MODULE, TAG_STRING, TAG_PACKAGE -> p += 2; + + // 3 + case TAG_METHODHANDLE -> p += 3; + + // 4 + case TAG_CONSTANTDYNAMIC, TAG_FIELDREF, TAG_FLOAT, TAG_INTEGER, + TAG_INTERFACEMETHODREF, TAG_INVOKEDYNAMIC, TAG_METHODREF, + TAG_NAMEANDTYPE -> p += 4; + + // 8 + case TAG_DOUBLE, TAG_LONG -> { + p += 8; + ++i; + } + case TAG_UTF8 -> p += 2 + readU2(p); + default -> throw new ConstantPoolException( + "Bad tag (" + tag + ") at index (" + i + ") position (" + p + ")"); + } + } + this.metadataStart = p; + this.cpOffset = cpOffset; + this.constantPoolCount = constantPoolCount; + this.cp = new PoolEntry[constantPoolCount]; + + this.flags = readU2(p); + this.thisClassPos = p + 2; + p += 6; + this.interfacesPos = p; + } + + public ClassFileImpl context() { + return context; + } + + @Override + public Function> customAttributes() { + return attributeMapper; + } + + @Override + public int size() { + return constantPoolCount; + } + + @Override + public int flags() { + return flags; + } + + @Override + public ClassEntry thisClassEntry() { + if (thisClass == null) { + thisClass = readClassEntry(thisClassPos); + } + return thisClass; + } + + @Override + public Optional superclassEntry() { + if (superclass == null) { + superclass = Optional.ofNullable(readEntryOrNull(thisClassPos + 2, ClassEntry.class)); + } + return superclass; + } + + public int thisClassPos() { + return thisClassPos; + } + + @Override + public int classfileLength() { + return classfileLength; + } + + //------ Bootstrap Method Table handling + + @Override + public int bootstrapMethodCount() { + return bootstrapMethodsAttribute().bootstrapMethodsSize(); + } + + @Override + public BootstrapMethodEntryImpl bootstrapMethodEntry(int index) { + if (index < 0 || index >= bootstrapMethodCount()) { + throw new ConstantPoolException("Bad BSM index: " + index); + } + return bsmEntries().get(index); + } + + private static IllegalArgumentException outOfBoundsError(IndexOutOfBoundsException cause) { + return new IllegalArgumentException("Reading beyond classfile bounds", cause); + } + + @Override + public int readU1(int p) { + try { + return buffer[p] & 0xFF; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } + } + + @Override + public int readU2(int p) { + try { + int b1 = buffer[p] & 0xFF; + int b2 = buffer[p + 1] & 0xFF; + return (b1 << 8) + b2; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } + } + + @Override + public int readS1(int p) { + try { + return buffer[p]; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } + } + + @Override + public int readS2(int p) { + try { + int b1 = buffer[p]; + int b2 = buffer[p + 1] & 0xFF; + return (b1 << 8) + b2; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } + } + + @Override + public int readInt(int p) { + try { + int ch1 = buffer[p] & 0xFF; + int ch2 = buffer[p + 1] & 0xFF; + int ch3 = buffer[p + 2] & 0xFF; + int ch4 = buffer[p + 3] & 0xFF; + return (ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4; + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } + } + + @Override + public long readLong(int p) { + try { + return ((long) buffer[p + 0] << 56) + ((long) (buffer[p + 1] & 255) << 48) + + ((long) (buffer[p + 2] & 255) << 40) + ((long) (buffer[p + 3] & 255) << 32) + + ((long) (buffer[p + 4] & 255) << 24) + ((buffer[p + 5] & 255) << 16) + ((buffer[p + 6] & 255) << 8) + + (buffer[p + 7] & 255); + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } + } + + @Override + public float readFloat(int p) { + return Float.intBitsToFloat(readInt(p)); + } + + @Override + public double readDouble(int p) { + return Double.longBitsToDouble(readLong(p)); + } + + @Override + public byte[] readBytes(int p, int len) { + try { + return Arrays.copyOfRange(buffer, p, p + len); + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } + } + + @Override + public void copyBytesTo(BufWriter buf, int p, int len) { + try { + buf.writeBytes(buffer, p, len); + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } + } + + BootstrapMethodsAttribute bootstrapMethodsAttribute() { + + if (bootstrapMethodsAttribute == null) { + bootstrapMethodsAttribute + = containedClass.findAttribute(Attributes.bootstrapMethods()) + .orElse(new UnboundAttribute.EmptyBootstrapAttribute()); + } + + return bootstrapMethodsAttribute; + } + + List bsmEntries() { + if (bsmEntries == null) { + bsmEntries = new ArrayList<>(); + BootstrapMethodsAttribute attr = bootstrapMethodsAttribute(); + List list = attr.bootstrapMethods(); + if (!list.isEmpty()) { + for (BootstrapMethodEntry bm : list) { + AbstractPoolEntry.MethodHandleEntryImpl handle = (AbstractPoolEntry.MethodHandleEntryImpl) bm.bootstrapMethod(); + List args = bm.arguments(); + int hash = BootstrapMethodEntryImpl.computeHashCode(handle, args); + bsmEntries.add(new BootstrapMethodEntryImpl(this, bsmEntries.size(), hash, handle, args)); + } + } + } + return bsmEntries; + } + + void setContainedClass(ClassModel containedClass) { + this.containedClass = containedClass; + } + + ClassModel getContainedClass() { + return containedClass; + } + + boolean writeBootstrapMethods(BufWriter buf) { + Optional a + = containedClass.findAttribute(Attributes.bootstrapMethods()); + if (a.isEmpty()) + return false; + a.get().writeTo(buf); + return true; + } + + void writeConstantPoolEntries(BufWriter buf) { + copyBytesTo(buf, ClassReaderImpl.CP_ITEM_START, + metadataStart - ClassReaderImpl.CP_ITEM_START); + } + + // Constantpool + @Override + public PoolEntry entryByIndex(int index) { + return entryByIndex(index, PoolEntry.class); + } + + private static boolean checkTag(int tag, Class cls) { + var type = switch (tag) { + // JVMS Table 4.4-B. Constant pool tags + case TAG_UTF8 -> AbstractPoolEntry.Utf8EntryImpl.class; + case TAG_INTEGER -> AbstractPoolEntry.IntegerEntryImpl.class; + case TAG_FLOAT -> AbstractPoolEntry.FloatEntryImpl.class; + case TAG_LONG -> AbstractPoolEntry.LongEntryImpl.class; + case TAG_DOUBLE -> AbstractPoolEntry.DoubleEntryImpl.class; + case TAG_CLASS -> AbstractPoolEntry.ClassEntryImpl.class; + case TAG_STRING -> AbstractPoolEntry.StringEntryImpl.class; + case TAG_FIELDREF -> AbstractPoolEntry.FieldRefEntryImpl.class; + case TAG_METHODREF -> AbstractPoolEntry.MethodRefEntryImpl.class; + case TAG_INTERFACEMETHODREF -> AbstractPoolEntry.InterfaceMethodRefEntryImpl.class; + case TAG_NAMEANDTYPE -> AbstractPoolEntry.NameAndTypeEntryImpl.class; + case TAG_METHODHANDLE -> AbstractPoolEntry.MethodHandleEntryImpl.class; + case TAG_METHODTYPE -> AbstractPoolEntry.MethodTypeEntryImpl.class; + case TAG_CONSTANTDYNAMIC -> AbstractPoolEntry.ConstantDynamicEntryImpl.class; + case TAG_INVOKEDYNAMIC -> AbstractPoolEntry.InvokeDynamicEntryImpl.class; + case TAG_MODULE -> AbstractPoolEntry.ModuleEntryImpl.class; + case TAG_PACKAGE -> AbstractPoolEntry.PackageEntryImpl.class; + default -> null; + }; + return type != null && cls.isAssignableFrom(type); + } + + static T checkType(PoolEntry e, int index, Class cls) { + if (cls.isInstance(e)) return cls.cast(e); + throw new ConstantPoolException("Not a " + cls.getSimpleName() + " at index: " + index); + } + + @Override + public T entryByIndex(int index, Class cls) { + Objects.requireNonNull(cls); + if (index <= 0 || index >= constantPoolCount) { + throw new ConstantPoolException("Bad CP index: " + index); + } + PoolEntry info = cp[index]; + if (info == null) { + int offset = cpOffset[index]; + if (offset == 0) { + throw new ConstantPoolException("Unusable CP index: " + index); + } + int tag = readU1(offset); + if (!checkTag(tag, cls)) { + throw new ConstantPoolException( + "Bad tag (" + tag + ") at index (" + index + ") position (" + offset + "), expected " + cls.getSimpleName()); + } + final int q = offset + 1; + info = switch (tag) { + case TAG_UTF8 -> new AbstractPoolEntry.Utf8EntryImpl(this, index, buffer, q + 2, readU2(q)); + case TAG_INTEGER -> new AbstractPoolEntry.IntegerEntryImpl(this, index, readInt(q)); + case TAG_FLOAT -> new AbstractPoolEntry.FloatEntryImpl(this, index, readFloat(q)); + case TAG_LONG -> new AbstractPoolEntry.LongEntryImpl(this, index, readLong(q)); + case TAG_DOUBLE -> new AbstractPoolEntry.DoubleEntryImpl(this, index, readDouble(q)); + case TAG_CLASS -> new AbstractPoolEntry.ClassEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); + case TAG_STRING -> new AbstractPoolEntry.StringEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); + case TAG_FIELDREF -> new AbstractPoolEntry.FieldRefEntryImpl(this, index, (AbstractPoolEntry.ClassEntryImpl) readClassEntry(q), + (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); + case TAG_METHODREF -> new AbstractPoolEntry.MethodRefEntryImpl(this, index, (AbstractPoolEntry.ClassEntryImpl) readClassEntry(q), + (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); + case TAG_INTERFACEMETHODREF -> new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, index, (AbstractPoolEntry.ClassEntryImpl) readClassEntry(q), + (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); + case TAG_NAMEANDTYPE -> new AbstractPoolEntry.NameAndTypeEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q), + (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q + 2)); + case TAG_METHODHANDLE -> new AbstractPoolEntry.MethodHandleEntryImpl(this, index, readU1(q), + readEntry(q + 1, AbstractPoolEntry.AbstractMemberRefEntry.class)); + case TAG_METHODTYPE -> new AbstractPoolEntry.MethodTypeEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); + case TAG_CONSTANTDYNAMIC -> new AbstractPoolEntry.ConstantDynamicEntryImpl(this, index, readU2(q), (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); + case TAG_INVOKEDYNAMIC -> new AbstractPoolEntry.InvokeDynamicEntryImpl(this, index, readU2(q), (AbstractPoolEntry.NameAndTypeEntryImpl) readNameAndTypeEntry(q + 2)); + case TAG_MODULE -> new AbstractPoolEntry.ModuleEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); + case TAG_PACKAGE -> new AbstractPoolEntry.PackageEntryImpl(this, index, (AbstractPoolEntry.Utf8EntryImpl) readUtf8Entry(q)); + default -> throw new ConstantPoolException( + "Bad tag (" + tag + ") at index (" + index + ") position (" + offset + ")"); + }; + cp[index] = info; + } + return checkType(info, index, cls); + } + + public int skipAttributeHolder(int offset) { + int p = offset; + int cnt = readU2(p); + p += 2; + for (int i = 0; i < cnt; ++i) { + int len = readInt(p + 2); + p += 6; + if (len < 0 || len > classfileLength - p) { + throw new IllegalArgumentException("attribute " + readUtf8Entry(p - 6).stringValue() + " too big to handle"); + } + p += len; + } + return p; + } + + @Override + public PoolEntry readEntry(int pos) { + return entryByIndex(readU2(pos)); + } + + @Override + public T readEntry(int pos, Class cls) { + Objects.requireNonNull(cls); + return entryByIndex(readU2(pos), cls); + } + + @Override + public PoolEntry readEntryOrNull(int pos) { + int index = readU2(pos); + if (index == 0) { + return null; + } + return entryByIndex(index); + } + + @Override + public T readEntryOrNull(int offset, Class cls) { + Objects.requireNonNull(cls); + int index = readU2(offset); + if (index == 0) { + return null; + } + return entryByIndex(index, cls); + } + + @Override + public Utf8Entry readUtf8Entry(int pos) { + return readEntry(pos, Utf8Entry.class); + } + + @Override + public Utf8Entry readUtf8EntryOrNull(int pos) { + return readEntryOrNull(pos, Utf8Entry.class); + } + + @Override + public ModuleEntry readModuleEntry(int pos) { + return readEntry(pos, ModuleEntry.class); + } + + @Override + public PackageEntry readPackageEntry(int pos) { + return readEntry(pos, PackageEntry.class); + } + + @Override + public ClassEntry readClassEntry(int pos) { + return readEntry(pos, ClassEntry.class); + } + + @Override + public NameAndTypeEntry readNameAndTypeEntry(int pos) { + return readEntry(pos, NameAndTypeEntry.class); + } + + @Override + public MethodHandleEntry readMethodHandleEntry(int pos) { + return readEntry(pos, MethodHandleEntry.class); + } + + @Override + public boolean compare(BufWriter bufWriter, + int bufWriterOffset, + int classReaderOffset, + int length) { + try { + return Arrays.equals(((BufWriterImpl) bufWriter).elems, + bufWriterOffset, bufWriterOffset + length, + buffer, classReaderOffset, classReaderOffset + length); + } catch (IndexOutOfBoundsException e) { + throw outOfBoundsError(e); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl$1.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..728fbf3ad8cd697e42b8d33f205f61310151c057 GIT binary patch literal 998 zcmb7CT~8B16g|_HZd}foQZQV z8SDf1(3UC^f#RO+csvZ>N>AAGXyDm34R^#59}Gm$B9FDo@Yw3SlabTk;sZ-_Te@=V zta9tWl_&OES!({giD?w5kr$0_x3R;pGHDn335zB!Vur!+16NY@49QBhWuU|`KYo<9 z-x)gnrWBsr2m(LQ{ACk!F@GoK*RIPZu4q@j(_QbjYHvoB>62?FuK#{Ax?|u5Lt#v_ z-8-OxF=U=Po>Ve=7FV;&kgEBvV3^*NO0{WXtRI+VPj9M2D>+8-&#zxw?!Cj_#ri6wv-Y<%qBtu zD-6|fr)QJ?heoMmt1=`Y&I)C%G`%CwP23`D5qgg#?SST2u#@k(&oDmeKmP?6 zQrjOWNepKRPL1I_!SonjC1}L(BT~p>2D7+?GI87?dlzeXNcIudQ74r(7l#4_0;Wk|rr>hn43jlM$W7uCr3761SM literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..c8f064ecadef02176f6d3d4b778ab67ac851c13c GIT binary patch literal 40081 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 Hpn?AnN`*cg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl.java new file mode 100644 index 00000000..d1a02d9a --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/ClassRemapperImpl.java @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassElement; +import java.lang.classfile.ClassSignature; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeModel; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.FieldBuilder; +import java.lang.classfile.FieldElement; +import java.lang.classfile.FieldModel; +import java.lang.classfile.FieldTransform; +import java.lang.classfile.Interfaces; +import java.lang.classfile.MethodBuilder; +import java.lang.classfile.MethodElement; +import java.lang.classfile.MethodModel; +import java.lang.classfile.MethodSignature; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.Signature; +import java.lang.classfile.Superclass; +import java.lang.classfile.TypeAnnotation; +import java.lang.classfile.attribute.AnnotationDefaultAttribute; +import java.lang.classfile.attribute.EnclosingMethodAttribute; +import java.lang.classfile.attribute.ExceptionsAttribute; +import java.lang.classfile.attribute.InnerClassInfo; +import java.lang.classfile.attribute.InnerClassesAttribute; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.classfile.attribute.ModuleProvideInfo; +import java.lang.classfile.attribute.NestHostAttribute; +import java.lang.classfile.attribute.NestMembersAttribute; +import java.lang.classfile.attribute.PermittedSubclassesAttribute; +import java.lang.classfile.attribute.RecordAttribute; +import java.lang.classfile.attribute.RecordComponentInfo; +import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; +import java.lang.classfile.attribute.SignatureAttribute; +import java.lang.classfile.components.ClassRemapper; +import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.classfile.instruction.ConstantInstruction.LoadConstantInstruction; +import java.lang.classfile.instruction.ExceptionCatch; +import java.lang.classfile.instruction.FieldInstruction; +import java.lang.classfile.instruction.InvokeDynamicInstruction; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.classfile.instruction.LocalVariable; +import java.lang.classfile.instruction.LocalVariableType; +import java.lang.classfile.instruction.NewMultiArrayInstruction; +import java.lang.classfile.instruction.NewObjectInstruction; +import java.lang.classfile.instruction.NewReferenceArrayInstruction; +import java.lang.classfile.instruction.TypeCheckInstruction; + +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDesc; +import java.lang.constant.DirectMethodHandleDesc; +import java.lang.constant.DynamicCallSiteDesc; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodHandleDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.List; +import java.util.function.Function; + +public record ClassRemapperImpl(Function mapFunction) implements ClassRemapper { + + @Override + public void accept(ClassBuilder clb, ClassElement cle) { + switch (cle) { + case FieldModel fm -> + clb.withField(fm.fieldName().stringValue(), map( + fm.fieldTypeSymbol()), fb -> + fm.forEachElement(asFieldTransform().resolve(fb).consumer())); + case MethodModel mm -> + clb.withMethod(mm.methodName().stringValue(), mapMethodDesc( + mm.methodTypeSymbol()), mm.flags().flagsMask(), mb -> + mm.forEachElement(asMethodTransform().resolve(mb).consumer())); + case Superclass sc -> + clb.withSuperclass(map(sc.superclassEntry().asSymbol())); + case Interfaces ins -> + clb.withInterfaceSymbols(Util.mappedList(ins.interfaces(), in -> + map(in.asSymbol()))); + case SignatureAttribute sa -> + clb.with(SignatureAttribute.of(mapClassSignature(sa.asClassSignature()))); + case InnerClassesAttribute ica -> + clb.with(InnerClassesAttribute.of(ica.classes().stream().map(ici -> + InnerClassInfo.of(map(ici.innerClass().asSymbol()), + ici.outerClass().map(oc -> map(oc.asSymbol())), + ici.innerName().map(Utf8Entry::stringValue), + ici.flagsMask())).toList())); + case EnclosingMethodAttribute ema -> + clb.with(EnclosingMethodAttribute.of(map(ema.enclosingClass().asSymbol()), + ema.enclosingMethodName().map(Utf8Entry::stringValue), + ema.enclosingMethodTypeSymbol().map(this::mapMethodDesc))); + case RecordAttribute ra -> + clb.with(RecordAttribute.of(ra.components().stream() + .map(this::mapRecordComponent).toList())); + case ModuleAttribute ma -> + clb.with(ModuleAttribute.of(ma.moduleName(), ma.moduleFlagsMask(), + ma.moduleVersion().orElse(null), + ma.requires(), ma.exports(), ma.opens(), + ma.uses().stream().map(ce -> + clb.constantPool().classEntry(map(ce.asSymbol()))).toList(), + ma.provides().stream().map(mp -> + ModuleProvideInfo.of(map(mp.provides().asSymbol()), + mp.providesWith().stream().map(pw -> + map(pw.asSymbol())).toList())).toList())); + case NestHostAttribute nha -> + clb.with(NestHostAttribute.of(map(nha.nestHost().asSymbol()))); + case NestMembersAttribute nma -> + clb.with(NestMembersAttribute.ofSymbols(nma.nestMembers().stream() + .map(nm -> map(nm.asSymbol())).toList())); + case PermittedSubclassesAttribute psa -> + clb.with(PermittedSubclassesAttribute.ofSymbols( + psa.permittedSubclasses().stream().map(ps -> + map(ps.asSymbol())).toList())); + case RuntimeVisibleAnnotationsAttribute aa -> + clb.with(RuntimeVisibleAnnotationsAttribute.of( + mapAnnotations(aa.annotations()))); + case RuntimeInvisibleAnnotationsAttribute aa -> + clb.with(RuntimeInvisibleAnnotationsAttribute.of( + mapAnnotations(aa.annotations()))); + case RuntimeVisibleTypeAnnotationsAttribute aa -> + clb.with(RuntimeVisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations()))); + case RuntimeInvisibleTypeAnnotationsAttribute aa -> + clb.with(RuntimeInvisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations()))); + default -> + clb.with(cle); + } + } + + @Override + public FieldTransform asFieldTransform() { + return (FieldBuilder fb, FieldElement fe) -> { + switch (fe) { + case SignatureAttribute sa -> + fb.with(SignatureAttribute.of( + mapSignature(sa.asTypeSignature()))); + case RuntimeVisibleAnnotationsAttribute aa -> + fb.with(RuntimeVisibleAnnotationsAttribute.of( + mapAnnotations(aa.annotations()))); + case RuntimeInvisibleAnnotationsAttribute aa -> + fb.with(RuntimeInvisibleAnnotationsAttribute.of( + mapAnnotations(aa.annotations()))); + case RuntimeVisibleTypeAnnotationsAttribute aa -> + fb.with(RuntimeVisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations()))); + case RuntimeInvisibleTypeAnnotationsAttribute aa -> + fb.with(RuntimeInvisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations()))); + default -> + fb.with(fe); + } + }; + } + + @Override + public MethodTransform asMethodTransform() { + return (MethodBuilder mb, MethodElement me) -> { + switch (me) { + case AnnotationDefaultAttribute ada -> + mb.with(AnnotationDefaultAttribute.of( + mapAnnotationValue(ada.defaultValue()))); + case CodeModel com -> + mb.transformCode(com, asCodeTransform()); + case ExceptionsAttribute ea -> + mb.with(ExceptionsAttribute.ofSymbols( + ea.exceptions().stream().map(ce -> + map(ce.asSymbol())).toList())); + case SignatureAttribute sa -> + mb.with(SignatureAttribute.of( + mapMethodSignature(sa.asMethodSignature()))); + case RuntimeVisibleAnnotationsAttribute aa -> + mb.with(RuntimeVisibleAnnotationsAttribute.of( + mapAnnotations(aa.annotations()))); + case RuntimeInvisibleAnnotationsAttribute aa -> + mb.with(RuntimeInvisibleAnnotationsAttribute.of( + mapAnnotations(aa.annotations()))); + case RuntimeVisibleParameterAnnotationsAttribute paa -> + mb.with(RuntimeVisibleParameterAnnotationsAttribute.of( + paa.parameterAnnotations().stream() + .map(this::mapAnnotations).toList())); + case RuntimeInvisibleParameterAnnotationsAttribute paa -> + mb.with(RuntimeInvisibleParameterAnnotationsAttribute.of( + paa.parameterAnnotations().stream() + .map(this::mapAnnotations).toList())); + case RuntimeVisibleTypeAnnotationsAttribute aa -> + mb.with(RuntimeVisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations()))); + case RuntimeInvisibleTypeAnnotationsAttribute aa -> + mb.with(RuntimeInvisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations()))); + default -> + mb.with(me); + } + }; + } + + @Override + public CodeTransform asCodeTransform() { + return (CodeBuilder cob, CodeElement coe) -> { + switch (coe) { + case FieldInstruction fai -> + cob.fieldAccess(fai.opcode(), map(fai.owner().asSymbol()), + fai.name().stringValue(), map(fai.typeSymbol())); + case InvokeInstruction ii -> + cob.invoke(ii.opcode(), map(ii.owner().asSymbol()), + ii.name().stringValue(), mapMethodDesc(ii.typeSymbol()), + ii.isInterface()); + case InvokeDynamicInstruction idi -> + cob.invokedynamic(DynamicCallSiteDesc.of( + mapDirectMethodHandle(idi.bootstrapMethod()), idi.name().stringValue(), + mapMethodDesc(idi.typeSymbol()), + idi.bootstrapArgs().stream().map(this::mapConstantValue).toArray(ConstantDesc[]::new))); + case NewObjectInstruction c -> + cob.new_(map(c.className().asSymbol())); + case NewReferenceArrayInstruction c -> + cob.anewarray(map(c.componentType().asSymbol())); + case NewMultiArrayInstruction c -> + cob.multianewarray(map(c.arrayType().asSymbol()), c.dimensions()); + case TypeCheckInstruction c -> + cob.with(TypeCheckInstruction.of(c.opcode(), map(c.type().asSymbol()))); + case ExceptionCatch c -> + cob.exceptionCatch(c.tryStart(), c.tryEnd(), c.handler(),c.catchType() + .map(d -> TemporaryConstantPool.INSTANCE.classEntry(map(d.asSymbol())))); + case LocalVariable c -> + cob.localVariable(c.slot(), c.name().stringValue(), map(c.typeSymbol()), + c.startScope(), c.endScope()); + case LocalVariableType c -> + cob.localVariableType(c.slot(), c.name().stringValue(), + mapSignature(c.signatureSymbol()), c.startScope(), c.endScope()); + case LoadConstantInstruction ldc -> + cob.loadConstant(ldc.opcode(), + mapConstantValue(ldc.constantValue())); + case RuntimeVisibleTypeAnnotationsAttribute aa -> + cob.with(RuntimeVisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations()))); + case RuntimeInvisibleTypeAnnotationsAttribute aa -> + cob.with(RuntimeInvisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations()))); + default -> + cob.with(coe); + } + }; + } + + @Override + public ClassDesc map(ClassDesc desc) { + if (desc == null) return null; + if (desc.isArray()) return map(desc.componentType()).arrayType(); + if (desc.isPrimitive()) return desc; + return mapFunction.apply(desc); + } + + MethodTypeDesc mapMethodDesc(MethodTypeDesc desc) { + return MethodTypeDesc.of(map(desc.returnType()), + desc.parameterList().stream().map(this::map).toArray(ClassDesc[]::new)); + } + + ClassSignature mapClassSignature(ClassSignature signature) { + return ClassSignature.of(mapTypeParams(signature.typeParameters()), + mapSignature(signature.superclassSignature()), + signature.superinterfaceSignatures().stream() + .map(this::mapSignature).toArray(Signature.ClassTypeSig[]::new)); + } + + MethodSignature mapMethodSignature(MethodSignature signature) { + return MethodSignature.of(mapTypeParams(signature.typeParameters()), + signature.throwableSignatures().stream().map(this::mapSignature).toList(), + mapSignature(signature.result()), + signature.arguments().stream() + .map(this::mapSignature).toArray(Signature[]::new)); + } + + RecordComponentInfo mapRecordComponent(RecordComponentInfo component) { + return RecordComponentInfo.of(component.name().stringValue(), + map(component.descriptorSymbol()), + component.attributes().stream().map(atr -> + switch (atr) { + case SignatureAttribute sa -> + SignatureAttribute.of( + mapSignature(sa.asTypeSignature())); + case RuntimeVisibleAnnotationsAttribute aa -> + RuntimeVisibleAnnotationsAttribute.of( + mapAnnotations(aa.annotations())); + case RuntimeInvisibleAnnotationsAttribute aa -> + RuntimeInvisibleAnnotationsAttribute.of( + mapAnnotations(aa.annotations())); + case RuntimeVisibleTypeAnnotationsAttribute aa -> + RuntimeVisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations())); + case RuntimeInvisibleTypeAnnotationsAttribute aa -> + RuntimeInvisibleTypeAnnotationsAttribute.of( + mapTypeAnnotations(aa.annotations())); + default -> atr; + }).toList()); + } + + DirectMethodHandleDesc mapDirectMethodHandle(DirectMethodHandleDesc dmhd) { + return switch (dmhd.kind()) { + case GETTER, SETTER, STATIC_GETTER, STATIC_SETTER -> + MethodHandleDesc.ofField(dmhd.kind(), map(dmhd.owner()), + dmhd.methodName(), + map(ClassDesc.ofDescriptor(dmhd.lookupDescriptor()))); + default -> + MethodHandleDesc.ofMethod(dmhd.kind(), map(dmhd.owner()), + dmhd.methodName(), + mapMethodDesc(MethodTypeDesc.ofDescriptor(dmhd.lookupDescriptor()))); + }; + } + + ConstantDesc mapConstantValue(ConstantDesc value) { + return switch (value) { + case ClassDesc cd -> + map(cd); + case DynamicConstantDesc dcd -> + mapDynamicConstant(dcd); + case DirectMethodHandleDesc dmhd -> + mapDirectMethodHandle(dmhd); + case MethodTypeDesc mtd -> + mapMethodDesc(mtd); + default -> value; + }; + } + + DynamicConstantDesc mapDynamicConstant(DynamicConstantDesc dcd) { + return DynamicConstantDesc.ofNamed(mapDirectMethodHandle(dcd.bootstrapMethod()), + dcd.constantName(), + map(dcd.constantType()), + dcd.bootstrapArgsList().stream().map(this::mapConstantValue).toArray(ConstantDesc[]::new)); + } + + @SuppressWarnings("unchecked") + S mapSignature(S signature) { + return (S) switch (signature) { + case Signature.ArrayTypeSig ats -> + Signature.ArrayTypeSig.of(mapSignature(ats.componentSignature())); + case Signature.ClassTypeSig cts -> + Signature.ClassTypeSig.of( + cts.outerType().map(this::mapSignature).orElse(null), + map(cts.classDesc()), + cts.typeArgs().stream().map(ta -> switch (ta) { + case Signature.TypeArg.Unbounded u -> u; + case Signature.TypeArg.Bounded bta -> Signature.TypeArg.bounded( + bta.wildcardIndicator(), mapSignature(bta.boundType())); + }).toArray(Signature.TypeArg[]::new)); + default -> signature; + }; + } + + List mapAnnotations(List annotations) { + return annotations.stream().map(this::mapAnnotation).toList(); + } + + Annotation mapAnnotation(Annotation a) { + return Annotation.of(map(a.classSymbol()), a.elements().stream().map(el -> + AnnotationElement.of(el.name(), mapAnnotationValue(el.value()))).toList()); + } + + AnnotationValue mapAnnotationValue(AnnotationValue val) { + return switch (val) { + case AnnotationValue.OfAnnotation oa -> + AnnotationValue.ofAnnotation(mapAnnotation(oa.annotation())); + case AnnotationValue.OfArray oa -> + AnnotationValue.ofArray(oa.values().stream().map(this::mapAnnotationValue).toList()); + case AnnotationValue.OfConstant oc -> oc; + case AnnotationValue.OfClass oc -> + AnnotationValue.ofClass(map(oc.classSymbol())); + case AnnotationValue.OfEnum oe -> + AnnotationValue.ofEnum(map(oe.classSymbol()), oe.constantName().stringValue()); + }; + } + + List mapTypeAnnotations(List typeAnnotations) { + return typeAnnotations.stream().map(a -> TypeAnnotation.of(a.targetInfo(), + a.targetPath(), map(a.classSymbol()), + a.elements().stream().map(el -> AnnotationElement.of(el.name(), + mapAnnotationValue(el.value()))).toList())).toList(); + } + + List mapTypeParams(List typeParams) { + return typeParams.stream().map(tp -> Signature.TypeParam.of(tp.identifier(), + tp.classBound().map(this::mapSignature), + tp.interfaceBounds().stream() + .map(this::mapSignature).toArray(Signature.RefTypeSig[]::new))).toList(); + } + +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$1.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..c892bd51875ca102723d620e27c4e30f0d931738 GIT binary patch literal 1155 zcma)*TW=CU6vzJql*@KY*J|sfYHP*HMY}dW(vY+SV-u{#HuyX&0}L*+&0h4?FJYn| z!$fQ1gYnr9WjwP$;h`aHvU6r<&-u;&oH_IN->=^Q>acT2AelkR#1hgByMxYqTdGj_ zio3Ss@*wC+SJ-lR?%H*)BaUfO*k?$GeHj#AE>}JK zb$cM3kcbCT$*{(dES6dZ@>tElGI0%S424DZV90kpzrme;!xclJh`C*C#v4VUbnR}W zoKSj-@=!rE6n?eT%HRgW)>O6Wn9@hYuo%CvU!_xd zCBnYfdBc4^6x0J0op9O=4@Om-lPbgdY&}M28f(s-%AVq3hHD?h-> zKau%HUkTi!F-?)cXWXZ8W8{S`V(Q0;X;gZeFOl0Pi=3$gY1G)mF*aBJ4pzCq%9N_R z75GBBzRr+ym*gCF@R0N#60ShL8u$DXSNVhM7g(R-W<{E@;0bCX%_4<(M3e+}@i?|c Wl*p#&5|{BbUddyRtU&;+j-LP5A{KuD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$2.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$2.class new file mode 100644 index 0000000000000000000000000000000000000000..808bf565919182673554018d5af093e9ecd3c5de GIT binary patch literal 1801 zcmb_dTXWM!6#kCwSg|95Nr<^8TwH1=5J9-KAQ}iE5VbbV6ebM3t>ql?+?)@Ks0hmXlfDEz*awZ0l zC!AbsJ+iz&$tV!M<@zFyA9}vDy!Ezk&4(@Nuuz#HdOt_(A_h?~P&6?F zlTca{kA>xnV8!~mxh7r37O!}Lr)CM+YHhiQVeB?gGO-6Egi1d?2&Nkbu@Zq=3PYc8 zwpy!i`PoWlQ>)EdoYdA4+rVDJ)R)g_TowWqZ49A|eFpZMIDmtM(_cQi%^e3UwUO%^ zPSBE12-m94wt(lg7rT!Xbhb$}c7b6#Y~l#U3B&SXOUArwyQ4hcs(Z2G zY>yHacY=1V8LLRRYAKeTR_HKNQODILD+`;(=Y?`tbyaA}j+;1v3Sn?Xs=8=OCSknl zd^&|>pX*`*Cv{PLOL$h@mi-o8UB$1s^)de`mv(J=2sKO^m@;t+ry0V8&J-{%P0?x* z#{n)Nu9k*Wt6^(NL}FcXKj71O;p&Pa7*&TK9R=|+Is9@c zw92o`sJXf%?ryYYQj~lvKFQtZSRm}WqlEjYA=GdF#)5VWy$5C#G@D^KFsrhfmitEHL4lh(~)JNBP+9a;0=#& zQNTNl<3H5#e-i0z*KrzY1D9|)$)o|BC7o>pS6Ip>(hn@<*n-7aTxE;bc-26r@QZ;_ p-k9Uh46gGJ4g58X8@QFM3}cb!gKR__)XxMQ{KU4E?N literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$3.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$3.class new file mode 100644 index 0000000000000000000000000000000000000000..b39e04b6620f08e11feb07de2551e9a161056f9e GIT binary patch literal 1884 zcmb_dTW=dh6#kCmWMgMbjLC&GNfW>n+ezy}D3`i~rXg__oHlBLB_7A?sk7;3*V-Ld z%^Um;{s7NNy$Fy{pZQUUbJniYO0|^-R@$AJb7s!@<~x`D=ifj72C$9&3{n`gkhU?7 z3BuKr)}x9S7##)5ueiR7($PsdhA72IS%Khev zb`4v+?FF9MB#aeHjSTX5&%%t2SQMK?sVeK5& zIcY+VQGw}%A(JP^b^;TfWpNpc7M5%*CQ`0Bh;_FWI(((5o5Z)U^TgF1iS)KI?y-=OW%fU` z@evAy$+k9i)zm)WO3`^cs6@{pUcps~?$pZ( z9Ff?Zd&(6K2(z!_?qw$1vQQyZN3lDosR5aLDrosS+DbSk?6Toe3DU30YLA;C1z2hj z(&CCRUH1ZguY20m(UEHUEXmhHSNRPUd9v;c(^95{i#acBRJk(uwK)!32P#shni~k8 z&K!E}K$&jDUaX?Sj{qUoki#!a>6l-ace;{7M`s2C3 zb^6e=hhaBz^)B}DcUrG3S8o1Z*V1reh1=6K;+Q-O$3~kPNb6P+Ek!f$)tK!76uG8-(jf<#N)- z0Uo*8a)(dxJB=F{!>38V=VmXG^7=DSdF>gj@(WD;o^1S#zY}Z*bRQc$pX(p~95;C- zX2c}n3!Z1#?$5cz&zHPRA;*e!e8pe!^AeVzKy5btD=hjAGv%kSp5oovbbkIh7G7fh z);NpkFRc6|s^#bSK*q)XxWwba_zQge2Z|{OzA*^CIldm~0mkVN89Kre{m9X4BzQM_ zF7XO)4PWDy+y^yOc_viUaGPgBK@H#VER7|sVH4l7-8(F`kjflbm}kWnFH^Y7|48sE ekMH=1Nb=a@@iH3`gYvAv!4Ftq{`06$Wc~vX*#KAo literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$4.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$4.class new file mode 100644 index 0000000000000000000000000000000000000000..ab174f6f240814bc03f1c24a8255f99b0b2ee89c GIT binary patch literal 1282 zcma)+?N8HC6vm&jv2Noc6G2{l0i^P#GDW}_6q%#Q1X{99(C`6ESD{c^(hdA-qF?-G zqJMyiCVo{h#u!6Pj9>htjOWZrAu(dp_PM_&r}vzD@7aF*{JaAojoWclAtWO#P>qO$ zwpC-xNIHhQoHQMySbShRR#M+Ey@I7o*=|8XWXo_it)c{_r*~ocfbfwRqKL_e3)DbJ z=vpnTC2hB4`L5yY$zZQp`%0=>$i!$F zhXm@7kPuI0v#EQF(|T%LLdSt6@($Ds96^Hw+4BoFl_nw7)0>fTR6=X8M9s@>nky5w z_^kOmdmHKJewy4+SruIoKv%9uS4Jzdtt7Z zgA{?&<)9f|%g}V}bqn;c7t-`u=01Tl%u#(-&88|r=LGuMjAYgPovg-j=LIgXRZS(N zr`WkDFj#Ral@1GBVy7-YnbqeP)w^kRHlNWo8CN7Eg4OFwtCm@!oYzdpcJ0z=d6VX- zay~fve%f{|ZF7Ce^7F=$Lr(p)XBy6&;oHm=vo=>U%r!dK3deKarf*sk)MyfF|MWmV z=cPGS*L1w1?Jmz)r4_FrgN{`BpC+O@HLF;f^omrn$hfZMr@5i6qKwIXr@Grzl|H8h zai=HRsdX>Yk3>o|bMx|uoU0fiy+-g9AsPYSKSA3065odWp6}X^I2_jB&?IGSBCHOu zl`sYx`;{gva*91JoEXw?j78pYVn$U=5 zbfSy28v__39YzY{q$*~SBhBMJOws~2P$Vtk5gwC1!81H3eSw#FMfw_Vu}%5`U-6AJ zgzL0jk@BVuVwA>J^xU9l6wUK8Ma=x=MSa+af4>mMSb4S-Zjy%Se+^VE&!5HwX+4dq Oa0{8S7CJ(@6476(gc6nj literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$ExceptionHandlerAction.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl$ExceptionHandlerAction.class new file mode 100644 index 0000000000000000000000000000000000000000..6f888912344687de657d27e86feaa579e02de05f GIT binary patch literal 292 zcma)%F>b;@5Jmq0@qz;=6(?{(8ukEGk(CHHP$1E7)&sJ$tdVyUJAtHPIwtR|J<5$L) zj@uX8EeZp|Q*FMCcE%s{=DlVc35l_touKB0)boyzZkx~6@|#2xCfD3WcS{(qImA^H zqQWB~yN8G{F1+V9?|?ZFX15U&0--Pe0wk~xNJRCar1vny=rU7`Wv1d3P)w518K<93 AP5=M^ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..28252f61fd382cdcc823fa1a12e4305ea6ae1f1a GIT binary patch literal 25867 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 ArrayLoadInstruction.of(o); + case ARRAY_STORE -> ArrayStoreInstruction.of(o); + case CONSTANT -> ConstantInstruction.ofIntrinsic(o); + case CONVERT -> ConvertInstruction.of(o); + case LOAD -> LoadInstruction.of(o, o.slot()); + case MONITOR -> MonitorInstruction.of(o); + case NOP -> NopInstruction.of(); + case OPERATOR -> OperatorInstruction.of(o); + case RETURN -> ReturnInstruction.of(o); + case STACK -> StackInstruction.of(o); + case STORE -> StoreInstruction.of(o, o.slot()); + case THROW_EXCEPTION -> ThrowInstruction.of(); + default -> throw new AssertionError("invalid opcode: " + o); + }; + } + } + } + + List exceptionTable; + List> attributes; + + // Inflated for iteration + LabelImpl[] labels; + int[] lineNumbers; + boolean inflated; + + public CodeImpl(AttributedElement enclosing, + ClassReader reader, + AttributeMapper mapper, + int payloadStart) { + super(enclosing, reader, mapper, payloadStart); + } + + // LabelContext + + @Override + public Label newLabel() { + throw new UnsupportedOperationException("CodeAttribute only supports fixed labels"); + } + + @Override + public void setLabelTarget(Label label, int bci) { + throw new UnsupportedOperationException("CodeAttribute only supports fixed labels"); + } + + @Override + public Label getLabel(int bci) { + if (bci < 0 || bci > codeLength) + throw new IllegalArgumentException(String.format("Bytecode offset out of range; bci=%d, codeLength=%d", + bci, codeLength)); + if (labels == null) + labels = new LabelImpl[codeLength + 1]; + LabelImpl l = labels[bci]; + if (l == null) + l = labels[bci] = new LabelImpl(this, bci); + return l; + } + + @Override + public int labelToBci(Label label) { + LabelImpl lab = (LabelImpl) label; + if (lab.labelContext() != this) + throw new IllegalArgumentException(String.format("Illegal label reuse; context=%s, label=%s", + this, lab.labelContext())); + return lab.getBCI(); + } + + private void inflateMetadata() { + if (!inflated) { + if (labels == null) + labels = new LabelImpl[codeLength + 1]; + if (classReader.context().lineNumbersOption() == ClassFile.LineNumbersOption.PASS_LINE_NUMBERS) + inflateLineNumbers(); + inflateJumpTargets(); + inflateTypeAnnotations(); + inflated = true; + } + } + + // CodeAttribute + + @Override + public List> attributes() { + if (attributes == null) { + attributes = BoundAttribute.readAttributes(this, classReader, attributePos, classReader.customAttributes()); + } + return attributes; + } + + @Override + public void writeTo(BufWriter buf) { + if (buf.canWriteDirect(classReader)) { + super.writeTo(buf); + } + else { + DirectCodeBuilder.build((MethodInfo) enclosingMethod, + new Consumer() { + @Override + public void accept(CodeBuilder cb) { + forEachElement(cb); + } + }, + (SplitConstantPool)buf.constantPool(), + ((BufWriterImpl)buf).context(), + null).writeTo(buf); + } + } + + // CodeModel + + @Override + public Optional parent() { + return Optional.of(enclosingMethod); + } + + @Override + public void forEachElement(Consumer consumer) { + inflateMetadata(); + boolean doLineNumbers = (lineNumbers != null); + generateCatchTargets(consumer); + if (classReader.context().debugElementsOption() == ClassFile.DebugElementsOption.PASS_DEBUG) + generateDebugElements(consumer); + for (int pos=codeStart; pos exceptionHandlers() { + if (exceptionTable == null) { + inflateMetadata(); + exceptionTable = new ArrayList<>(exceptionHandlerCnt); + iterateExceptionHandlers(new ExceptionHandlerAction() { + @Override + public void accept(int s, int e, int h, int c) { + ClassEntry catchTypeEntry = c == 0 + ? null + : constantPool().entryByIndex(c, ClassEntry.class); + exceptionTable.add(new AbstractPseudoInstruction.ExceptionCatchImpl(getLabel(h), getLabel(s), getLabel(e), catchTypeEntry)); + } + }); + exceptionTable = Collections.unmodifiableList(exceptionTable); + } + return exceptionTable; + } + + public boolean compareCodeBytes(BufWriter buf, int offset, int len) { + return codeLength == len + && classReader.compare(buf, offset, codeStart, codeLength); + } + + private int adjustForObjectOrUninitialized(int bci) { + int vt = classReader.readU1(bci); + //inflate newTarget labels from Uninitialized VTIs + if (vt == 8) inflateLabel(classReader.readU2(bci + 1)); + return (vt == 7 || vt == 8) ? bci + 3 : bci + 1; + } + + private void inflateLabel(int bci) { + if (bci < 0 || bci > codeLength) + throw new IllegalArgumentException(String.format("Bytecode offset out of range; bci=%d, codeLength=%d", + bci, codeLength)); + if (labels[bci] == null) + labels[bci] = new LabelImpl(this, bci); + } + + private void inflateLineNumbers() { + for (Attribute a : attributes()) { + if (a.attributeMapper() == Attributes.lineNumberTable()) { + BoundLineNumberTableAttribute attr = (BoundLineNumberTableAttribute) a; + if (lineNumbers == null) + lineNumbers = new int[codeLength + 1]; + + int nLn = classReader.readU2(attr.payloadStart); + int p = attr.payloadStart + 2; + int pEnd = p + (nLn * 4); + for (; p < pEnd; p += 4) { + int startPc = classReader.readU2(p); + if (startPc > codeLength) { + throw new IllegalArgumentException(String.format( + "Line number start_pc out of range; start_pc=%d, codeLength=%d", startPc, codeLength)); + } + int lineNumber = classReader.readU2(p + 2); + lineNumbers[startPc] = lineNumber; + } + } + } + } + + private void inflateJumpTargets() { + Optional a = findAttribute(Attributes.stackMapTable()); + if (a.isEmpty()) { + if (classReader.readU2(6) <= ClassFile.JAVA_6_VERSION) { + //fallback to jump targets inflation without StackMapTableAttribute + for (int pos=codeStart; pos br.target(); + case DiscontinuedInstruction.JsrInstruction jsr -> jsr.target(); + default -> {} + } + pos += i.sizeInBytes(); + } + } + return; + } + @SuppressWarnings("unchecked") + int stackMapPos = ((BoundAttribute) a.get()).payloadStart; + + int bci = -1; //compensate for offsetDelta + 1 + int nEntries = classReader.readU2(stackMapPos); + int p = stackMapPos + 2; + for (int i = 0; i < nEntries; ++i) { + int frameType = classReader.readU1(p); + int offsetDelta; + if (frameType < 64) { + offsetDelta = frameType; + ++p; + } + else if (frameType < 128) { + offsetDelta = frameType & 0x3f; + p = adjustForObjectOrUninitialized(p + 1); + } + else + switch (frameType) { + case 247 -> { + offsetDelta = classReader.readU2(p + 1); + p = adjustForObjectOrUninitialized(p + 3); + } + case 248, 249, 250, 251 -> { + offsetDelta = classReader.readU2(p + 1); + p += 3; + } + case 252, 253, 254 -> { + offsetDelta = classReader.readU2(p + 1); + int k = frameType - 251; + p += 3; + for (int c = 0; c < k; ++c) { + p = adjustForObjectOrUninitialized(p); + } + } + case 255 -> { + offsetDelta = classReader.readU2(p + 1); + p += 3; + int k = classReader.readU2(p); + p += 2; + for (int c = 0; c < k; ++c) { + p = adjustForObjectOrUninitialized(p); + } + k = classReader.readU2(p); + p += 2; + for (int c = 0; c < k; ++c) { + p = adjustForObjectOrUninitialized(p); + } + } + default -> throw new IllegalArgumentException("Bad frame type: " + frameType); + } + bci += offsetDelta + 1; + inflateLabel(bci); + } + } + + private void inflateTypeAnnotations() { + findAttribute(Attributes.runtimeVisibleTypeAnnotations()).ifPresent(RuntimeVisibleTypeAnnotationsAttribute::annotations); + findAttribute(Attributes.runtimeInvisibleTypeAnnotations()).ifPresent(RuntimeInvisibleTypeAnnotationsAttribute::annotations); + } + + private void generateCatchTargets(Consumer consumer) { + // We attach all catch targets to bci zero, because trying to attach them + // to their range could subtly affect the order of exception processing + iterateExceptionHandlers(new ExceptionHandlerAction() { + @Override + public void accept(int s, int e, int h, int c) { + ClassEntry catchType = c == 0 + ? null + : classReader.entryByIndex(c, ClassEntry.class); + consumer.accept(new AbstractPseudoInstruction.ExceptionCatchImpl(getLabel(h), getLabel(s), getLabel(e), catchType)); + } + }); + } + + private void generateDebugElements(Consumer consumer) { + for (Attribute a : attributes()) { + if (a.attributeMapper() == Attributes.characterRangeTable()) { + var attr = (BoundCharacterRangeTableAttribute) a; + int cnt = classReader.readU2(attr.payloadStart); + int p = attr.payloadStart + 2; + int pEnd = p + (cnt * 14); + for (; p < pEnd; p += 14) { + var instruction = new BoundCharacterRange(this, p); + inflateLabel(instruction.startPc()); + inflateLabel(instruction.endPc() + 1); + consumer.accept(instruction); + } + } + else if (a.attributeMapper() == Attributes.localVariableTable()) { + var attr = (BoundLocalVariableTableAttribute) a; + int cnt = classReader.readU2(attr.payloadStart); + int p = attr.payloadStart + 2; + int pEnd = p + (cnt * 10); + for (; p < pEnd; p += 10) { + BoundLocalVariable instruction = new BoundLocalVariable(this, p); + inflateLabel(instruction.startPc()); + inflateLabel(instruction.startPc() + instruction.length()); + consumer.accept(instruction); + } + } + else if (a.attributeMapper() == Attributes.localVariableTypeTable()) { + var attr = (BoundLocalVariableTypeTableAttribute) a; + int cnt = classReader.readU2(attr.payloadStart); + int p = attr.payloadStart + 2; + int pEnd = p + (cnt * 10); + for (; p < pEnd; p += 10) { + BoundLocalVariableType instruction = new BoundLocalVariableType(this, p); + inflateLabel(instruction.startPc()); + inflateLabel(instruction.startPc() + instruction.length()); + consumer.accept(instruction); + } + } + else if (a.attributeMapper() == Attributes.runtimeVisibleTypeAnnotations()) { + consumer.accept((BoundRuntimeVisibleTypeAnnotationsAttribute) a); + } + else if (a.attributeMapper() == Attributes.runtimeInvisibleTypeAnnotations()) { + consumer.accept((BoundRuntimeInvisibleTypeAnnotationsAttribute) a); + } + } + } + + public interface ExceptionHandlerAction { + void accept(int start, int end, int handler, int catchTypeIndex); + } + + public void iterateExceptionHandlers(ExceptionHandlerAction a) { + int p = exceptionHandlerPos + 2; + for (int i = 0; i < exceptionHandlerCnt; ++i) { + a.accept(classReader.readU2(p), classReader.readU2(p + 2), classReader.readU2(p + 4), classReader.readU2(p + 6)); + p += 8; + } + } + + private Instruction bcToInstruction(int bc, int pos) { + return switch (bc) { + case BIPUSH -> new AbstractInstruction.BoundArgumentConstantInstruction(Opcode.BIPUSH, CodeImpl.this, pos); + case SIPUSH -> new AbstractInstruction.BoundArgumentConstantInstruction(Opcode.SIPUSH, CodeImpl.this, pos); + case LDC -> new AbstractInstruction.BoundLoadConstantInstruction(Opcode.LDC, CodeImpl.this, pos); + case LDC_W -> new AbstractInstruction.BoundLoadConstantInstruction(Opcode.LDC_W, CodeImpl.this, pos); + case LDC2_W -> new AbstractInstruction.BoundLoadConstantInstruction(Opcode.LDC2_W, CodeImpl.this, pos); + case ILOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.ILOAD, CodeImpl.this, pos); + case LLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.LLOAD, CodeImpl.this, pos); + case FLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.FLOAD, CodeImpl.this, pos); + case DLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.DLOAD, CodeImpl.this, pos); + case ALOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.ALOAD, CodeImpl.this, pos); + case ISTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.ISTORE, CodeImpl.this, pos); + case LSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.LSTORE, CodeImpl.this, pos); + case FSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.FSTORE, CodeImpl.this, pos); + case DSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.DSTORE, CodeImpl.this, pos); + case ASTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.ASTORE, CodeImpl.this, pos); + case IINC -> new AbstractInstruction.BoundIncrementInstruction(Opcode.IINC, CodeImpl.this, pos); + case IFEQ -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFEQ, CodeImpl.this, pos); + case IFNE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFNE, CodeImpl.this, pos); + case IFLT -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFLT, CodeImpl.this, pos); + case IFGE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFGE, CodeImpl.this, pos); + case IFGT -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFGT, CodeImpl.this, pos); + case IFLE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFLE, CodeImpl.this, pos); + case IF_ICMPEQ -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPEQ, CodeImpl.this, pos); + case IF_ICMPNE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPNE, CodeImpl.this, pos); + case IF_ICMPLT -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPLT, CodeImpl.this, pos); + case IF_ICMPGE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPGE, CodeImpl.this, pos); + case IF_ICMPGT -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPGT, CodeImpl.this, pos); + case IF_ICMPLE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ICMPLE, CodeImpl.this, pos); + case IF_ACMPEQ -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ACMPEQ, CodeImpl.this, pos); + case IF_ACMPNE -> new AbstractInstruction.BoundBranchInstruction(Opcode.IF_ACMPNE, CodeImpl.this, pos); + case GOTO -> new AbstractInstruction.BoundBranchInstruction(Opcode.GOTO, CodeImpl.this, pos); + case TABLESWITCH -> new AbstractInstruction.BoundTableSwitchInstruction(Opcode.TABLESWITCH, CodeImpl.this, pos); + case LOOKUPSWITCH -> new AbstractInstruction.BoundLookupSwitchInstruction(Opcode.LOOKUPSWITCH, CodeImpl.this, pos); + case GETSTATIC -> new AbstractInstruction.BoundFieldInstruction(Opcode.GETSTATIC, CodeImpl.this, pos); + case PUTSTATIC -> new AbstractInstruction.BoundFieldInstruction(Opcode.PUTSTATIC, CodeImpl.this, pos); + case GETFIELD -> new AbstractInstruction.BoundFieldInstruction(Opcode.GETFIELD, CodeImpl.this, pos); + case PUTFIELD -> new AbstractInstruction.BoundFieldInstruction(Opcode.PUTFIELD, CodeImpl.this, pos); + case INVOKEVIRTUAL -> new AbstractInstruction.BoundInvokeInstruction(Opcode.INVOKEVIRTUAL, CodeImpl.this, pos); + case INVOKESPECIAL -> new AbstractInstruction.BoundInvokeInstruction(Opcode.INVOKESPECIAL, CodeImpl.this, pos); + case INVOKESTATIC -> new AbstractInstruction.BoundInvokeInstruction(Opcode.INVOKESTATIC, CodeImpl.this, pos); + case INVOKEINTERFACE -> new AbstractInstruction.BoundInvokeInterfaceInstruction(Opcode.INVOKEINTERFACE, CodeImpl.this, pos); + case INVOKEDYNAMIC -> new AbstractInstruction.BoundInvokeDynamicInstruction(Opcode.INVOKEDYNAMIC, CodeImpl.this, pos); + case NEW -> new AbstractInstruction.BoundNewObjectInstruction(CodeImpl.this, pos); + case NEWARRAY -> new AbstractInstruction.BoundNewPrimitiveArrayInstruction(Opcode.NEWARRAY, CodeImpl.this, pos); + case ANEWARRAY -> new AbstractInstruction.BoundNewReferenceArrayInstruction(Opcode.ANEWARRAY, CodeImpl.this, pos); + case CHECKCAST -> new AbstractInstruction.BoundTypeCheckInstruction(Opcode.CHECKCAST, CodeImpl.this, pos); + case INSTANCEOF -> new AbstractInstruction.BoundTypeCheckInstruction(Opcode.INSTANCEOF, CodeImpl.this, pos); + + case WIDE -> { + int bclow = classReader.readU1(pos + 1); + yield switch (bclow) { + case ILOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.ILOAD_W, this, pos); + case LLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.LLOAD_W, this, pos); + case FLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.FLOAD_W, this, pos); + case DLOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.DLOAD_W, this, pos); + case ALOAD -> new AbstractInstruction.BoundLoadInstruction(Opcode.ALOAD_W, this, pos); + case ISTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.ISTORE_W, this, pos); + case LSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.LSTORE_W, this, pos); + case FSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.FSTORE_W, this, pos); + case DSTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.DSTORE_W, this, pos); + case ASTORE -> new AbstractInstruction.BoundStoreInstruction(Opcode.ASTORE_W, this, pos); + case IINC -> new AbstractInstruction.BoundIncrementInstruction(Opcode.IINC_W, this, pos); + case RET -> new AbstractInstruction.BoundRetInstruction(Opcode.RET_W, this, pos); + default -> throw new IllegalArgumentException("unknown wide instruction: " + bclow); + }; + } + + case MULTIANEWARRAY -> new AbstractInstruction.BoundNewMultidimensionalArrayInstruction(Opcode.MULTIANEWARRAY, CodeImpl.this, pos); + case IFNULL -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFNULL, CodeImpl.this, pos); + case IFNONNULL -> new AbstractInstruction.BoundBranchInstruction(Opcode.IFNONNULL, CodeImpl.this, pos); + case GOTO_W -> new AbstractInstruction.BoundBranchInstruction(Opcode.GOTO_W, CodeImpl.this, pos); + + case JSR -> new AbstractInstruction.BoundJsrInstruction(Opcode.JSR, CodeImpl.this, pos); + case RET -> new AbstractInstruction.BoundRetInstruction(Opcode.RET, this, pos); + case JSR_W -> new AbstractInstruction.BoundJsrInstruction(Opcode.JSR_W, CodeImpl.this, pos); + default -> { + Instruction instr = SINGLETON_INSTRUCTIONS[bc]; + if (instr == null) + throw new IllegalArgumentException("unknown instruction: " + bc); + yield instr; + } + }; + } + + @Override + public String toString() { + return String.format("CodeModel[id=%d]", System.identityHashCode(this)); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeLocalsShifterImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeLocalsShifterImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..6e23d14bb8beaf1ea2e5500bf13bf4c00bf494d9 GIT binary patch literal 4774 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 X;ukz^ + cob.loadLocal( + li.typeKind(), + shift(cob, li.slot(), li.typeKind())); + case StoreInstruction si -> + cob.storeLocal( + si.typeKind(), + shift(cob, si.slot(), si.typeKind())); + case IncrementInstruction ii -> + cob.iinc( + shift(cob, ii.slot(), TypeKind.IntType), + ii.constant()); + case LocalVariable lv -> + cob.localVariable( + shift(cob, lv.slot(), TypeKind.fromDescriptor(lv.type().stringValue())), + lv.name(), + lv.type(), + lv.startScope(), + lv.endScope()); + case LocalVariableType lvt -> + cob.localVariableType( + shift(cob, lvt.slot(), + (lvt.signatureSymbol() instanceof Signature.BaseTypeSig bsig) + ? TypeKind.fromDescriptor(bsig.signatureString()) + : TypeKind.ReferenceType), + lvt.name(), + lvt.signature(), + lvt.startScope(), + lvt.endScope()); + default -> cob.with(coe); + } + } + + private int shift(CodeBuilder cob, int slot, TypeKind tk) { + if (tk == TypeKind.VoidType) throw new IllegalArgumentException("Illegal local void type"); + if (slot >= fixed) { + int key = 2*slot - fixed + tk.slotSize() - 1; + if (key >= locals.length) locals = Arrays.copyOf(locals, key + 20); + slot = locals[key] - 1; + if (slot < 0) { + slot = cob.allocateLocal(tk); + locals[key] = slot + 1; + if (tk.slotSize() == 2) locals[key - 1] = slot + 1; + } + } + return slot; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeRelabelerImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeRelabelerImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..4a20e102a92ac2595862f57e9fbe733060c5d7ba GIT binary patch literal 8317 zcmcIp349z?8UKH|CfS{mG>}3l(1TKPHQQ3?k%U5?(hG; z_vXp}?As5ZRTe~0fI(j23h+rCy)NquJY8)+?nit1qk`Wx1HZK}Xq|Nnqa{Zu1 zh3AII62iHX&NxQLu{cf;$?i;ZHn-KbX_zTk5GHsc znaQRH9ec-Cq>W^}uPxsb#SF~WaXjYG%XTVGqJraU{PN{lZg9rwlNp$+<3!YOP1Z8&EYb-i=${nOv8K~ z3vd#nEX*!GTGXT4v5a7AxJ;hvp+dPV!^QD2Y1VMEU~!lzeiyad_V&S)>->PD7GjZ( z#meYYddyy9(8_LdY#+r!EY;D3X2yTq$e0Ym%A7Zx#A;7uvh>=iSf=4L9j9YC!!#ed zYM2&al$geVV0vJ!+Z*e22AeA(XjQqmQee|klSzGl0*>j?AQLIBn3e5oZZ>%W+V~%g*)T@#2r+ zybmT4Bb|ap-HVaBE`{FLc8e}#Tv)iKRz!n`_)lgYqVq2dx zrg|5t$I?n}0j)~Q3v^rvgD9ONgB$C?%%f|A_M0`NhZX8dzRhPugl-k5v4Z?I3+mX~^EBQ*Z z>7AX#MTX6GT%;rI0%dyVs$`Gq%IX+YU0R=!?BTws`YzUS3Ak~U#TB(pgnz-bKq78% zm>Cx1vk{l+xEyb07MlSn1lNwG`nWE1w#$5OjtJsm875-Hx2W1+xRl6K4T4?Vu)2(N zLPc8?yKse$D^-vdWh|Ta+l8xiT#akkku(Nqlg6A)4iPnOb5App*_3Ttv9q(iOI9W6 z1={LbyhFoo9oOM{L0y;toN1 zCb2DPWCzn`r)SbxL6Z(k-kF<7o8F2W)#GNBA|KarH$K4{EnqP>v#uM@Y9Z9$IJ4a| z0kmoDGtx$!MRo`4a@uT<(sYl~bPqnQ<1;E}4vz;Wc@VS*_v!eo8lM^*chG1L?$_~v z8ZGX%jBOcZxrcN-j3I(caK7N&*9k6dZEfR+kK+7!9bdo~ne5zL`vjxxtxguL<{2Yb z{*FRiIZ;i^6^t4l8KV^Rh^b2TOFACKm$~~JafR`MRpE;Ji@VV9P!ooQ?26)Xd_}`o zbv&UA9tuW&aCB?HR#tS*zK}7!P5W`oRiwVI<0*VYP+<28)&?Rv54K|^Z#Xa3c!l_u zj&I{>wUyZ}rm*az4JK9Y`Mu%+lOp|H9naudlI}Ayeab+BlO|2NO;P&3j_2?Lx`_ua z!(!FDaZZ`4 zaf8ft@iJDcv%N4Kjdycx7jw(Cd3k#xX|5j}=r+?%HOVtW5SrDF%-Pw#1T7nzr0-e0 z1gR0|JvJ5V%xs_Cvypf5k%;J{hYLUq@e*U zuiP>Qx_gW{?oK;rK^_basY3m^7E0cqWBHwPlv|=vCet?z=!VJAAECm07WAF=U^;H9 z+Jiu-BoEwyI!8-xTe;iSiWRn<&1BO?%7w;E1&%H+mcv+zNVzVW6jjL7QE#S3QN_Re z=6x{AWO6%PaXUhnLMbXmw4A5Y@)9{JBGq!VCewK@DaUYw$p>wEFqusZm@(JX!x|9H zuki;-BDurfZpK{2);Qx;?SLC-MQ!#-1q;qhEi3Xh0}=?E$`RL!4rRn z7asly2x#sZ#;^M@sOoLWq?vX|ni);z@j^Wx#UWI3;i*ZCH{oMXWfHrw%xmUSUZDwo z$X})UFv9nbd81!|=MiDM7(Zdf`T~14vaf*eNZmt_y7~v8-N(NQ@l!raI1{`j{~4dt z+*$ZJe!;&u-=q3VwiR`^=Xth%#da|RmoJy)i|pi8JD-Z-IubAByS(mxX!Q+4m{N!X zIQ(9A75KQu9Ii9nsl!~$dFA$Nhg&&*gO|8M)Y-@-U3e3Y)#mkui;Ct| z745@x;2x5fm-tZsH2xa-JBz>F{5{Rz%N(!aub;oY^A2D}Q*nKD@epS5WTf6FP=^Om zJA`?K*nGF#$teq)O6u#XONMZYJEodT1Vd=yn)-cM0k&5a@NuTfg*WY|2{N9MdBne&Sk|KmxfyQ!4?ONYQuVyN!j$ZpR{t`uDH!0lO6s@n04&g&w#n*>(6xjZVqQLi^ISOolEJxukhr$|C*wds_e0>O? z%*|tauiIALpCVeybQjGcP<_a05=`C0G+~n$RJqqf=Vx@3lBvy3i%(^Tgdx$7k4oIkw1^ z*eX{u0IsL!Z^3zTJI_3RUf#C&-{N=7@dQ7`{GKwFIJ*1+e`Msp#7zDZ{> z@+uil<d`QvO5tD!HRdZwJF-&fkPNg<)f9QS6a%fKa4jIUW@ygaX3F z9uQ8ct3QCoh6C9DAP%Uo^~0cFrzsvW1+ZmQq=N4XR1~Np$y4zH6gh}l#VmM?sm9mW z+^l&RPv!-!t2;}H>#vqN>D&%tp8pQvs1Zf8JV3%W~WY! z8H%J-nM2AX;;5=N6%`%cP9{ VQz}(5P3pOl`=B&Pqs&M3{{RcAj>7-| literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeRelabelerImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/CodeRelabelerImpl.java new file mode 100644 index 00000000..f191cbf3 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/CodeRelabelerImpl.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.Label; +import java.lang.classfile.components.CodeRelabeler; +import java.lang.classfile.instruction.BranchInstruction; +import java.lang.classfile.instruction.CharacterRange; +import java.lang.classfile.instruction.ExceptionCatch; +import java.lang.classfile.instruction.LabelTarget; +import java.lang.classfile.instruction.LocalVariable; +import java.lang.classfile.instruction.LocalVariableType; +import java.lang.classfile.instruction.LookupSwitchInstruction; +import java.lang.classfile.instruction.SwitchCase; +import java.lang.classfile.instruction.TableSwitchInstruction; + +import java.util.function.BiFunction; + +public record CodeRelabelerImpl(BiFunction mapFunction) implements CodeRelabeler { + + @Override + public Label relabel(Label label, CodeBuilder cob) { + return mapFunction.apply(label, cob); + } + + @Override + public void accept(CodeBuilder cob, CodeElement coe) { + switch (coe) { + case BranchInstruction bi -> + cob.branch( + bi.opcode(), + relabel(bi.target(), cob)); + case LookupSwitchInstruction lsi -> + cob.lookupswitch( + relabel(lsi.defaultTarget(), cob), + lsi.cases().stream().map(c -> + SwitchCase.of( + c.caseValue(), + relabel(c.target(), cob))).toList()); + case TableSwitchInstruction tsi -> + cob.tableswitch( + tsi.lowValue(), + tsi.highValue(), + relabel(tsi.defaultTarget(), cob), + tsi.cases().stream().map(c -> + SwitchCase.of( + c.caseValue(), + relabel(c.target(), cob))).toList()); + case LabelTarget lt -> + cob.labelBinding( + relabel(lt.label(), cob)); + case ExceptionCatch ec -> + cob.exceptionCatch( + relabel(ec.tryStart(), cob), + relabel(ec.tryEnd(), cob), + relabel(ec.handler(), cob), + ec.catchType()); + case LocalVariable lv -> + cob.localVariable( + lv.slot(), + lv.name().stringValue(), + lv.typeSymbol(), + relabel(lv.startScope(), cob), + relabel(lv.endScope(), cob)); + case LocalVariableType lvt -> + cob.localVariableType( + lvt.slot(), + lvt.name().stringValue(), + lvt.signatureSymbol(), + relabel(lvt.startScope(), cob), + relabel(lvt.endScope(), cob)); + case CharacterRange chr -> + cob.characterRange( + relabel(chr.startScope(), cob), + relabel(chr.endScope(), cob), + chr.characterRangeStart(), + chr.characterRangeEnd(), + chr.flags()); + default -> + cob.with(coe); + } + } + +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$1.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..0329f251e35c5fda6933fa8bf66eef990cebd5e2 GIT binary patch literal 1622 zcmb`GZ*SXF6vm(1WO0+;u36i$ZVXmvwza^PHv7Y$jcu9Zw5F+3YPa1eW4MmDy7TPf zq~k3Td;lc)07#p}TVNAH(=;J%uXu$79{>qH01~`LoO2iEAPpoWr1(DmJ$iiZaeVG~ zf84zfK*!|*`jF9(mDqutz`jlQhFcEZ=xW&u-FEv*5c=ijmKV2tf!qx@-1gf72PUW1 z8vmR;l}A7F8VV8vkOGy>*0pjFb^Ii9!=Adq^{ue1Q)#>7de@wU7C$k`EX@cUEZOe| z9dBd7-74``C2p$pxT(@#P4%srd3uMP5<@5o&$VuByo`atZ5muY#f%DR7Rs~ydd$SGU{F9h{RE4 z)VjvB#0(pm#pWWHI3{si1&AwboRoN31!~JG@T$aXk18xb3Y?aBosAp?E?=18XUKl<4#_b@wy5M&<;+BTD1*ZS&bW{J9 z-|o!CZF&`HMv#-j(t!^Ki;ON=5<*BlJ|X=SpW!CyEqsC7q<8Qw9*{o7 z_xOSINBo4JNq@nw_>J^;0g=IOkrhQTLOLqO#RO?dOp9Zr$Hh6JQ!ayL8iE{ubgH#N wYad;!bX~#Zsz!;0CoC3w|IdOfE~s5E;w{oF)@Z$?oHe{dT2LcOH^u%x0f(eZTL1t6 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$Item.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$Item.class new file mode 100644 index 0000000000000000000000000000000000000000..38d49c5136cbba4cff03511e48c9bedc3f725965 GIT binary patch literal 1904 zcmbVNZBNrs6n^g5=$OTg2`Hd|3OdG1!8e2
$Ifkp^1`l;KltgLHidq?y?`9Tti z2_O6c{wU+QZDBP`g8Q(0+tYKNbDs0IU%yX&0>~quKm=V1qAFtOW=I|Ahq`9!*1q(IfS0tqJyg4Y?M;!A@wj22t&TE@HdZPTzSIqB@GiX>8GVe!v`VX@ee$6T7& zrd3=+KSNyDJHj!neTL0Uhj>$=$bB%+#h{AoxIr$ex?7d}8J0VCQIJ6os~EvessjJi z)J>P6*ePBp;@71EUKY8j_YCg{?yTf(YS3wZ_NZij0+L0;;@i!7i95S`$)uE|i*{Kz z_jJdQ?}0EXss_eN!{tz!_OFu1Y!6%0CztGw+ zW>}IcoiuiiA+cjOoibmiDPS0CHv)4qC~A>y?urfD6$<7U=Kt3pb;Rj_rq*m*xWdsJ ze(u~j9x(LC5zEP`Nirz(>rHm!Ndk*_s$faQGAP=yR)UIPQ4VB`$xfZhRGK73#ce~No(q2RVszg8}qcVA~duSq~(5;J4bFW zy1Pjh!!0^T>1~VdF1nN1A7I((V<_2~WAq-8D1tFhozc0DaXQC+RowP~$jF11-;*AA z1b67UCqiN=0{Upp-35hB&kJ-*RV8~ua(tu5^Bz=RCGgNkD{P{T`2g_sQsyI=49r)^ znaoE#JAHzof7uWEI%fpqxQF|Mz=%;MK+?Q-AeQ|OhE-gVEQ2=R7Ez*oRT|R7HUN&!H^4SV8krTzxQ#5T}YSq`dyQZ&OWa%wBhHh1K*OYqO7?cCX zFndbG^hBO!YL$zcQ+=wtdYw}i6i=z?%@S3_8>*KKagX1s-e|)zI_W=FA%7YvTBK}l z*t%%BM0xp03EK|7#hZiuiWQD{ozSK^3K}gtE!W`7^z0Z0PkM7>vJ+IcCEKu^rfF~Z zNvXJpS%$EA(4FKy?PDAWBV6K5@yKZk1@{@oI~_d+b;Y*1yC}a8oN5^IYDNu}Gl^lE ztuPp_k%W91Kq4W(FQf(OAHxkg$IY`w7E=qjD9|V zNm3}_H5BORfq?;3F#>)hp>!K|0C7xUh|nZ~09a3Af#7eq;bmHqaVYl{BQm~UC_fFq wKzB%WflMGU6XOQGMea16;R%IRF3v literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$Stack.class b/tests/test_data/std/jdk/internal/classfile/impl/CodeStackTrackerImpl$Stack.class new file mode 100644 index 0000000000000000000000000000000000000000..f0a1b08ba6a4339a5795527d2792b24beaa15414 GIT binary patch literal 2219 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 { + + private Item top; + private int count, realSize; + + Stack(Item top, int count, int realSize) { + this.top = top; + this.count = count; + this.realSize = realSize; + } + + @Override + public Iterator iterator() { + return new Iterator() { + Item i = top; + + @Override + public boolean hasNext() { + return i != null; + } + + @Override + public TypeKind next() { + if (i == null) { + throw new NoSuchElementException(); + } + var t = i.type; + i = i.next; + return t; + } + }; + } + + @Override + public int size() { + return count; + } + + private void push(TypeKind type) { + top = new Item(type, top); + realSize += type.slotSize(); + count++; + if (maxSize != null && realSize > maxSize) maxSize = realSize; + } + + private TypeKind pop() { + var t = top.type; + realSize -= t.slotSize(); + count--; + top = top.next; + return t; + } + } + + private Stack stack = new Stack(null, 0, 0); + private Integer maxSize = 0; + + public CodeStackTrackerImpl(TypeKind... initialStack) { + for (int i = initialStack.length - 1; i >= 0; i--) + push(initialStack[i]); + } + + @Override + public Optional> stack() { + return Optional.ofNullable(fork()); + } + + @Override + public Optional maxStackSize() { + return Optional.ofNullable(maxSize); + } + + private final Map map = new HashMap<>(); + + private void push(TypeKind type) { + if (stack != null) { + if (type != TypeKind.VoidType) stack.push(type); + } else { + maxSize = null; + } + } + + private void pop(int i) { + if (stack != null) { + while (i-- > 0) stack.pop(); + } else { + maxSize = null; + } + } + + private Stack fork() { + return stack == null ? null : new Stack(stack.top, stack.count, stack.realSize); + } + + private void withStack(Consumer c) { + if (stack != null) c.accept(stack); + else maxSize = null; + } + + @Override + public void accept(CodeBuilder cb, CodeElement el) { + cb.with(el); + switch (el) { + case ArrayLoadInstruction i -> { + pop(2);push(i.typeKind()); + } + case ArrayStoreInstruction i -> + pop(3); + case BranchInstruction i -> { + if (i.opcode() == Opcode.GOTO || i.opcode() == Opcode.GOTO_W) { + map.put(i.target(), stack); + stack = null; + } else { + pop(1); + map.put(i.target(), fork()); + } + } + case ConstantInstruction i -> + push(i.typeKind()); + case ConvertInstruction i -> { + pop(1);push(i.toType()); + } + case FieldInstruction i -> { + switch (i.opcode()) { + case GETSTATIC -> + push(TypeKind.fromDescriptor(i.type().stringValue())); + case GETFIELD -> { + pop(1);push(TypeKind.fromDescriptor(i.type().stringValue())); + } + case PUTSTATIC -> + pop(1); + case PUTFIELD -> + pop(2); + } + } + case InvokeDynamicInstruction i -> { + var type = i.typeSymbol(); + pop(type.parameterCount()); + push(TypeKind.from(type.returnType())); + } + case InvokeInstruction i -> { + var type = i.typeSymbol(); + pop(type.parameterCount()); + if (i.opcode() != Opcode.INVOKESTATIC) pop(1); + push(TypeKind.from(type.returnType())); + } + case LoadInstruction i -> + push(i.typeKind()); + case StoreInstruction i -> + pop(1); + case LookupSwitchInstruction i -> { + map.put(i.defaultTarget(), stack); + for (var c : i.cases()) map.put(c.target(), fork()); + stack = null; + } + case MonitorInstruction i -> + pop(1); + case NewMultiArrayInstruction i -> { + pop(i.dimensions());push(TypeKind.ReferenceType); + } + case NewObjectInstruction i -> + push(TypeKind.ReferenceType); + case NewPrimitiveArrayInstruction i -> { + pop(1);push(TypeKind.ReferenceType); + } + case NewReferenceArrayInstruction i -> { + pop(1);push(TypeKind.ReferenceType); + } + case NopInstruction i -> {} + case OperatorInstruction i -> { + switch (i.opcode()) { + case ARRAYLENGTH, INEG, LNEG, FNEG, DNEG -> pop(1); + default -> pop(2); + } + push(i.typeKind()); + } + case ReturnInstruction i -> + stack = null; + case StackInstruction i -> { + switch (i.opcode()) { + case POP -> pop(1); + case POP2 -> withStack(s -> { + if (s.pop().slotSize() == 1) s.pop(); + }); + case DUP -> withStack(s -> { + var v = s.pop();s.push(v);s.push(v); + }); + case DUP2 -> withStack(s -> { + var v1 = s.pop(); + if (v1.slotSize() == 1) { + var v2 = s.pop(); + s.push(v2);s.push(v1); + s.push(v2);s.push(v1); + } else { + s.push(v1);s.push(v1); + } + }); + case DUP_X1 -> withStack(s -> { + var v1 = s.pop(); + var v2 = s.pop(); + s.push(v1);s.push(v2);s.push(v1); + }); + case DUP_X2 -> withStack(s -> { + var v1 = s.pop(); + var v2 = s.pop(); + if (v2.slotSize() == 1) { + var v3 = s.pop(); + s.push(v1);s.push(v3);s.push(v2);s.push(v1); + } else { + s.push(v1);s.push(v2);s.push(v1); + } + }); + case DUP2_X1 -> withStack(s -> { + var v1 = s.pop(); + var v2 = s.pop(); + if (v1.slotSize() == 1) { + var v3 = s.pop(); + s.push(v2);s.push(v1);s.push(v3);s.push(v2);s.push(v1); + } else { + s.push(v1);s.push(v2);s.push(v1); + } + }); + case DUP2_X2 -> withStack(s -> { + var v1 = s.pop(); + var v2 = s.pop(); + if (v1.slotSize() == 1) { + var v3 = s.pop(); + if (v3.slotSize() == 1) { + var v4 = s.pop(); + s.push(v2);s.push(v1);s.push(v4);s.push(v3);s.push(v2);s.push(v1); + } else { + s.push(v2);s.push(v1);s.push(v3);s.push(v2);s.push(v1); + } + } else { + if (v2.slotSize() == 1) { + var v3 = s.pop(); + s.push(v1);s.push(v3);s.push(v2);s.push(v1); + } else { + s.push(v1);s.push(v2);s.push(v1); + } + } + }); + case SWAP -> withStack(s -> { + var v1 = s.pop(); + var v2 = s.pop(); + s.push(v1);s.push(v2); + }); + } + } + case TableSwitchInstruction i -> { + map.put(i.defaultTarget(), stack); + for (var c : i.cases()) map.put(c.target(), fork()); + stack = null; + } + case ThrowInstruction i -> + stack = null; + case TypeCheckInstruction i -> { + switch (i.opcode()) { + case CHECKCAST -> { + pop(1);push(TypeKind.ReferenceType); + } + case INSTANCEOF -> { + pop(1);push(TypeKind.IntType); + } + } + } + case ExceptionCatch i -> + map.put(i.handler(), new Stack(new Item(TypeKind.ReferenceType, null), 1, 1)); + case LabelTarget i -> + stack = map.getOrDefault(i.label(), stack); + default -> {} + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectClassBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/DirectClassBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..8761d42888df397a12147b067f49993db6061344 GIT binary patch literal 10213 zcmdT~33wFM9sj*#lL^THX}F9rpdy-V0s)~y2}Vc&iA@3)gc@sQ*i2wyvm1A3RcxV$ zt=6NK)?U!NwbH}3wl#~9s^HZYkKVPlm%VH6*4`KW{ol;a?!siV)PD8r=SOzt&3pgj z_dnlz9{JbZ_X6lr>#9+Paswd~6{u8Luzg@hTQu(2$+#73i^Qx{YA_nJ+oD6mv9=Xk zQclu}I4h$`JK}Vvqp<-ysZhBr8jm_13YRwZ6kEQ2I2Luf67iH{#hrDDM6A8&^e$n( zn#{Y&yS;g%fhvV5+pR0CwzLzaG|8m3vnQHzs$rm7 z3N7PO*Z66L1fiKGX5mzYNzS%tD)))ljL$kZz1_g+3XMU$^(65O;dX|JIXF|HVlZZH zrO{Nkj5e8Q78xd|(!+K#BCe$6t40f24a_w$4{Zw5G7sT zbrP#a4>n1rda=USiX(kI`xD?Zewt~z=K({UYQI*X-;?4+clB0lT-TfRNp#fe^O;xcSzm|humw&|}5-NF8|iJon3 ziP@glkCFbgnX=im23rs@Fkr&Qpu)@`&(0}LDF(&g`m7;l@Ojx}Q7nb$02Nl-Ohko` zOJ>8)Va7=hc9@7^h@-5y@zh`<$>(*!Dt0A?h7;-dKvu;->-&zlAxlpO6hppkd;|3A zQs?1QjW{kBCuZq?;{VWzy94oYRm{0@9FDkgI*0nRaNq*`v z%M85S#4d4%SwU`>C#AFw+AQLDvi21wUMUN`VR0lGeznxcYnY(N@XQsFh|NArif4Nb zUW;oDTxa5SQhx$P$eS-dE9-i#)DH2A9W}TSHyL=niJS2T=J;H7m9oiI+zu4ny;Zzb;Uz&j1R%f!1yx;%>R1a`9aeFold;sdx<;nW=KYyt7R zu$6WyBK<mK*276Opwz1n=E)mTI?ca%1^Gk$`dHz_>gdXSmBoc z0mpoo8$&1GZQ4EgK4;?dI6~jmotPV-Q#@I7t*)!f?Gl}jnRpyupbJ{rhK`=kp1ue$ ze)qN}A$vtS|CjJ(17DH8^Q+_at647Y+A%vs-_*MOxD8)7@dUoXG^6$EOe7rHwGO+f zlM;{7Xy%dW7cp-a8-B~gxA7f1`>^FiwlT*rM>KVJ6T$K$+(OsjDSY3+4@~?}VkB_0 z;?pG+EfJ~6x*wbPi7aw^?~BfsyzpiD@U)4a;}?Y4n>}D(#UfpT6Xosk7^zR;S0;Wf zglcny)+YPyWI{gv*2M3``tC=ues_Ez%2FU7Z6?Ps%lq?H&A2q5r=}JFi3Vh@V#y z@xla{OBN#D4MhEf>|1ntVX_QFaV%k)H_{WjxYgjsz9$;D`_e;O?BoXN?^$1Z5)mu5 z(Mm?;-5U(a8HB?8q7nt{YH54_^g^M`BK>hPop&~tZNeGYw(G{sIDtwQIIY6O^^O(U z(Q6HRlJ5<6^#W*e8;L*;Mdyy)&IX(%X<4)TBdN`Lv(tJaT$#`Y*#9J>!@6f+;g1i* z@EuJ%C^=+sI%C@WxZiY3Zd5)hMphjrCc*dDA@eklv|9(O{{ zeM(|qIiz>Z3a1sJ>7D~9%qcP_$CoWo3H8O5HfzkWXdlx+(B$U_%5coQ5*iJK9lCw}y1UfLvyGm2meZ;f}0XyTcNKKwwT{%1)9>|+0a5E$BObuz4&3czd&!3 zx%bFzB-aiOQa*1t#^Ev%a!K}>p;*rD%DZ38#adsm1+~%SA}QOo z6>$%lmLpi}y45->$xeutC017!%>mh~KeyNP2nE|+OXX&uj^N|@W6E&#`b0Vzu|-0K z8OL|C^W@|O3%G?ZgHmj5c`?cxI$i+R$rUNbc+Q4072-SZHvRVs&gU(fe3QE_f4q|K zyt&fjyou7kyo1xfJip^_Ew^kH%HWDBzTJs(g!sEA+|qggDtr*e#Ro891ZM8BF5EKr zE=)Uwh7mM|LnD|SRwFnod>6tan9rYuBUsFzr6V}^lfp?&;NLK+`L_#|SWNkr;1r%K zG+`CyVl^c`pHi;jHCH#EE>JQv?8>2Pl*u z!Dwd7VJzQ^+Ll9D-rE|^pmRTJ!hBnup>}t0M!A-&PV?!5iM2%ZLdvyX^B1}%@3AMT z$(q+pUy_-sRtds&q!B{dRAPtA)D-F|2=3w`s36!tzl}+62%+T40RF}sOPikeVd_9=7{Sa4HWMb z)#yR8i-&_EQgeYsqp+9-MzNKDDO=y%mevfmhbf~L(6yS2&Sp%3g+|_h%tjU3?LtJG`{o$Kk*6%?hB=*08TX(T+u^`Q(>8C-EJK0A1C zALE_<4$XRzOTcH{=;PDqDPFH%jaSp&C- zz=a81lLoFu1IMc~54cVIB9@;>Z!#&%4Q1Gr=f!f!1H2qH*rnM_cPIO7Cel8wR5Ir< zGBTGVuEWfu2)yM8U{*I4vsaPXtH)s0bR4rL)#fvs&sbfc&h{|x@HDFow=j$35{9eN zwZ!teJT8^KN|id{N!%~Q5l`@S`LyN>EjP$rS~rl^jls0kBAqmI@KmZrs?wME`Q&nr zTI@-DA-M=_HDPAJ#o<#5@|+veH#c9Kgt-50$^Euni#E~`NAbNf)Q32H?kIlbJucRddOg$GPxa^7xz7aUXEKvf z^-K9}9mQ|tcND)@5RQ**{!G=x8M`}at98xx*x#^zCxQkN#uWsyLsw-5YONq z_7jI$OYdhqq&$1n zYIQyga%)g)R5vSdHYhbU#g0Z--UTrJfs+h0%=sryHgKbX%-_&#cB!LCpvu5Re&R4Y zo2Lxi$5slpE3l5rxQ!08kq*F$@B#cqFm+QmL!QrPYyI59TH$KN#Yfc(y)?7XOEVLs gpZI$Q|13sef=fX4kZ^^FA-p6Xl&N0Tr+?S}8@f_*mjD0& literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectClassBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/DirectClassBuilder.java new file mode 100644 index 00000000..915c3ad8 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.classfile.impl; + +import java.lang.constant.ConstantDescs; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +import java.lang.classfile.BufWriter; +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassElement; +import java.lang.classfile.ClassModel; +import java.lang.classfile.ClassFile; +import java.lang.classfile.CustomAttribute; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.FieldBuilder; +import java.lang.classfile.FieldModel; +import java.lang.classfile.FieldTransform; +import java.lang.classfile.MethodBuilder; +import java.lang.classfile.MethodModel; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.WritableElement; +import java.lang.classfile.constantpool.Utf8Entry; + +public final class DirectClassBuilder + extends AbstractDirectBuilder + implements ClassBuilder { + + final ClassEntry thisClassEntry; + private final List> fields = new ArrayList<>(); + private final List> methods = new ArrayList<>(); + private ClassEntry superclassEntry; + private List interfaceEntries; + private int majorVersion; + private int minorVersion; + private int flags; + private int sizeHint; + + public DirectClassBuilder(SplitConstantPool constantPool, + ClassFileImpl context, + ClassEntry thisClass) { + super(constantPool, context); + this.thisClassEntry = AbstractPoolEntry.maybeClone(constantPool, thisClass); + this.flags = ClassFile.DEFAULT_CLASS_FLAGS; + this.superclassEntry = null; + this.interfaceEntries = Collections.emptyList(); + this.majorVersion = ClassFile.latestMajorVersion(); + this.minorVersion = ClassFile.latestMinorVersion(); + } + + @Override + public ClassBuilder with(ClassElement element) { + if (element instanceof AbstractElement ae) { + ae.writeTo(this); + } else { + writeAttribute((CustomAttribute)element); + } + return this; + } + + @Override + public ClassBuilder withField(Utf8Entry name, + Utf8Entry descriptor, + Consumer handler) { + return withField(new DirectFieldBuilder(constantPool, context, name, descriptor, null) + .run(handler)); + } + + @Override + public ClassBuilder transformField(FieldModel field, FieldTransform transform) { + DirectFieldBuilder builder = new DirectFieldBuilder(constantPool, context, field.fieldName(), + field.fieldType(), field); + builder.transform(field, transform); + return withField(builder); + } + + @Override + public ClassBuilder withMethod(Utf8Entry name, + Utf8Entry descriptor, + int flags, + Consumer handler) { + return withMethod(new DirectMethodBuilder(constantPool, context, name, descriptor, flags, null) + .run(handler)); + } + + @Override + public ClassBuilder transformMethod(MethodModel method, MethodTransform transform) { + DirectMethodBuilder builder = new DirectMethodBuilder(constantPool, context, method.methodName(), + method.methodType(), + method.flags().flagsMask(), + method); + builder.transform(method, transform); + return withMethod(builder); + } + + // internal / for use by elements + + public ClassBuilder withField(WritableElement field) { + fields.add(field); + return this; + } + + public ClassBuilder withMethod(WritableElement method) { + methods.add(method); + return this; + } + + void setSuperclass(ClassEntry superclassEntry) { + this.superclassEntry = superclassEntry; + } + + void setInterfaces(List interfaces) { + this.interfaceEntries = interfaces; + } + + void setVersion(int major, int minor) { + this.majorVersion = major; + this.minorVersion = minor; + } + + void setFlags(int flags) { + this.flags = flags; + } + + public void setSizeHint(int sizeHint) { + this.sizeHint = sizeHint; + } + + + public byte[] build() { + + // The logic of this is very carefully ordered. We want to avoid + // repeated buffer copyings, so we accumulate lists of writers which + // all get written later into the same buffer. But, writing can often + // trigger CP / BSM insertions, so we cannot run the CP writer or + // BSM writers until everything else is written. + + // Do this early because it might trigger CP activity + ClassEntry superclass = superclassEntry; + if (superclass != null) + superclass = AbstractPoolEntry.maybeClone(constantPool, superclass); + else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisClassEntry.asInternalName())) + superclass = constantPool.classEntry(ConstantDescs.CD_Object); + List ies = new ArrayList<>(interfaceEntries.size()); + for (ClassEntry ce : interfaceEntries) + ies.add(AbstractPoolEntry.maybeClone(constantPool, ce)); + + // We maintain two writers, and then we join them at the end + int size = sizeHint == 0 ? 256 : sizeHint; + BufWriter head = new BufWriterImpl(constantPool, context, size); + BufWriterImpl tail = new BufWriterImpl(constantPool, context, size, thisClassEntry, majorVersion); + + // The tail consists of fields and methods, and attributes + // This should trigger all the CP/BSM mutation + tail.writeList(fields); + tail.writeList(methods); + int attributesOffset = tail.size(); + attributes.writeTo(tail); + + // Now we have to append the BSM, if there is one + boolean written = constantPool.writeBootstrapMethods(tail); + if (written) { + // Update attributes count + tail.patchInt(attributesOffset, 2, attributes.size() + 1); + } + + // Now we can make the head + head.writeInt(ClassFile.MAGIC_NUMBER); + head.writeU2(minorVersion); + head.writeU2(majorVersion); + constantPool.writeTo(head); + head.writeU2(flags); + head.writeIndex(thisClassEntry); + head.writeIndexOrZero(superclass); + head.writeListIndices(ies); + + // Join head and tail into an exact-size buffer + byte[] result = new byte[head.size() + tail.size()]; + head.copyTo(result, 0); + tail.copyTo(result, head.size()); + return result; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$1.class b/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$1.class new file mode 100644 index 0000000000000000000000000000000000000000..1a77df0db18bec0d03a1aa5fc7a9ee00af947031 GIT binary patch literal 2960 zcmbtWTWl0n82-+7yR+L4P)ZjmP*|bWZMSqODk96RSG%&bl?5uG*4dfU?X=UGb!L{U z3MzPsk3JY5jK&8^d{TpuYN9@vn3(u%;*&i3;9a9ZE&gY=onF{hh@0%pIscsh|G)EJ zzH`2u`sfn?U3fWy04gK|WmF=>kQ~#-le+10+fa=C*WGRR|*@p-M(IWQNpI+K0`YRW!8@*R}Or(dCUDTA!u* zQ$n#zH+6RpLp+`tQ%)#JLoxGn@cT;-D1`#IQ_V-Ju^cNT)W}$gT84&lTAjs_AzPi_H>V@0LsY_Q8Fyd}!#QEdPrD-5_HFHZn*j1+>H42wOZY_Olju%GiX>3}Jy;aV^5VI^I0TdU{$; z9-45Mgu7+L(acag>t<#NIT%%(etydJc704}BxJN=3pq4Baovn!)!TblpHsxg6eRejP1Ce z)C?gyWOb@K!-n!jP||8n3wIC5*eTqFxv6>1L{@jn*bOQoNwug2#Lg2-7Il~Ck6!AJ zG_?o8*@q4Zoig=RH$(GMbumwqDnR3k=D~9Y3L-!Z+ZNfnui4nWKqnPJFCLW8CnJrA z7D>Y5>V%^E;K1N;cTY$6aHgZPCzEB^TDF@OH$v&pFl?Glf7&p3UNJiCd~t%CZqF%| zdm9X+pCLBg*D)`7G2M*$y%DoTb5vnJ1_ePp%n+TM)GQH!nfKbb4Otn7L=Ug>wY|>D zib4_{b413F=$NqAF=>;8Z8$39m{3|dU#Z8`#Meh{=5|vJHVl~=!#7l3drJbeQD*s?U!1)N z4a+fXEW4#ykL06Z5zLTkXT7sz85O8HP6yI-_99t5Zz^ulru3d&GKK$f9RBa%R%NZC zt#ZL^l<1qzFpu4-D0@uRupH{cQZ8hi!+8cdCoTtFfbb*biAxK}z8=O6wOUR>n(_GwB`+XAvgj4nQ5x&yJA8gccZQGou{$kAJ+ z(Q$Dx5|Wn0hhQzOS0TMm(+X(x41v+}J8*i&O3N^UJk5j&VNQIn#wc_$Ge%?CmyDCd zAW4M$ov)z*VZa1TdXiuE9)cdOYl%rLW7yqt8SFAvO`@J*PoiNG>jUs*F@~MN`rsrQ z8D7V0V${O$8QOMMiZ%6>lc1Z~72LZ$G&A2(noH48;7vrLQs6CYF4;?6!QKzh^9~{x zDsEgt@5k7GwD!PN41Ai1hCIKCs1(#nBVqa=!z2y|kPwqc=1z`_2?4!ygE#nKX#;OV zPOPt_O*|gNY&83^ih}SxB>X^!@Q+xBpRgA{V*tNk7{6j1zu_!?$FukYui!df#b0;> zf8$;JgR7Xr=M?NO7{k{rfNxoamz6%UHh>~56et_RBzuxZ64|{78xG|NxaQ~V8eCdS z2S2{S30fB*9ADuijVf@8R<46IMfW5op=nB-@okJnBY$GYbp+OssnfJ1fHMSAyr06; k^bV4VX9%*8)ZsaLuO(xm#>6j-=W#J84(u23(!TnC0aZvl4gdfE literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$2.class b/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$2.class new file mode 100644 index 0000000000000000000000000000000000000000..9aaf50621cc2366276bf71001ce6c58d12e9be99 GIT binary patch literal 2626 zcmbtW+fy556#pFvEP(}5q~&6Nf5{k7d;nF~;M8m~~i^U7wBpj^iz9ocPiZC)0zO!e)bI$MF_wN_K{|R6ct{+vXR^U@n zgIYp#Gq)AhO;^~aW<;}w<~VD*A)1+);lDoITg*OqOagF)~)`a?me4)-SgXvIYZmsGT& zop9|m;3q;xXfmv_`&Q@Z2E8qg`Bz0P+%ROL4kbC-%YaD||J zEs-s927KY9bf*(oD^4ku+v-{z7|az%3uet=;GF%=^i zCG?(_$|I7TwVcp$DJ>%mXRaWfA`Be~$U*azB}0j0GBH2KaZ5p5#RMh^1C;{zYH>!9 zxHC7unwW|wR#WkbsZ^RUSg`?Kt%OrH#o<1%oHPuvt{HKAy_grKJ9R%RJO}IWAt6+1 z#h@Ww59(&nE9c;Lsh)%GgMz3>0!i7|9}zAd&SRSU*IX}kUrNOcX1QDonw#B7nw-1Z za5BloOju^A^Gu>xMW;`8Jr}Q>UxenAZi?ArJ|pY}*@xT&M~bq<^vUT)xPCq~p`jT2 zlJ`apq32B4xL1z?;5e2*WX_^sq~axQe_|eOIZtspIv;V9ry*?(HA9CwwM%F*SifcHej^;e!5a?Tu^ zTnO@qLmhuZP#_>b9hj=(Ujyd&oM-AY`C%bBeUV>5ef>|N{LGKl_=Nx0f>_dzJ4^@n zt|5&Dev&GrI)2a8B9>UqGSh0A^C@%gGRM#M9tD_SO;}-jB<)f+d>)#e$SxWQqkT_6 zPw?6BJv&S!=b(K}JnIEA>F4wTBk9|1sd5C=gsZgj9t<=Qpy&2;a z;2C)VE7XE})QU}NL!R344Rzo<>h$7sgX1xd2tLObOaVLPNbTTDtg_n*9^oD|j!P>X zWSFW(mT$J9<^`{JQqc1cZYmgf4*zphwX>QWzpjG7ns=^agHIoe>o7b{EAo7HvLcyP R`Bw)M1)tnkU%|Q6@h|?1-Aw=h literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$3.class b/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$3.class new file mode 100644 index 0000000000000000000000000000000000000000..143e998e1438fc643d822afc769c77d91b0c47f8 GIT binary patch literal 2658 zcmb_e+fy556#pFvEP-iQ4w=}|x%!Kdk+3%e5JNNzj`R{)M7>Dae6{;2Z zRMeoB5M9fyM|IN`wy7D>tf4v1if)LgzELou3EdW1cihT}v7&C|gdH3t)Viy>6YOKr z)R|;s^{9hiLA{CwsDxN0>3K6_70q1Sb!|OUbVV?po3yf}M@BKCo4Pwn2!&E>+NKsY zG&6q)f9dL!RwxKN7G7w;Ih0d_C;e!_1qByX zT*75SPbJ_dLPlsdtgL1%Xtu6p3^DhhARI!|F6yGI8_|^RxUmMbNqDaj&Uwg6ZzS$^ z6|dteLHR)F4R5Hph7LlVgsr(2L%$dbAJU%OIMF?Srbzo-y z3L99}oN2M;dX6tiiHM4B^sqtGW4G+<_ToL0S>pnUDTosK%LP<79oH^qUEMOHspDa2 zKri}L41lX@*Rwf`aIJhoOR0&4mt;cTRB;n;v0&EX>XnEi73*ZWY zhxZ7ON-**WY4(Bn=eQf6Ux-g|;3e#M&15BXc>gs+1|P)G4R8N~(VyV|y86WK`+m2B}xsF5o*?K^nihXeNq*d0&@ z6bhn+csJ8^o|`u?Pay~ja}`8Tq+V=M6yH!EzN3CGR6`t^yNKXpe8Lp4T?*PZKE*Oe zK*6{83>t^11rL#7sv23oc?mVoF+`-G^B>$)(EAMjXQ;Z&YI6L#3IZ$Mna3)hJ{H$u bc$^k&@Y%+SWP;^i9ZVE_a*uru=XUGA3qk5c literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$4.class b/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$4.class new file mode 100644 index 0000000000000000000000000000000000000000..20f149ff731466fa96b121f507a0ceec7292abc9 GIT binary patch literal 5466 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 NQi4y?Appypo?l`bQZE1i literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$8.class b/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder$8.class new file mode 100644 index 0000000000000000000000000000000000000000..43fdce95b6464db075c4c38a54876614997ded05 GIT binary patch literal 972 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 DY{44v literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder.java new file mode 100644 index 00000000..0b6549a8 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -0,0 +1,786 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.constant.MethodTypeDesc; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +import java.lang.classfile.Attribute; +import java.lang.classfile.Attributes; +import java.lang.classfile.BufWriter; +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeModel; +import java.lang.classfile.CustomAttribute; +import java.lang.classfile.Instruction; +import java.lang.classfile.Label; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; +import java.lang.classfile.instruction.SwitchCase; +import java.lang.classfile.attribute.CodeAttribute; +import java.lang.classfile.attribute.LineNumberTableAttribute; +import java.lang.classfile.attribute.StackMapTableAttribute; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.DoubleEntry; +import java.lang.classfile.constantpool.FieldRefEntry; +import java.lang.classfile.constantpool.InterfaceMethodRefEntry; +import java.lang.classfile.constantpool.InvokeDynamicEntry; +import java.lang.classfile.constantpool.LoadableConstantEntry; +import java.lang.classfile.constantpool.LongEntry; +import java.lang.classfile.constantpool.MemberRefEntry; +import java.lang.classfile.instruction.CharacterRange; +import java.lang.classfile.instruction.ExceptionCatch; +import java.lang.classfile.instruction.LocalVariable; +import java.lang.classfile.instruction.LocalVariableType; + +import static java.lang.classfile.Opcode.GOTO; +import static java.lang.classfile.Opcode.GOTO_W; +import static java.lang.classfile.Opcode.IINC; +import static java.lang.classfile.Opcode.IINC_W; +import static java.lang.classfile.Opcode.JSR; +import static java.lang.classfile.Opcode.JSR_W; +import static java.lang.classfile.Opcode.LDC2_W; +import static java.lang.classfile.Opcode.LDC_W; + +public final class DirectCodeBuilder + extends AbstractDirectBuilder + implements TerminalCodeBuilder { + private final List characterRanges = new ArrayList<>(); + final List handlers = new ArrayList<>(); + private final List localVariables = new ArrayList<>(); + private final List localVariableTypes = new ArrayList<>(); + private final boolean transformFwdJumps, transformBackJumps; + private final Label startLabel, endLabel; + final MethodInfo methodInfo; + final BufWriter bytecodesBufWriter; + private CodeAttribute mruParent; + private int[] mruParentTable; + private Map parentMap; + private DedupLineNumberTableAttribute lineNumberWriter; + private int topLocal; + + List deferredLabels; + + /* Locals management + lazily computed maxLocal = -1 + first time: derive count from methodType descriptor (for new methods) & ACC_STATIC, + or model maxLocals (for transformation) + block builders inherit parent count + allocLocal(TypeKind) bumps by nSlots + */ + + public static Attribute build(MethodInfo methodInfo, + Consumer handler, + SplitConstantPool constantPool, + ClassFileImpl context, + CodeModel original) { + DirectCodeBuilder cb; + try { + handler.accept(cb = new DirectCodeBuilder(methodInfo, constantPool, context, original, false)); + cb.buildContent(); + } catch (LabelOverflowException loe) { + if (context.shortJumpsOption() == ClassFile.ShortJumpsOption.FIX_SHORT_JUMPS) { + handler.accept(cb = new DirectCodeBuilder(methodInfo, constantPool, context, original, true)); + cb.buildContent(); + } + else + throw loe; + } + return cb.content; + } + + private DirectCodeBuilder(MethodInfo methodInfo, + SplitConstantPool constantPool, + ClassFileImpl context, + CodeModel original, + boolean transformFwdJumps) { + super(constantPool, context); + setOriginal(original); + this.methodInfo = methodInfo; + this.transformFwdJumps = transformFwdJumps; + this.transformBackJumps = context.shortJumpsOption() == ClassFile.ShortJumpsOption.FIX_SHORT_JUMPS; + bytecodesBufWriter = (original instanceof CodeImpl cai) ? new BufWriterImpl(constantPool, context, cai.codeLength()) + : new BufWriterImpl(constantPool, context); + this.startLabel = new LabelImpl(this, 0); + this.endLabel = new LabelImpl(this, -1); + this.topLocal = Util.maxLocals(methodInfo.methodFlags(), methodInfo.methodTypeSymbol()); + if (original != null) + this.topLocal = Math.max(this.topLocal, original.maxLocals()); + } + + @Override + public CodeBuilder with(CodeElement element) { + if (element instanceof AbstractElement ae) { + ae.writeTo(this); + } else { + writeAttribute((CustomAttribute)element); + } + return this; + } + + @Override + public Label newLabel() { + return new LabelImpl(this, -1); + } + + @Override + public Label startLabel() { + return startLabel; + } + + @Override + public Label endLabel() { + return endLabel; + } + + @Override + public int receiverSlot() { + return methodInfo.receiverSlot(); + } + + @Override + public int parameterSlot(int paramNo) { + return methodInfo.parameterSlot(paramNo); + } + + public int curTopLocal() { + return topLocal; + } + + @Override + public int allocateLocal(TypeKind typeKind) { + int retVal = topLocal; + topLocal += typeKind.slotSize(); + return retVal; + } + + public int curPc() { + return bytecodesBufWriter.size(); + } + + public MethodInfo methodInfo() { + return methodInfo; + } + + private Attribute content = null; + + private void writeExceptionHandlers(BufWriter buf) { + int pos = buf.size(); + int handlersSize = handlers.size(); + buf.writeU2(handlersSize); + for (AbstractPseudoInstruction.ExceptionCatchImpl h : handlers) { + int startPc = labelToBci(h.tryStart()); + int endPc = labelToBci(h.tryEnd()); + int handlerPc = labelToBci(h.handler()); + if (startPc == -1 || endPc == -1 || handlerPc == -1) { + if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { + handlersSize--; + } else { + throw new IllegalArgumentException("Unbound label in exception handler"); + } + } else { + buf.writeU2(startPc); + buf.writeU2(endPc); + buf.writeU2(handlerPc); + buf.writeIndexOrZero(h.catchTypeEntry()); + handlersSize++; + } + } + if (handlersSize < handlers.size()) + buf.patchInt(pos, 2, handlersSize); + } + + private void buildContent() { + if (content != null) return; + setLabelTarget(endLabel); + + // Backfill branches for which Label didn't have position yet + processDeferredLabels(); + + if (context.debugElementsOption() == ClassFile.DebugElementsOption.PASS_DEBUG) { + if (!characterRanges.isEmpty()) { + Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.characterRangeTable()) { + + @Override + public void writeBody(BufWriter b) { + int pos = b.size(); + int crSize = characterRanges.size(); + b.writeU2(crSize); + for (CharacterRange cr : characterRanges) { + var start = labelToBci(cr.startScope()); + var end = labelToBci(cr.endScope()); + if (start == -1 || end == -1) { + if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { + crSize--; + } else { + throw new IllegalArgumentException("Unbound label in character range"); + } + } else { + b.writeU2(start); + b.writeU2(end - 1); + b.writeInt(cr.characterRangeStart()); + b.writeInt(cr.characterRangeEnd()); + b.writeU2(cr.flags()); + } + } + if (crSize < characterRanges.size()) + b.patchInt(pos, 2, crSize); + } + }; + attributes.withAttribute(a); + } + + if (!localVariables.isEmpty()) { + Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) { + @Override + public void writeBody(BufWriter b) { + int pos = b.size(); + int lvSize = localVariables.size(); + b.writeU2(lvSize); + for (LocalVariable l : localVariables) { + if (!l.writeTo(b)) { + if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { + lvSize--; + } else { + throw new IllegalArgumentException("Unbound label in local variable type"); + } + } + } + if (lvSize < localVariables.size()) + b.patchInt(pos, 2, lvSize); + } + }; + attributes.withAttribute(a); + } + + if (!localVariableTypes.isEmpty()) { + Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) { + @Override + public void writeBody(BufWriter b) { + int pos = b.size(); + int lvtSize = localVariableTypes.size(); + b.writeU2(localVariableTypes.size()); + for (LocalVariableType l : localVariableTypes) { + if (!l.writeTo(b)) { + if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { + lvtSize--; + } else { + throw new IllegalArgumentException("Unbound label in local variable type"); + } + } + } + if (lvtSize < localVariableTypes.size()) + b.patchInt(pos, 2, lvtSize); + } + }; + attributes.withAttribute(a); + } + } + + if (lineNumberWriter != null) { + attributes.withAttribute(lineNumberWriter); + } + + content = new UnboundAttribute.AdHocAttribute<>(Attributes.code()) { + + private void writeCounters(boolean codeMatch, BufWriterImpl buf) { + if (codeMatch) { + buf.writeU2(original.maxStack()); + buf.writeU2(original.maxLocals()); + } else { + StackCounter cntr = StackCounter.of(DirectCodeBuilder.this, buf); + buf.writeU2(cntr.maxStack()); + buf.writeU2(cntr.maxLocals()); + } + } + + private void generateStackMaps(BufWriterImpl buf) throws IllegalArgumentException { + //new instance of generator immediately calculates maxStack, maxLocals, all frames, + // patches dead bytecode blocks and removes them from exception table + StackMapGenerator gen = StackMapGenerator.of(DirectCodeBuilder.this, buf); + attributes.withAttribute(gen.stackMapTableAttribute()); + buf.writeU2(gen.maxStack()); + buf.writeU2(gen.maxLocals()); + } + + private void tryGenerateStackMaps(boolean codeMatch, BufWriterImpl buf) { + if (buf.getMajorVersion() >= ClassFile.JAVA_6_VERSION) { + try { + generateStackMaps(buf); + } catch (IllegalArgumentException e) { + //failover following JVMS-4.10 + if (buf.getMajorVersion() == ClassFile.JAVA_6_VERSION) { + writeCounters(codeMatch, buf); + } else { + throw e; + } + } + } else { + writeCounters(codeMatch, buf); + } + } + + @Override + public void writeBody(BufWriter b) { + BufWriterImpl buf = (BufWriterImpl) b; + buf.setLabelContext(DirectCodeBuilder.this); + + int codeLength = curPc(); + if (codeLength == 0 || codeLength >= 65536) { + throw new IllegalArgumentException(String.format( + "Code length %d is outside the allowed range in %s%s", + codeLength, + methodInfo.methodName().stringValue(), + methodInfo.methodTypeSymbol().displayDescriptor())); + } + + if (codeAndExceptionsMatch(codeLength)) { + switch (context.stackMapsOption()) { + case STACK_MAPS_WHEN_REQUIRED -> { + attributes.withAttribute(original.findAttribute(Attributes.stackMapTable()).orElse(null)); + writeCounters(true, buf); + } + case GENERATE_STACK_MAPS -> + generateStackMaps(buf); + case DROP_STACK_MAPS -> + writeCounters(true, buf); + } + } else { + switch (context.stackMapsOption()) { + case STACK_MAPS_WHEN_REQUIRED -> + tryGenerateStackMaps(false, buf); + case GENERATE_STACK_MAPS -> + generateStackMaps(buf); + case DROP_STACK_MAPS -> + writeCounters(false, buf); + } + } + + buf.writeInt(codeLength); + buf.writeBytes(bytecodesBufWriter); + writeExceptionHandlers(b); + attributes.writeTo(b); + buf.setLabelContext(null); + } + }; + } + + private static class DedupLineNumberTableAttribute extends UnboundAttribute.AdHocAttribute { + private final BufWriterImpl buf; + private int lastPc, lastLine, writtenLine; + + public DedupLineNumberTableAttribute(ConstantPoolBuilder constantPool, ClassFileImpl context) { + super(Attributes.lineNumberTable()); + buf = new BufWriterImpl(constantPool, context); + lastPc = -1; + writtenLine = -1; + } + + private void push() { + //subsequent identical line numbers are skipped + if (lastPc >= 0 && lastLine != writtenLine) { + buf.writeU2(lastPc); + buf.writeU2(lastLine); + writtenLine = lastLine; + } + } + + //writes are expected ordered by pc in ascending sequence + public void writeLineNumber(int pc, int lineNo) { + //for each pc only the latest line number is written + if (lastPc != pc && lastLine != lineNo) { + push(); + lastPc = pc; + } + lastLine = lineNo; + } + + @Override + public void writeBody(BufWriter b) { + throw new UnsupportedOperationException(); + } + + @Override + public void writeTo(BufWriter b) { + b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE)); + push(); + b.writeInt(buf.size() + 2); + b.writeU2(buf.size() / 4); + b.writeBytes(buf); + } + } + + private boolean codeAndExceptionsMatch(int codeLength) { + boolean codeAttributesMatch; + if (original instanceof CodeImpl cai && canWriteDirect(cai.constantPool())) { + codeAttributesMatch = cai.codeLength == curPc() + && cai.compareCodeBytes(bytecodesBufWriter, 0, codeLength); + if (codeAttributesMatch) { + BufWriter bw = new BufWriterImpl(constantPool, context); + writeExceptionHandlers(bw); + codeAttributesMatch = cai.classReader.compare(bw, 0, cai.exceptionHandlerPos, bw.size()); + } + } + else + codeAttributesMatch = false; + return codeAttributesMatch; + } + + // Writing support + + private record DeferredLabel(int labelPc, int size, int instructionPc, Label label) { } + + private void writeLabelOffset(int nBytes, int instructionPc, Label label) { + int targetBci = labelToBci(label); + if (targetBci == -1) { + int pc = curPc(); + bytecodesBufWriter.writeIntBytes(nBytes, 0); + if (deferredLabels == null) + deferredLabels = new ArrayList<>(); + deferredLabels.add(new DeferredLabel(pc, nBytes, instructionPc, label)); + } + else { + int branchOffset = targetBci - instructionPc; + if (nBytes == 2 && (short)branchOffset != branchOffset) throw new LabelOverflowException(); + bytecodesBufWriter.writeIntBytes(nBytes, branchOffset); + } + } + + private void processDeferredLabels() { + if (deferredLabels != null) { + for (DeferredLabel dl : deferredLabels) { + int branchOffset = labelToBci(dl.label) - dl.instructionPc; + if (dl.size == 2 && (short)branchOffset != branchOffset) throw new LabelOverflowException(); + bytecodesBufWriter.patchInt(dl.labelPc, dl.size, branchOffset); + } + } + } + + // Instruction writing + + public void writeBytecode(Opcode opcode) { + if (opcode.isWide()) + bytecodesBufWriter.writeU1(ClassFile.WIDE); + bytecodesBufWriter.writeU1(opcode.bytecode() & 0xFF); + } + + public void writeLocalVar(Opcode opcode, int localVar) { + writeBytecode(opcode); + switch (opcode.sizeIfFixed()) { + case 1 -> { } + case 2 -> bytecodesBufWriter.writeU1(localVar); + case 4 -> bytecodesBufWriter.writeU2(localVar); + default -> throw new IllegalArgumentException("Unexpected instruction size: " + opcode); + } + } + + public void writeIncrement(int slot, int val) { + Opcode opcode = (slot < 256 && val < 128 && val > -127) + ? IINC + : IINC_W; + writeBytecode(opcode); + if (opcode.isWide()) { + bytecodesBufWriter.writeU2(slot); + bytecodesBufWriter.writeU2(val); + } else { + bytecodesBufWriter.writeU1(slot); + bytecodesBufWriter.writeU1(val); + } + } + + public void writeBranch(Opcode op, Label target) { + int instructionPc = curPc(); + int targetBci = labelToBci(target); + //transform short-opcode forward jumps if enforced, and backward jumps if enabled and overflowing + if (op.sizeIfFixed() == 3 && (targetBci == -1 + ? transformFwdJumps + : (transformBackJumps + && targetBci - instructionPc < Short.MIN_VALUE))) { + if (op == GOTO) { + writeBytecode(GOTO_W); + writeLabelOffset(4, instructionPc, target); + } else if (op == JSR) { + writeBytecode(JSR_W); + writeLabelOffset(4, instructionPc, target); + } else { + writeBytecode(BytecodeHelpers.reverseBranchOpcode(op)); + Label bypassJump = newLabel(); + writeLabelOffset(2, instructionPc, bypassJump); + writeBytecode(GOTO_W); + writeLabelOffset(4, instructionPc + 3, target); + labelBinding(bypassJump); + } + } else { + writeBytecode(op); + writeLabelOffset(op.sizeIfFixed() == 3 ? 2 : 4, instructionPc, target); + } + } + + public void writeLookupSwitch(Label defaultTarget, List cases) { + int instructionPc = curPc(); + writeBytecode(Opcode.LOOKUPSWITCH); + int pad = 4 - (curPc() % 4); + if (pad != 4) + bytecodesBufWriter.writeIntBytes(pad, 0); + writeLabelOffset(4, instructionPc, defaultTarget); + bytecodesBufWriter.writeInt(cases.size()); + cases = new ArrayList<>(cases); + cases.sort(new Comparator() { + @Override + public int compare(SwitchCase c1, SwitchCase c2) { + return Integer.compare(c1.caseValue(), c2.caseValue()); + } + }); + for (var c : cases) { + bytecodesBufWriter.writeInt(c.caseValue()); + writeLabelOffset(4, instructionPc, c.target()); + } + } + + public void writeTableSwitch(int low, int high, Label defaultTarget, List cases) { + int instructionPc = curPc(); + writeBytecode(Opcode.TABLESWITCH); + int pad = 4 - (curPc() % 4); + if (pad != 4) + bytecodesBufWriter.writeIntBytes(pad, 0); + writeLabelOffset(4, instructionPc, defaultTarget); + bytecodesBufWriter.writeInt(low); + bytecodesBufWriter.writeInt(high); + var caseMap = new HashMap(cases.size()); + for (var c : cases) { + caseMap.put(c.caseValue(), c.target()); + } + for (long l = low; l<=high; l++) { + writeLabelOffset(4, instructionPc, caseMap.getOrDefault((int)l, defaultTarget)); + } + } + + public void writeFieldAccess(Opcode opcode, FieldRefEntry ref) { + writeBytecode(opcode); + bytecodesBufWriter.writeIndex(ref); + } + + public void writeInvokeNormal(Opcode opcode, MemberRefEntry ref) { + writeBytecode(opcode); + bytecodesBufWriter.writeIndex(ref); + } + + public void writeInvokeInterface(Opcode opcode, + InterfaceMethodRefEntry ref, + int count) { + writeBytecode(opcode); + bytecodesBufWriter.writeIndex(ref); + bytecodesBufWriter.writeU1(count); + bytecodesBufWriter.writeU1(0); + } + + public void writeInvokeDynamic(InvokeDynamicEntry ref) { + writeBytecode(Opcode.INVOKEDYNAMIC); + bytecodesBufWriter.writeIndex(ref); + bytecodesBufWriter.writeU2(0); + } + + public void writeNewObject(ClassEntry type) { + writeBytecode(Opcode.NEW); + bytecodesBufWriter.writeIndex(type); + } + + public void writeNewPrimitiveArray(int newArrayCode) { + writeBytecode(Opcode.NEWARRAY); + bytecodesBufWriter.writeU1(newArrayCode); + } + + public void writeNewReferenceArray(ClassEntry type) { + writeBytecode(Opcode.ANEWARRAY); + bytecodesBufWriter.writeIndex(type); + } + + public void writeNewMultidimensionalArray(int dimensions, ClassEntry type) { + writeBytecode(Opcode.MULTIANEWARRAY); + bytecodesBufWriter.writeIndex(type); + bytecodesBufWriter.writeU1(dimensions); + } + + public void writeTypeCheck(Opcode opcode, ClassEntry type) { + writeBytecode(opcode); + bytecodesBufWriter.writeIndex(type); + } + + public void writeArgumentConstant(Opcode opcode, int value) { + writeBytecode(opcode); + if (opcode.sizeIfFixed() == 3) { + bytecodesBufWriter.writeU2(value); + } else { + bytecodesBufWriter.writeU1(value); + } + } + + public void writeLoadConstant(Opcode opcode, LoadableConstantEntry value) { + // Make sure Long and Double have LDC2_W and + // rewrite to _W if index is > 256 + int index = AbstractPoolEntry.maybeClone(constantPool, value).index(); + Opcode op = opcode; + if (value instanceof LongEntry || value instanceof DoubleEntry) { + op = LDC2_W; + } else if (index >= 256) + op = LDC_W; + + writeBytecode(op); + if (op.sizeIfFixed() == 3) { + bytecodesBufWriter.writeU2(index); + } else { + bytecodesBufWriter.writeU1(index); + } + } + + @Override + public Label getLabel(int bci) { + throw new UnsupportedOperationException("Lookup by BCI not supported by CodeBuilder"); + } + + @Override + public int labelToBci(Label label) { + LabelImpl lab = (LabelImpl) label; + LabelContext context = lab.labelContext(); + if (context == this) { + return lab.getBCI(); + } + else if (context == mruParent) { + return mruParentTable[lab.getBCI()] - 1; + } + else if (context instanceof CodeAttribute parent) { + if (parentMap == null) + parentMap = new IdentityHashMap<>(); + //critical JDK bootstrap path, cannot use lambda here + int[] table = parentMap.computeIfAbsent(parent, new Function() { + @Override + public int[] apply(CodeAttribute x) { + return new int[parent.codeLength() + 1]; + } + }); + + mruParent = parent; + mruParentTable = table; + return mruParentTable[lab.getBCI()] - 1; + } + else if (context instanceof BufferedCodeBuilder) { + // Hijack the label + return lab.getBCI(); + } + else { + throw new IllegalStateException(String.format("Unexpected label context %s in =%s", context, this)); + } + } + + public void setLineNumber(int lineNo) { + if (lineNumberWriter == null) + lineNumberWriter = new DedupLineNumberTableAttribute(constantPool, context); + lineNumberWriter.writeLineNumber(curPc(), lineNo); + } + + public void setLabelTarget(Label label) { + setLabelTarget(label, curPc()); + } + + @Override + public void setLabelTarget(Label label, int bci) { + LabelImpl lab = (LabelImpl) label; + LabelContext context = lab.labelContext(); + + if (context == this) { + if (lab.getBCI() != -1) + throw new IllegalArgumentException("Setting label target for already-set label"); + lab.setBCI(bci); + } + else if (context == mruParent) { + mruParentTable[lab.getBCI()] = bci + 1; + } + else if (context instanceof CodeAttribute parent) { + if (parentMap == null) + parentMap = new IdentityHashMap<>(); + int[] table = parentMap.computeIfAbsent(parent, new Function() { + @Override + public int[] apply(CodeAttribute x) { + return new int[parent.codeLength() + 1]; + } + }); + + mruParent = parent; + mruParentTable = table; + mruParentTable[lab.getBCI()] = bci + 1; + } + else if (context instanceof BufferedCodeBuilder) { + // Hijack the label + lab.setBCI(bci); + } + else { + throw new IllegalStateException(String.format("Unexpected label context %s in =%s", context, this)); + } + } + + public void addCharacterRange(CharacterRange element) { + characterRanges.add(element); + } + + public void addHandler(ExceptionCatch element) { + AbstractPseudoInstruction.ExceptionCatchImpl el = (AbstractPseudoInstruction.ExceptionCatchImpl) element; + ClassEntry type = el.catchTypeEntry(); + if (type != null && !constantPool.canWriteDirect(type.constantPool())) + el = new AbstractPseudoInstruction.ExceptionCatchImpl(element.handler(), element.tryStart(), element.tryEnd(), AbstractPoolEntry.maybeClone(constantPool, type)); + handlers.add(el); + } + + public void addLocalVariable(LocalVariable element) { + localVariables.add(element); + } + + public void addLocalVariableType(LocalVariableType element) { + localVariableTypes.add(element); + } + + @Override + public String toString() { + return String.format("CodeBuilder[id=%d]", System.identityHashCode(this)); + } + + //ToDo: consolidate and open all exceptions + private static final class LabelOverflowException extends IllegalArgumentException { + + private static final long serialVersionUID = 1L; + + public LabelOverflowException() { + super("Label target offset overflow"); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectFieldBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/DirectFieldBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..50da2961939a83ab9ea7cc20ac93c699cd43fd53 GIT binary patch literal 3453 zcmbtWU3U{z6x}yzGfg@`sil0jR8U$br2&e7rdHZOrP>d)1^hytB$IaNWYRUc5%>}Q z0Dpn6x|WoM4=#Q6!8iYo%YA1ilax-UEPa`|bLX71&)Mgkd(WT${Q4V!5}X`TNNecP z(Tj}0mB-bsg6&Gnb4{mEam;43W;<5Fu5UYqxpGr_W<}n%J*y(;TeefRJb}!N?b>oy z;L*fVlKR@VW6M&*ZA#OX_ZkhSm?&OS;0pv_BzE!QgB<#h)sWNC4_#m?2`cb#!M2=g zMl7HaVcnd)6!KFsUbRL+Vt-iy}9=U0=kS`|&7jtm1i4s-z z(#Q5B1JZgbS^9~(ySZdU^4T{1?`uSd^;j%vT|@|^OsX8vpW*ctmIPZ;vx4K5?Y2Kc zNBq#5G%H)n=5|PC+H1K2t6>AgpKYr46Ry-)s zW2tKl2`2;wyb^zwMFrX}g?NBStYdIs*^--$>OIrrEWtaAt@l@AJ+$xrpe{l~GqLe> zmH%w=Bo%jZQX__=S5D2>0Ok$3)@XSZOHFD5$M+WWlmgMnWbY0%Pvi{ z@`bPRISn1xaFjRraa`x^djre-KN}ds3Rd|=v)s8yD7E?opVA4nQjVql)f!hl{%Rff z>6TFUUg(-fX(ct9{{ts}z(D?YoLHVTc5v!P^c(yd-NBgg6D876z76`8iu7v+L&QCU zTfR?Y{I8Rm2YBe?k4D~&;xl|sv@fXLgVd0s=1Y7zH;m)^QnOvt(=Cgt+ek-6^?kIa1jE>@0UnQl$5Dj^F)&BhYawufZxv{-@d7g{DJefG8GrMFZzf=(H!wrx+t{F#VqiM- eI;+xpYX|d52C|_an+lDPEbdgutBuD#^47o8V8gEf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectFieldBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/DirectFieldBuilder.java new file mode 100644 index 00000000..7bdab531 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/DirectFieldBuilder.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.classfile.impl; + +import java.util.function.Consumer; + +import java.lang.classfile.BufWriter; +import java.lang.classfile.CustomAttribute; +import java.lang.classfile.FieldBuilder; +import java.lang.classfile.FieldElement; +import java.lang.classfile.FieldModel; +import java.lang.classfile.WritableElement; +import java.lang.classfile.constantpool.Utf8Entry; + +public final class DirectFieldBuilder + extends AbstractDirectBuilder + implements TerminalFieldBuilder, WritableElement { + private final Utf8Entry name; + private final Utf8Entry desc; + private int flags; + + public DirectFieldBuilder(SplitConstantPool constantPool, + ClassFileImpl context, + Utf8Entry name, + Utf8Entry type, + FieldModel original) { + super(constantPool, context); + setOriginal(original); + this.name = name; + this.desc = type; + this.flags = 0; + } + + @Override + public FieldBuilder with(FieldElement element) { + if (element instanceof AbstractElement ae) { + ae.writeTo(this); + } else { + writeAttribute((CustomAttribute)element); + } + return this; + } + + public DirectFieldBuilder run(Consumer handler) { + handler.accept(this); + return this; + } + + void setFlags(int flags) { + this.flags = flags; + } + + @Override + public void writeTo(BufWriter buf) { + buf.writeU2(flags); + buf.writeIndex(name); + buf.writeIndex(desc); + attributes.writeTo(buf); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder$1.class b/tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder$1.class new file mode 100644 index 0000000000000000000000000000000000000000..486bd80821696263cb7de26598bdfa5f3dadba88 GIT binary patch literal 1546 zcmb7ETTc@~6#k|yEG>(yD2P`?s?u^2@fCyR&33Jo{>*KgI+! z`e1zaM;Xs_D_xTALz`@8_slux`_7#2%%8tMe*tLVSrIwp4HQg_V3eVD-2Pxo6^TG` z*LGYUhKJG>w)9S1`=tzo6YYrT$Zx-hrP~%kxyCSd%H6W#w*|x8_Ax)@w#!u~72Ke` z9eUilMjJCxM2TTSheZKb;h`UR3=5gD2mhVwC775naK*$VEC#EO_O5kI+!#hTq>|Al zLw>Q+9LE%{8Mtm@8Z*SM@7}LWlj{}3P)zaJTg)Kjo%pe8Z@Iz~Dyk25(g*j74z5qV z(kxN&vnFoh7SZI6BTk5KISb{2RlU+QaEIY`mwg;b*FKDu6G>m$4PS+^Cjy33$}?Q+ zGMHcVYH(q+ovw+YpbwB?a$72~8+$Dg9PpM)mZ@#u;ck-$Qh)c1h3H6z4C}*^E!XOF zXgavOMk*aPoPw=Hw|hL`o*;b_3!{~Ym|;G%*q$^f!F0M)iQK3)q?vu$Q9OzRs`-5? zPtPT>3~t*-%6*_B>zf2z+V|tY5n4_Rvjc{3RV#y9u%#T=52flPr5dmq>>*WQqJ}3l zoEL+Tw6~Kk{xa2MvNJ15sb!$grR#*M9orRQ^u`ZqHq5t5iJ+lpNrbph<70y606ELj zw-rDuT_tpp<>{HkUGlisz1DIlXiIhZ9IU!>4x{=V<6p^?!yNsOQX1eBr37Zkri174 zfL8ssfHLhrr1uHR`_by+Xe_2@m;N=zYr^aXE>+J6;|#_RT+O48p{E`Aj4Sw(f%6ED z!K~+$bdh{@(sf#ORI$4B8<Kqn|EKS)T$q^(bqiBV-_+BdE|v4pl65*JZ5GTEHsS RD7W5O#Zy{KltAOq?;qKppL75K literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..195c799251241c342f2635708c7d51aaccbefadb GIT binary patch literal 7273 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder.java new file mode 100644 index 00000000..50daf243 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/DirectMethodBuilder.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.classfile.impl; + +import java.lang.constant.MethodTypeDesc; +import java.util.function.Consumer; + +import java.lang.classfile.BufWriter; +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeModel; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.CustomAttribute; +import java.lang.classfile.MethodBuilder; +import java.lang.classfile.MethodElement; +import java.lang.classfile.MethodModel; +import java.lang.classfile.WritableElement; +import java.lang.classfile.constantpool.Utf8Entry; + +public final class DirectMethodBuilder + extends AbstractDirectBuilder + implements TerminalMethodBuilder, WritableElement, MethodInfo { + + final Utf8Entry name; + final Utf8Entry desc; + int flags; + int[] parameterSlots; + MethodTypeDesc mDesc; + + public DirectMethodBuilder(SplitConstantPool constantPool, + ClassFileImpl context, + Utf8Entry nameInfo, + Utf8Entry typeInfo, + int flags, + MethodModel original) { + super(constantPool, context); + setOriginal(original); + this.name = nameInfo; + this.desc = typeInfo; + this.flags = flags; + } + + void setFlags(int flags) { + boolean wasStatic = (this.flags & ClassFile.ACC_STATIC) != 0; + boolean isStatic = (flags & ClassFile.ACC_STATIC) != 0; + if (wasStatic != isStatic) + throw new IllegalArgumentException("Cannot change ACC_STATIC flag of method"); + this.flags = flags; + } + + @Override + public Utf8Entry methodName() { + return name; + } + + @Override + public Utf8Entry methodType() { + return desc; + } + + @Override + public MethodTypeDesc methodTypeSymbol() { + if (mDesc == null) { + if (original instanceof MethodInfo mi) { + mDesc = mi.methodTypeSymbol(); + } else { + mDesc = MethodTypeDesc.ofDescriptor(methodType().stringValue()); + } + } + return mDesc; + } + + @Override + public int methodFlags() { + return flags; + } + + @Override + public int parameterSlot(int paramNo) { + if (parameterSlots == null) + parameterSlots = Util.parseParameterSlots(methodFlags(), methodTypeSymbol()); + return parameterSlots[paramNo]; + } + + @Override + public BufferedCodeBuilder bufferedCodeBuilder(CodeModel original) { + return new BufferedCodeBuilder(this, constantPool, context, original); + } + + @Override + public MethodBuilder with(MethodElement element) { + if (element instanceof AbstractElement ae) { + ae.writeTo(this); + } else { + writeAttribute((CustomAttribute)element); + } + return this; + } + + private MethodBuilder withCode(CodeModel original, + Consumer handler) { + var cb = DirectCodeBuilder.build(this, handler, constantPool, context, original); + writeAttribute(cb); + return this; + } + + @Override + public MethodBuilder withCode(Consumer handler) { + return withCode(null, handler); + } + + @Override + public MethodBuilder transformCode(CodeModel code, CodeTransform transform) { + return withCode(code, new Consumer<>() { + @Override + public void accept(CodeBuilder builder) { + builder.transform(code, transform); + } + }); + } + + public DirectMethodBuilder run(Consumer handler) { + handler.accept(this); + return this; + } + + @Override + public void writeTo(BufWriter b) { + BufWriterImpl buf = (BufWriterImpl) b; + buf.writeU2(flags); + buf.writeIndex(name); + buf.writeIndex(desc); + attributes.writeTo(buf); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/EntryMap.class b/tests/test_data/std/jdk/internal/classfile/impl/EntryMap.class new file mode 100644 index 0000000000000000000000000000000000000000..b7cbbc45f17d1ddcadc1226838f7f84d164ab2a5 GIT binary patch literal 3525 zcmbVPZF3Xn6+Mr%vMjN(!C>4V83YI-39y49q>YIZ@Jonjg4D6^kbR+ivEUv%+SztSF&USA2O9kyU*)=&b{Z} z^T_}D;%|2W^x%3B9(euGbokJquzt!oZ*=Ajd$MzAe9Fu?3Jr%X+j3G0-gsivk4A+Z z^+oA?-kdb@M@o~kGp6nI&1KA@V-@U11QjCvRzBZvWSl}NIx|~#qT^=NvZL{*_D1(7 zg78C^Q$q@^@xi*uVW(u-lii8YMl>sI9=0x;wcW)+*>bG&=Jp^qpv8}kIyRwIAvTqr z?zC*jEZIiBGm|&URqPGIx#S_|6sbSwu)?(R17hKjj%V;y@>((l0%y2)RA!#l(T&3- zx;RUd43ImX!t;K-pyLRRDm2x38Z6k8binn0!1z z^y5W8j_F8aV2zREh9d|vrj?gXy@_4{GN|J?PH>@w;N`*vu|IO5P%%3o)?U`}b$o+R zXN)<4IxvtJaF2U|=lLX82)~q(ZT#PQubLg=vLGr%+i#j^dB*?B*6pf7K%(K?l+M6$~*xd7_j2#{s=}ysNXxK3_(=7NZqQI~^}I%zv=&K;ev*5d|_RBNv`=Cfpp zRF6|~#gZ2N)QV$nktvG_XPXy#YTmBnT)ihNdnpipkqRXMSSXDvIl}G)zl>}A@W`{P zQm|U+sYi$C;&5TMlrbs7bUd`8f*n#9+ICi%$1Rm7kViWdW~5MI^Gmg2yG2CN9isxe zZ_0@KrsBD8>KxzexYvgQpGEfm11~hbN0YaqV(WhKF#<9Dy$=w&1OHe{;5OF%Bm7ad z*W~tM%UGXE#ul+T*?u`Tb!8D-lI>b{5nGe(zMM3+OXKgsMZ^|pS;M#Z?1IkcQTBSU z9=+ItK5V5f#BmHARG9-9z+t?^*+KptXI-2?i93=NbST4Nk2pmfiCtRauZO$inB|xk z=Q*lZ=gPRi-W7dKPBk7~;rFXv$6c?J zpJD4IZSFa~W08(j`}^>DZncMRz!$ld3`drbyv5xWUw0$G_Aq-RXd=!woT9H|*n!iC z;S3TKh&_09m496||GMy9*S|J|afvMtcW%P>9`aAtulN^$x9PvUQ&j_9;6+q*WSLt< zV0T4Q?Y?t_z5P;3z_)iC(pohaeyb+<+i%@`@b4P-9cW~GoSU=E6cZaU!8lKnuN-eq zi#|-bxDV3!Ml`#~B!70*JlIwBK*qlBdf?#=E558|NY<}-5Q6tUJnBB$)aSel6n;>n zV~Cq1?E?ZmtexwSD0|(E5_iG;mn_*_SyaOia8FjNG9pktPvM8;-s5sD42khja>e=* zI{y670i{(3glY$b9yvhf#G!gp@oKJcp*|#J;o{!olWGkw&$uLohuoKTE+UOCez$yr z4KB{RzT6U?zDd+$oYBrLqHDora(#76N8|>yg~yWqe;a@Bm%8x>H|u3R&g1~YtkL%- z`rgKJ+QxEV~>Tfgs;7> zd04u2G7cfcvwlS)Zjgvis2sl`5x=G0{Emuu6HhZRDTcQff1u*tqQ-toHTsk5Rf;%! zdBlQ!;+kEgz%5aRZ!<7|b)iJ*D34>F%0()zYrKLK*B!)93D4tRI0Szmy&^3YEqIr? JENSuc{{eA{ygUE^ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/EntryMap.java b/tests/test_data/std/jdk/internal/classfile/impl/EntryMap.java new file mode 100644 index 00000000..4270dbf7 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/EntryMap.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +/** + * An open-chain multimap used to map nonzero hashes to indexes (of either CP + * elements or BSM entries). Code transformed from public domain implementation + * (http://java-performance.info/). + * + * The internal data structure is an array of 2N int elements, where the first + * element is the hash and the second is the mapped index. To look something up + * in the map, provide a hash value and an index to map it to, and invoke + * firstToken(hash). This returns an opaque token that can be provided to + * nextToken(hash, token) to get the next candidate, or to getElementByToken(token) + * or getIndexByToken to get the mapped element or index. + */ +public abstract class EntryMap { + public static final int NO_VALUE = -1; + + /** + * Keys and values + */ + private int[] data; + + /** + * Fill factor, must be between (0 and 1) + */ + private final float fillFactor; + /** + * We will resize a map once it reaches this size + */ + private int resizeThreshold; + /** + * Current map size + */ + private int size; + + /** + * Mask to calculate the original position + */ + private int mask1; + private int mask2; + + public EntryMap(int size, float fillFactor) { + if (fillFactor <= 0 || fillFactor >= 1) + throw new IllegalArgumentException("FillFactor must be in (0, 1)"); + if (size <= 0) + throw new IllegalArgumentException("Size must be positive!"); + + int capacity = arraySize(size, fillFactor); + this.fillFactor = fillFactor; + this.resizeThreshold = (int) (capacity * fillFactor); + this.mask1 = capacity - 1; + this.mask2 = capacity * 2 - 1; + data = new int[capacity * 2]; + } + + protected abstract T fetchElement(int index); + + public int firstToken(int hash) { + if (hash == 0) + throw new IllegalArgumentException("hash must be nonzero"); + + int ix = (hash & mask1) << 1; + int k = data[ix]; + + if (k == 0) + return NO_VALUE; //end of chain already + else if (k == hash) + return ix; + else + return nextToken(hash, ix); + } + + public int nextToken(int hash, int token) { + int ix = token; + while (true) { + ix = (ix + 2) & mask2; // next index + int k = data[ix]; + if (k == 0) + return NO_VALUE; + else if (k == hash) + return ix; + } + } + + public int getIndexByToken(int token) { + return data[token + 1]; + } + + public T getElementByToken(int token) { + return fetchElement(data[token + 1]); + } + + public void put(int hash, int index) { + if (hash == 0) + throw new IllegalArgumentException("hash must be nonzero"); + + int ptr = (hash & mask1) << 1; + int k = data[ptr]; + if (k == 0) { + data[ptr] = hash; + data[ptr + 1] = index; + if (size >= resizeThreshold) + rehash(data.length * 2); //size is set inside + else + ++size; + return; + } + else if (k == hash && data[ptr + 1] == index) { + return; + } + + while (true) { + ptr = (ptr + 2) & mask2; // next index + k = data[ptr]; + if (k == 0) { + data[ptr] = hash; + data[ptr + 1] = index; + if (size >= resizeThreshold) + rehash(data.length * 2); //size is set inside + else + ++size; + return; + } + else if (k == hash && data[ptr + 1] == index) { + return; + } + } + } + + public int size() { + return size; + } + + private void rehash(final int newCapacity) { + resizeThreshold = (int) (newCapacity / 2 * fillFactor); + mask1 = newCapacity / 2 - 1; + mask2 = newCapacity - 1; + + final int oldCapacity = data.length; + final int[] oldData = data; + + data = new int[newCapacity]; + size = 0; + + for (int i = 0; i < oldCapacity; i += 2) { + final int oldHash = oldData[i]; + if (oldHash != 0) + put(oldHash, oldData[i + 1]); + } + } + + public static long nextPowerOfTwo( long x ) { + return 1L << -Long.numberOfLeadingZeros(x - 1); + } + + public static int arraySize( final int expected, final float f ) { + final long s = Math.max( 2, nextPowerOfTwo( (long)Math.ceil( expected / f ) ) ); + if ( s > (1 << 30) ) + throw new IllegalArgumentException("Too large (" + expected + + " expected elements with load factor " + f + ")" ); + return (int)s; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/FieldImpl$1.class b/tests/test_data/std/jdk/internal/classfile/impl/FieldImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..cf8dd4d35737dd6b2e195babe1657c07af58a97e GIT binary patch literal 1182 zcma)*T~8B16o%hv3#H2n6$L-=1F;Bgm6dQ=LV^_{NktO~_tWjPow}VR`=Ph~B@@NO z3*)sv%J}ZK&|YZMO?J-g>^aZ8=ggVke}4P~P=`}M2H8AvHfAs@u-R*UaI}e3V5H}` zo(#jb_LQUh7oKyZmDf7vth6IA8+CP9ddZN+R53LRb139t*_ekdQ0&Q%(($C}IPaQ0 zMKL&+EydoDUP(~v}5B& z+BZ(!H(}gYL9KkA$8CCz)Qpl&^L-U-ucZQuby~4;2Y0Dcx~{q)dt=B>v-o#hy1{*c z)d?a5Dg;eac+v!Nb-$$q78}~Alephh!I^A&Tv=-PuJq1jpp)<6VlFu+f%0@4ly+)7 znzt(I`mOgekbT8gV0fn86j&cra#FSe%i}c}oNTJPaH=~-MsYx)r(>X@%cMiv8*~3p zmG>#zI`!kgRY&Ys_Q7?tZYPyzxekr%`JpzQL3TE(crK9t6zE8u`2xF>&)~HV*rfI3 zMhsgbO>6E%h0z;7WH;Ey#;73mP$AaXFmn*N2T?30my7o;%Xc2D{PTdbecBAIRjGc1 zsC-BM3%@dW$Z?jDfWjk=D+4b)CNp`glqT?m^BKB*F4CEe$uYqm46%jESBUB*Zj7i& z69Zl9(qrVpHMxLwJf+?P;!5;QaJ$#I>Mz{7#PSF?F49f~U!ks~6{!##q-5|6o2lJG WnKsAUUBQcVWdYl?76FMmK7Rqp;vlF1 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/FieldImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/FieldImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..43a4bf8a34ed913637256a26e263b90a06e7b70d GIT binary patch literal 5059 zcmb7H`Fj)B6+KUuJzmDdHipItivzf}WrNsC2m-?DR>U?m1`|TlGM2_hAdeJj1UOxi zE=f!GC0*Pt-D#UHw8g|qniRUFq5JYf|CWCJ+MfGnB#p3aQh%Q{Z|2>1@45G$d*6Gv z{`2B101o0G%?P2+K-fe*8WaZ3CC^7wj%()}D;-Uwt$cnmmA0d)>1;Z>e)&(n? zww$Se;e!ILWa{RUzCL?~k`&4b~dyHgO-;EwX%nB4OwALuqS@ z@Qlo)c2{8o*VlA1ARjZZ;SOmCghWEvjP-b@@KJb}2MhvaZnP;ntRiQ+YQgR(G4&1G2X*QOLWQ>HTGvFs)TsCkswO;t(D32lQ_r z_8T~0vW5;RM3y4^flR?kmX#|k6DP~>WXPppR1@WzD~lxkf{O)$UlG%J^eZGDaC0H( zV5a;a4B^cN-eMw-BMPf)mBN9- zCGNu}Mlh<-lE`Fd4$QDDk7uMhYPwgpAB)HP$D3K!$4tBx50h7uUV*JI!`o$DPjFt)@}(|km^G? zXW~3q#ZB6}Bwt~rP;q_;o~N9AfKBqrrfiB&x_ag zP-tXLr0o*3muOMG0XD{hLhn+j%Dc*jEzNLoQT8+jIYJ0a>}uszI=&8`5HH@TFk2gW zRc+Uadv4u+b&>)m*dfhSEoh4(7lTWQw|)N%K+xEW=c z?iE3QO1*o$1@FfP3_NY(8GMi>UeV=|q)|%Wax*Od>i!+~zZ1=6eAvK8Onej{tJ*wD zA}p)3R({mJL=-$Jum@bmCro@2pW>eC=+B)c+G@XjbOt`NNK-1eMgyN!=&sebbXt9S zHRAIMoAnpH;hml=mGYjR{9w0!lS1;|q^s=dNj_#^mU}}*w}+|)U&5CSe8t39@tk!2 z8i$tJ9AU%b`6=a0ja%sgn@F|KV|t1k%h&M@1K%|9Eqt3BdPRMlr?M$&!^Q$%O%U za!8{etz)j0I6q=#efv90l-B_%9kgl(MQiiUY7&wiRZFE%YcE?6OK*FV-F98=s8)7c z325C!fh=2FGfx#sg>6)}M2B6tTd>uV#}nSx!P5MHm$Olk!H2EH+45ba+jnTOwn~GF zR9IKj8BN*JUPK~UJPI!6csZy{M59!?v~BjO0J|5oVT!J-<{-O`&x6{C%2uQd6!tHr zy>{}ed=edpmW&%Qh zj-As)w)4CgH1gu9@B?nq9dcphZL~vfcKXSSoPP55#%D;*^OXIO9{(849M|J2e}BR+ zPjSAU&wC;-Kt%@TU_@5Up*6C44(*W@;W>1QR0uy688q-Wf-nZqgh4FheP=l~p$k#` zj5FIkO}K_RzKOgbQ+g!WLV6_V>hwtPg*ngTsE;N_8If;~TqBTcXf5ImA7fh>tGex~hb@>5(k&`^&@>lHcq9PG)D>+bqrig7JhPxX7 zz5xEVGJYOR7t>?Z)^oU~9v)@=IGkZh1Wym~-2W<8MIt`1PI(qVUeDvfIovPvx5wiM z3_OHx-Zmt=Ua)(rqtNX~;U!x6IbQbBKToTY>=Of?mBS&-dZ~~Pt^Ah+w2W#l+c zm$OJ9K57}gf?p7(WHF3T@1O>L!w2q?;Q~COfnUe;EKEU@J$VIpYgl|qyae|Y%jLp# z%$$^@duTeS54@zbkbIrIWAq~(KoBV-h~OrESwYa*$?>o7Yd>MP_>_9w=f~t-A0-m1y?vwwOQ8v{ zRhq|cp6?$-LF1Ep-cFwX2EXN~7c1~8ey8hUUm5d0yoOuE`Fm=Wy6~j_;7h%RKl=Wd zsQWiM4P5U17p1(8^C!;z8PD-oFeQ9KZt3`3!^`->sX8y$UsM=76_(%@p~v+cdz6^R w*T&}Yok|6H#X7?l^aLBwOn{tQe86@13r&UaSNu(fLDAj6b0n?L<&%H^100rO*Z=?k literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/FieldImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/FieldImpl.java new file mode 100644 index 00000000..6645ddb9 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/FieldImpl.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +import java.lang.classfile.*; +import java.lang.classfile.constantpool.Utf8Entry; + +public final class FieldImpl + extends AbstractElement + implements FieldModel { + + private final ClassReader reader; + private final int startPos, endPos, attributesPos; + private List> attributes; + + public FieldImpl(ClassReader reader, int startPos, int endPos, int attributesPos) { + this.reader = reader; + this.startPos = startPos; + this.endPos = endPos; + this.attributesPos = attributesPos; + } + + @Override + public AccessFlags flags() { + return AccessFlags.ofField(reader.readU2(startPos)); + } + + @Override + public Optional parent() { + if (reader instanceof ClassReaderImpl cri) + return Optional.of(cri.getContainedClass()); + else + return Optional.empty(); + } + + @Override + public Utf8Entry fieldName() { + return reader.readUtf8Entry(startPos + 2); + } + + @Override + public Utf8Entry fieldType() { + return reader.readUtf8Entry(startPos + 4); + } + + @Override + public List> attributes() { + if (attributes == null) { + attributes = BoundAttribute.readAttributes(this, reader, attributesPos, reader.customAttributes()); + } + return attributes; + } + + @Override + public void writeTo(BufWriter buf) { + if (buf.canWriteDirect(reader)) { + reader.copyBytesTo(buf, startPos, endPos - startPos); + } + else { + buf.writeU2(flags().flagsMask()); + buf.writeIndex(fieldName()); + buf.writeIndex(fieldType()); + buf.writeList(attributes()); + } + } + + // FieldModel + + @Override + public void writeTo(DirectClassBuilder builder) { + if (builder.canWriteDirect(reader)) { + builder.withField(this); + } + else { + builder.withField(fieldName(), fieldType(), new Consumer<>() { + @Override + public void accept(FieldBuilder fb) { + FieldImpl.this.forEachElement(fb); + } + }); + } + } + + @Override + public void forEachElement(Consumer consumer) { + consumer.accept(flags()); + for (Attribute attr : attributes()) { + if (attr instanceof FieldElement e) + consumer.accept(e); + } + } + + @Override + public String toString() { + return String.format("FieldModel[fieldName=%s, fieldType=%s, flags=%d]", + fieldName().stringValue(), fieldType().stringValue(), flags().flagsMask()); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/InterfacesImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/InterfacesImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f5336b919e9c16fd535443ed2206c27b17f7e376 GIT binary patch literal 2797 zcmb7GYggMw5WQ<2!nSxhDG5#UXad9-f@snLsR=1K5NMsy*2HZ}(q=8MK_E+xB&Uae z)t=Kw$T{r~=;?3j>8vCpIi^neU`rb9+_`giW>$aw^X5+g1vFDgphrQkiazu+%p6n? zHN*0RV{uc{P42oi!xWlPZ9Mv-C2b>p@r zIoG%@+%2NYkn)r84Gbf1Bd2g4?u@%t2Eyui_)zrgS>ug+*XHE`xGlQ&Cxa3=3ggU!KA~cS_=A zQ&_ratCW!P351{B$0|O-0)gp4c`?k#lj!gXbBJw3K7}RRRq&~bJeJ#bij?>H_1A2t z&Z)BR#)$@R^SeRG#S!B{!c}Rk;J$*-RIFl6cAxAS-zRE4-L_nhTVBJqP0cUEb<1;T zn|m!@7gW5h-R|c1#H%g&ZY0kGtSi`1@erG`sooXx#FZgU!cppFZZ;|K`L@7eMhZS> zxN;h3)Cmm9lCfuTujvrX{kNKPIi}n@RmiX8Nr-}7C7|J=VTs4hdPO)pyke3iQ?zw% zmbqid=g`>e?Hg2Qv&C*rACZ;ggkp@fLmf3*aBK0xlC6JM{?lb5+LH2QUQ)=_4&zy& zsR4d;3{ULX40niUm)YJq6%3;$uUD#kqGg$wm-(G(r%!1g z8hM5s@eH@l1VzU~$!7DYU(m6cK#@Lr zsD^Nn?jMn5m#zuA4(5Ib%gwxo@+$^^CPNP%)Bg}%L1$+#ZbC&C+w?RRIN(csMNi}! z2KbupRRRwz#gmXFx*Nq#7*L}pxu!4o3kH9pn}i>z-#5Y_-*8Sc4uIs>9Y}xy+>WtLp0G{gTRbHghVQT$!o5HcK9?Eq{R5Yt_DIxY zTxNKK4}oJ$CXgX*ZXM%J0;ShjjEHAQ8(@J{S;S>JK&R+lsuU!V3*wHXWKV?A7X0Y6 xB6o~?jL-`V5njM#F@~YyIld>v9{fQ63A_Lg@%PDAK^1$j$&w=61{`=8{}<673UL4c literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/InterfacesImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/InterfacesImpl.java new file mode 100644 index 00000000..242ec02c --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/InterfacesImpl.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.util.List; +import java.util.stream.Collectors; + +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.Interfaces; + +public final class InterfacesImpl + extends AbstractElement + implements Interfaces { + private final List interfaces; + + public InterfacesImpl(List interfaces) { + this.interfaces = List.copyOf(interfaces); + } + + @Override + public List interfaces() { + return interfaces; + } + + @Override + public void writeTo(DirectClassBuilder builder) { + builder.setInterfaces(interfaces); + } + + @Override + public String toString() { + return String.format("Interfaces[interfaces=%s]", interfaces.stream() + .map(iface -> iface.name().stringValue()) + .collect(Collectors.joining(", "))); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/LabelContext.class b/tests/test_data/std/jdk/internal/classfile/impl/LabelContext.class new file mode 100644 index 0000000000000000000000000000000000000000..0676014ed95f123db31ca223933f82a104ead815 GIT binary patch literal 478 zcmaKpK~BRk5Jmr#l9U3arEDo17Rd%5fL$XYMXCf+Blb>WDhD?~i36OC1qbM%5ECm> zciH&cnm42Q--o}SUjPwqe2fS|k-rOFT2+_Qh|I{QdDBJ-z5g&`BU5FfimTt&$CxlL zKS<|zLthtSF7Yxjf!&k!8 zbn7P7I@5&J5FW-%Z>zS>)DxQ}EZkbX(}&IjVfmu!y|z~6+ctG(RO4eo5JQnAT@yzc zRk>QX+T^PCu_W9NHFa>zfqMkP3I7f-=Cn`Y@rB@H;`9ttr{}m}VuVX~&Tz%*@q3Qz Ee`OUN9%C_iW- zN=!6<_D31-Ot(-97Sm*A=k9%+bMBq(??2yv0$9O|I21%wL^ZS^#xQ=c`^K={fcviL z7?xv}%X_xN4ZHN#F_wzuz&EX6&EX~P1`M$|+qHuQhDa*C6-O)DRKzu0fyU5zU>=%A zC9oZ1qjB4SV@TCHCR>puA@>Ci_0V)Gd}EKHHEjy&Fq|Sc72u5OT|56cM89Ozlv!wxnkZV`qS68 zOA}kM0^4(qGjdK5mL`)feQWK_rneZPqCE_WobB>_rBvkprdf2zlFWIQ>1>(4EzY4a z8oah?-p4L4B4#hcFp(nK{|ksTrI}b>$;yjIYmBBv9;4JG0^8zw|kfHUuwT7(9phFnEDVDWa6#e}$V$MzH2zT=@|9;lI>W!y}IV;Qw#OLH_YIcW35_lAkaB(yLK=kpyUg+BoaufNNGqz z6DaP6RIy!arm?zU`DFqN#2p?8h_VFf*3g4qfpm+1%MxFGVmJ+Jc1a*h zwvkN37fk3R22~7cIEDO<7}dbH-DMVI$@5nYR^>`Q;@`S0Ma658Dn+A&uT&Ie;r>}> z0j)eUckABF!%F#Xd5$tod#s1y1~r+E0w`P5Un(ik)7ERwSa5ifsd%R0)C}L2c6b;M z9@%w))0N#S)P|D%Qxb@Iluq9%U8H;e-X!E(4Gi<~U1Kc_&OR=)7*BmWu;x60QA)YX zK>X1tr9zE`Xu7kg`hPkLBm!@{oc;N~6o@azO*UI|=!7khs(KCIv~F`ocXXtb<%}#O z&T$fA5GX)F4#Uv6Kh4>XVT3jZjr)uoS+1Qt<;d{G8Cth##ki)58xX|<@1VY-6@$+I zZlZyhaTJjx>RDRZ)@w!_rA5Ccs^I;3TnI7e=_hzMkn2;no+JGlUAfV9q(35YKevIt zm%LM&5i-OEd8o8{h`*0}8AbA^f5>=@dlj*sJ1WWWlYxt2Af2mx*in27^#wOA-kr_E zu?SK}$XDPJE{D!jd@VCi4omO%=x--3zn8#Oidu>!o&2425?6RDW0x=km;AxW>}7isFS>L)7mR3UAP*lv-M5rIy<|R-Zwv y|NJU>x8%&y5B&Zlaf0POi6dMG`P-H>&1RTrHi48hiP(3f#W(C{*vTfv>%Rcn_+Qfi literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/LineNumberImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/LineNumberImpl.java new file mode 100644 index 00000000..4fc4a342 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/LineNumberImpl.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.instruction.LineNumber; + +public final class LineNumberImpl + extends AbstractElement + implements LineNumber { + private static final int INTERN_LIMIT = 1000; + private static final LineNumber[] internCache = new LineNumber[INTERN_LIMIT]; + static { + for (int i=0; i`oKogq2Pqzb1-OiHz&{uzeiT)K6 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 attributes; + private int[] parameterSlots; + private MethodTypeDesc mDesc; + + public MethodImpl(ClassReader reader, int startPos, int endPos, int attrStart) { + this.reader = reader; + this.startPos = startPos; + this.endPos = endPos; + this.attributesPos = attrStart; + } + + @Override + public AccessFlags flags() { + return AccessFlags.ofMethod(reader.readU2(startPos)); + } + + @Override + public Optional parent() { + if (reader instanceof ClassReaderImpl cri) + return Optional.of(cri.getContainedClass()); + else + return Optional.empty(); + } + + @Override + public Utf8Entry methodName() { + return reader.readUtf8Entry(startPos + 2); + } + + @Override + public Utf8Entry methodType() { + return reader.readUtf8Entry(startPos + 4); + } + + @Override + public MethodTypeDesc methodTypeSymbol() { + if (mDesc == null) { + mDesc = MethodTypeDesc.ofDescriptor(methodType().stringValue()); + } + return mDesc; + } + + @Override + public int methodFlags() { + return reader.readU2(startPos); + } + + @Override + public int parameterSlot(int paramNo) { + if (parameterSlots == null) + parameterSlots = Util.parseParameterSlots(methodFlags(), methodTypeSymbol()); + return parameterSlots[paramNo]; + } + + @Override + public List> attributes() { + if (attributes == null) { + attributes = BoundAttribute.readAttributes(this, reader, attributesPos, reader.customAttributes()); + } + return attributes; + } + + @Override + public void writeTo(BufWriter b) { + BufWriterImpl buf = (BufWriterImpl) b; + if (buf.canWriteDirect(reader)) { + reader.copyBytesTo(buf, startPos, endPos - startPos); + } + else { + buf.writeU2(flags().flagsMask()); + buf.writeIndex(methodName()); + buf.writeIndex(methodType()); + buf.writeList(attributes()); + } + } + + // MethodModel + + @Override + public Optional code() { + return findAttribute(Attributes.code()).map(a -> (CodeModel) a); + } + + @Override + public void forEachElement(Consumer consumer) { + consumer.accept(flags()); + for (Attribute attr : attributes()) { + if (attr instanceof MethodElement e) + consumer.accept(e); + } + } + + @Override + public void writeTo(DirectClassBuilder builder) { + if (builder.canWriteDirect(reader)) { + builder.withMethod(this); + } + else { + builder.withMethod(methodName(), methodType(), methodFlags(), + new Consumer<>() { + @Override + public void accept(MethodBuilder mb) { + MethodImpl.this.forEachElement(mb); + } + }); + } + } + + @Override + public String toString() { + return String.format("MethodModel[methodName=%s, methodType=%s, flags=%d]", + methodName().stringValue(), methodType().stringValue(), flags().flagsMask()); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/MethodInfo.class b/tests/test_data/std/jdk/internal/classfile/impl/MethodInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..cf4b528da3d235d335479d749d7e606cd8d93792 GIT binary patch literal 723 zcma)4O>fgc5Pe&RBu$()1RBamX$k^t4)qnO6_?OTmXdOCsl;*PY|>5FyOzDJ$c6vG zf8dS)3GV$-h;d>y<;G!m=IzeBnSHa@e}4P|(8u!{));nX{E7#P>uC@xp63&(M9?q1 zWAd7);7$!y7d6xwUe3lBfz(!HnyXv!GD%f16!zSVLp?DJ&13cD~>+JBDK=!I$VaXHnzugPwL!q9gE(QtATZFxY$ISp?WB_v~L-mw9V!RH`%B2 zl(O4PsscpwWMmY>i+>4Ano^b`@SVtG;&C$(3wb57NEvFX(l=uw+#Eh2b9V17x>K+r@(grawXv4BKQG9+DryArIJo{T&XeR{#73 zt)E!`*lB)4>$mfj?i@U#eS<9U3NAc!;o~tOcbSVP*dg?k7O{1y@Gg1;81`si!?VA~ CRJdIL literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/MethodInfo.java b/tests/test_data/std/jdk/internal/classfile/impl/MethodInfo.java new file mode 100644 index 00000000..0dd81776 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/MethodInfo.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.constant.MethodTypeDesc; +import java.lang.classfile.constantpool.Utf8Entry; + +import static java.lang.classfile.ClassFile.ACC_STATIC; + +public interface MethodInfo { + Utf8Entry methodName(); + Utf8Entry methodType(); + MethodTypeDesc methodTypeSymbol(); + int methodFlags(); + + default int receiverSlot() { + if ((methodFlags() & ACC_STATIC) != 0) + throw new IllegalStateException("not an instance method"); + return 0; + } + + int parameterSlot(int paramNo); +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/ModuleAttributeBuilderImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..528f5f939559b719542c2e89a6180c479db1be16 GIT binary patch literal 8025 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 requires = new LinkedHashSet<>(); + private final Set exports = new LinkedHashSet<>(); + private final Set opens = new LinkedHashSet<>(); + private final Set uses = new LinkedHashSet<>(); + private final Set provides = new LinkedHashSet<>(); + + public ModuleAttributeBuilderImpl(ModuleEntry moduleName) { + this.moduleEntry = moduleName; + this.moduleFlags = 0; + } + + public ModuleAttributeBuilderImpl(ModuleDesc moduleName) { + this(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(moduleName.name()))); + } + + @Override + public ModuleAttribute build() { + return new UnboundAttribute.UnboundModuleAttribute(moduleEntry, moduleFlags, moduleVersion, + requires, exports, opens, uses, provides); + } + + @Override + public ModuleAttributeBuilder moduleName(ModuleDesc moduleName) { + Objects.requireNonNull(moduleName); + moduleEntry = TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(moduleName.name())); + return this; + } + + @Override + public ModuleAttributeBuilder moduleFlags(int flags) { + this.moduleFlags = flags; + return this; + } + + @Override + public ModuleAttributeBuilder moduleVersion(String version) { + moduleVersion = version == null ? null : TemporaryConstantPool.INSTANCE.utf8Entry(version); + return this; + } + + @Override + public ModuleAttributeBuilder requires(ModuleDesc module, int flags, String version) { + Objects.requireNonNull(module); + return requires(ModuleRequireInfo.of(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(module.name())), flags, version == null ? null : TemporaryConstantPool.INSTANCE.utf8Entry(version))); + } + + @Override + public ModuleAttributeBuilder requires(ModuleRequireInfo requires) { + Objects.requireNonNull(requires); + this.requires.add(requires); + return this; + } + + @Override + public ModuleAttributeBuilder exports(PackageDesc pkge, int flags, ModuleDesc... exportsToModules) { + Objects.requireNonNull(pkge); + var exportsTo = new ArrayList(exportsToModules.length); + for (var e : exportsToModules) + exportsTo.add(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(e.name()))); + return exports(ModuleExportInfo.of(TemporaryConstantPool.INSTANCE.packageEntry(TemporaryConstantPool.INSTANCE.utf8Entry(pkge.internalName())), flags, exportsTo)); + } + + @Override + public ModuleAttributeBuilder exports(ModuleExportInfo exports) { + Objects.requireNonNull(exports); + this.exports.add(exports); + return this; + } + + @Override + public ModuleAttributeBuilder opens(PackageDesc pkge, int flags, ModuleDesc... opensToModules) { + Objects.requireNonNull(pkge); + var opensTo = new ArrayList(opensToModules.length); + for (var e : opensToModules) + opensTo.add(TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(e.name()))); + return opens(ModuleOpenInfo.of(TemporaryConstantPool.INSTANCE.packageEntry(TemporaryConstantPool.INSTANCE.utf8Entry(pkge.internalName())), flags, opensTo)); + } + + @Override + public ModuleAttributeBuilder opens(ModuleOpenInfo opens) { + Objects.requireNonNull(opens); + this.opens.add(opens); + return this; + } + + @Override + public ModuleAttributeBuilder uses(ClassDesc service) { + Objects.requireNonNull(service); + return uses(TemporaryConstantPool.INSTANCE.classEntry(service)); + } + + @Override + public ModuleAttributeBuilder uses(ClassEntry uses) { + Objects.requireNonNull(uses); + this.uses.add(uses); + return this; + } + + @Override + public ModuleAttributeBuilder provides(ClassDesc service, ClassDesc... implClasses) { + Objects.requireNonNull(service); + var impls = new ArrayList(implClasses.length); + for (var seq : implClasses) + impls.add(TemporaryConstantPool.INSTANCE.classEntry(seq)); + return provides(ModuleProvideInfo.of(TemporaryConstantPool.INSTANCE.classEntry(service), impls)); + } + + @Override + public ModuleAttributeBuilder provides(ModuleProvideInfo provides) { + Objects.requireNonNull(provides); + this.provides.add(provides); + return this; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/NonterminalCodeBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/NonterminalCodeBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..3f6341ca0ae37626f541f6b2accf4ba557a01425 GIT binary patch literal 2243 zcmb7F-%}e^7(F*6YzRwfX{DtU3YE4HC|i)y%2Ha1)J7AECbo2ZakII?!m=AT8_<8i zf5iuV&>1_mbw+*m-|^jg?j|&g$uJ|s{k7lsoqO*2?)~!DKd*lWki&Kc3G`@4>PVqi z;Ow4tXc?~M?HErgd(sXCdRHCK3D*RAre~h^A&ou_86Ex51s3wIE37m`k z8=>R2*wqEj1oG>K6G-m1*>GKf8`Ck^<{`|P&QC);{{3ecjV)`T<9iug#APMvs6aN3R|*5i+c9Hw%DaJoWK~>gHq{-| zF^;PO>0|8#77C}yT<+A^)G#Sv{LiRhD^d39*j_!4P_sC4G?h0IOXR>XN z-9&+@cpAIu?#0fTaDetlgBFZB(Ax}tuiIQ z5!mt(pSHkgcSiF{L4osI>NIw zAB)Jd=CFXR`+ist1FKe);jUk;5B8#%!6u$)*iz5^Q-N#kWCsl|bPlA^eEe@?sq1&~ zd^_Huzb}m@_qqC8 z{Zeq;&c1}m&c1+_oqhf*2A&mr*5<}u<2>*K&A7~#P!s-5u?e=t-*EA{5HB(E$K0Pt zuOvs3zu?OE=;vx;B{h(xk^Nol~lk&L``i;uNDoVDkr}vga`Ci()25Y(O0;U z=zv&`AcmW6Z%@*XhxmXXLRHxo*nj9`1%4uQoQ~O*4r?mCx*TY}6X9VOg!O2b99gj5 scIUF#iL}uLNo7zm-oPV{y_|i7JU-z(L)-$_X-qJ;&2 cb.terminal; + case TerminalCodeBuilder cb -> cb; + }; + } + + @Override + public int receiverSlot() { + return terminal.receiverSlot(); + } + + @Override + public int parameterSlot(int paramNo) { + return terminal.parameterSlot(paramNo); + } + + @Override + public ConstantPoolBuilder constantPool() { + return terminal.constantPool(); + } + + @Override + public Optional original() { + return terminal.original(); + } + + @Override + public Label newLabel() { + return terminal.newLabel(); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/RawBytecodeHelper.class b/tests/test_data/std/jdk/internal/classfile/impl/RawBytecodeHelper.class new file mode 100644 index 0000000000000000000000000000000000000000..5c1cbe2ce45eee3a97324658598d9779fc92d6ff GIT binary patch literal 4398 zcmb7{33yc1703T~)+9{GOhPa#AYy>93`ry^BoGoIM24Uw1Ob&yW+r69Fi9s9S*p;A zMOt?el}f3Y+Ek>q3PfwgZnU-5?wj3LYxjN87L4bA<}pkGKfmVt-tXOa-g*Cf?s?~) zH+k`mXP*bqgoqn9gYw?s4MBe_7~kLz#exF^-O*UY-^9@p8RftMryDL0+{iNUo^f8$ z)f)*V4P156cr>}dz&>qyM>cXW#tn}Lxfp9Ot2eySAB`s?iFh!UAs^k;AM>vaZf@L~ zjD-5ak)@GXe0O*IOkLkrqSRM=azVqK2vF*;lWJIl6l0Qa&P24zXx*| zpF0uU+$xcCDb*g-;1aO~7PmIHFKsiht!w0sS`RM8WuhG&SRD;VWa(>Zp69`QUAkyA zNiL~d@4*6w;S9#28{)Jyc(90;Tn#K7*|Mry^3OX>9$di~a?*FI?7--#M9>llEN)&D zkf)mZ;seQGJlPS94Myyv@+Y+r9cWATB_guUzCd3n7)vc|t(+K#L0%vlkF*YM>WU=V zgIzJP35{*3;k*HZIEpf?lW>TxgUKfg4dnKo>Z!i&xaEBR;KW8V*X1$_H-i||dY8HyI z1o<#%mMa^UN>NLR$T*+dOwNWoLeH`b^ek1ZXDJOmOXbMfi)^&uO7UMNSIwej?iMMqKZpSbj_QPVeBOr9Chabyj>`8f}RW( z`8!Z2LDWkw7N7tNQHlngXM9QvE72x?qN@3lmxgw%vSwT&KForz@~BL46lDkBA_+|y zq5CXJD+zfG)Rb0WY1Uh-$QHfq(h*ENI}Obl;bo`8%huOOsSa5}DxdRYaSYEZQhAkx zqjLlob)K!bEF(IvrD)iU-Xf%mvjtYXO-QTXCZy@-gw%H4kfhmIA=OEZY5g%vr&m_# z!{|9xvpPd5KfSnX(u-SU736=%QaeZIhCa>yAjMjldK%M z2dtOU@66E4N$cfcjTANCp>+1tLhX6-4&Aa#NBI5$ZrFFkyg*y9qO{JkoN^l==LgH=lNkQ^uE zn8GO>ot#99-8PI73E;F0%S-cD&bXzC;iLa;#^Vd(6Kj5FP!Ck zBM8^MHfOVA)<~@~Q$yllx zJ|g=G2unkbpa|Wv;WwZfJ@Q$O%Gb45+T2EIj+>;}#HGFTV>c4mivjGzAdX-Qj$sVYTBbUrOFXbn*PQ>-}letrOovc}_vWv_CZT!;a%wDPgeAx%As~UJuq16~ywYT^r zip(3RHO7p}ymmKojO=e(Poct?*I;ij6C6{=%eLq|y*WfQ)dh;>CCuF?eU7ikDW$Y< z7;f2njof>gAESdA&7jzd&g#SCnz-?TY3;d|_Ly|zTzFy?dh?MPT)y*0{xjPDp}}~L%X>YFF)vT-sLlRE^Ce5(Z0qZhf@xh z9Bw(XyvPfC1Ea9`I zL>W;|Oduu_lZXq6$;3s(6yjo{f|yE7Bc>CT#0+94F^iZ@_=!106;Vyp5SI{hiCT^5 zQsrgJ%a!w#^XXDY)DsJcg+v3fh-f65h%1Q2#1f*JSW2`IR}#yJ0I{5CB~}nu5myr{ zi8i90SVeRYtBGrfHN;wC9dRvj9dSLep6DckL>Cbv!bF7VCN>Z~M3m?yHWD#n6A>r+ zh<@T7M1mL~lEff!1F@OdLTn|r5$_~!ByJ+M6FUSxyi56R<;}{S%3Hi4-hPi>>{8yU z+^u}C@_owNl(#GIP~NG$OL@2Q9_78tJ<9u(dzJSqA5cE1+$YuR!~2yFDfcTspgf@b zpz>kmLFFULA?1gZk19W`99Dir`54Q}heLMqaphs1_@l~?DW6b&T=}H(DSh~e@~HBd zazy#G@)_kPvZ(y5@{?+LPPV2G$94R?s(niNX|;St`B}AmPI*G3`n;P@eL?SjQTc*u zeo6VF`g~dKFDbvG{HpS6%C9TGq5P)uTgq=MzoY!F@_WjcmETwXK>0)Ek2I$9(_{Wt3WTOI#S`FrIb)aQ?S_fIUt$a=Sy7E8D|0+)^PbuF}j@sIfpo;%dn2i5YDDHXFik0>K$L Ax&QzG literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/RawBytecodeHelper.java b/tests/test_data/std/jdk/internal/classfile/impl/RawBytecodeHelper.java new file mode 100644 index 00000000..3e5d6624 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/RawBytecodeHelper.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.nio.ByteBuffer; +import static java.lang.classfile.ClassFile.ASTORE_3; +import static java.lang.classfile.ClassFile.ISTORE; +import static java.lang.classfile.ClassFile.LOOKUPSWITCH; +import static java.lang.classfile.ClassFile.TABLESWITCH; +import static java.lang.classfile.ClassFile.WIDE; + +public final class RawBytecodeHelper { + + public static final int ILLEGAL = -1; + + private static final byte[] LENGTHS = new byte[] { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, 3, 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 2 | (4 << 4), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 | (6 << 4), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2 | (4 << 4), 0, 0, 1, 1, 1, + 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3, 5, 5, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 4, 4, 4, 2, 4, 3, 3, 0, 0, 1, 3, 2, 3, 3, 3, 1, 2, 1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + public static boolean isStoreIntoLocal(int code) { + return (ISTORE <= code && code <= ASTORE_3); + } + + public static int align(int n) { + return (n + 3) & ~3; + } + + private final ByteBuffer bytecode; + public int bci, nextBci, endBci; + public int rawCode; + public boolean isWide; + + public RawBytecodeHelper(ByteBuffer bytecode) { + this.bytecode = bytecode; + this.bci = 0; + this.nextBci = 0; + this.endBci = bytecode.capacity(); + } + + public boolean isLastBytecode() { + return nextBci >= endBci; + } + + public int getShort(int bci) { + return bytecode.getShort(bci); + } + + public int dest() { + return bci + getShort(bci + 1); + } + + public int getInt(int bci) { + return bytecode.getInt(bci); + } + + public int destW() { + return bci + getInt(bci + 1); + } + + public int getIndexU1() { + return bytecode.get(bci + 1) & 0xff; + } + + public int getU1(int bci) { + return bytecode.get(bci) & 0xff; + } + + public int rawNext(int jumpTo) { + this.nextBci = jumpTo; + return rawNext(); + } + + public int rawNext() { + bci = nextBci; + int code = bytecode.get(bci) & 0xff; + int len = LENGTHS[code] & 0xf; + if (len > 0 && (bci <= endBci - len)) { + isWide = false; + nextBci += len; + if (nextBci <= bci) { + code = ILLEGAL; + } + rawCode = code; + return code; + } else { + len = switch (bytecode.get(bci) & 0xff) { + case WIDE -> { + if (bci + 1 >= endBci) { + yield -1; + } + yield LENGTHS[bytecode.get(bci + 1) & 0xff] >> 4; + } + case TABLESWITCH -> { + int aligned_bci = align(bci + 1); + if (aligned_bci + 3 * 4 >= endBci) { + yield -1; + } + int lo = bytecode.getInt(aligned_bci + 1 * 4); + int hi = bytecode.getInt(aligned_bci + 2 * 4); + int l = aligned_bci - bci + (3 + hi - lo + 1) * 4; + if (l > 0) yield l; else yield -1; + } + case LOOKUPSWITCH -> { + int aligned_bci = align(bci + 1); + if (aligned_bci + 2 * 4 >= endBci) { + yield -1; + } + int npairs = bytecode.getInt(aligned_bci + 4); + int l = aligned_bci - bci + (2 + 2 * npairs) * 4; + if (l > 0) yield l; else yield -1; + } + default -> + 0; + }; + if (len <= 0 || (bci > endBci - len) || (bci - len >= nextBci)) { + code = ILLEGAL; + } else { + nextBci += len; + isWide = false; + if (code == WIDE) { + if (bci + 1 >= endBci) { + code = ILLEGAL; + } else { + code = bytecode.get(bci + 1) & 0xff; + isWide = true; + } + } + } + rawCode = code; + return code; + } + } + + public int getIndex() { + return (isWide) ? getIndexU2Raw(bci + 2) : getIndexU1(); + } + + public int getIndexU2() { + return getIndexU2Raw(bci + 1); + } + + public int getIndexU2Raw(int bci) { + return bytecode.getShort(bci) & 0xffff; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$1.class b/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..0e0ce8c582399504cc86f10b12e7b50ab7e93ece GIT binary patch literal 1080 zcmbtTZBNrs6n^g3t!x$2uzG{`!6fpoWJ3Q@7&gk4!|f}& zdsM&x3MPscuEAnh?s&&l8N@;b-2a22Jn8yeFmczdV*nS zTLz+;oE!H}GA#Xj1&MQ0MDdF-BKlS%2!yKXo)nRZC5DB5j29K{_rQ6pnpkF- zzVs;NuGiNlsthZa9zOSbJ_2;PHw+BJe~m+Fmil*!CXJOQbO&pVEVnUDa)wX`S<-;= zH?XrG#V;^F>v!-ghK=2iFkYr`oM0}6pQz#mjA0x%FoAh2lFZ@`dB|%&YzDKWXK3A} zWx+Tw>BNrSU|=r&HV>Pmfd$&{rIrPhNzRe2g8Nv>7qCj&1Ckli)}BogXL?ElzX9ww BB1r%M literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$ArrayTypeSigImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$ArrayTypeSigImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..2982b1fd08c228745c889ae6a27b700c8aadb882 GIT binary patch literal 2406 zcmbtWYg5}s6g_JjOEw}V4hf}sQb=k$50$p*%j5+##f>2;rnH2<7JG{YvZP9KX7YbJ z(=Ywd%rr11GyMVmQEl%^vMtvR&4dqLX|L`*_w3obcm3DjhkpWC#1B~{kW`S;FoHD0 z_%46Kb(32=`kJWQZi68`Z&-$Zn;}^!Ze*Y$qadqc6dFT$x3Q-imM>h3n|j^kp7*0+ z3f*Wqrd~64Ebg~m;Z2i{!js7<3$rjp&p|F^kIz zu4s501%~rI+C!vZ$ax*jI}|4hgWv(Nl7_1iQuXc7H%|p|T^esNd_g2%e`m`>QcCo9 zG|b^$O4;OIbJ1?l=H5MKqKd?QU&Bp&KpKmm+T8RQ){ci7+n|TryQ1!wi;oq2#85g? z{=N!lNQEoRRSiq5wp-i6UFX{-tvO${>)hPnt|8}J#^2)}7J9&wkq z1RYC)%-8LfV_U-VyJv=By00vT)KZyYtmgCj-U@djigf-fvebvkL+8boE9(gqDMzQg zX1CqCxKDk7;Z&DH&=hV+e=3Mo;rYw9=PUSJs{G2OM|<9BQ{xM^?R&nB)*uYoRYkK_Mw&fcwp@-{;Fc~u2oiq&3;!+sa6MIkS zq2n^Q8m91OtG2z@cFHkXqSg?zM1iu|EeWsg8jf$f@sLH?R^x^UV`~s3p1toBc6URo zSe9@DNI}IhKG>DDxJkh`43~SV9I;9T-!WV`+LiVzl!O|AN;eO~hcxEpWkTmTFMB^d zRkBk%r!ODVY(?Hs^vsnGz)EMILn&Q*j+9jd~b6`X&a}iIgPn>g*tdpG@Cfb) zEBy@1!Lxz~^gKa4!?FyEvKrXvYNR4jsVE=f5fu#RKSGk`6>MUPig^}~(-~~xTYQhH Fe*s(EM5_P* literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$BaseTypeSigImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$BaseTypeSigImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..bad091802af965b766b10e024fb478da6d5954be GIT binary patch literal 1962 zcmbtUT~pIQ6g>;HDQ&P&R0L5JLEHKfzdtB~w5U`If;h~mPuq5dK$_GfWyb&HgU%?< z;EX@OKjVY%j(3x^jZhg!9@^b|bMM)6&%L|ff9-w)P{2wYUFcTOqauPRL;oh<=9sme~hNJ2IDY+EM zd0NJfF)S0E|JJ1gaS!~gigBDHA{*SwZN} z42dLzl8j<5jy&kX&8v8bM+{?au6Dz8^_tLp&Os(aZ@CG^@G)GrZf;v!Lh}O`xLGxX zGf}dvtwuc;lE4=(>EmG%*;h89N0 zjncn_ouhDiT`}|(eJ{Ttnd;v`D*Fk_4vz0&_yc_kpYhW>L*h|NaK?aqC O7x6UOixQTwjN#uWZsT?U literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$ClassSignatureImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$ClassSignatureImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..eec9d901f11f5dfc9890acc6f219a871348b0b1e GIT binary patch literal 3531 zcmbtXTUXRp6#mW(k^zIjpeVH}S}ZUFOzpi6q6M|k&VUNVR(lJ>5duRpCK;=3|44s9 zedt=PYgJo)=;~7+`ZM}7x>hgWNixX{kF&_@*5xq&2kY zIDl4xt~KMHQK%Z$O5ujA*v_&*>$qu|-h@DUXn3&=8MJ9=*KrWKz=gHt^@3@6(y@$c zp;9$m_l{YW1#_cTEzFxMmf_VM>CW(VU`l z$#lJ-lNRQWZkSTOQ(1c$MK?u6FN@f zl(HTnvRiZloo*wDK&Qarp{naL!ia-$;sH~meyp&^J9NY$J;8m8P5)4$?`CqSHz;gJVV`2Rd17* zqSAjs#{@3YDBWJ2vX`a6 zSL0OTWDB%KM@gW#sqn{}RL2@3fr04c6eozq#B)mfo;1$7QZN_RZQM|Hv7gYe$$D{k zk+l^-*I6*0NV!V_eNBcFU5F@l%zH*INm^q1N1dfDZ z`aLNsQvqQsFycZDKarT|HU4Hh=^!H3XuX+|A&oya}|=+jXZR zuX5CK;zWnXpR;2saCVtl>3Y+)%kJ3PnB-lPw(Yr|W7LA0aWi0RFM5e#RorIC2DEJ^ zWhc8Ze;xdFcecW8#~Ri(RCR2Cz@CahaO#$4ZpcCaMrfa{VyWShz@uh7P3xY$E(-zU zv|%k*r8`iv?e%&sY$?s7s0r;*P=Rz=x)sN)an3Z0_}OeGgyZb?Rwd2W6Ky>zDSgJW zq~oiUJm*<|7XhL!IT|?SPQ;0*M3=hyq> zZQ*)2_cKH;{}@_scqF_4JR_3LEg4U13Z;18jL<=juue!<~Vo|}%RctPL^ z`fu{3`*)0~~T*u3=hS_ap5m&v`m{gHfd^Q4V9y;0orkKnFi0^$=2jV^G6s4WoadAKmH-6FPs6 ztBP66J;OVIGMn0xPz4TILgn4Oj4W;=J`Q}pC-F(#48_N3Orep<<)7iw|H%jVWFkB> z_y`|UgJ9&hD6c>$`0v001;S2I90=6}MR=QHo%n>$%}P4xH5)be-`u+onU!i0G literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$ClassTypeSigImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$ClassTypeSigImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..60c856b00565f101db5efa9ac395ddc68561317a GIT binary patch literal 5345 zcmb_g340UQ6+O?AHIh8WvRF-60tm2W8-+HcU^#4t6j9p{%o3I^V`;DlWQ{T!v2;t< zbZ;qLXh_?1r+W(tCO{kL-ll8XrY+rmN4|XdXwRD&Nh9oFr&LConKyU8=iYZ8&)&T9 z41hlTJBkJb6a-Z?A|wzyq8-yxd95&#+NEbrD<=@@H428kULerku{VM+A_}4^nxG1# zkK~S~jDoFO1udV-=CxAku#wkO##k|*8Zt%-nq9W^QihL-KKXX{$)e76xgZcR%jA?x z0<-!Z&1Kujr*;%=!=%8p)HXv!3t}X8qz`IiB#yhpj+sNYWfVpn(zuG5m?aRlDRPrF zQldXTvHeELPKPl^K=em34{ZwOtGEjbC~%^3YBWkaX}n&r9p4W~o<%Aa<8D5W=vhFrY?JX1 z+omfxjO`3!x(WRlP%x-shlI(D8cZaZ1QesRb*yNglyncO*o7g=FbHbRHZAF$r`CaW z##^VUyG9^msJ%V5SLUIHuw_PB3N1CzAA4K;^W*s-9ZAO-!kW#qnmmMZsHDyiGQT z4X-F%li96st1#HIrSXrbcn99eIv>j!5 zo-kx{$LEVk74-s}T~q3|_FkWPlR?;#U%|urw7@!_5ZQaD65!Q9+Tr!ON1X*}p9OUt z#i4R$g^s=Kxo(PE`i+7cr;%2Rg!Y^DBc}K2 z*8RLXrV4DSw6{8lO%=6UvOuMEVjK)|#-6Y^mE2l3*rs~3d2fD?4w+>ut3SX2onvFQ zK%MD)l`L&i59%d*n<+<|P-Xs)Z8lB2WLsL%1z$K+lEo4Ck=w zz@K)Qz z)SpqKaLhcar(CPIX@y)~FD3d-^JuyFvc>N}p^i}oGkws9vkFjrOCCd?md_7y`b*RN zUq$gOey!j)Dt?RK2`rvyzAMNJsvc*2>tHX z1;dSE-PTww4mDFK=$0c=XDVXOozzXF$@89qKME|Yg~369b6TuIQ9$)`5fGA};NYD% zs}UTNj7`znB)~vcL8svFb+hs$zElvQ;GY7EYSv9g%A#=LgVj8kHgMBkf*|7ZD9roE zI1)GDET4H^<$YWpMyuT9XC*H|Bs(ucNp@XCbF%v) zTF-MmfY0+cL>>qgPw+nJ(&G#GBA>|V>6dp>bAz)cbqDYz-p}z?nrIuPaD65o=esZS zzBxc%^Fc$Z||;J!*aME}{-9e*#^=-@!beLm8gW?s77H{YjdH@|x^ zo7!3t5OFk%nOG=hp-0TdLt-utig`R`wZRngaZKEWGhzWNX(4WiMck?ui>SC;w2Gzt zTPBu^gy<40L`tj_>qLixm-R%?4W3WGimws1XE@TG!`GQqlMU({_$Do2ay>K!#7@R8 zM#m501$^5<(|2g)8Z^Iz9tB+sZ=#(S1#1=TxrrqT4)LEzL|&5r*)SFfy@;7FfWHkd z5;d*zRPEx3B|~c|N=aV9`vB>C!vt*0IwFZ@O)DqudnRH3AZXfj*iYfR9(ym9$&7}R zomcSDm*aO!C0s47Fuq4arQJ<9PkvdjDd!nzlqGOGFB&~DZeO@Sww7uz{6d|5i` z>q~grxt=EYfdnyB-viwaSl9n>g_QFs`p5i^;VOPfX<_^j*I36t!teQZJ0TOsY5ajj zw*=4OPoW47@%m?8$9VTVuSL=!7UubN41d|!#*^Z6_$$}1^8MdGlAp9YeY^V@?G`NfX%OJk01U+Ocb~9c>DBsMv{J0@3v=N6|7C?J!!RO{}w2ovs4OMjY}?pUWDl zDcwrcVh{EzXjich`vtb;JyEoeT56e$o~CDZb@s0eSBDN9RB%YeVRX{a#by-<8#K7) zn3h0mrw`*=eZZ$D>JUXtLAQz?91&>BBjmOSC^MQptUsX1866Xn<2e;aaZDhTcF8R{ zY}Xf;CujAflTdJ6V0T`@GA^n^FHWd<0WS(P*ttmZEFn;g>QP+-o|M*02=w@dcTe@# zSGUz^6@5}o#jr2TXPk!$&dLx7(xHru9is)|Scfw>A${1d;=GhP?3mucP0X~5lK6_i zDCOEz$|RO+k&p)rsCX5x@l-lwrr(^>1^PFC)_{Z_QZbCnj63~aR!cEQ$2JXIkOY26 zbWJFDUEn}DgO^kerfiVO0*R6gJ5_*P)@QjCP4qEN`Zmg4;Bgn==*9qCo~wRv=8Iej zh_BO%<*Rgi*EsXdb9%#|k=BQ^^OL$YDhnm^cF;^}sd3FRakS*zke2Z+$B6aC#YW4P85e zJI#&Vvm56xc7(vb9K?#=5a`YA31nYGOjo$t5i@Hg^^0slcq0cz!tFnfNDHw(4(qma z$+YRV>Rg8tIcJ)V?O0mI3t2l1F83C2Yu4B`rOb((R5x)11p@ z3M+R~x$kH!6w?cxCabr11;ps(}Q4n|PKsv2kE~L&H)9i5s z-tZbfweap#@QJ|TykSp*9PPQ;%HpT*15Mpb| zUYFymybCKZ!a1AKU_Qz@n@_Ga$$m1RkD-R+DvYBN*SPvMd8_!{5&a1w8e4=C?OsHE zv}X~KXj^CzEl;>wi8uJJCMU!gu5*0cN??S;aDE%JAS8|CC0yY^dlMP=yB+uVJ;snJt^%bsKvsa_{I^JHqAm}a&tcfeVgdK@ j03VRPpLk*ZZhnY1{x|gEqv{%b%F`&w0+d=as+zIrs~}GS)|t!x;l3Ch{l?_Jn33(SBBwp$5ocI z-*K%CXWNreH&9`d*UFRMJ8Ci5*0jLHZ;orXWnecw+iAp=k$G0ELK<+E{0nsj0kI8x5K23p(*?{z7Dq zM?z{&;B__+j`z~vQ&u9lB0bwxVWs8!d)-bWlasW4Gn`aW503{bYzIzu(|Ivu|M3=iXrKHCZ`)%3m!GF^|tk&m^Mw92MTE z6hrenDGi>(Rnny#*_s7Ra1nh$fEm*BJhiA%KOi5kNFKFdCL*bY3GSFLk5Rt}{BbJv zX;f471scmyr&ymoz|?=~UrJc=Ll*dk^ zoX55JrPpD_=MCKCd5(T2Sxs{KRm|fezz8#c3%BtN?vZzs=_}#}?(@lu{CDYxLWwo8 Yh=)9XB-Ok>g`dc8@xF>j_ytq{0$GK1+yDRo literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$TypeParamImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$TypeParamImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..a3dc117877903f0feb16c514eab73543fdfa3a30 GIT binary patch literal 2736 zcmbtWZBrXn6n<_3Y@mxFfug7_TEQlv?OLtcb}6k;D`*N85FP!rBo|m%cH{1*qd&v{ z;Rib-;|w4C0sbh*=k9K@n-ZDOen{@yIp;a=XaD*4^ltzw_+bn=jA|IuaS6J>-NWXQVY{L9UCS{VjuixZwj&Mu zxaAmI_P%R{ZC?g!JkD+Z+LF&K-#S(&fib%&-O%2%r7uvfr?^|8Z@c@ZLV80-5fh}1 zBrkhym-mV7TLOj9 ziy;NpEA>}3$gG|*p}D!8}bPopTK0d6r!$o zOJyRfe_aOQsuzSB76od9HyPG=rw>modtMlXzSW8oBPigJzMOCyd*g2W2n?SKos$OhGRpL<8rhzVCMx9P}W zuI_n9?N(A?(J<*L!{{bqRCWJY1`XeCg`S^fSy9s@dy&ZaDO25j(0dwjH?Qqx#V+cN8|KL4;r=^vXr%t{vGdWU~yeNpOo1V zyBfDSEprffA9_rv&*9M?(l3u%V9PSyT`s4bj8 ztKB%kcAcPJ z?Iz#G^JE6uKqZl=d}%3$=w)T=_r#*u+BDB?WwpPa?f9b?s30C_9F0e?mLYis3{Izi4oW;7W}w z^Y|dlaqvGS;v_!nBcwFAkk6Sdcd0`T_i#U2O+4T_#~8*L*PCy>*|tPVm5q-nrGSU{ k0?YjV{D!yJm`4SesAGot`xF}^qj<)3lj|0~!}pl^4`|c2vH$=8 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$TypeVarSigImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl$TypeVarSigImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..2fb1367c401ace63e0b224fadb523be6c842409f GIT binary patch literal 1990 zcmbtUTTc@~6#k~A-BK0`LY2_Khvznnfa}2@6_*OF_XqFI_(E^!aW-q_5XokZrL)Dd>uG;ptrgKFr6m?}o z+c8w9WN~|$%#qDcMZTq4~gEt&YGj>uE+8BDzy5~!pp66B+ ztq4ZY!N4}fzEegQx~W*TSmXv(J(;LS9ItcvXej~FDle&ZsG#)G5*){X)s-+e~fozn}OzJ`ApT7yHmfK zr@P(%MDws=maH6Kr1@d!tWe<&&y-+`lwRewvt-(igeMHifA1)gvpml2^QP(8j-?j8 zyVw!5#2BPl7|)}4fq4mO84GyHFjUpZD$%GGxZ+joXEHQr%U}$LwK8eOfw|8WFK|gU z@;bLiGN!p-Dv|<~H^v|J8jqhS9*YHT=Pa%0m{x5{T0Anf4j%e!kzB@)N-hPC5@+%}-+EYj9IYQqT`d)j`Z}%YC%kvNF5HF^WIZdm; zl#(YH1kR>=b$aPiC4Cro8>C+cKA$ZZ*tQ!~_xp*5Sk zy1`Yweqg9Yy=H25%i_%(En_=oxzRGKyt@72fM=|l*bITer@)T@Loin;Zf6SFO@>Uq zN53iIIH({5nL&z`GWng&BE$1{Jv)}6pkIQlU;u**{)*8sIYTs_$nR^1nrdifP2DQ* z^NO94F@%VOVFgj#U>N8qY?`e)C3dJ8ExxtOuomyK&I%Y)T^mK)(#=|`JA!cF_#ahp z6Jrd4v~KG5I>Sh}E7vlYCEK{=S$O2yXkQ) zoT*&7*l1Z5{*oG$VYr>J)18ar+9>G)Z`!XKO9jb$t{PwoB)Yl)$S4= zG0a|zArhVtQU9w-1a|2}__xDtEEB_rXiUMgF(#fCAUrN!0(!UnB&RV+r!%ygCMiDo z2+~*dok96bD~1^T1LBM=kbV@i@HqObB!z_>VaZd3&%lJf=P&(xw4^g17D%gCY=f~S+t?C*2=p+rY$H1u*3w8`BkhXa z6`0T@h0;Ki&^k@h+B6Bo4JbScPB5|@hgaG{okx>4Z60k24Na3KP1-a~+k^9D zI%DmKr{lvtcZ^t+s;t^!Sqs~q$Yh&k!cr5LAgW+$R%9%hP-w`F)|&L#bU9qnDy%!> zNofw2nOKe$RQHgT9Lyfn>TWY|nZkTe$(z&Z_#Lu%7*!~cpBfV})N*vZzh9wzCROh> zP_MAz{55AY=khAb6j>WhybCK8!bzHS)t2Fr>>Uc1J1c6nxa{TZ>sMACRtw0kQ0Vf{ z(W>;BXjWy}V?D|>yA7;SSngr0E!l4!?i$T@4YZ_2ll_@3hx@FNY$BB`!divO&QvxU zkKPs^O7utdYEeSK29Ai?WTF}C6+%`zok}aL_3P9DkRQHnLqpbJd}woeaCF#8X5Ga! zJ~o=T8k-ah$0>-n>Q-^12wF_E;u@|q9MAUA-qNvGI<}hFhV7h_&B5u?+2Ewty4J*X zXr~XQtpO`-CHpKFk9D&VSkY|_bPDJn04#z1XWzJdjFLw^@sh zae4JVAI9v^mIJBwQD?q^cPnhX09Wa-vIkTB(|lzg_6yW+Qs{mgsC)4Bu{DFDo8OA| zBE%II`_(tbRcO8dS8nx{H?}t)$HU@tk9a

`S2>i5@T9_=cru!Bqnv>g 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 SHns=&+{U(#?R9MXQStu>=eSP* literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl.java new file mode 100644 index 00000000..77f6933a --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/SignaturesImpl.java @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Collections; +import java.lang.classfile.ClassSignature; +import java.lang.classfile.MethodSignature; +import java.lang.classfile.Signature; +import java.lang.classfile.Signature.*; + +public final class SignaturesImpl { + + public SignaturesImpl(String signature) { + this.sig = Objects.requireNonNull(signature); + this.sigp = 0; + } + + private final String sig; + private int sigp; + + public ClassSignature parseClassSignature() { + try { + List typeParamTypes = parseParamTypes(); + ClassTypeSig superclass = classTypeSig(); + ArrayList superinterfaces = null; + while (sigp < sig.length()) { + if (superinterfaces == null) + superinterfaces = new ArrayList<>(); + superinterfaces.add(classTypeSig()); + } + return new ClassSignatureImpl(typeParamTypes, superclass, null2Empty(superinterfaces)); + } catch (IndexOutOfBoundsException e) { + throw error("Not a valid class signature"); + } + } + + public MethodSignature parseMethodSignature() { + try { + List typeParamTypes = parseParamTypes(); + require('('); + ArrayList paramTypes = null; + while (!match(')')) { + if (paramTypes == null) + paramTypes = new ArrayList<>(); + paramTypes.add(typeSig()); + } + Signature returnType = typeSig(); + ArrayList throwsTypes = null; + while (sigp < sig.length()) { + require('^'); + if (throwsTypes == null) + throwsTypes = new ArrayList<>(); + var t = referenceTypeSig(); + if (t instanceof ThrowableSig ts) + throwsTypes.add(ts); + else + throw error("Not a valid throwable signature %s in".formatted(t.signatureString())); + } + return new MethodSignatureImpl(typeParamTypes, null2Empty(throwsTypes), returnType, null2Empty(paramTypes)); + } catch (IndexOutOfBoundsException e) { + throw error("Not a valid method signature"); + } + } + + public Signature parseSignature() { + try { + var s = typeSig(); + if (sigp == sig.length()) + return s; + } catch (IndexOutOfBoundsException e) { + } + throw error("Not a valid type signature"); + } + + private List parseParamTypes() { + ArrayList typeParamTypes = null; + if (match('<')) { + typeParamTypes = new ArrayList<>(); + // cannot have empty <> + do { + String name = sig.substring(sigp, requireIdentifier()); + RefTypeSig classBound = null; + ArrayList interfaceBounds = null; + require(':'); + if (sig.charAt(sigp) != ':') + classBound = referenceTypeSig(); + while (match(':')) { + if (interfaceBounds == null) + interfaceBounds = new ArrayList<>(); + interfaceBounds.add(referenceTypeSig()); + } + typeParamTypes.add(new TypeParamImpl(name, Optional.ofNullable(classBound), null2Empty(interfaceBounds))); + } while (!match('>')); + } + return null2Empty(typeParamTypes); + } + + private Signature typeSig() { + char c = sig.charAt(sigp++); + switch (c) { + case 'B','C','D','F','I','J','V','S','Z': return Signature.BaseTypeSig.of(c); + default: + sigp--; + return referenceTypeSig(); + } + } + + private RefTypeSig referenceTypeSig() { + return switch (sig.charAt(sigp)) { + case 'L' -> classTypeSig(); + case 'T' -> { + sigp++; + var ty = Signature.TypeVarSig.of(sig.substring(sigp, requireIdentifier())); + require(';'); + yield ty; + } + case '[' -> { + sigp++; + yield ArrayTypeSig.of(typeSig()); + } + default -> throw unexpectedError("a type signature"); + }; + } + + private TypeArg typeArg() { + char c = sig.charAt(sigp++); + switch (c) { + case '*': return TypeArg.unbounded(); + case '+': return TypeArg.extendsOf(referenceTypeSig()); + case '-': return TypeArg.superOf(referenceTypeSig()); + default: + sigp--; + return TypeArg.of(referenceTypeSig()); + } + } + + private ClassTypeSig classTypeSig() { + require('L'); + Signature.ClassTypeSig t = null; + + do { + int start = sigp; + requireIdentifier(); + if (t == null) { + while (match('/')) { + requireIdentifier(); + } + } + String className = sig.substring(start, sigp); + + ArrayList argTypes; + if (match('<')) { + // cannot have empty <> + argTypes = new ArrayList<>(); + do { + argTypes.add(typeArg()); + } while (!match('>')); + } else { + argTypes = null; + } + + boolean end = match(';'); + if (end || match('.')) { + t = new ClassTypeSigImpl(Optional.ofNullable(t), className, null2Empty(argTypes)); + if (end) + return t; + } else { + throw unexpectedError(". or ;"); + } + } while (true); + } + + /** + * Tries to match a character, and moves pointer if it matches. + */ + private boolean match(char c) { + if (sigp < sig.length() && sig.charAt(sigp) == c) { + sigp++; + return true; + } + return false; + } + + /** + * Requires a character and moves past it, failing otherwise. + */ + private void require(char c) { + if (!match(c)) + throw unexpectedError(String.valueOf(c)); + } + + /** + * Requires an identifier, moving pointer to next illegal character and returning + * its position. Fails if the identifier is empty. + */ + private int requireIdentifier() { + int start = sigp; + l: + while (sigp < sig.length()) { + switch (sig.charAt(sigp)) { + case '.', ';', '[', '/', '<', '>', ':' -> { + break l; + } + } + sigp++; + } + if (start == sigp) { + throw unexpectedError("an identifier"); + } + return sigp; + } + + public static record BaseTypeSigImpl(char baseType) implements Signature.BaseTypeSig { + + @Override + public String signatureString() { + return "" + baseType; + } + } + + public static record TypeVarSigImpl(String identifier) implements Signature.TypeVarSig { + + @Override + public String signatureString() { + return "T" + identifier + ';'; + } + } + + public static record ArrayTypeSigImpl(int arrayDepth, Signature elemType) implements Signature.ArrayTypeSig { + + @Override + public Signature componentSignature() { + return arrayDepth > 1 ? new ArrayTypeSigImpl(arrayDepth - 1, elemType) : elemType; + } + + @Override + public String signatureString() { + return "[".repeat(arrayDepth) + elemType.signatureString(); + } + } + + public static record ClassTypeSigImpl(Optional outerType, String className, List typeArgs) + implements Signature.ClassTypeSig { + + @Override + public String signatureString() { + String prefix = "L"; + if (outerType.isPresent()) { + prefix = outerType.get().signatureString(); + assert prefix.charAt(prefix.length() - 1) == ';'; + prefix = prefix.substring(0, prefix.length() - 1) + '.'; + } + String suffix = ";"; + if (!typeArgs.isEmpty()) { + var sb = new StringBuilder(); + sb.append('<'); + for (var ta : typeArgs) { + switch (ta) { + case TypeArg.Bounded b -> { + switch (b.wildcardIndicator()) { + case SUPER -> sb.append('-'); + case EXTENDS -> sb.append('+'); + } + sb.append(b.boundType().signatureString()); + } + case TypeArg.Unbounded _ -> sb.append('*'); + } + } + suffix = sb.append(">;").toString(); + } + return prefix + className + suffix; + } + } + + public static enum UnboundedTypeArgImpl implements TypeArg.Unbounded { + INSTANCE; + } + + public static record TypeArgImpl(WildcardIndicator wildcardIndicator, RefTypeSig boundType) implements Signature.TypeArg.Bounded { + } + + public static record TypeParamImpl(String identifier, Optional classBound, List interfaceBounds) + implements TypeParam { + } + + private static StringBuilder printTypeParameters(List typeParameters) { + var sb = new StringBuilder(); + if (typeParameters != null && !typeParameters.isEmpty()) { + sb.append('<'); + for (var tp : typeParameters) { + sb.append(tp.identifier()).append(':'); + if (tp.classBound().isPresent()) + sb.append(tp.classBound().get().signatureString()); + if (tp.interfaceBounds() != null) for (var is : tp.interfaceBounds()) + sb.append(':').append(is.signatureString()); + } + sb.append('>'); + } + return sb; + } + + public static record ClassSignatureImpl(List typeParameters, ClassTypeSig superclassSignature, + List superinterfaceSignatures) implements ClassSignature { + + @Override + public String signatureString() { + var sb = printTypeParameters(typeParameters); + sb.append(superclassSignature.signatureString()); + if (superinterfaceSignatures != null) for (var in : superinterfaceSignatures) + sb.append(in.signatureString()); + return sb.toString(); + } + } + + public static record MethodSignatureImpl( + List typeParameters, + List throwableSignatures, + Signature result, + List arguments) implements MethodSignature { + + @Override + public String signatureString() { + var sb = printTypeParameters(typeParameters); + sb.append('('); + for (var a : arguments) + sb.append(a.signatureString()); + sb.append(')').append(result.signatureString()); + if (!throwableSignatures.isEmpty()) + for (var t : throwableSignatures) + sb.append('^').append(t.signatureString()); + return sb.toString(); + } + } + + private static List null2Empty(ArrayList l) { + return l == null ? List.of() : Collections.unmodifiableList(l); + } + + private IllegalArgumentException unexpectedError(String expected) { + return error(sigp < sig.length() ? "Unexpected character %c at position %d, expected %s" + .formatted(sig.charAt(sigp), sigp, expected) + : "Unexpected end of signature at position %d, expected %s".formatted(sigp, expected)); + } + + private IllegalArgumentException error(String message) { + return new IllegalArgumentException("%s: %s".formatted(message, sig)); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool$1.class b/tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool$1.class new file mode 100644 index 0000000000000000000000000000000000000000..e0dba9809591166ce0039f81fb46dbc904bf7fd6 GIT binary patch literal 1837 zcmbtVT~8BH5Iq+vYjKfU6;VMDi?$W42!0k(+GrpFV^YM#CvV#YSGT*(?k#>i`QQ)m z)dxS~i_a#Y(FcEkf5U%ajCyW?Do_i=P4>>+)44Ne=FUvN{`~v}Ko;3Bn$T<@WMT(e z1XA~l4^pz*s^G{Vn6n)#WtYlMDpz)FmG#^}Nmt$UJSR3JU@S-{maohS^i18C z3o_+McmA)FnabR4-=@K|cD2()7_9;=>Yg3MPSfGkwmha=VWQ2zZWHZ@2&5aGzUAh< zid!64%D3|sWyQve6JDYANfx8FYpXGVc)Tw6n(DMHml;7~HjF6t8rWxIKRN^k8@b<* zE+#7MY(mBM^#DCT3entKE=VcXL6_e|n5$Bg?gPQ~I)G zv3(hHxLSf4ugKyOHs8EJTTaQs1NO&Cdcrw--j%B2Gk=d7=4g}d{6F@sIj`autm~Xz zOyh=5Jf)kBSANYcI9_18^UJ}S7{z6Q{VQ>jS#A(gz%U)+FBj`u2xo2V(?Y zlEo`@<2Bj6qKh{*&QUTSMh9KdQH}jDMyk=BCCY!CABc+Y9Fse6jzAO6<3d$l#3jlQ Yr)U~uRV0cllu_zvgZeRX6`4@@Hx;}F#sB~S literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool$2.class b/tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool$2.class new file mode 100644 index 0000000000000000000000000000000000000000..0074ee13e935703d827905251225d253b1ad229d GIT binary patch literal 1163 zcmb7DTTc@~6#l04&H@z$FQA|nEk#@;zJWYgX>3xE1j75U9boEqw%Hww_~cL0#7m+H zKfoVl{H6tik~HZiJLjC4bH49fW`6ztaR#7<R&tUcCAd4-|Pp<>sH$fJ-$(ZeV_f%2f}O=IKJ zE!idAx;ENw2xKaa`r>{ONno%BO# zjxLoSoEP0?(Y~v^mk>)x;f9APN9`Rd8ys(jszXeH=anJb;i?fx*P@mZm}qLFwof_- zD&CU^A$KO5Q6R&88Ea>sZ>C-E1)dE@RbE{qQKCN(Rx|{PoN!o|fsJBr)CEdg${t6p z9U04x;#D9;M)x~3^>2sX9JEzn30K(FM@HI{n3#J5)43Ss`Y?^&AVqOEI*9{S=XDgA zzB0_GZf@+{rU}9*(dMXMgoi~`1x7mV@>D7u?|=(_ksI0a+bXfIqlBaM8pf!&=H7xz zFwdFi`F2F9zFjPR+K@NEVx7&W<`r4>S z%fR&l8OMiypj^M#58S(R@X=r`)>#_0b?52aBk2q*`$=nXPIyz3Zoel5luO#pY=k zv#(B5YZcY)Q&BPIIRL|aTB2OGFN&uj{v(*C{t{37l(XEO+R{ge+U&w-6y8(L;4;@d z1lRAl!nHQA!&S^sqDO*f?;XtI8a?dkI_8Kt&+{mW-j;b7d|5k$gtMfNXl%`kwGR+8 zpD_B4!k>&k5=I*%jeav0af3Xf{De?9d1s+kxLd1yjW`$o#u-HJBw6H7aOP>9W7rHW ghg%dfs9+)4Z{rU4EZ=YyONnL-ce$4cU`hD>0^ivr&j0`b literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool.class b/tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool.class new file mode 100644 index 0000000000000000000000000000000000000000..3f23da772cdc91f86a0269eb6086daab7e5636db GIT binary patch literal 28208 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 BJe2?d literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool.java b/tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool.java new file mode 100644 index 00000000..b034328f --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/SplitConstantPool.java @@ -0,0 +1,606 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.constant.ConstantDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.Arrays; +import java.util.List; + +import java.lang.classfile.Attribute; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassReader; +import java.lang.classfile.ClassFile; +import java.lang.classfile.BootstrapMethodEntry; +import java.lang.classfile.BufWriter; +import java.lang.classfile.attribute.BootstrapMethodsAttribute; +import java.lang.classfile.constantpool.*; +import java.util.Objects; + +import static java.lang.classfile.ClassFile.TAG_CLASS; +import static java.lang.classfile.ClassFile.TAG_CONSTANTDYNAMIC; +import static java.lang.classfile.ClassFile.TAG_DOUBLE; +import static java.lang.classfile.ClassFile.TAG_FIELDREF; +import static java.lang.classfile.ClassFile.TAG_FLOAT; +import static java.lang.classfile.ClassFile.TAG_INTEGER; +import static java.lang.classfile.ClassFile.TAG_INTERFACEMETHODREF; +import static java.lang.classfile.ClassFile.TAG_INVOKEDYNAMIC; +import static java.lang.classfile.ClassFile.TAG_LONG; +import static java.lang.classfile.ClassFile.TAG_METHODHANDLE; +import static java.lang.classfile.ClassFile.TAG_METHODREF; +import static java.lang.classfile.ClassFile.TAG_METHODTYPE; +import static java.lang.classfile.ClassFile.TAG_MODULE; +import static java.lang.classfile.ClassFile.TAG_NAMEANDTYPE; +import static java.lang.classfile.ClassFile.TAG_PACKAGE; +import static java.lang.classfile.ClassFile.TAG_STRING; + +public final class SplitConstantPool implements ConstantPoolBuilder { + + private final ClassReaderImpl parent; + private final int parentSize, parentBsmSize; + + private int size, bsmSize; + private PoolEntry[] myEntries; + private BootstrapMethodEntryImpl[] myBsmEntries; + private boolean doneFullScan; + private EntryMap map; + private EntryMap bsmMap; + + public SplitConstantPool() { + this.size = 1; + this.bsmSize = 0; + this.myEntries = new PoolEntry[1024]; + this.myBsmEntries = new BootstrapMethodEntryImpl[8]; + this.parent = null; + this.parentSize = 0; + this.parentBsmSize = 0; + this.doneFullScan = true; + } + + public SplitConstantPool(ClassReader parent) { + this.parent = (ClassReaderImpl) parent; + this.parentSize = parent.size(); + this.parentBsmSize = parent.bootstrapMethodCount(); + this.size = parentSize; + this.bsmSize = parentBsmSize; + this.myEntries = new PoolEntry[8]; + this.myBsmEntries = new BootstrapMethodEntryImpl[8]; + this.doneFullScan = true; + } + + @Override + public int size() { + return size; + } + + @Override + public int bootstrapMethodCount() { + return bsmSize; + } + + @Override + public PoolEntry entryByIndex(int index) { + if (index <= 0 || index >= size()) { + throw new ConstantPoolException("Bad CP index: " + index); + } + PoolEntry pe = (index < parentSize) + ? parent.entryByIndex(index) + : myEntries[index - parentSize]; + if (pe == null) { + throw new ConstantPoolException("Unusable CP index: " + index); + } + return pe; + } + + @Override + public T entryByIndex(int index, Class cls) { + Objects.requireNonNull(cls); + return ClassReaderImpl.checkType(entryByIndex(index), index, cls); + } + + @Override + public BootstrapMethodEntryImpl bootstrapMethodEntry(int index) { + if (index < 0 || index >= bootstrapMethodCount()) { + throw new ConstantPoolException("Bad BSM index: " + index); + } + return (index < parentBsmSize) + ? parent.bootstrapMethodEntry(index) + : myBsmEntries[index - parentBsmSize]; + } + + @Override + public boolean canWriteDirect(ConstantPool other) { + return this == other || parent == other; + } + + @Override + public boolean writeBootstrapMethods(BufWriter buf) { + if (bsmSize == 0) + return false; + int pos = buf.size(); + if (parent != null && parentBsmSize != 0) { + parent.writeBootstrapMethods(buf); + for (int i = parentBsmSize; i < bsmSize; i++) + bootstrapMethodEntry(i).writeTo(buf); + int attrLen = buf.size() - pos; + buf.patchInt(pos + 2, 4, attrLen - 6); + buf.patchInt(pos + 6, 2, bsmSize); + } + else { + Attribute a + = new UnboundAttribute.AdHocAttribute<>(Attributes.bootstrapMethods()) { + + @Override + public void writeBody(BufWriter b) { + buf.writeU2(bsmSize); + for (int i = 0; i < bsmSize; i++) + bootstrapMethodEntry(i).writeTo(buf); + } + }; + a.writeTo(buf); + } + return true; + } + + @Override + public void writeTo(BufWriter buf) { + int writeFrom = 1; + if (size() >= 65536) { + throw new IllegalArgumentException(String.format("Constant pool is too large %d", size())); + } + buf.writeU2(size()); + if (parent != null && buf.constantPool().canWriteDirect(this)) { + parent.writeConstantPoolEntries(buf); + writeFrom = parent.size(); + } + for (int i = writeFrom; i < size(); ) { + PoolEntry info = entryByIndex(i); + info.writeTo(buf); + i += info.width(); + } + } + + private EntryMap map() { + if (map == null) { + map = new EntryMap<>(Math.max(size, 1024), .75f) { + @Override + protected PoolEntry fetchElement(int index) { + return entryByIndex(index); + } + }; + // Doing a full scan here yields fall-off-the-cliff performance results, + // especially if we only need a few entries that are already + // inflated (such as attribute names). + // So we inflate the map with whatever we've got from the parent, and + // later, if we miss, we do a one-time full inflation before creating + // a new entry. + for (int i=1; i bsmMap() { + if (bsmMap == null) { + bsmMap = new EntryMap<>(Math.max(bsmSize, 16), .75f) { + @Override + protected BootstrapMethodEntryImpl fetchElement(int index) { + return bootstrapMethodEntry(index); + } + }; + for (int i=0; i E internalAdd(E cpi) { + return internalAdd(cpi, cpi.hashCode()); + } + + private E internalAdd(E cpi, int hash) { + int newIndex = size-parentSize; + if (newIndex + 2 > myEntries.length) { + myEntries = Arrays.copyOf(myEntries, 2 * newIndex, PoolEntry[].class); + } + myEntries[newIndex] = cpi; + size += cpi.width(); + map().put(hash, cpi.index()); + return cpi; + } + + private BootstrapMethodEntryImpl internalAdd(BootstrapMethodEntryImpl bsm, int hash) { + int newIndex = bsmSize-parentBsmSize; + if (newIndex + 2 > myBsmEntries.length) { + myBsmEntries = Arrays.copyOf(myBsmEntries, 2 * newIndex, BootstrapMethodEntryImpl[].class); + } + myBsmEntries[newIndex] = bsm; + bsmSize += 1; + bsmMap().put(hash, bsm.index); + return bsm; + } + + private PoolEntry findPrimitiveEntry(int tag, T val) { + int hash = AbstractPoolEntry.hash1(tag, val.hashCode()); + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = map.getElementByToken(token); + if (e.tag() == tag + && e instanceof AbstractPoolEntry.PrimitiveEntry ce + && ce.value().equals(val)) + return e; + } + if (!doneFullScan) { + fullScan(); + return findPrimitiveEntry(tag, val); + } + return null; + } + + private AbstractPoolEntry findEntry(int tag, T ref1) { + // invariant: canWriteDirect(ref1.constantPool()) + int hash = AbstractPoolEntry.hash1(tag, ref1.index()); + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = map.getElementByToken(token); + if (e.tag() == tag + && e instanceof AbstractPoolEntry.AbstractRefEntry re + && re.ref1 == ref1) + return re; + } + if (!doneFullScan) { + fullScan(); + return findEntry(tag, ref1); + } + return null; + } + + private + AbstractPoolEntry findEntry(int tag, T ref1, U ref2) { + // invariant: canWriteDirect(ref1.constantPool()), canWriteDirect(ref2.constantPool()) + int hash = AbstractPoolEntry.hash2(tag, ref1.index(), ref2.index()); + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = map.getElementByToken(token); + if (e.tag() == tag + && e instanceof AbstractPoolEntry.AbstractRefsEntry re + && re.ref1 == ref1 + && re.ref2 == ref2) { + return re; + } + } + if (!doneFullScan) { + fullScan(); + return findEntry(tag, ref1, ref2); + } + return null; + } + + private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, String target) { + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; + token = map.nextToken(hash, token)) { + PoolEntry e = map.getElementByToken(token); + if (e.tag() == ClassFile.TAG_UTF8 + && e instanceof AbstractPoolEntry.Utf8EntryImpl ce + && ce.hashCode() == hash + && target.equals(ce.stringValue())) + return ce; + } + if (!doneFullScan) { + fullScan(); + return tryFindUtf8(hash, target); + } + return null; + } + + private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, AbstractPoolEntry.Utf8EntryImpl target) { + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = map.getElementByToken(token); + if (e.tag() == ClassFile.TAG_UTF8 + && e instanceof AbstractPoolEntry.Utf8EntryImpl ce + && target.equalsUtf8(ce)) + return ce; + } + if (!doneFullScan) { + fullScan(); + return tryFindUtf8(hash, target); + } + return null; + } + + @Override + public AbstractPoolEntry.Utf8EntryImpl utf8Entry(String s) { + int hash = AbstractPoolEntry.hashString(s.hashCode()); + var ce = tryFindUtf8(hash, s); + return ce == null ? internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, s, hash)) : ce; + } + + AbstractPoolEntry.Utf8EntryImpl maybeCloneUtf8Entry(Utf8Entry entry) { + AbstractPoolEntry.Utf8EntryImpl e = (AbstractPoolEntry.Utf8EntryImpl) entry; + if (e.constantPool == this || e.constantPool == parent) + return e; + AbstractPoolEntry.Utf8EntryImpl ce = tryFindUtf8(e.hashCode(), e); + return ce == null ? internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, e)) : ce; + } + + @Override + public AbstractPoolEntry.ClassEntryImpl classEntry(Utf8Entry nameEntry) { + AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry); + var e = (AbstractPoolEntry.ClassEntryImpl) findEntry(TAG_CLASS, ne); + return e == null ? internalAdd(new AbstractPoolEntry.ClassEntryImpl(this, size, ne)) : e; + } + + @Override + public PackageEntry packageEntry(Utf8Entry nameEntry) { + AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry); + var e = (AbstractPoolEntry.PackageEntryImpl) findEntry(TAG_PACKAGE, ne); + return e == null ? internalAdd(new AbstractPoolEntry.PackageEntryImpl(this, size, ne)) : e; + } + + @Override + public ModuleEntry moduleEntry(Utf8Entry nameEntry) { + AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry); + var e = (AbstractPoolEntry.ModuleEntryImpl) findEntry(TAG_MODULE, ne); + return e == null ? internalAdd(new AbstractPoolEntry.ModuleEntryImpl(this, size, ne)) : e; + } + + @Override + public AbstractPoolEntry.NameAndTypeEntryImpl nameAndTypeEntry(Utf8Entry nameEntry, Utf8Entry typeEntry) { + AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry); + AbstractPoolEntry.Utf8EntryImpl te = maybeCloneUtf8Entry(typeEntry); + var e = (AbstractPoolEntry.NameAndTypeEntryImpl) findEntry(TAG_NAMEANDTYPE, ne, te); + return e == null ? internalAdd(new AbstractPoolEntry.NameAndTypeEntryImpl(this, size, ne, te)) : e; + } + + @Override + public FieldRefEntry fieldRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) { + AbstractPoolEntry.ClassEntryImpl oe = (AbstractPoolEntry.ClassEntryImpl) owner; + AbstractPoolEntry.NameAndTypeEntryImpl ne = (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType; + if (!canWriteDirect(oe.constantPool)) + oe = classEntry(owner.name()); + if (!canWriteDirect(ne.constantPool)) + ne = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); + var e = (AbstractPoolEntry.FieldRefEntryImpl) findEntry(TAG_FIELDREF, oe, ne); + return e == null ? internalAdd(new AbstractPoolEntry.FieldRefEntryImpl(this, size, oe, ne)) : e; + } + + @Override + public MethodRefEntry methodRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) { + AbstractPoolEntry.ClassEntryImpl oe = (AbstractPoolEntry.ClassEntryImpl) owner; + AbstractPoolEntry.NameAndTypeEntryImpl ne = (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType; + if (!canWriteDirect(oe.constantPool)) + oe = classEntry(owner.name()); + if (!canWriteDirect(ne.constantPool)) + ne = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); + var e = (AbstractPoolEntry.MethodRefEntryImpl) findEntry(TAG_METHODREF, oe, ne); + return e == null ? internalAdd(new AbstractPoolEntry.MethodRefEntryImpl(this, size, oe, ne)) : e; + } + + @Override + public InterfaceMethodRefEntry interfaceMethodRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) { + AbstractPoolEntry.ClassEntryImpl oe = (AbstractPoolEntry.ClassEntryImpl) owner; + AbstractPoolEntry.NameAndTypeEntryImpl ne = (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType; + if (!canWriteDirect(oe.constantPool)) + oe = classEntry(owner.name()); + if (!canWriteDirect(ne.constantPool)) + ne = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); + var e = (AbstractPoolEntry.InterfaceMethodRefEntryImpl) findEntry(TAG_INTERFACEMETHODREF, oe, ne); + return e == null ? internalAdd(new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, size, oe, ne)) : e; + } + + @Override + public MethodTypeEntry methodTypeEntry(MethodTypeDesc descriptor) { + var ret = (AbstractPoolEntry.MethodTypeEntryImpl)methodTypeEntry(utf8Entry(descriptor.descriptorString())); + ret.sym = descriptor; + return ret; + } + + @Override + public MethodTypeEntry methodTypeEntry(Utf8Entry descriptor) { + AbstractPoolEntry.Utf8EntryImpl de = maybeCloneUtf8Entry(descriptor); + var e = (AbstractPoolEntry.MethodTypeEntryImpl) findEntry(TAG_METHODTYPE, de); + return e == null ? internalAdd(new AbstractPoolEntry.MethodTypeEntryImpl(this, size, de)) : e; + } + + @Override + public MethodHandleEntry methodHandleEntry(int refKind, MemberRefEntry reference) { + if (!canWriteDirect(reference.constantPool())) { + reference = switch (reference.tag()) { + case TAG_FIELDREF -> fieldRefEntry(reference.owner(), reference.nameAndType()); + case TAG_METHODREF -> methodRefEntry(reference.owner(), reference.nameAndType()); + case TAG_INTERFACEMETHODREF -> interfaceMethodRefEntry(reference.owner(), reference.nameAndType()); + default -> throw new IllegalArgumentException(String.format("Bad tag %d", reference.tag())); + }; + } + + int hash = AbstractPoolEntry.hash2(TAG_METHODHANDLE, refKind, reference.index()); + EntryMap map1 = map(); + for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) { + PoolEntry e = map1.getElementByToken(token); + if (e.tag() == TAG_METHODHANDLE + && e instanceof AbstractPoolEntry.MethodHandleEntryImpl ce + && ce.kind() == refKind && ce.reference() == reference) + return ce; + } + if (!doneFullScan) { + fullScan(); + return methodHandleEntry(refKind, reference); + } + return internalAdd(new AbstractPoolEntry.MethodHandleEntryImpl(this, size, + hash, refKind, (AbstractPoolEntry.AbstractMemberRefEntry) reference), hash); + } + + @Override + public InvokeDynamicEntry invokeDynamicEntry(BootstrapMethodEntry bootstrapMethodEntry, + NameAndTypeEntry nameAndType) { + if (!canWriteDirect(bootstrapMethodEntry.constantPool())) + bootstrapMethodEntry = bsmEntry(bootstrapMethodEntry.bootstrapMethod(), + bootstrapMethodEntry.arguments()); + if (!canWriteDirect(nameAndType.constantPool())) + nameAndType = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); + int hash = AbstractPoolEntry.hash2(TAG_INVOKEDYNAMIC, + bootstrapMethodEntry.bsmIndex(), nameAndType.index()); + EntryMap map1 = map(); + for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) { + PoolEntry e = map1.getElementByToken(token); + if (e.tag() == TAG_INVOKEDYNAMIC + && e instanceof AbstractPoolEntry.InvokeDynamicEntryImpl ce + && ce.bootstrap() == bootstrapMethodEntry && ce.nameAndType() == nameAndType) + return ce; + } + if (!doneFullScan) { + fullScan(); + return invokeDynamicEntry(bootstrapMethodEntry, nameAndType); + } + + AbstractPoolEntry.InvokeDynamicEntryImpl ce = + new AbstractPoolEntry.InvokeDynamicEntryImpl(this, size, hash, + (BootstrapMethodEntryImpl) bootstrapMethodEntry, + (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType); + internalAdd(ce, hash); + return ce; + } + + @Override + public ConstantDynamicEntry constantDynamicEntry(BootstrapMethodEntry bootstrapMethodEntry, + NameAndTypeEntry nameAndType) { + if (!canWriteDirect(bootstrapMethodEntry.constantPool())) + bootstrapMethodEntry = bsmEntry(bootstrapMethodEntry.bootstrapMethod(), + bootstrapMethodEntry.arguments()); + if (!canWriteDirect(nameAndType.constantPool())) + nameAndType = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); + int hash = AbstractPoolEntry.hash2(TAG_CONSTANTDYNAMIC, + bootstrapMethodEntry.bsmIndex(), nameAndType.index()); + EntryMap map1 = map(); + for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) { + PoolEntry e = map1.getElementByToken(token); + if (e.tag() == TAG_CONSTANTDYNAMIC + && e instanceof AbstractPoolEntry.ConstantDynamicEntryImpl ce + && ce.bootstrap() == bootstrapMethodEntry && ce.nameAndType() == nameAndType) + return ce; + } + if (!doneFullScan) { + fullScan(); + return constantDynamicEntry(bootstrapMethodEntry, nameAndType); + } + + AbstractPoolEntry.ConstantDynamicEntryImpl ce = + new AbstractPoolEntry.ConstantDynamicEntryImpl(this, size, hash, + (BootstrapMethodEntryImpl) bootstrapMethodEntry, + (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType); + internalAdd(ce, hash); + return ce; + } + + @Override + public IntegerEntry intEntry(int value) { + var e = (IntegerEntry) findPrimitiveEntry(TAG_INTEGER, value); + return e == null ? internalAdd(new AbstractPoolEntry.IntegerEntryImpl(this, size, value)) : e; + } + + @Override + public FloatEntry floatEntry(float value) { + var e = (FloatEntry) findPrimitiveEntry(TAG_FLOAT, value); + return e == null ? internalAdd(new AbstractPoolEntry.FloatEntryImpl(this, size, value)) : e; + } + + @Override + public LongEntry longEntry(long value) { + var e = (LongEntry) findPrimitiveEntry(TAG_LONG, value); + return e == null ? internalAdd(new AbstractPoolEntry.LongEntryImpl(this, size, value)) : e; + } + + @Override + public DoubleEntry doubleEntry(double value) { + var e = (DoubleEntry) findPrimitiveEntry(TAG_DOUBLE, value); + return e == null ? internalAdd(new AbstractPoolEntry.DoubleEntryImpl(this, size, value)) : e; + } + + @Override + public StringEntry stringEntry(Utf8Entry utf8) { + AbstractPoolEntry.Utf8EntryImpl ue = maybeCloneUtf8Entry(utf8); + var e = (AbstractPoolEntry.StringEntryImpl) findEntry(TAG_STRING, ue); + return e == null ? internalAdd(new AbstractPoolEntry.StringEntryImpl(this, size, ue)) : e; + } + + @Override + public BootstrapMethodEntry bsmEntry(MethodHandleEntry methodReference, + List arguments) { + if (!canWriteDirect(methodReference.constantPool())) + methodReference = methodHandleEntry(methodReference.kind(), methodReference.reference()); + for (LoadableConstantEntry a : arguments) { + if (!canWriteDirect(a.constantPool())) { + // copy args list + LoadableConstantEntry[] arr = arguments.toArray(new LoadableConstantEntry[0]); + for (int i = 0; i < arr.length; i++) + arr[i] = AbstractPoolEntry.maybeClone(this, arr[i]); + arguments = List.of(arr); + + break; + } + } + AbstractPoolEntry.MethodHandleEntryImpl mre = (AbstractPoolEntry.MethodHandleEntryImpl) methodReference; + int hash = BootstrapMethodEntryImpl.computeHashCode(mre, arguments); + EntryMap map = bsmMap(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + BootstrapMethodEntryImpl e = map.getElementByToken(token); + if (e.bootstrapMethod() == mre && e.arguments().equals(arguments)) { + return e; + } + } + BootstrapMethodEntryImpl ne = new BootstrapMethodEntryImpl(this, bsmSize, hash, mre, arguments); + return internalAdd(ne, hash); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackCounter$Target.class b/tests/test_data/std/jdk/internal/classfile/impl/StackCounter$Target.class new file mode 100644 index 0000000000000000000000000000000000000000..da09c223c5cca3a97bf6348ea3301a640e9b41fd GIT binary patch literal 1653 zcmbVMTT|0O6#llfOh8^PSuN{B`gHKou`?NT5eUQb!7DhW>57%MF`5TgE$K zO1H_7UbGy`Ut;JfmNv7xDl2NSH zN}CMHkYT=VIbyB5(-7_kZ`j1SP?sjRH@R!6dn8QyEsI#ppF3An@>SutWb-X|`HrAc z5zJumgcJr1P-7UPNdGiRj5w2u+p%8^xpmofO|eXk!7vc-idm&i1z8iGzal+f!)=D* zS<6k?KkU)|ms0wk@A6I5-sQL5(@>X_BQdPU{uAtCl|4V H=NS174Qp~3 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackCounter.class b/tests/test_data/std/jdk/internal/classfile/impl/StackCounter.class new file mode 100644 index 0000000000000000000000000000000000000000..4ae7f68a6fca0de0117f5aab39e3ec828e2f07bb GIT binary patch literal 13079 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 DEye}1 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackCounter.java b/tests/test_data/std/jdk/internal/classfile/impl/StackCounter.java new file mode 100644 index 00000000..899a4357 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/StackCounter.java @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.TypeKind; +import java.lang.classfile.constantpool.ConstantDynamicEntry; +import java.lang.classfile.constantpool.DynamicConstantPoolEntry; +import java.lang.classfile.constantpool.MemberRefEntry; +import java.lang.constant.MethodTypeDesc; +import java.nio.ByteBuffer; +import java.util.ArrayDeque; +import java.util.BitSet; +import java.util.List; +import java.util.Queue; + +import static java.lang.classfile.ClassFile.*; +import java.lang.constant.ClassDesc; +import java.util.stream.Collectors; + +public final class StackCounter { + + private record Target(int bci, int stack) {} + + static StackCounter of(DirectCodeBuilder dcb, BufWriterImpl buf) { + return new StackCounter( + dcb, + buf.thisClass().asSymbol(), + dcb.methodInfo.methodName().stringValue(), + dcb.methodInfo.methodTypeSymbol(), + (dcb.methodInfo.methodFlags() & ACC_STATIC) != 0, + ((BufWriterImpl) dcb.bytecodesBufWriter).asByteBuffer(), + dcb.constantPool, + dcb.handlers); + } + + private int stack, maxStack, maxLocals, rets; + + private final RawBytecodeHelper bcs; + private final ClassDesc thisClass; + private final String methodName; + private final MethodTypeDesc methodDesc; + private final boolean isStatic; + private final ByteBuffer bytecode; + private final SplitConstantPool cp; + private final Queue targets; + private final BitSet visited; + + private void jump(int targetBci) { + if (!visited.get(targetBci)) { + targets.add(new Target(targetBci, stack)); + } + } + + private void addStackSlot(int delta) { + stack += delta; + if (stack > maxStack) maxStack = stack; + } + + private void ensureLocalSlot(int index) { + if (index >= maxLocals) maxLocals = index + 1; + } + + private boolean next() { + Target en; + while ((en = targets.poll()) != null) { + if (!visited.get(en.bci)) { + bcs.nextBci = en.bci; + stack = en.stack; + return true; + } + } + bcs.nextBci = bcs.endBci; + return false; + } + + public StackCounter(LabelContext labelContext, + ClassDesc thisClass, + String methodName, + MethodTypeDesc methodDesc, + boolean isStatic, + ByteBuffer bytecode, + SplitConstantPool cp, + List handlers) { + this.thisClass = thisClass; + this.methodName = methodName; + this.methodDesc = methodDesc; + this.isStatic = isStatic; + this.bytecode = bytecode; + this.cp = cp; + targets = new ArrayDeque<>(); + maxStack = stack = rets = 0; + for (var h : handlers) targets.add(new Target(labelContext.labelToBci(h.handler), 1)); + maxLocals = isStatic ? 0 : 1; + maxLocals += Util.parameterSlots(methodDesc); + bcs = new RawBytecodeHelper(bytecode); + visited = new BitSet(bcs.endBci); + targets.add(new Target(0, 0)); + while (next()) { + while (!bcs.isLastBytecode()) { + bcs.rawNext(); + int opcode = bcs.rawCode; + int bci = bcs.bci; + visited.set(bci); + switch (opcode) { + case NOP, LALOAD, DALOAD, SWAP, INEG, ARRAYLENGTH, INSTANCEOF, LNEG, FNEG, DNEG, I2F, L2D, F2I, D2L, I2B, I2C, I2S, + NEWARRAY, CHECKCAST, ANEWARRAY -> {} + case RETURN -> + next(); + case ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, SIPUSH, BIPUSH, + FCONST_0, FCONST_1, FCONST_2, DUP, DUP_X1, DUP_X2, I2L, I2D, F2L, F2D, NEW -> + addStackSlot(+1); + case LCONST_0, LCONST_1, DCONST_0, DCONST_1, DUP2, DUP2_X1, DUP2_X2 -> + addStackSlot(+2); + case POP, MONITORENTER, MONITOREXIT, IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IOR, IXOR, IAND, + LSHL, LSHR, LUSHR, FADD, FSUB, FMUL, FDIV, FREM, L2I, L2F, D2F, FCMPL, FCMPG, D2I -> + addStackSlot(-1); + case POP2, LADD, LSUB, LMUL, LDIV, LREM, LAND, LOR, LXOR, DADD, DSUB, DMUL, DDIV, DREM -> + addStackSlot(-2); + case IASTORE, BASTORE, CASTORE, SASTORE, FASTORE, AASTORE, LCMP, DCMPL, DCMPG -> + addStackSlot(-3); + case LASTORE, DASTORE -> + addStackSlot(-4); + case LDC -> + processLdc(bcs.getIndexU1()); + case LDC_W, LDC2_W -> + processLdc(bcs.getIndexU2()); + case ILOAD, FLOAD, ALOAD -> { + ensureLocalSlot(bcs.getIndex()); + addStackSlot(+1); + } + case LLOAD, DLOAD -> { + ensureLocalSlot(bcs.getIndex() + 1); + addStackSlot(+2); + } + case ILOAD_0, FLOAD_0, ALOAD_0 -> { + ensureLocalSlot(0); + addStackSlot(+1); + } + case ILOAD_1, FLOAD_1, ALOAD_1 -> { + ensureLocalSlot(1); + addStackSlot(+1); + } + case ILOAD_2, FLOAD_2, ALOAD_2 -> { + ensureLocalSlot(2); + addStackSlot(+1); + } + case ILOAD_3, FLOAD_3, ALOAD_3 -> { + ensureLocalSlot(3); + addStackSlot(+1); + } + case LLOAD_0, DLOAD_0 -> { + ensureLocalSlot(1); + addStackSlot(+2); + } + case LLOAD_1, DLOAD_1 -> { + ensureLocalSlot(2); + addStackSlot(+2); + } + case LLOAD_2, DLOAD_2 -> { + ensureLocalSlot(3); + addStackSlot(+2); + } + case LLOAD_3, DLOAD_3 -> { + ensureLocalSlot(4); + addStackSlot(+2); + } + case IALOAD, BALOAD, CALOAD, SALOAD, FALOAD, AALOAD -> { + addStackSlot(-1); + } + case ISTORE, FSTORE, ASTORE -> { + ensureLocalSlot(bcs.getIndex()); + addStackSlot(-1); + } + case LSTORE, DSTORE -> { + ensureLocalSlot(bcs.getIndex() + 1); + addStackSlot(-2); + } + case ISTORE_0, FSTORE_0, ASTORE_0 -> { + ensureLocalSlot(0); + addStackSlot(-1); + } + case ISTORE_1, FSTORE_1, ASTORE_1 -> { + ensureLocalSlot(1); + addStackSlot(-1); + } + case ISTORE_2, FSTORE_2, ASTORE_2 -> { + ensureLocalSlot(2); + addStackSlot(-1); + } + case ISTORE_3, FSTORE_3, ASTORE_3 -> { + ensureLocalSlot(3); + addStackSlot(-1); + } + case LSTORE_0, DSTORE_0 -> { + ensureLocalSlot(1); + addStackSlot(-2); + } + case LSTORE_1, DSTORE_1 -> { + ensureLocalSlot(2); + addStackSlot(-2); + } + case LSTORE_2, DSTORE_2 -> { + ensureLocalSlot(3); + addStackSlot(-2); + } + case LSTORE_3, DSTORE_3 -> { + ensureLocalSlot(4); + addStackSlot(-2); + } + case IINC -> + ensureLocalSlot(bcs.getIndex()); + case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE -> { + addStackSlot(-2); + jump(bcs.dest()); + } + case IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL -> { + addStackSlot(-1); + jump(bcs.dest()); + } + case GOTO -> { + jump(bcs.dest()); + next(); + } + case GOTO_W -> { + jump(bcs.destW()); + next(); + } + case TABLESWITCH, LOOKUPSWITCH -> { + int alignedBci = RawBytecodeHelper.align(bci + 1); + int defaultOfset = bcs.getInt(alignedBci); + int keys, delta; + addStackSlot(-1); + if (bcs.rawCode == TABLESWITCH) { + int low = bcs.getInt(alignedBci + 4); + int high = bcs.getInt(alignedBci + 2 * 4); + if (low > high) { + throw error("low must be less than or equal to high in tableswitch"); + } + keys = high - low + 1; + if (keys < 0) { + throw error("too many keys in tableswitch"); + } + delta = 1; + } else { + keys = bcs.getInt(alignedBci + 4); + if (keys < 0) { + throw error("number of keys in lookupswitch less than 0"); + } + delta = 2; + for (int i = 0; i < (keys - 1); i++) { + int this_key = bcs.getInt(alignedBci + (2 + 2 * i) * 4); + int next_key = bcs.getInt(alignedBci + (2 + 2 * i + 2) * 4); + if (this_key >= next_key) { + throw error("Bad lookupswitch instruction"); + } + } + } + int target = bci + defaultOfset; + jump(target); + for (int i = 0; i < keys; i++) { + alignedBci = RawBytecodeHelper.align(bcs.bci + 1); + target = bci + bcs.getInt(alignedBci + (3 + i * delta) * 4); + jump(target); + } + next(); + } + case LRETURN, DRETURN -> { + addStackSlot(-2); + next(); + } + case IRETURN, FRETURN, ARETURN, ATHROW -> { + addStackSlot(-1); + next(); + } + case GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD -> { + var tk = TypeKind.fromDescriptor(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).nameAndType().type()); + switch (bcs.rawCode) { + case GETSTATIC -> + addStackSlot(tk.slotSize()); + case PUTSTATIC -> + addStackSlot(-tk.slotSize()); + case GETFIELD -> + addStackSlot(tk.slotSize() - 1); + case PUTFIELD -> + addStackSlot(-tk.slotSize() - 1); + default -> throw new AssertionError("Should not reach here"); + } + } + case INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, INVOKEDYNAMIC -> { + var cpe = cp.entryByIndex(bcs.getIndexU2()); + var nameAndType = opcode == INVOKEDYNAMIC ? ((DynamicConstantPoolEntry)cpe).nameAndType() : ((MemberRefEntry)cpe).nameAndType(); + var mtd = Util.methodTypeSymbol(nameAndType); + addStackSlot(Util.slotSize(mtd.returnType()) - Util.parameterSlots(mtd)); + if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { + addStackSlot(-1); + } + } + case MULTIANEWARRAY -> + addStackSlot (1 - bcs.getU1(bcs.bci + 3)); + case JSR -> { + addStackSlot(+1); + jump(bcs.dest()); //here we lost track of the exact stack size after return from subroutine + addStackSlot(-1); + } + case JSR_W -> { + addStackSlot(+1); + jump(bcs.destW()); //here we lost track of the exact stack size after return from subroutine + addStackSlot(-1); + } + case RET -> { + ensureLocalSlot(bcs.getIndex()); + rets++; //subroutines must be counted for later maxStack correction + next(); + } + default -> + throw error(String.format("Bad instruction: %02x", opcode)); + } + } + } + //correction of maxStack when subroutines are present by calculation of upper bounds + //the worst scenario is that all subroutines are chained and each subroutine also requires maxStack for its own code + maxStack += rets * maxStack; + } + + /** + * Calculated maximum number of the locals required + * @return maximum number of the locals required + */ + public int maxLocals() { + return maxLocals; + } + + /** + * Calculated maximum stack size required + * @return maximum stack size required + */ + public int maxStack() { + return maxStack; + } + + private void processLdc(int index) { + switch (cp.entryByIndex(index).tag()) { + case TAG_UTF8, TAG_STRING, TAG_CLASS, TAG_INTEGER, TAG_FLOAT, TAG_METHODHANDLE, TAG_METHODTYPE -> + addStackSlot(+1); + case TAG_DOUBLE, TAG_LONG -> + addStackSlot(+2); + case TAG_CONSTANTDYNAMIC -> + addStackSlot(cp.entryByIndex(index, ConstantDynamicEntry.class).typeKind().slotSize()); + default -> + throw error("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag())); + } + } + + private IllegalArgumentException error(String msg) { + var sb = new StringBuilder("%s at bytecode offset %d of method %s(%s)".formatted( + msg, + bcs.bci, + methodName, + methodDesc.parameterList().stream().map(ClassDesc::displayName).collect(Collectors.joining(",")))); + Util.dumpMethod(cp, thisClass, methodName, methodDesc, isStatic ? ACC_STATIC : 0, bytecode, sb::append); + return new IllegalArgumentException(sb.toString()); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder$ObjectVerificationTypeInfoImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder$ObjectVerificationTypeInfoImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f807c5bc3f1c219dfb8e891b9546c02bcd7c8182 GIT binary patch literal 1715 zcmb_cOHUL*5dL~!vpWs~D-T6c)))H_7ZpWa!~;rPv!D?}BA%M1VF!m9ob5H?r}zgv zanM8~nrQUuukqkPjWJfw47&pYYT{w0x@W4ss_(1n{`B+hdjJ!-t|7wEzs#TTqQ&i{ zV%6gH`l4xx;)GgF(n?1RaSaIr8j=hhE$4fp>bMIGi80eQ@Rh*H$`e=%;-XNd_;hwxRzbvY9R=DP(S>@7n?E7o0qHHfZ zWpZaodF4&>6~Qo6X%*6{y6V_<$!)pnIF?W0rY+sIl8z2^YDgP6fG&nkFSa2~tLW#f z6ASUU!7W-0W<${a@6zvIa&sDbw#ebTs!RtB96}#Mtj6m#hMw%h9pcOTa0LAtjv6?I z0fxdq@L|}`>*YXIUyrVAE|g?Ox~9EU(r{e0V2Ac{NgneJDVj}~bV*mG^&V|t7!Hf` zXWetNq{0L>m!Z94+G4t~GB4cweBPoj>55b3)+~2TwGTeVWX+@|R4V^(a7xssDIsgl z!dodq=jNz%S>uv{IjY!}jDZJ3+vWrZ#V1w6eY#2M_)TCa zZfVV*MPtxsoQ7K!>i98qZ6*nh$yrqhLvmWw@iLZeY>OL99i26;y*CX+8bLp-)#_z3+ex(XklPvu`Cb%ve|w68}MaMUX_O(cP@ zMC%&?eWw%u!%H$i{|~^RYO-GWnP&MJoJElm4pUqV5v`Zj=bF`D@k9gKWAD)YAgZ#? zY@l}=6UIVJ+M7(yV<2EMLRN{OD}XmR%(hVew|7n{$VPyhe` literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder$StackMapFrameImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder$StackMapFrameImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..2a246fa535523918daccf98b35ffcbe13de10c59 GIT binary patch literal 2840 zcmb_eT~ixX7=8}<*no?Wv`_)tYNe8dwrl;?O+kSo(Lig1(WzG_$pIFY-MD+w8UKMl z#tSc!fn{4q-jTSHJ&sk*7-7H*TO1MVNJQ!E(PF0HDnkl)pD2k(*d;+JmV{O)CO z6CONi9*UMUOV2gjWiW=NflCTqvnxeE*J(rSOxAq+_yB_)b)0w1H5_;mSj(}Ti z2+!KHT3lMLqX<(a9p;M3uv)AR1q&&1Mz48xU1~6-!<k*PAw5RLnVsLw;H5k#xP`6Gs#186a$LK2Wr?>sIG4A0MPUYUms6Lq)iwZtZs zLvprP`=VO-KzT<6VMq9K%k`y(M-0msC_eP$d-ZvG&2^Cgv(Kkt7p1zr>EWVk*7OEP))$tu_47cM1cwI+Y$HE8`5ow|K-Rvo5c$rL? z<-Bl@gb`lc;!fKZ{$kB_kGh@c{RIsss*s6vMuO^jZwSBTSsm$mNs)EcVUimW#?R+L zlG+Cfb3`Wwz3Mo^3m^qOv3xH_{r;rkDZ@q_hnQ9uEmXvSVf9Nxo#Ae*U_{_F{J?N) z^i?877-c-9#yAFsMWj(st(tm8K{eK3q<%?f@6&t?OSDg&F|p3kJcA-qDAA4I=uU>l z`SM?2<%JVy<$EWXEZ;vtzC4#c!OTlKO`%M`S&{@>z%tE04yAAp_i07)ffaO4GiAqE zFjJPKf|;@*jR!QJ?Vm06&z9)SptF3MU_bz%rVlb4ksBW%Prwh!0A;iql`5@#inoA2 zXgYSzLOr|^S(v95{oxStw}IbZOZ*N#io`3VOu3gUFQ4L_SILKN=K2B3QOG_a1V$eA z3^9T=kSYHOZIl_A2!>H;K8?&s3Qvv-K`eX?pONJ%f=S{0>j;Nz`kZv%7z#3T5s(bN z2x9&v%wViwg~l?GAf$3g%{cPiuR@3qo?Gbu#U5 z%0n`fk{LSFAJ8Aw$yrHQifKtZ(>%cLS)KEpbG~!&pMM?v0bm&q42&^c+~H5S?QnP7 z?l?RMwxlEMWqn(vTLI(98pv5NU@}Z5$`3@x^ScbW1?ft)$dD;lT6q+3!hmIA0`D>0 z-|6n!(pAEDxs!sIdws{=P`tCd&ig9_)D`~hLstVy?#N$7wa>_vjP^%nyiZN>%Vp>C-AF;gK-Vq&jjHQVg23FAkmn>Yy z6$Vpzkwb=4<)c1pB`V?j7Cyi%>GpWgTP6}2S`_jB&3Ua-*WRvMxPdaUBYqxmCt&Ek z3tuUA4{3XBpsIW6Z~Bxgs%m?n#IT!IeZCiV%iH^j;ZnN3qYYGPF^os778}wP&B0z< z_?x`#5YMHC*Wpf!`%=sCKWU8tVdy~lNeG*RRzqxg0>cXfu-=~RZy zQCE37*o3?I6V3e_T{W6KLt(=k_#L5_0JY%Au-?>w)Obx1s5LK81{N6R{zKmdCYt;TzxCJfhNU}03So5fqOJh$E#A&BgS!y zekaDkP@%t){;i<>lB2tUIgH^$k{0P4qq9(bg-mtsH{@TCG=}+D6Rd!nbUzbm!Nx}< zk$#BA$ODjNB!FN)#wYY&!_L#m=*&!-&*(_wO@w$>^f|_(mcy0Ubd|KV>CEpaK6-_z zQfVKjsxOh>$GOr4y6@xS^AXIc6y{8fIYmqRFq~V2s4h0Aw?-hAsIvS8~8L1 zX@Nr0B$?H@16=zj`-mcQNRf%pa65E7fzM+kJCunsozQ3&=`gY}Ocq~+x!%E-;aS61 qIuL@1s<}v#4*XkWs3u?I8?4dG`B18%j%lj>4`}4_SjS!5$MkE^5Ig_? literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder.class b/tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder.class new file mode 100644 index 0000000000000000000000000000000000000000..934d3fa439a56377d0f8babc8833df061ff1ecff GIT binary patch literal 13944 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 R3)k{VH!Ztlx4egn{{^Psj935w literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder.java b/tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder.java new file mode 100644 index 00000000..2ea8922d --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/StackMapDecoder.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.classfile.impl; + +import java.lang.classfile.BufWriter; +import java.lang.classfile.ClassReader; +import java.lang.classfile.Label; +import java.lang.classfile.MethodModel; +import java.lang.classfile.attribute.StackMapFrameInfo; +import java.lang.classfile.attribute.StackMapFrameInfo.*; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; +import java.util.List; +import java.util.Objects; +import java.util.TreeMap; + +import static java.lang.classfile.ClassFile.*; + +public class StackMapDecoder { + + private static final int + SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, + SAME_EXTENDED = 251; + + private final ClassReader classReader; + private final int pos; + private final LabelContext ctx; + private final List initFrameLocals; + private int p; + + StackMapDecoder(ClassReader classReader, int pos, LabelContext ctx, List initFrameLocals) { + this.classReader = classReader; + this.pos = pos; + this.ctx = ctx; + this.initFrameLocals = initFrameLocals; + } + + static List initFrameLocals(MethodModel method) { + return initFrameLocals(method.parent().orElseThrow().thisClass(), + method.methodName().stringValue(), + method.methodTypeSymbol(), + method.flags().has(AccessFlag.STATIC)); + } + + public static List initFrameLocals(ClassEntry thisClass, String methodName, MethodTypeDesc methodType, boolean isStatic) { + VerificationTypeInfo vtis[]; + int i = 0; + if (!isStatic) { + vtis = new VerificationTypeInfo[methodType.parameterCount() + 1]; + if ("".equals(methodName) && !ConstantDescs.CD_Object.equals(thisClass.asSymbol())) { + vtis[i++] = SimpleVerificationTypeInfo.ITEM_UNINITIALIZED_THIS; + } else { + vtis[i++] = new StackMapDecoder.ObjectVerificationTypeInfoImpl(thisClass); + } + } else { + vtis = new VerificationTypeInfo[methodType.parameterCount()]; + } + for (int pi = 0; pi < methodType.parameterCount(); pi++) { + var arg = methodType.parameterType(pi); + vtis[i++] = switch (arg.descriptorString().charAt(0)) { + case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.ITEM_INTEGER; + case 'J' -> SimpleVerificationTypeInfo.ITEM_LONG; + case 'F' -> SimpleVerificationTypeInfo.ITEM_FLOAT; + case 'D' -> SimpleVerificationTypeInfo.ITEM_DOUBLE; + case 'V' -> throw new IllegalArgumentException("Illegal method argument type: " + arg); + default -> new StackMapDecoder.ObjectVerificationTypeInfoImpl(TemporaryConstantPool.INSTANCE.classEntry(arg)); + }; + } + return List.of(vtis); + } + + public static void writeFrames(BufWriter b, List entries) { + var buf = (BufWriterImpl)b; + var dcb = (DirectCodeBuilder)buf.labelContext(); + var mi = dcb.methodInfo(); + var prevLocals = StackMapDecoder.initFrameLocals(buf.thisClass(), + mi.methodName().stringValue(), + mi.methodTypeSymbol(), + (mi.methodFlags() & ACC_STATIC) != 0); + int prevOffset = -1; + var map = new TreeMap(); + //sort by resolved label offsets first to allow unordered entries + for (var fr : entries) { + map.put(dcb.labelToBci(fr.target()), fr); + } + b.writeU2(map.size()); + for (var me : map.entrySet()) { + int offset = me.getKey(); + var fr = me.getValue(); + writeFrame(buf, offset - prevOffset - 1, prevLocals, fr); + prevOffset = offset; + prevLocals = fr.locals(); + } + } + + private static void writeFrame(BufWriterImpl out, int offsetDelta, List prevLocals, StackMapFrameInfo fr) { + if (offsetDelta < 0) throw new IllegalArgumentException("Invalid stack map frames order"); + if (fr.stack().isEmpty()) { + int commonLocalsSize = Math.min(prevLocals.size(), fr.locals().size()); + int diffLocalsSize = fr.locals().size() - prevLocals.size(); + if (-3 <= diffLocalsSize && diffLocalsSize <= 3 && equals(fr.locals(), prevLocals, commonLocalsSize)) { + if (diffLocalsSize == 0 && offsetDelta < 64) { //same frame + out.writeU1(offsetDelta); + } else { //chop, same extended or append frame + out.writeU1(251 + diffLocalsSize); + out.writeU2(offsetDelta); + for (int i=commonLocalsSize; i l1, List l2, int compareSize) { + for (int i = 0; i < compareSize; i++) { + if (!l1.get(i).equals(l2.get(i))) return false; + } + return true; + } + + private static void writeTypeInfo(BufWriterImpl bw, VerificationTypeInfo vti) { + bw.writeU1(vti.tag()); + switch (vti) { + case SimpleVerificationTypeInfo svti -> + {} + case ObjectVerificationTypeInfo ovti -> + bw.writeIndex(ovti.className()); + case UninitializedVerificationTypeInfo uvti -> + bw.writeU2(bw.labelContext().labelToBci(uvti.newTarget())); + } + } + + List entries() { + p = pos; + List locals = initFrameLocals, stack = List.of(); + int bci = -1; + var entries = new StackMapFrameInfo[u2()]; + for (int ei = 0; ei < entries.length; ei++) { + int frameType = classReader.readU1(p++); + if (frameType < 64) { + bci += frameType + 1; + stack = List.of(); + } else if (frameType < 128) { + bci += frameType - 63; + stack = List.of(readVerificationTypeInfo()); + } else { + if (frameType < SAME_LOCALS_1_STACK_ITEM_EXTENDED) + throw new IllegalArgumentException("Invalid stackmap frame type: " + frameType); + bci += u2() + 1; + if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { + stack = List.of(readVerificationTypeInfo()); + } else if (frameType < SAME_EXTENDED) { + locals = locals.subList(0, locals.size() + frameType - SAME_EXTENDED); + stack = List.of(); + } else if (frameType == SAME_EXTENDED) { + stack = List.of(); + } else if (frameType < SAME_EXTENDED + 4) { + int actSize = locals.size(); + var newLocals = locals.toArray(new VerificationTypeInfo[actSize + frameType - SAME_EXTENDED]); + for (int i = actSize; i < newLocals.length; i++) + newLocals[i] = readVerificationTypeInfo(); + locals = List.of(newLocals); + stack = List.of(); + } else { + var newLocals = new VerificationTypeInfo[u2()]; + for (int i=0; i SimpleVerificationTypeInfo.ITEM_TOP; + case VT_INTEGER -> SimpleVerificationTypeInfo.ITEM_INTEGER; + case VT_FLOAT -> SimpleVerificationTypeInfo.ITEM_FLOAT; + case VT_DOUBLE -> SimpleVerificationTypeInfo.ITEM_DOUBLE; + case VT_LONG -> SimpleVerificationTypeInfo.ITEM_LONG; + case VT_NULL -> SimpleVerificationTypeInfo.ITEM_NULL; + case VT_UNINITIALIZED_THIS -> SimpleVerificationTypeInfo.ITEM_UNINITIALIZED_THIS; + case VT_OBJECT -> new ObjectVerificationTypeInfoImpl(classReader.entryByIndex(u2(), ClassEntry.class)); + case VT_UNINITIALIZED -> new UninitializedVerificationTypeInfoImpl(ctx.getLabel(u2())); + default -> throw new IllegalArgumentException("Invalid verification type tag: " + tag); + }; + } + + public static record ObjectVerificationTypeInfoImpl( + ClassEntry className) implements ObjectVerificationTypeInfo { + + @Override + public int tag() { return VT_OBJECT; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof ObjectVerificationTypeInfoImpl that) { + return Objects.equals(className, that.className); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(className); + } + + @Override + public String toString() { + return className.asInternalName(); + } + } + + public static record UninitializedVerificationTypeInfoImpl(Label newTarget) implements UninitializedVerificationTypeInfo { + + @Override + public int tag() { return VT_UNINITIALIZED; } + + @Override + public String toString() { + return "UNINIT(" + newTarget +")"; + } + } + + private int u2() { + int v = classReader.readU2(p); + p += 2; + return v; + } + + public static record StackMapFrameImpl(int frameType, + Label target, + List locals, + List stack) + implements StackMapFrameInfo { + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator$1.class b/tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator$1.class new file mode 100644 index 0000000000000000000000000000000000000000..45adcada24e4ab1aad55fd75bcea216bd4a78162 GIT binary patch literal 2913 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator$RawExceptionCatch.class b/tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator$RawExceptionCatch.class new file mode 100644 index 0000000000000000000000000000000000000000..e66ebf3b0f99e0835971de716adc3665faa75f37 GIT binary patch literal 2251 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator.class b/tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator.class new file mode 100644 index 0000000000000000000000000000000000000000..100a511b1d73233db9ec901dfe3d39721191d825 GIT binary patch literal 28550 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator.java b/tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator.java new file mode 100644 index 00000000..dd4d7d42 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/StackMapGenerator.java @@ -0,0 +1,1402 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.constantpool.InvokeDynamicEntry; +import java.lang.classfile.constantpool.NameAndTypeEntry; +import java.lang.constant.ClassDesc; +import static java.lang.constant.ConstantDescs.*; +import java.lang.constant.MethodTypeDesc; +import java.lang.classfile.ClassFile; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantDynamicEntry; +import java.lang.classfile.constantpool.DynamicConstantPoolEntry; +import java.lang.classfile.constantpool.MemberRefEntry; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.lang.classfile.Attribute; + +import static java.lang.classfile.ClassFile.*; +import java.lang.classfile.BufWriter; +import java.lang.classfile.Label; +import java.lang.classfile.attribute.StackMapTableAttribute; +import java.lang.classfile.Attributes; + +/** + * StackMapGenerator is responsible for stack map frames generation. + *

+ * Stack map frames are computed from serialized bytecode similar way they are verified during class loading process. + *

+ * The {@linkplain #generate() frames computation} consists of following steps: + *

    + *
  1. {@linkplain #detectFrameOffsets() Detection} of mandatory stack map frames offsets:
      + *
    • Mandatory stack map frame offsets include all jump and switch instructions targets, + * offsets immediately following {@linkplain #noControlFlow(int) "no control flow"} + * and all exception table handlers. + *
    • Detection is performed in a single fast pass through the bytecode, + * with no auxiliary structures construction nor further instructions processing. + *
    + *
  2. Generator loop {@linkplain #processMethod() processing bytecode instructions}:
      + *
    • Generator loop simulates sequence instructions {@linkplain #processBlock(RawBytecodeHelper) processing effect on the actual stack and locals}. + *
    • All mandatory {@linkplain Frame frames} detected in the step #1 are {@linkplain Frame#checkAssignableTo(Frame) retro-filled} + * (or {@linkplain Frame#merge(Type, Type[], int, Frame) reverse-merged} in subsequent processing) + * with the actual stack and locals for all matching jump, switch and exception handler targets. + *
    • All frames modified by reverse merges are marked as {@linkplain Frame#dirty dirty} for further processing. + *
    • Code blocks with not yet known entry frame content are skipped and related frames are also marked as dirty. + *
    • Generator loop process is repeated until all mandatory frames are cleared or until an error state is reached. + *
    • Generator loop always passes all instructions at least once to calculate {@linkplain #maxStack max stack} + * and {@linkplain #maxLocals max locals} code attributes. + *
    • More than one pass is usually not necessary, except for more complex bytecode sequences.
      + * (Note: experimental measurements showed that more than 99% of the cases required only single pass to clear all frames, + * less than 1% of the cases required second pass and remaining 0,01% of the cases required third pass to clear all frames.). + *
    + *
  3. Dead code patching to pass class loading verification:
      + *
    • Dead code blocks are indicated by frames remaining without content after leaving the Generator loop. + *
    • Each dead code block is filled with NOP instructions, terminated with + * ATHROW instruction, and removed from exception handlers table. + *
    • Dead code block entry frame is set to java.lang.Throwable single stack item and no locals. + *
    + *
+ *

+ * {@linkplain Frame#merge(Type, Type[], int, Frame) Reverse-merge} of the stack map frames + * may in some situations require to determine {@linkplain ClassHierarchyImpl class hierarchy} relations. + *

+ * Reverse-merge of individual {@linkplain Type types} is performed when a target frame has already been retro-filled + * and it is necessary to adjust its existing stack entries and locals to also match actual stack map frame conditions. + * Following tables describe how new target stack entry or local type is calculated, based on the actual frame stack entry or local ("from") + * and actual value of the target stack entry or local ("to"). + * + * + * + *
Reverse-merge of general type categories
to \ fromTOPPRIMITIVEUNINITIALIZEDREFERENCE + *
TOPTOPTOPTOPTOP + *
PRIMITIVETOPReverse-merge of primitive typesTOPTOP + *
UNINITIALIZEDTOPTOPIs NEW offset matching ? UNINITIALIZED : TOPTOP + *
REFERENCETOPTOPTOPReverse-merge of reference types + *
+ *

+ * + * + *
Reverse-merge of primitive types
to \ fromSHORTBYTEBOOLEANLONGDOUBLEFLOATINTEGER + *
SHORTSHORTTOPTOPTOPTOPTOPSHORT + *
BYTETOPBYTETOPTOPTOPTOPBYTE + *
BOOLEANTOPTOPBOOLEANTOPTOPTOPBOOLEAN + *
LONGTOPTOPTOPLONGTOPTOPTOP + *
DOUBLETOPTOPTOPTOPDOUBLETOPTOP + *
FLOATTOPTOPTOPTOPTOPFLOATTOP + *
INTEGERTOPTOPTOPTOPTOPTOPINTEGER + *
+ *

+ * + * + *
Reverse merge of reference types
to \ fromNULLj.l.Objectj.l.Cloneablej.i.SerializableARRAYINTERFACE*OBJECT** + *
NULLNULLj.l.Objectj.l.Cloneablej.i.SerializableARRAYINTERFACEOBJECT + *
j.l.Objectj.l.Objectj.l.Objectj.l.Objectj.l.Objectj.l.Objectj.l.Objectj.l.Object + *
j.l.Cloneablej.l.Cloneablej.l.Cloneablej.l.Cloneablej.l.Cloneablej.l.Objectj.l.Cloneablej.l.Cloneable + *
j.i.Serializablej.i.Serializablej.i.Serializablej.i.Serializablej.i.Serializablej.l.Objectj.i.Serializablej.i.Serializable + *
ARRAYARRAYj.l.Objectj.l.Objectj.l.ObjectReverse merge of arraysj.l.Objectj.l.Object + *
INTERFACE*INTERFACEj.l.Objectj.l.Objectj.l.Objectj.l.Objectj.l.Objectj.l.Object + *
OBJECT**OBJECTj.l.Objectj.l.Objectj.l.Objectj.l.Objectj.l.ObjectResolved common ancestor + *
*any interface reference except for j.l.Cloneable and j.i.Serializable
**any object reference except for j.l.Object + *
+ *

+ * Array types are reverse-merged as reference to array type constructed from reverse-merged components. + * Reference to j.l.Object is an alternate result when construction of the array type is not possible (when reverse-merge of components returned TOP or other non-reference and non-primitive type). + *

+ * Custom class hierarchy resolver has been implemented as a part of the library to avoid heavy class loading + * and to allow stack maps generation even for code with incomplete dependency classpath. + * However stack maps generated with {@linkplain ClassHierarchyImpl#resolve(java.lang.constant.ClassDesc) warnings of unresolved dependencies} may later fail to verify during class loading process. + *

+ * Focus of the whole algorithm is on high performance and low memory footprint:

    + *
  • It does not produce, collect nor visit any complex intermediate structures + * (beside {@linkplain RawBytecodeHelper traversing} the {@linkplain #bytecode bytecode in binary form}). + *
  • It works with only minimal mandatory stack map frames. + *
  • It does not spend time on any non-essential verifications. + *
+ */ + +public final class StackMapGenerator { + + static StackMapGenerator of(DirectCodeBuilder dcb, BufWriterImpl buf) { + return new StackMapGenerator( + dcb, + buf.thisClass().asSymbol(), + dcb.methodInfo.methodName().stringValue(), + dcb.methodInfo.methodTypeSymbol(), + (dcb.methodInfo.methodFlags() & ACC_STATIC) != 0, + ((BufWriterImpl) dcb.bytecodesBufWriter).asByteBuffer(), + dcb.constantPool, + dcb.context, + dcb.handlers); + } + + private static final String OBJECT_INITIALIZER_NAME = ""; + private static final int FLAG_THIS_UNINIT = 0x01; + private static final int FRAME_DEFAULT_CAPACITY = 10; + private static final int T_BOOLEAN = 4, T_LONG = 11; + + private static final int ITEM_TOP = 0, + ITEM_INTEGER = 1, + ITEM_FLOAT = 2, + ITEM_DOUBLE = 3, + ITEM_LONG = 4, + ITEM_NULL = 5, + ITEM_UNINITIALIZED_THIS = 6, + ITEM_OBJECT = 7, + ITEM_UNINITIALIZED = 8, + ITEM_BOOLEAN = 9, + ITEM_BYTE = 10, + ITEM_SHORT = 11, + ITEM_CHAR = 12, + ITEM_LONG_2ND = 13, + ITEM_DOUBLE_2ND = 14; + + private static final Type[] ARRAY_FROM_BASIC_TYPE = {null, null, null, null, + Type.BOOLEAN_ARRAY_TYPE, Type.CHAR_ARRAY_TYPE, Type.FLOAT_ARRAY_TYPE, Type.DOUBLE_ARRAY_TYPE, + Type.BYTE_ARRAY_TYPE, Type.SHORT_ARRAY_TYPE, Type.INT_ARRAY_TYPE, Type.LONG_ARRAY_TYPE}; + + static record RawExceptionCatch(int start, int end, int handler, Type catchType) {} + + private final Type thisType; + private final String methodName; + private final MethodTypeDesc methodDesc; + private final ByteBuffer bytecode; + private final SplitConstantPool cp; + private final boolean isStatic; + private final LabelContext labelContext; + private final List handlers; + private final List rawHandlers; + private final ClassHierarchyImpl classHierarchy; + private final boolean patchDeadCode; + private final boolean filterDeadLabels; + private List frames; + private final Frame currentFrame; + private int maxStack, maxLocals; + + /** + * Primary constructor of the Generator class. + * New Generator instance must be created for each individual class/method. + * Instance contains only immutable results, all the calculations are processed during instance construction. + * + * @param labelContext LabelContext instance used to resolve or patch ExceptionHandler + * labels to bytecode offsets (or vice versa) + * @param thisClass class to generate stack maps for + * @param methodName method name to generate stack maps for + * @param methodDesc method descriptor to generate stack maps for + * @param isStatic information whether the method is static + * @param bytecode R/W ByteBuffer wrapping method bytecode, the content is altered in case Generator detects and patches dead code + * @param cp R/W ConstantPoolBuilder instance used to resolve all involved CP entries and also generate new entries referenced from the generated stack maps + * @param handlers R/W ExceptionHandler list used to detect mandatory frame offsets as well as to determine stack maps in exception handlers + * and also to be altered when dead code is detected and must be excluded from exception handlers + */ + public StackMapGenerator(LabelContext labelContext, + ClassDesc thisClass, + String methodName, + MethodTypeDesc methodDesc, + boolean isStatic, + ByteBuffer bytecode, + SplitConstantPool cp, + ClassFileImpl context, + List handlers) { + this.thisType = Type.referenceType(thisClass); + this.methodName = methodName; + this.methodDesc = methodDesc; + this.isStatic = isStatic; + this.bytecode = bytecode; + this.cp = cp; + this.labelContext = labelContext; + this.handlers = handlers; + this.rawHandlers = new ArrayList<>(handlers.size()); + this.classHierarchy = new ClassHierarchyImpl(context.classHierarchyResolverOption().classHierarchyResolver()); + this.patchDeadCode = context.deadCodeOption() == ClassFile.DeadCodeOption.PATCH_DEAD_CODE; + this.filterDeadLabels = context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS; + this.currentFrame = new Frame(classHierarchy); + generate(); + } + + /** + * Calculated maximum number of the locals required + * @return maximum number of the locals required + */ + public int maxLocals() { + return maxLocals; + } + + /** + * Calculated maximum stack size required + * @return maximum stack size required + */ + public int maxStack() { + return maxStack; + } + + private Frame getFrame(int offset) { + //binary search over frames ordered by offset + int low = 0; + int high = frames.size() - 1; + while (low <= high) { + int mid = (low + high) >>> 1; + var f = frames.get(mid); + if (f.offset < offset) + low = mid + 1; + else if (f.offset > offset) + high = mid - 1; + else + return f; + } + return null; + } + + private void checkJumpTarget(Frame frame, int target) { + frame.checkAssignableTo(getFrame(target)); + } + + private int exMin, exMax; + + private boolean isAnyFrameDirty() { + for (var f : frames) { + if (f.dirty) return true; + } + return false; + } + + private void generate() { + exMin = bytecode.capacity(); + exMax = -1; + for (var exhandler : handlers) { + int start_pc = labelContext.labelToBci(exhandler.tryStart()); + int end_pc = labelContext.labelToBci(exhandler.tryEnd()); + int handler_pc = labelContext.labelToBci(exhandler.handler()); + if (start_pc >= 0 && end_pc >= 0 && end_pc > start_pc && handler_pc >= 0) { + if (start_pc < exMin) exMin = start_pc; + if (end_pc > exMax) exMax = end_pc; + var catchType = exhandler.catchType(); + rawHandlers.add(new RawExceptionCatch(start_pc, end_pc, handler_pc, + catchType.isPresent() ? cpIndexToType(catchType.get().index(), cp) + : Type.THROWABLE_TYPE)); + } + } + BitSet frameOffsets = detectFrameOffsets(); + int framesCount = frameOffsets.cardinality(); + frames = new ArrayList<>(framesCount); + int offset = -1; + for (int i = 0; i < framesCount; i++) { + offset = frameOffsets.nextSetBit(offset + 1); + frames.add(new Frame(offset, classHierarchy)); + } + do { + processMethod(); + } while (isAnyFrameDirty()); + maxLocals = currentFrame.frameMaxLocals; + maxStack = currentFrame.frameMaxStack; + + //dead code patching + for (int i = 0; i < framesCount; i++) { + var frame = frames.get(i); + if (frame.flags == -1) { + if (!patchDeadCode) throw generatorError("Unable to generate stack map frame for dead code", frame.offset); + //patch frame + frame.pushStack(Type.THROWABLE_TYPE); + if (maxStack < 1) maxStack = 1; + int blockSize = (i < framesCount - 1 ? frames.get(i + 1).offset : bytecode.limit()) - frame.offset; + //patch bytecode + bytecode.position(frame.offset); + for (int n=1; n= handlerEnd || rangeEnd <= handlerStart) { + //out of range + continue; + } + if (rangeStart <= handlerStart) { + if (rangeEnd >= handlerEnd) { + //complete removal + it.remove(); + } else { + //cut from left + Label newStart = labelContext.newLabel(); + labelContext.setLabelTarget(newStart, rangeEnd); + it.set(new AbstractPseudoInstruction.ExceptionCatchImpl(e.handler(), newStart, e.tryEnd(), e.catchType())); + } + } else if (rangeEnd >= handlerEnd) { + //cut from right + Label newEnd = labelContext.newLabel(); + labelContext.setLabelTarget(newEnd, rangeStart); + it.set(new AbstractPseudoInstruction.ExceptionCatchImpl(e.handler(), e.tryStart(), newEnd, e.catchType())); + } else { + //split + Label newStart = labelContext.newLabel(); + labelContext.setLabelTarget(newStart, rangeEnd); + Label newEnd = labelContext.newLabel(); + labelContext.setLabelTarget(newEnd, rangeStart); + it.set(new AbstractPseudoInstruction.ExceptionCatchImpl(e.handler(), e.tryStart(), newEnd, e.catchType())); + it.add(new AbstractPseudoInstruction.ExceptionCatchImpl(e.handler(), newStart, e.tryEnd(), e.catchType())); + } + } + } + + /** + * Getter of the generated StackMapTableAttribute or null if stack map is empty + * @return StackMapTableAttribute or null if stack map is empty + */ + public Attribute stackMapTableAttribute() { + return frames.isEmpty() ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { + @Override + public void writeBody(BufWriter b) { + b.writeU2(frames.size()); + Frame prevFrame = new Frame(classHierarchy); + prevFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType); + prevFrame.trimAndCompress(); + for (var fr : frames) { + fr.trimAndCompress(); + fr.writeTo(b, prevFrame, cp); + prevFrame = fr; + } + } + }; + } + + private static Type cpIndexToType(int index, ConstantPoolBuilder cp) { + return Type.referenceType(cp.entryByIndex(index, ClassEntry.class).asSymbol()); + } + + private void processMethod() { + currentFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType); + currentFrame.stackSize = 0; + currentFrame.flags = 0; + currentFrame.offset = -1; + int stackmapIndex = 0; + RawBytecodeHelper bcs = new RawBytecodeHelper(bytecode); + boolean ncf = false; + while (!bcs.isLastBytecode()) { + bcs.rawNext(); + currentFrame.offset = bcs.bci; + if (stackmapIndex < frames.size()) { + int thisOffset = frames.get(stackmapIndex).offset; + if (ncf && thisOffset > bcs.bci) { + throw generatorError("Expecting a stack map frame"); + } + if (thisOffset == bcs.bci) { + if (!ncf) { + currentFrame.checkAssignableTo(frames.get(stackmapIndex)); + } + Frame nextFrame = frames.get(stackmapIndex++); + while (!nextFrame.dirty) { //skip unmatched frames + if (stackmapIndex == frames.size()) return; //skip the rest of this round + nextFrame = frames.get(stackmapIndex++); + } + bcs.rawNext(nextFrame.offset); //skip code up-to the next frame + currentFrame.offset = bcs.bci; + currentFrame.copyFrom(nextFrame); + nextFrame.dirty = false; + } else if (thisOffset < bcs.bci) { + throw new ClassFormatError(String.format("Bad stack map offset %d", thisOffset)); + } + } else if (ncf) { + throw generatorError("Expecting a stack map frame"); + } + ncf = processBlock(bcs); + } + } + + private boolean processBlock(RawBytecodeHelper bcs) { + int opcode = bcs.rawCode; + boolean ncf = false; + boolean this_uninit = false; + boolean verified_exc_handlers = false; + int bci = bcs.bci; + Type type1, type2, type3, type4; + if (RawBytecodeHelper.isStoreIntoLocal(opcode) && bci >= exMin && bci < exMax) { + processExceptionHandlerTargets(bci, this_uninit); + verified_exc_handlers = true; + } + switch (opcode) { + case NOP -> {} + case RETURN -> { + ncf = true; + } + case ACONST_NULL -> + currentFrame.pushStack(Type.NULL_TYPE); + case ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, SIPUSH, BIPUSH -> + currentFrame.pushStack(Type.INTEGER_TYPE); + case LCONST_0, LCONST_1 -> + currentFrame.pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case FCONST_0, FCONST_1, FCONST_2 -> + currentFrame.pushStack(Type.FLOAT_TYPE); + case DCONST_0, DCONST_1 -> + currentFrame.pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case LDC -> + processLdc(bcs.getIndexU1()); + case LDC_W, LDC2_W -> + processLdc(bcs.getIndexU2()); + case ILOAD -> + currentFrame.checkLocal(bcs.getIndex()).pushStack(Type.INTEGER_TYPE); + case ILOAD_0, ILOAD_1, ILOAD_2, ILOAD_3 -> + currentFrame.checkLocal(opcode - ILOAD_0).pushStack(Type.INTEGER_TYPE); + case LLOAD -> + currentFrame.checkLocal(bcs.getIndex() + 1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case LLOAD_0, LLOAD_1, LLOAD_2, LLOAD_3 -> + currentFrame.checkLocal(opcode - LLOAD_0 + 1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case FLOAD -> + currentFrame.checkLocal(bcs.getIndex()).pushStack(Type.FLOAT_TYPE); + case FLOAD_0, FLOAD_1, FLOAD_2, FLOAD_3 -> + currentFrame.checkLocal(opcode - FLOAD_0).pushStack(Type.FLOAT_TYPE); + case DLOAD -> + currentFrame.checkLocal(bcs.getIndex() + 1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case DLOAD_0, DLOAD_1, DLOAD_2, DLOAD_3 -> + currentFrame.checkLocal(opcode - DLOAD_0 + 1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case ALOAD -> + currentFrame.pushStack(currentFrame.getLocal(bcs.getIndex())); + case ALOAD_0, ALOAD_1, ALOAD_2, ALOAD_3 -> + currentFrame.pushStack(currentFrame.getLocal(opcode - ALOAD_0)); + case IALOAD, BALOAD, CALOAD, SALOAD -> + currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + case LALOAD -> + currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case FALOAD -> + currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + case DALOAD -> + currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case AALOAD -> + currentFrame.pushStack((type1 = currentFrame.decStack(1).popStack()) == Type.NULL_TYPE ? Type.NULL_TYPE : type1.getComponent()); + case ISTORE -> + currentFrame.decStack(1).setLocal(bcs.getIndex(), Type.INTEGER_TYPE); + case ISTORE_0, ISTORE_1, ISTORE_2, ISTORE_3 -> + currentFrame.decStack(1).setLocal(opcode - ISTORE_0, Type.INTEGER_TYPE); + case LSTORE -> + currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.LONG_TYPE, Type.LONG2_TYPE); + case LSTORE_0, LSTORE_1, LSTORE_2, LSTORE_3 -> + currentFrame.decStack(2).setLocal2(opcode - LSTORE_0, Type.LONG_TYPE, Type.LONG2_TYPE); + case FSTORE -> + currentFrame.decStack(1).setLocal(bcs.getIndex(), Type.FLOAT_TYPE); + case FSTORE_0, FSTORE_1, FSTORE_2, FSTORE_3 -> + currentFrame.decStack(1).setLocal(opcode - FSTORE_0, Type.FLOAT_TYPE); + case DSTORE -> + currentFrame.decStack(2).setLocal2(bcs.getIndex(), Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case DSTORE_0, DSTORE_1, DSTORE_2, DSTORE_3 -> + currentFrame.decStack(2).setLocal2(opcode - DSTORE_0, Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case ASTORE -> + currentFrame.setLocal(bcs.getIndex(), currentFrame.popStack()); + case ASTORE_0, ASTORE_1, ASTORE_2, ASTORE_3 -> + currentFrame.setLocal(opcode - ASTORE_0, currentFrame.popStack()); + case LASTORE, DASTORE -> + currentFrame.decStack(4); + case IASTORE, BASTORE, CASTORE, SASTORE, FASTORE, AASTORE -> + currentFrame.decStack(3); + case POP, MONITORENTER, MONITOREXIT -> + currentFrame.decStack(1); + case POP2 -> + currentFrame.decStack(2); + case DUP -> + currentFrame.pushStack(type1 = currentFrame.popStack()).pushStack(type1); + case DUP_X1 -> { + type1 = currentFrame.popStack(); + type2 = currentFrame.popStack(); + currentFrame.pushStack(type1).pushStack(type2).pushStack(type1); + } + case DUP_X2 -> { + type1 = currentFrame.popStack(); + type2 = currentFrame.popStack(); + type3 = currentFrame.popStack(); + currentFrame.pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1); + } + case DUP2 -> { + type1 = currentFrame.popStack(); + type2 = currentFrame.popStack(); + currentFrame.pushStack(type2).pushStack(type1).pushStack(type2).pushStack(type1); + } + case DUP2_X1 -> { + type1 = currentFrame.popStack(); + type2 = currentFrame.popStack(); + type3 = currentFrame.popStack(); + currentFrame.pushStack(type2).pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1); + } + case DUP2_X2 -> { + type1 = currentFrame.popStack(); + type2 = currentFrame.popStack(); + type3 = currentFrame.popStack(); + type4 = currentFrame.popStack(); + currentFrame.pushStack(type2).pushStack(type1).pushStack(type4).pushStack(type3).pushStack(type2).pushStack(type1); + } + case SWAP -> { + type1 = currentFrame.popStack(); + type2 = currentFrame.popStack(); + currentFrame.pushStack(type1); + currentFrame.pushStack(type2); + } + case IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IOR, IXOR, IAND -> + currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + case INEG, ARRAYLENGTH, INSTANCEOF -> + currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE); + case LADD, LSUB, LMUL, LDIV, LREM, LAND, LOR, LXOR -> + currentFrame.decStack(4).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case LNEG -> + currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case LSHL, LSHR, LUSHR -> + currentFrame.decStack(3).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case FADD, FSUB, FMUL, FDIV, FREM -> + currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + case FNEG -> + currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE); + case DADD, DSUB, DMUL, DDIV, DREM -> + currentFrame.decStack(4).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case DNEG -> + currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case IINC -> + currentFrame.checkLocal(bcs.getIndex()); + case I2L -> + currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case L2I -> + currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + case I2F -> + currentFrame.decStack(1).pushStack(Type.FLOAT_TYPE); + case I2D -> + currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case L2F -> + currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + case L2D -> + currentFrame.decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case F2I -> + currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE); + case F2L -> + currentFrame.decStack(1).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case F2D -> + currentFrame.decStack(1).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case D2L -> + currentFrame.decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case D2F -> + currentFrame.decStack(2).pushStack(Type.FLOAT_TYPE); + case I2B, I2C, I2S -> + currentFrame.decStack(1).pushStack(Type.INTEGER_TYPE); + case LCMP, DCMPL, DCMPG -> + currentFrame.decStack(4).pushStack(Type.INTEGER_TYPE); + case FCMPL, FCMPG, D2I -> + currentFrame.decStack(2).pushStack(Type.INTEGER_TYPE); + case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE -> + checkJumpTarget(currentFrame.decStack(2), bcs.dest()); + case IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL -> + checkJumpTarget(currentFrame.decStack(1), bcs.dest()); + case GOTO -> { + checkJumpTarget(currentFrame, bcs.dest()); + ncf = true; + } + case GOTO_W -> { + checkJumpTarget(currentFrame, bcs.destW()); + ncf = true; + } + case TABLESWITCH, LOOKUPSWITCH -> { + processSwitch(bcs); + ncf = true; + } + case LRETURN, DRETURN -> { + currentFrame.decStack(2); + ncf = true; + } + case IRETURN, FRETURN, ARETURN, ATHROW -> { + currentFrame.decStack(1); + ncf = true; + } + case GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD -> + processFieldInstructions(bcs); + case INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, INVOKEDYNAMIC -> + this_uninit = processInvokeInstructions(bcs, (bci >= exMin && bci < exMax), this_uninit); + case NEW -> + currentFrame.pushStack(Type.uninitializedType(bci)); + case NEWARRAY -> + currentFrame.decStack(1).pushStack(getNewarrayType(bcs.getIndex())); + case ANEWARRAY -> + processAnewarray(bcs.getIndexU2()); + case CHECKCAST -> + currentFrame.decStack(1).pushStack(cpIndexToType(bcs.getIndexU2(), cp)); + case MULTIANEWARRAY -> { + type1 = cpIndexToType(bcs.getIndexU2(), cp); + int dim = bcs.getU1(bcs.bci + 3); + for (int i = 0; i < dim; i++) { + currentFrame.popStack(); + } + currentFrame.pushStack(type1); + } + case JSR, JSR_W, RET -> + throw generatorError("Instructions jsr, jsr_w, or ret must not appear in the class file version >= 51.0"); + default -> + throw generatorError(String.format("Bad instruction: %02x", opcode)); + } + if (!verified_exc_handlers && bci >= exMin && bci < exMax) { + processExceptionHandlerTargets(bci, this_uninit); + } + return ncf; + } + + private void processExceptionHandlerTargets(int bci, boolean this_uninit) { + for (var ex : rawHandlers) { + if (bci == ex.start || (currentFrame.localsChanged && bci > ex.start && bci < ex.end)) { + int flags = currentFrame.flags; + if (this_uninit) flags |= FLAG_THIS_UNINIT; + Frame newFrame = currentFrame.frameInExceptionHandler(flags, ex.catchType); + checkJumpTarget(newFrame, ex.handler); + } + } + currentFrame.localsChanged = false; + } + + private void processLdc(int index) { + switch (cp.entryByIndex(index).tag()) { + case TAG_UTF8 -> + currentFrame.pushStack(Type.OBJECT_TYPE); + case TAG_STRING -> + currentFrame.pushStack(Type.STRING_TYPE); + case TAG_CLASS -> + currentFrame.pushStack(Type.CLASS_TYPE); + case TAG_INTEGER -> + currentFrame.pushStack(Type.INTEGER_TYPE); + case TAG_FLOAT -> + currentFrame.pushStack(Type.FLOAT_TYPE); + case TAG_DOUBLE -> + currentFrame.pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case TAG_LONG -> + currentFrame.pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case TAG_METHODHANDLE -> + currentFrame.pushStack(Type.METHOD_HANDLE_TYPE); + case TAG_METHODTYPE -> + currentFrame.pushStack(Type.METHOD_TYPE); + case TAG_CONSTANTDYNAMIC -> + currentFrame.pushStack(cp.entryByIndex(index, ConstantDynamicEntry.class).asSymbol().constantType()); + default -> + throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag())); + } + } + + private void processSwitch(RawBytecodeHelper bcs) { + int bci = bcs.bci; + int alignedBci = RawBytecodeHelper.align(bci + 1); + int defaultOfset = bcs.getInt(alignedBci); + int keys, delta; + currentFrame.popStack(); + if (bcs.rawCode == TABLESWITCH) { + int low = bcs.getInt(alignedBci + 4); + int high = bcs.getInt(alignedBci + 2 * 4); + if (low > high) { + throw generatorError("low must be less than or equal to high in tableswitch"); + } + keys = high - low + 1; + if (keys < 0) { + throw generatorError("too many keys in tableswitch"); + } + delta = 1; + } else { + keys = bcs.getInt(alignedBci + 4); + if (keys < 0) { + throw generatorError("number of keys in lookupswitch less than 0"); + } + delta = 2; + for (int i = 0; i < (keys - 1); i++) { + int this_key = bcs.getInt(alignedBci + (2 + 2 * i) * 4); + int next_key = bcs.getInt(alignedBci + (2 + 2 * i + 2) * 4); + if (this_key >= next_key) { + throw generatorError("Bad lookupswitch instruction"); + } + } + } + int target = bci + defaultOfset; + checkJumpTarget(currentFrame, target); + for (int i = 0; i < keys; i++) { + alignedBci = RawBytecodeHelper.align(bcs.bci + 1); + target = bci + bcs.getInt(alignedBci + (3 + i * delta) * 4); + checkJumpTarget(currentFrame, target); + } + } + + private void processFieldInstructions(RawBytecodeHelper bcs) { + var desc = Util.fieldTypeSymbol(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).nameAndType()); + switch (bcs.rawCode) { + case GETSTATIC -> + currentFrame.pushStack(desc); + case PUTSTATIC -> { + currentFrame.popStack(); + if (Util.isDoubleSlot(desc)) currentFrame.popStack(); + } + case GETFIELD -> { + currentFrame.popStack(); + currentFrame.pushStack(desc); + } + case PUTFIELD -> { + currentFrame.popStack(); + currentFrame.popStack(); + if (Util.isDoubleSlot(desc)) currentFrame.popStack(); + } + default -> throw new AssertionError("Should not reach here"); + } + } + + private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBlock, boolean thisUninit) { + int index = bcs.getIndexU2(); + int opcode = bcs.rawCode; + var nameAndType = opcode == INVOKEDYNAMIC + ? cp.entryByIndex(index, InvokeDynamicEntry.class).nameAndType() + : cp.entryByIndex(index, MemberRefEntry.class).nameAndType(); + String invokeMethodName = nameAndType.name().stringValue(); + var mDesc = Util.methodTypeSymbol(nameAndType); + int bci = bcs.bci; + currentFrame.decStack(Util.parameterSlots(mDesc)); + if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { + if (OBJECT_INITIALIZER_NAME.equals(invokeMethodName)) { + Type type = currentFrame.popStack(); + if (type == Type.UNITIALIZED_THIS_TYPE) { + if (inTryBlock) { + processExceptionHandlerTargets(bci, true); + } + currentFrame.initializeObject(type, thisType); + thisUninit = true; + } else if (type.tag == ITEM_UNINITIALIZED) { + int new_offset = type.bci; + int new_class_index = bcs.getIndexU2Raw(new_offset + 1); + Type new_class_type = cpIndexToType(new_class_index, cp); + if (inTryBlock) { + processExceptionHandlerTargets(bci, thisUninit); + } + currentFrame.initializeObject(type, new_class_type); + } else { + throw generatorError("Bad operand type when invoking "); + } + } else { + currentFrame.popStack(); + } + } + currentFrame.pushStack(mDesc.returnType()); + return thisUninit; + } + + private Type getNewarrayType(int index) { + if (index < T_BOOLEAN || index > T_LONG) throw generatorError("Illegal newarray instruction type %d".formatted(index)); + return ARRAY_FROM_BASIC_TYPE[index]; + } + + private void processAnewarray(int index) { + currentFrame.popStack(); + currentFrame.pushStack(cpIndexToType(index, cp).toArray()); + } + + /** + * {@return the generator error with attached details} + * @param msg error message + */ + private IllegalArgumentException generatorError(String msg) { + return generatorError(msg, currentFrame.offset); + } + + /** + * {@return the generator error with attached details} + * @param msg error message + * @param offset bytecode offset where the error occurred + */ + private IllegalArgumentException generatorError(String msg, int offset) { + var sb = new StringBuilder("%s at bytecode offset %d of method %s(%s)".formatted( + msg, + offset, + methodName, + methodDesc.parameterList().stream().map(ClassDesc::displayName).collect(Collectors.joining(",")))); + Util.dumpMethod(cp, thisType.sym(), methodName, methodDesc, isStatic ? ACC_STATIC : 0, bytecode, sb::append); + return new IllegalArgumentException(sb.toString()); + } + + /** + * Performs detection of mandatory stack map frames offsets + * in a single bytecode traversing pass + * @return java.lang.BitSet of detected frames offsets + */ + private BitSet detectFrameOffsets() { + var offsets = new BitSet() { + @Override + public void set(int i) { + if (i < 0 || i >= bytecode.capacity()) throw new IllegalArgumentException(); + super.set(i); + } + }; + RawBytecodeHelper bcs = new RawBytecodeHelper(bytecode); + boolean no_control_flow = false; + int opcode, bci = 0; + while (!bcs.isLastBytecode()) try { + opcode = bcs.rawNext(); + bci = bcs.bci; + if (no_control_flow) { + offsets.set(bci); + } + no_control_flow = switch (opcode) { + case GOTO -> { + offsets.set(bcs.dest()); + yield true; + } + case GOTO_W -> { + offsets.set(bcs.destW()); + yield true; + } + case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, + IF_ICMPGT, IF_ICMPLE, IFEQ, IFNE, + IFLT, IFGE, IFGT, IFLE, IF_ACMPEQ, + IF_ACMPNE , IFNULL , IFNONNULL -> { + offsets.set(bcs.dest()); + yield false; + } + case TABLESWITCH, LOOKUPSWITCH -> { + int aligned_bci = RawBytecodeHelper.align(bci + 1); + int default_ofset = bcs.getInt(aligned_bci); + int keys, delta; + if (bcs.rawCode == TABLESWITCH) { + int low = bcs.getInt(aligned_bci + 4); + int high = bcs.getInt(aligned_bci + 2 * 4); + keys = high - low + 1; + delta = 1; + } else { + keys = bcs.getInt(aligned_bci + 4); + delta = 2; + } + offsets.set(bci + default_ofset); + for (int i = 0; i < keys; i++) { + offsets.set(bci + bcs.getInt(aligned_bci + (3 + i * delta) * 4)); + } + yield true; + } + case IRETURN, LRETURN, FRETURN, DRETURN, + ARETURN, RETURN, ATHROW -> true; + default -> false; + }; + } catch (IllegalArgumentException iae) { + throw generatorError("Detected branch target out of bytecode range", bci); + } + for (var exhandler : rawHandlers) try { + offsets.set(exhandler.handler()); + } catch (IllegalArgumentException iae) { + if (!filterDeadLabels) + throw generatorError("Detected exception handler out of bytecode range"); + } + return offsets; + } + + private final class Frame { + + int offset; + int localsSize, stackSize; + int flags; + int frameMaxStack = 0, frameMaxLocals = 0; + boolean dirty = false; + boolean localsChanged = false; + + private final ClassHierarchyImpl classHierarchy; + + private Type[] locals, stack; + + Frame(ClassHierarchyImpl classHierarchy) { + this(-1, 0, 0, 0, null, null, classHierarchy); + } + + Frame(int offset, ClassHierarchyImpl classHierarchy) { + this(offset, -1, 0, 0, null, null, classHierarchy); + } + + Frame(int offset, int flags, int locals_size, int stack_size, Type[] locals, Type[] stack, ClassHierarchyImpl classHierarchy) { + this.offset = offset; + this.localsSize = locals_size; + this.stackSize = stack_size; + this.flags = flags; + this.locals = locals; + this.stack = stack; + this.classHierarchy = classHierarchy; + } + + @Override + public String toString() { + return (dirty ? "frame* @" : "frame @") + offset + " with locals " + (locals == null ? "[]" : Arrays.asList(locals).subList(0, localsSize)) + " and stack " + (stack == null ? "[]" : Arrays.asList(stack).subList(0, stackSize)); + } + + Frame pushStack(ClassDesc desc) { + return switch (desc.descriptorString().charAt(0)) { + case 'J' -> + pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); + case 'D' -> + pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); + case 'I', 'Z', 'B', 'C', 'S' -> + pushStack(Type.INTEGER_TYPE); + case 'F' -> + pushStack(Type.FLOAT_TYPE); + case 'V' -> + this; + default -> + pushStack(Type.referenceType(desc)); + }; + } + + Frame pushStack(Type type) { + checkStack(stackSize); + stack[stackSize++] = type; + return this; + } + + Frame pushStack(Type type1, Type type2) { + checkStack(stackSize + 1); + stack[stackSize++] = type1; + stack[stackSize++] = type2; + return this; + } + + Type popStack() { + if (stackSize < 1) throw generatorError("Operand stack underflow"); + return stack[--stackSize]; + } + + Frame decStack(int size) { + stackSize -= size; + if (stackSize < 0) throw generatorError("Operand stack underflow"); + return this; + } + + Frame frameInExceptionHandler(int flags, Type excType) { + return new Frame(offset, flags, localsSize, 1, locals, new Type[] {excType}, classHierarchy); + } + + void initializeObject(Type old_object, Type new_object) { + int i; + for (i = 0; i < localsSize; i++) { + if (locals[i].equals(old_object)) { + locals[i] = new_object; + localsChanged = true; + } + } + for (i = 0; i < stackSize; i++) { + if (stack[i].equals(old_object)) { + stack[i] = new_object; + } + } + if (old_object == Type.UNITIALIZED_THIS_TYPE) { + flags = 0; + } + } + + Frame checkLocal(int index) { + if (index >= frameMaxLocals) frameMaxLocals = index + 1; + if (locals == null) { + locals = new Type[index + FRAME_DEFAULT_CAPACITY]; + Arrays.fill(locals, Type.TOP_TYPE); + } else if (index >= locals.length) { + int current = locals.length; + locals = Arrays.copyOf(locals, index + FRAME_DEFAULT_CAPACITY); + Arrays.fill(locals, current, locals.length, Type.TOP_TYPE); + } + return this; + } + + private void checkStack(int index) { + if (index >= frameMaxStack) frameMaxStack = index + 1; + if (stack == null) { + stack = new Type[index + FRAME_DEFAULT_CAPACITY]; + Arrays.fill(stack, Type.TOP_TYPE); + } else if (index >= stack.length) { + int current = stack.length; + stack = Arrays.copyOf(stack, index + FRAME_DEFAULT_CAPACITY); + Arrays.fill(stack, current, stack.length, Type.TOP_TYPE); + } + } + + private void setLocalRawInternal(int index, Type type) { + checkLocal(index); + localsChanged |= !type.equals(locals[index]); + locals[index] = type; + } + + void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, Type thisKlass) { + int localsSize = 0; + // Pre-emptively create a locals array that encompass all parameter slots + checkLocal(methodDesc.parameterCount() + (isStatic ? -1 : 0)); + if (!isStatic) { + localsSize++; + if (OBJECT_INITIALIZER_NAME.equals(name) && !CD_Object.equals(thisKlass.sym)) { + setLocal(0, Type.UNITIALIZED_THIS_TYPE); + flags |= FLAG_THIS_UNINIT; + } else { + setLocalRawInternal(0, thisKlass); + } + } + for (int i = 0; i < methodDesc.parameterCount(); i++) { + var desc = methodDesc.parameterType(i); + if (!desc.isPrimitive()) { + setLocalRawInternal(localsSize++, Type.referenceType(desc)); + } else switch (desc.descriptorString().charAt(0)) { + case 'J' -> { + setLocalRawInternal(localsSize++, Type.LONG_TYPE); + setLocalRawInternal(localsSize++, Type.LONG2_TYPE); + } + case 'D' -> { + setLocalRawInternal(localsSize++, Type.DOUBLE_TYPE); + setLocalRawInternal(localsSize++, Type.DOUBLE2_TYPE); + } + case 'I', 'Z', 'B', 'C', 'S' -> + setLocalRawInternal(localsSize++, Type.INTEGER_TYPE); + case 'F' -> + setLocalRawInternal(localsSize++, Type.FLOAT_TYPE); + default -> throw new AssertionError("Should not reach here"); + } + } + this.localsSize = localsSize; + } + + void copyFrom(Frame src) { + if (locals != null && src.localsSize < locals.length) Arrays.fill(locals, src.localsSize, locals.length, Type.TOP_TYPE); + localsSize = src.localsSize; + checkLocal(src.localsSize - 1); + if (src.localsSize > 0) System.arraycopy(src.locals, 0, locals, 0, src.localsSize); + if (stack != null && src.stackSize < stack.length) Arrays.fill(stack, src.stackSize, stack.length, Type.TOP_TYPE); + stackSize = src.stackSize; + checkStack(src.stackSize - 1); + if (src.stackSize > 0) System.arraycopy(src.stack, 0, stack, 0, src.stackSize); + flags = src.flags; + localsChanged = true; + } + + void checkAssignableTo(Frame target) { + if (target.flags == -1) { + target.locals = locals == null ? null : Arrays.copyOf(locals, localsSize); + target.localsSize = localsSize; + target.stack = stack == null ? null : Arrays.copyOf(stack, stackSize); + target.stackSize = stackSize; + target.flags = flags; + target.dirty = true; + } else { + if (target.localsSize > localsSize) { + target.localsSize = localsSize; + target.dirty = true; + } + for (int i = 0; i < target.localsSize; i++) { + merge(locals[i], target.locals, i, target); + } + if (stackSize != target.stackSize) { + throw generatorError("Stack size mismatch"); + } + for (int i = 0; i < target.stackSize; i++) { + if (merge(stack[i], target.stack, i, target) == Type.TOP_TYPE) { + throw generatorError("Stack content mismatch"); + } + } + } + } + + private Type getLocalRawInternal(int index) { + checkLocal(index); + return locals[index]; + } + + Type getLocal(int index) { + Type ret = getLocalRawInternal(index); + if (index >= localsSize) { + localsSize = index + 1; + } + return ret; + } + + void setLocal(int index, Type type) { + Type old = getLocalRawInternal(index); + if (old == Type.DOUBLE_TYPE || old == Type.LONG_TYPE) { + setLocalRawInternal(index + 1, Type.TOP_TYPE); + } + if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { + setLocalRawInternal(index - 1, Type.TOP_TYPE); + } + setLocalRawInternal(index, type); + if (index >= localsSize) { + localsSize = index + 1; + } + } + + void setLocal2(int index, Type type1, Type type2) { + Type old = getLocalRawInternal(index + 1); + if (old == Type.DOUBLE_TYPE || old == Type.LONG_TYPE) { + setLocalRawInternal(index + 2, Type.TOP_TYPE); + } + old = getLocalRawInternal(index); + if (old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE) { + setLocalRawInternal(index - 1, Type.TOP_TYPE); + } + setLocalRawInternal(index, type1); + setLocalRawInternal(index + 1, type2); + if (index >= localsSize - 1) { + localsSize = index + 2; + } + } + + private Type merge(Type me, Type[] toTypes, int i, Frame target) { + var to = toTypes[i]; + var newTo = to.mergeFrom(me, classHierarchy); + if (to != newTo && !to.equals(newTo)) { + toTypes[i] = newTo; + target.dirty = true; + } + return newTo; + } + + private static int trimAndCompress(Type[] types, int count) { + while (count > 0 && types[count - 1] == Type.TOP_TYPE) count--; + int compressed = 0; + for (int i = 0; i < count; i++) { + if (!types[i].isCategory2_2nd()) { + types[compressed++] = types[i]; + } + } + return compressed; + } + + void trimAndCompress() { + localsSize = trimAndCompress(locals, localsSize); + stackSize = trimAndCompress(stack, stackSize); + } + + private static boolean equals(Type[] l1, Type[] l2, int commonSize) { + if (l1 == null || l2 == null) return commonSize == 0; + return Arrays.equals(l1, 0, commonSize, l2, 0, commonSize); + } + + void writeTo(BufWriter out, Frame prevFrame, ConstantPoolBuilder cp) { + int offsetDelta = offset - prevFrame.offset - 1; + if (stackSize == 0) { + int commonLocalsSize = localsSize > prevFrame.localsSize ? prevFrame.localsSize : localsSize; + int diffLocalsSize = localsSize - prevFrame.localsSize; + if (-3 <= diffLocalsSize && diffLocalsSize <= 3 && equals(locals, prevFrame.locals, commonLocalsSize)) { + if (diffLocalsSize == 0 && offsetDelta < 64) { //same frame + out.writeU1(offsetDelta); + } else { //chop, same extended or append frame + out.writeU1(251 + diffLocalsSize); + out.writeU2(offsetDelta); + for (int i=commonLocalsSize; i + from == INTEGER_TYPE ? this : TOP_TYPE; + default -> + isReference() && from.isReference() ? mergeReferenceFrom(from, context) : TOP_TYPE; + }; + } + } + + Type mergeComponentFrom(Type from, ClassHierarchyImpl context) { + if (this == TOP_TYPE || this == from || equals(from)) { + return this; + } else { + return switch (tag) { + case ITEM_BOOLEAN, ITEM_BYTE, ITEM_CHAR, ITEM_SHORT -> + TOP_TYPE; + default -> + isReference() && from.isReference() ? mergeReferenceFrom(from, context) : TOP_TYPE; + }; + } + } + + private static final ClassDesc CD_Cloneable = ClassDesc.of("java.lang.Cloneable"); + private static final ClassDesc CD_Serializable = ClassDesc.of("java.io.Serializable"); + + private Type mergeReferenceFrom(Type from, ClassHierarchyImpl context) { + if (from == NULL_TYPE) { + return this; + } else if (this == NULL_TYPE) { + return from; + } else if (sym.equals(from.sym)) { + return this; + } else if (isObject()) { + if (CD_Object.equals(sym)) { + return this; + } + if (context.isInterface(sym)) { + if (!from.isArray() || CD_Cloneable.equals(sym) || CD_Serializable.equals(sym)) { + return this; + } + } else if (from.isObject()) { + var anc = context.commonAncestor(sym, from.sym); + return anc == null ? this : Type.referenceType(anc); + } + } else if (isArray() && from.isArray()) { + Type compThis = getComponent(); + Type compFrom = from.getComponent(); + if (compThis != TOP_TYPE && compFrom != TOP_TYPE) { + return compThis.mergeComponentFrom(compFrom, context).toArray(); + } + } + return OBJECT_TYPE; + } + + Type toArray() { + return switch (tag) { + case ITEM_BOOLEAN -> BOOLEAN_ARRAY_TYPE; + case ITEM_BYTE -> BYTE_ARRAY_TYPE; + case ITEM_CHAR -> CHAR_ARRAY_TYPE; + case ITEM_SHORT -> SHORT_ARRAY_TYPE; + case ITEM_INTEGER -> INT_ARRAY_TYPE; + case ITEM_LONG -> LONG_ARRAY_TYPE; + case ITEM_FLOAT -> FLOAT_ARRAY_TYPE; + case ITEM_DOUBLE -> DOUBLE_ARRAY_TYPE; + case ITEM_OBJECT -> Type.referenceType(sym.arrayType()); + default -> OBJECT_TYPE; + }; + } + + Type getComponent() { + if (isArray()) { + var comp = sym.componentType(); + if (comp.isPrimitive()) { + return switch (comp.descriptorString().charAt(0)) { + case 'Z' -> Type.BOOLEAN_TYPE; + case 'B' -> Type.BYTE_TYPE; + case 'C' -> Type.CHAR_TYPE; + case 'S' -> Type.SHORT_TYPE; + case 'I' -> Type.INTEGER_TYPE; + case 'J' -> Type.LONG_TYPE; + case 'F' -> Type.FLOAT_TYPE; + case 'D' -> Type.DOUBLE_TYPE; + default -> Type.TOP_TYPE; + }; + } + return Type.referenceType(comp); + } + return Type.TOP_TYPE; + } + + void writeTo(BufWriter bw, ConstantPoolBuilder cp) { + bw.writeU1(tag); + switch (tag) { + case ITEM_OBJECT -> + bw.writeU2(cp.classEntry(sym).index()); + case ITEM_UNINITIALIZED -> + bw.writeU2(bci); + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SuperclassImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/SuperclassImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..ef004e70e3495289c1242384acb1db26366aabb0 GIT binary patch literal 1502 zcmb7EYflqF6g^W4+s8toAfhNf!9IWmQ3MMlSTQka;6t&-5I<~}0T;KsxI3%yUuoh4 zO!No%ql|ZUOSc6n@k6IOckVs++|3&0VrcFg&2Ai#8vd7kD++5`&Kh;!ChOo zG{e$8Z_l*2W;PBjZN2UZS2x6l#T(of41Fu6ZHhI9o?O0`LIOzzDHUm`3_}O{dtLK| zX=z*a18xY9VZi0@eADHdj=kwy7QH#pUsYoEtCaWBN)QrN9D?qX8Gl!|-E$w^(5vK7jZCUu$ieoeQ0 zN<7k$xEdVMFbXItm{u`^*^Y`s2a@ET<2H2C=5l+Vo8dcclMhANp|+-%f;npVznDiu zp#GGdU80$(m^R<^8+Gn(>vfAP*@|Q6R!w(Jxo;Zd;*CicV7k&xJ`uc>Zizwb=)pP7 zFGpHsP(HY(;M)$v0@dH;E}xZZDPN=b`iXAm{x_TV>sSoxI!Q?to{WadWu{C literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/SuperclassImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/SuperclassImpl.java new file mode 100644 index 00000000..2e93c9b9 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/SuperclassImpl.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.Superclass; + +import static java.util.Objects.requireNonNull; + +public final class SuperclassImpl + extends AbstractElement + implements Superclass { + private final ClassEntry superclassEntry; + + public SuperclassImpl(ClassEntry superclassEntry) { + requireNonNull(superclassEntry); + this.superclassEntry = superclassEntry; + } + + @Override + public ClassEntry superclassEntry() { + return superclassEntry; + } + + @Override + public void writeTo(DirectClassBuilder builder) { + builder.setSuperclass(superclassEntry); + } + + @Override + public String toString() { + return String.format("Superclass[superclassEntry=%s]", superclassEntry.name().stringValue()); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$CatchTargetImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$CatchTargetImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..d9d2004e98f6da9a9169699a4263b2e9eb49242c GIT binary patch literal 2001 zcmbtV+foxj5IqA)HVLZ%6cz6xY7*2H?;5;>7-g-1h$+g_2Wv=1vasyL-3g`tP| zG^E>PNKILerS3BH=L?G&q><5()iD5_;r2>%)vz2TT!-66!{(m%+OmaVt+j2V&fR69 zOy{*U$sDh6)o4XNvKjV?w++!&mUQZT$rh&56mJ=rnZaJyUP`?K>hId3 z>^M?!KYl!f^_>J;eO{@~*Ucw$ujb1O<=JYzy1-!6{t2cuO!Vy6F@ggOX(gX2*K(E_ z=JU1xFS%5RB@rS9=N!^8ioTc6W~Hr+-w(F&w7`iZ>l@dkjx^1sco! z$ z7T$PG%GFN06e~XBEar&<{iZw+UcYGlYFCh0=%12u_$ z!~UgAgP)@3Bun08 zNk#?;Hje`R`>+>jWwa(fVb2Fzlm$Pf@NuA?f1829EqKKBObvr6Y|CQOyJ0M2x78Wbre!?b1j_ zFi99evX`iDK4q72)lYbI%dh(;`pJ78H*k+UV@Qy78TaWku@_}j?vGNx%XpB= Kpo&K@G5QlzYxmUv literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$EmptyTargetImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$EmptyTargetImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..6d3294d7ff303c411f90a3d27def82bfa5613e8c GIT binary patch literal 2103 zcmbtUSyK~15dH>8HpJBg5D*nmL?uC4!P~?G@gN%TqIl4!Nivd!%}(5%P{n`pL94X1 zc<=}Kqbz%NSF(6uC?0l>-s!KqzdpYI*!~7!0Z$EdF^sPBO>Q~dU9+kV_x-oFBdi5| zdPJu*dXO-XG+`jckZnJHDXP+|F(iw&YpXj9-BY>MG}1U^z%+3fM;P+!wGGR5mGE5d z#Nh2l)3H{#wAfQgLNVcQS;~!a}K( z+owh^vgk9=Z(;yP8E$p%>*T{mQ*A~5hrX*I80`szwNFR-DH}s3hH;D`rQ|E++3p&{ zbE2SQ`hIt*5N9JqENDB&O`O0d9-Ma^~Q_`?wCdP4!ib1?(FyqhK06Qi{giSa5|3FLsy$#hO<%trtTY@F zbT)7XU6`cX68-O@y)XX--TCS4Kz8sedOsuck%V11OY0GI)B1!SJ|(y^&e3fsRKj^o z(T&staE2V66I7gmXc&32rLD};&S*FC+ZY5s&@seL2I9p4(+ra@i5toM_8m>jQj*U Czc6+H literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$FormalParameterTargetImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$FormalParameterTargetImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..1bcc8113d9cc17d66aab155617f543d7b1611e07 GIT binary patch literal 2086 zcmb_d+foxj5IqA)HVLa>xEb#vY7*2H?;2FXC9+m9RG@f(2Wm+MSlH~u-HE0D@tQdq?U%y!S5Gu@|qIzNBy{{S$H*GcrCS3yKY6fuT@UE`ghS%$r> zRd`i6HHO%fX`Au|LvJR#nm`;01xXcsP#NZSYkQh$OYYc)rByA%b+=55Yi7M+X)A`a z&82Q{37yRGqHyYlwPZL(of9C~r5%Q$t%G~IUE}W=n4Z9C^eY%paRw=d+nwk-cddMA z@Pcg%X-HGp<36wFWEfqXUs)*6Z4}Fu#X@OgsZc49XTHLqmHvw=pCYw}R19N;Auh$T zbWD4jVJ%ZS2?g@mP&ht!>&CMx(l|#q?ilXQtf)~+`bpiWdnsK|aS@lO#{6y5uv~`q z6QU30Q{LR=RhiGODY(M$N*s6;Gy4^gtH5+!3{Q8xwa@wi?}UxyekpmdEJQJhlG;Oi=&Ud(#<)sUqz+ z+18RChww5!v_;`8i>6cMMS6z}g9jhs9q&B#(;M!}1>s5s_Zf1>Z(-_`KVxBFMhNLj z$7uM9xN-FLGbsHrJWb*m@(QL@JO>Sq%bh5lrY+4n*Zf2RBtv5J4;jPfaKfhjPV8~b zKe%AnHH*9BB_Z~jjeIEiK(ml10D484<8IY48&Wu7$gDT4!j6Dr{V+-R_5)8fCh=Fk5X}cWid%p zz6Vq|`b&9}o<>ECzN5HG{xPy%(Aq<5GWQ)Ucm5lc&t&!BT5u95W1PN6{8PA&8)VV> z78}D&`i?R(K(rZT>Ay#NhgL>wFm%NYg7%#~)h6q{rFik%(r%}M{beig2 Nz+5bWdAx#-^lx+S8TJ4G literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$LocalVarTargetImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$LocalVarTargetImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..8c1ca4fc2a9bc1d6c099029cc50d243fc3498ddb GIT binary patch literal 2952 zcmbtW?|ai!6n<~FHd~2n>0mPF0CDKrG2&EI%ozKDxXRd&&8Z+t+GT6DEU8J#^PvBd zALM!D0r$Z_z(2~z_a<4Jc0VZWLvnAO zX;s_s{Y}d@wFNo5%~=+`NGr&wP|zokZ*9JBR$XsHATw<_Rxl&bGhSTJB8yWBR26Sw zK%lg}v7=c|V0w;WC*ZB!x~;7l-j*4ZolUpQPl0T;W>$CB4cj7WWqhe+s^!<()4Dn5 zIBsABmg|f~5K^d@%f;8!=tmx>6%rYoU1;*pJglh|~ZJSjY2|Yf1Q$?4jdsoFM z&I_aiqhiymeB@PYlQer##e29U(Cb^jaSyXtE|4B$DlX##fxf_94Lr-)5?H0}uJd_F zjP{)jxfX%y($u($B1$w>GyK|uyFoAJPi!hY#1$2jxXSREzcvip7g#$fZX&NMm2C!J zFFsK4k-$_JbZw`NK>w<>{d*&J!DZ~->N0QV_|Plvl!o-CuE4gP&+zrQ*0rB*9>az#y!I`c1>0k zTKhe|3?0R*>vO(&jAek%j3+Bj%x8hKNvE0|5fH9GA(7O0iOgxkIWpIYT1TLLoz`6z zxN|`G<_BasUUeH@)s#&@U@)$9ak0KC$<7PAZ2G~X8y2Yjc95TU-M|k#qaNkU??aiD zr&S#Fuo&e8a(qT|8Qjfc87m6zsrVN61unF1lGktoYuD7GSjB+6HXrww$9uI0Tg^MaOu@5Ok#^Ql6{A?t$}u-f}aGgy&Af+yptFQ4N$1y z7lF$yykjz?fRs9a{8pCoD4m#Mf9nN1EmA1R4$ekWknN7LDb7>)n7=H7&nM`?r<63f zzlY;+=>>X96ZzTv+)MO7N3L|`CC)y_$TKeX;2PfrZUr9mZO}{w=TOCGlw6De@HxKV z7okGKBAiLnDO~4VrCGT)N*7Z2lJou)H-ZAhzUkb;uFJRd>^fnkN-mwxl>WlV-?$)9 zd;AAQsnDNHxV#zq5TWN{A5ODNPscD*93_lW+Qa+6pB?It66#7*z1Z|3ss16*Y5j2Z zN!*C7Pt(^FP4<;0_Aqgj{!p~18Noix;AZIeAZBAEE&K-3j79FaQ>0@U{={OAz%rIe z<&kcbBeKjR%|Bup?_2mP9J9F1QTiK^tDRb3b8UcrE|DX7EaDs7!761X;;dmEKgk{{vdd6OsS` literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$LocalVarTargetInfoImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$LocalVarTargetInfoImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..8ed4f21b98b6a4e46b1c31b0079af1cf3bcea7d9 GIT binary patch literal 2269 zcmb_dTXWM!6#h1jE!!v;JBgb>6IvP|QBqWBDHKy^2&6F>bDhv>pJaPUl*qfTw9ddA zKd297rkQr~&>zqr#c)=VBRSAaX2^rQ(%EzU&UcRgd$<2DfK@y#Vh9-n!zQxGF^q3J zyN>NSV$*)gThebc zydg!S=Xnel7V3%DNUgf~p{RgSj2Rd=Q9_wvWxKs&yFzhaIG)||oFI7Vdfaw9UC(~* z_?ukS#7kMD&-uD+Io^ij4~iLzfpUCRcbc5iIFkyQxC<|sC_$#<-^>v7sj8T^_W2x2vR|Hd)nMC@qM6{Pv-fbo7C_KIofS6N3ApOHQPy z^qDx=Ap;K>&Lv#RNj)t5G?ww zkS)+58-W5O#p_@eT`ZB*iacQ%U(*-)3^QQio6cb1Lb?TOl@#5?r@%8$V&4q^C)L6xUIsE?>ZX N)N=(q#3MYx%zHd3DEI&X literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$OffsetTargetImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$OffsetTargetImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f1fd0af9220d4c1fe64aec1867451a72c12e2089 GIT binary patch literal 2471 zcmbtVTT|Oc6#mv2%XU?4oJ&gyNlHixCW%V#tw~Dal;G5u1PE!9r?tJt0wKB5Iy3F` z@`w7+%rw&s51l^uM|FBuE07?BIKzXj-J^59bIx}z`uD%xzX4S7*g%S5Vv9fJmc!jm ztL5+@=-7_1s_L{zr##XaHjpu4Aj?pUl~+Z}^V#Cc^`YX5do4MBjnHHDu`Miir;} zO^&)e=vKWpQM+(LM>Ul|*~BcaQpUt7cZl89lc6T~+N%W3)^%!xqliD$!^vJ^SWcF8 zkiJj&j@5OoW;PhonzlmSc15GV(-i(XZ#qO|sqVG7v%!5^-6LUIc5R~L#)*naTVh$r zuGhZLeZC`T_zCj#bh0_48izZh#&9N?^ge?O%u{j397eAg<_@66c^{%Su^wp8y~0Lw zMeAqH>-#OCmL9{YXttx}bX~@$eF2h!2;<4iAW82BMtQ$pX3celA3}=2 zzzV~)IOhS%XW#+DNqt^u>6Fx#rDulZ1}u8>A>BHpH$=~K<-aggo-J03i!YFSjzanB3!M1}g(|7ZIDg*^OfF5U-V)0Rm2R8c`i(6$H>{I-Zd0f|%5v6XT3!3pgGfsn1q*3tjugE~6S z@Zb;dM>*a!p$+9@aCm4p_h#?ed(ORk^XKpGZvc5bOQH?!3L+|^h%t0+86OSJGVBfQ z6)y{?!VsG_ZBx!Lw5Kzx3B-|5kW|qDm0@P9vaOl6nzt$eKT{s=rTqcx= zk6J(Lyov!_ptCj&cQY?4L?M6rvviNfB^84hq6+d4HN$clUY{B`#Nox-7B9z$Q;h3HsI3se?Brdb3tp_#x zb1pYU<)z^mJDhr$P?NIWw0Hb*|qXouQxfZ``kje$@2B<9gr~ zrBf6&r_7h=PBHZEzfcq2e(IYQ?#gB1N(HwWvL|m+>WjTA-Zd|TbfsfdeMQ_jI#LWu zDu#ziJVH*vw2H@|A#k~wrBkz|xx+P|ND#@8Sla_*_!cH?+8@O>*ZhskhF!6^J5ms0 zyH?GG$OoE*JVBsWlm+gV9kVKh6AsCHgD30=Fy0*m37@|2N(SX%P<7kpP92g{NA$LI ztvAaQ%rgu(l{l(3sDRdD@s zx_OdK;f|LG!T6QCOP0s`0ouuXk1F$oJi~~PHHBIFd~{+C`Pl)g_Z${t2`u6%bPW6h DV~GNM literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$ThrowsTargetImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$ThrowsTargetImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..c8d18c3062f44a10074dd6bdded9c0cb0593e9f3 GIT binary patch literal 1994 zcmbtVTT|0O6#f?4rY(_jS46xZXj_B`-YpXxr3xbj{SQ4Q-hh zg84gRb;nsZOs*N*6;mtd_6CGSyTYL5{|lMvAVIoRbfbqMD#ePl4QqqpO)`IuBr~Z%6dq;mpi3%xahVP( z>rQ!2lqm4&a~_m)6S$(HA6H2Q{;{f?4#V>KSOd{7t!?t6%%t8cxK8SxMchDn8A8ci zYLyl*+eF^5_+oW?joSr%&7}N0@}j7ltGaEtw(ktdvO!r)o~s7b)~~oMi_&Y|*0(uz zD^bQ}tv$V_8A}H1bcR05FmxTj__eJ~NsghLWUo(BT{&uR;U;?I6@{}Rs&KBkdCzVil>MZMN5J~Nks4@j;F{dm{2hZ z8ux3BDDA2xjcu-ZiTFr{*xEiB!)`EP!`cyBT=O<&b*p4@XD~0sR<)7|B=2h$@c2Nt zDD&JY+D1hRI|!L`ub802=lF1xBzXFPG4#v9pyn)#+cio~9np69hEg!gFwl_Uq`si) z1#ciV$fIC^VW`1ziZlwc3|CLzN~QF4#2DSgO`tN-ufx5KY5F7d9L5du50EuQYZI;U z^e?b<-%lvJWHsTYzY|!+AU*eZyD)@XWYPW_8^djS4l^=9v`M7s-=!U;mC+jdjtk#t z4HCYq5vtyMpRk>-)U=Ns^RY^L51qhaxEGHHSL*Oy3?Bo(2z)(s`tk67-0|TP6ss#p zG(EhBzLW5t9MQTQQH=OGx6}jC{5-0{A~8O%-hQoUy|ABo{PULc3wf5rXx&j0`b literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$TypeArgumentTargetImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$TypeArgumentTargetImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..9c2f59a0c1bdf728674f242067287bcadeb2cdbb GIT binary patch literal 2676 zcmb_eS##4?6#j0!$Z-XBOh}uihGu~#3ZSMf-JDW_X^4t3l%#<|myzvDtVEVvNoLAx zXS)5DKEO;fW%AJJbAME)=jtk!LYA7DJlJvz6;uKxLV=Pv+Ne5YWDp}c86Hg(%{ zHuR=#`u-!!=6Y4kmT8tp8W{yy6$)|;#aQ?*Z@ONKA-iZfR&a$OH9NPSM;@;zP*t43 zNd|4RwWV85z&*#b6XvZ>*VfleZ-WPh^T;)5$&hchd2?&sv@NpQn61UG;<(nHbor9w zxPcj1t}`P|h|P*&%)O+>Fp3yaP*QOUqYO)f$2t>+;cfIf+zFyIWC}r;lQ?G3UoxIN z#_+0w*Hnz-b%v2J|6X9(`t8OhZw5ZYNsoWuvpimRoqEqE%+4oal46x44$+o^HyFkb z0<>l}xGj)4qv9;yq;kp>7$y!3Ka{Tsg((%&n4vfWQIiM^!)fs!7?@EahMiaO7G@c8 zfx8-bmb1ZdkK!Ge5{JONCqZerBHU>z=5c}CwN1ZWbz4+|6sl)J%kL8&L-I%6+dh} z2E*xO?tM6kjjo6`1~fWiSlDANPX9%m`x?eY*E2^n>+Td=Wv5zI_@VGIj!uwZ3Tt`{mS&4EM!s3;}+@) zZmYP1FBs0od3!x4usS?yCy^h9;l{3OhG$6#E$6Yj#dRsTVmd9G`!hAy-RgBK2{@xF zBz7W20poS3z6XO0#n-pDdwff{id#AKvU67LxG z!IEg?;Yj_NMupB5yo({cN2@0!pQdqA`x7Z`zIdZ}^ErmMQP3_t$LYT@v5m4;-p1rJ z5*or~`X57v{(mC1pUK@Xn82^(;5WQayP7nH5AY$a$ZQw{3uhvXp>QSwN#P@!pGc7a zC_>Qd0gTWK@iE0GB3qzQC@R_x&H+zpD*b1}?H@ybsuYR*jZnw0(9VnMbHMKdsq0vb z)ECK_2sWq9@8IHL`eRb2pKcDH;0jrwtBy}2OM18lGTI*~9F;{TGDDXXR}WAw52ifb zhal;B@+bgyJ!h~K!gP(k1_j!AT&HoAY9*;8i6m+C8J!d<%A3T7B9^fN1E1qA?M@K~ dR`Dh7T^*;BJnqv6%mS^y$`0cJzQ(s0{|_MOyX^n~ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$TypeParameterBoundTargetImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$TypeParameterBoundTargetImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..2973c60fc63017bb42504afe1129d2ad3af7c9fd GIT binary patch literal 2518 zcmb_dTXWk~5dKblkz-WsxN)ePq=k@{M4=Uda#cv1OWTOLX=y?pU|>eJPh%yDWTfK` z{3jmh3>la_@B{c!4107GOQEeXojlm*w!7b6zFqzG_sO3CHt>yxF^1U#=b2-Aj=yiV zJtvBux*j(-@XBpT;CO|47r8Hy)w#pLxZm40^VdW z4myXX>kA(Gj+Zg-9`!tP*9rHzu>GfjO-F`uyUW{$dyeOl)z(5Yg-ZR}{kg~2d_NG5 za07o{nUI&3Z7=>$jd4^lp`oVZA|@H`kM8TdM11Uo&Jm~3)`Py^NrF*+?=Q;mu`tK$l;GL%HHBSP2TXZW5nIdT<- zMrLI*tjt>y^c@{@c$YxCPSo89Iuv#D96@b~aZSf{yhm)~KlU9jV))_w5Hb~d)H>j8 zVJ&{EVUfWag@V}oq96$B?Jpflh%nV(#EN$KN`w;Af$I0p$Nq6X6EG=<3%!}1wxqck`1d?)CK zZ7xR=!^N|sUt1}NQ6#L1r?R>CBs76pw^2mW~D7vVW`lr zPQON_i1ji}%}ot=b=<>!hO23CVc!?-5jRzk2^hn8>lB~ic{We3|13Ds4&9yz!mLU>y0aIFjqhGGl0`q$+=Ei-w(s*WHpwFm zUoqTBV;-S$8k!7q|E)p=Ry9>ab4D%$0%p2OeJL)z>RH3r4A)Y)Az9Y2!*FG|C=p4O z1j{sX^C0FRhnoCe&`7GuAsw$YiD}j7U4wx!EYT?<`8=)D#_z}(OVx>L?GKC}qhib) zqi)O|qw$=c$M8P=PoY5nYoxGFKpUuI6PIxpH|W+-W^fZGoycGe&*GhQU@YEA7jpQ3 z_7`#_0P;SSHV;PjZ!tnsI^|;8)rz{9=5)8sq6oB*B}Y(f%Rb{9FBP;Fpoq zuj8XceTBfJvn6Bc1oN-bpHeb|a7(y_kI4dcJw8b+neiDY7{8%1EQ&&6hEY0BqsS`P zhsBU8Prp>TF^X~lpT=qW44=nq8DG#kNwrcWQWR1IvgoBsp{)@cs#w7)ZsQKN=yr}c cVB-NE-f7TF8QW+O6(8VHaU75F1iNVb1EgbyuK)l5 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$TypeParameterTargetImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl$TypeParameterTargetImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..5b610d78a385299e2e55079fd6216770afe49fe7 GIT binary patch literal 2337 zcmb_cZBr9T5Pl|vY?50E1kmGr;}Deubw%&gyWk5i0;>V^w5U_7tlA_aSy*;*yAwjy@Z+Ac4PrrQlclSMj1>84~VmQ9#Ja;V5@i(oy z=Y-)i*W=cLx-HQyk2LxXWK0;yG7NT=|KN2IG#E0ouJ6hl41H6jjXd)B!GLMv5C#~^ zTa9hY^(7B{$4j_(cUqqH&|uQBvwVgY_K&9X4?U zKQa_$62kTy`~?HEi&VIuOdQ2AhO871WZ?Rn41W?^Jv05K=qpJAwdab$J7MA^#tE|QXlcZ+Kv}8JUS5P3GUZxTf8nSrN;)&FkI=Suae~J`Z8Sp z=9VmNFr+nOg{tfGwf0U;^-Iko4vSS$cf1WJaMe2&re)J53KkEdoHVVgTsB3c)2ZZn zWa=|jj%L?p7)@r_VU7AusBpWy#h(~vKJwPfn9`U(5bdDO)pB7Nj)x~+0v8kpb=n#a z<%$R;b;aJA8JrhFhB9zkI;k*=-)VVu=dJST#1t3`^cyW?a3hbKxMg6@#5@)lPIj{i z+P-vmxTUj-y))!$dw>kDlf=0GbFs}Wt+?X&4UdPDRUx+9txAHVc!Cm=*ibEpMIP1z zwNuuQV{!i@~M*~`bUG?sf}s-J`W<7JT$PxaK4*!52Z4&!Z7i56RM~#qF#DO z)Y0j#Qv((FS-zzq2-RWVE~uO<1Z+aWL(=~ z8t3RmULq_O-4t31=jonHkr)II4AJtwKmjP|89J4!QQpNE@HbsGnu-vlrVvc65+e-J zF1ASWfAizOtDekH;bLq)OJFIo$(E;g@$;AL4{M!Hf?10C5_zE6B^q=fDj*ebfB7F2 z_RFF_cEgB@y)2T(qx}z81+Cu2abd@f#|b#UjZj c=zSZ@uy2i#JdZoX{AqgM&E!zU8t!52Ki4Q_HUIzs literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TargetInfoImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..00fa9004929e4da14f0127c5ffe7fff70396a029 GIT binary patch literal 2407 zcmb7GZF3q`6n-v{Zc1pHCQVz~Sh1#+&=)kmmo_FLp`{X11&Q%>mgPb=S$1*RRr?40 zAI|s#^h@H{8U5~$a(ph(uwXN0VTNb#-E*FE?sLw)m%sn{<4*v2d>cmuQ4O&KCU8bz zW?%na&sw_O%5K;9rQr#jd0^V6w;~WtFV*6h#90mT1g4M>xX?5AJ<}SPcLkfLVdNLm$J^yWOT~$!zsmN3Pknjy0&g*hea^k9V^?HzGyd{B8LL8ywgxsD4Dh_`|Y}Pt9sqy%xuXqbgQPjrWy|> zW8R+0R=HC;eTbYu+}M-G0jq0L*m^MWVR9#SNUm56N^u$wMjSSkKsL~`r*l8+awExt z>$C+#Q9$dBtB%0Ail-X~TY6_8NW9|st|1F-a)G%~aqp?N6qqW@uD2zXv|SC9W9{_f zE%sy?H2r{`Wz+CbAQysWyV>k=!}WHWs=J1d1n!3*$m^c57xZ5Xw~iOhG^&t>yuiZ{ zX^heIRko#O-W_?#P|9Pbi=xUov|!WofbtTsF; zUZOVdu@R?XK6ndhUiaz~;g=Uac*=A1Hc=2KGDi@<^ rangeTo) + throw new IllegalArgumentException("Wrong target type specified " + targetType); + return targetType; + } + + public record TypeParameterTargetImpl(TargetType targetType, int typeParameterIndex) + implements TypeParameterTarget { + + public TypeParameterTargetImpl(TargetType targetType, int typeParameterIndex) { + this.targetType = checkValid(targetType, TAT_CLASS_TYPE_PARAMETER, TAT_METHOD_TYPE_PARAMETER); + this.typeParameterIndex = typeParameterIndex; + } + } + + public record SupertypeTargetImpl(int supertypeIndex) implements SupertypeTarget { + @Override + public TargetType targetType() { + return TargetType.CLASS_EXTENDS; + } + } + + public record TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterIndex, int boundIndex) + implements TypeParameterBoundTarget { + + public TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterIndex, int boundIndex) { + this.targetType = checkValid(targetType, TAT_CLASS_TYPE_PARAMETER_BOUND, TAT_METHOD_TYPE_PARAMETER_BOUND); + this.typeParameterIndex = typeParameterIndex; + this.boundIndex = boundIndex; + } + } + + public record EmptyTargetImpl(TargetType targetType) implements EmptyTarget { + + public EmptyTargetImpl(TargetType targetType) { + this.targetType = checkValid(targetType, TAT_FIELD, TAT_METHOD_RECEIVER); + } + } + + public record FormalParameterTargetImpl(int formalParameterIndex) implements FormalParameterTarget { + @Override + public TargetType targetType() { + return TargetType.METHOD_FORMAL_PARAMETER; + } + } + + public record ThrowsTargetImpl(int throwsTargetIndex) implements ThrowsTarget { + @Override + public TargetType targetType() { + return TargetType.THROWS; + } + } + + public record LocalVarTargetImpl(TargetType targetType, List table) + implements LocalVarTarget { + + public LocalVarTargetImpl(TargetType targetType, List table) { + this.targetType = checkValid(targetType, TAT_LOCAL_VARIABLE, TAT_RESOURCE_VARIABLE); + this.table = List.copyOf(table); + } + @Override + public int size() { + return 2 + 6 * table.size(); + } + } + + public record LocalVarTargetInfoImpl(Label startLabel, Label endLabel, int index) + implements LocalVarTargetInfo { + + public LocalVarTargetInfoImpl { + requireNonNull(startLabel); + requireNonNull(endLabel); + } + } + + public record CatchTargetImpl(int exceptionTableIndex) implements CatchTarget { + @Override + public TargetType targetType() { + return TargetType.EXCEPTION_PARAMETER; + } + } + + public record OffsetTargetImpl(TargetType targetType, Label target) implements OffsetTarget { + + public OffsetTargetImpl(TargetType targetType, Label target) { + this.targetType = checkValid(targetType, TAT_INSTANCEOF, TAT_METHOD_REFERENCE); + this.target = requireNonNull(target); + } + } + + public record TypeArgumentTargetImpl(TargetType targetType, Label target, int typeArgumentIndex) + implements TypeArgumentTarget { + + public TypeArgumentTargetImpl(TargetType targetType, Label target, int typeArgumentIndex) { + this.targetType = checkValid(targetType, TAT_CAST, TAT_METHOD_REFERENCE_TYPE_ARGUMENT); + this.target = requireNonNull(target); + this.typeArgumentIndex = typeArgumentIndex; + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TemporaryConstantPool.class b/tests/test_data/std/jdk/internal/classfile/impl/TemporaryConstantPool.class new file mode 100644 index 0000000000000000000000000000000000000000..b6c6ca5a82e7c0dade6aaa02cfc0fd2169a88aa8 GIT binary patch literal 8679 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

MNWM*SkmR384v~C^ arguments) { + throw new UnsupportedOperationException(); + } + + @Override + public PoolEntry entryByIndex(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + throw new UnsupportedOperationException(); + } + + @Override + public T entryByIndex(int index, Class cls) { + throw new UnsupportedOperationException(); + } + + @Override + public BootstrapMethodEntry bootstrapMethodEntry(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public int bootstrapMethodCount() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean canWriteDirect(ConstantPool constantPool) { + return false; + } + + @Override + public boolean writeBootstrapMethods(BufWriter buf) { + throw new UnsupportedOperationException(); + } + + @Override + public void writeTo(BufWriter buf) { + throw new UnsupportedOperationException(); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TerminalCodeBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/TerminalCodeBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..2f5b9ababa0ca8848e05ccb56c26fe53bdba6cbf GIT binary patch literal 400 zcmaiwO-chn5QSfjn%2ahs2g`~<3jrmi3mbKA-Ona~u`^7ToImd;U`J{C`&OSJf3j2g% zZQhIyrg_m%Wz9Az^a$6R>E_PX>LFpYOK)mQ7BQiDPlSQZao#Sctu=wLH@bNw^k;33 zmLCL>aPxZb0Wr%hsZ&O+a35Mx6{`f`0FxkGeog=mL$(xNTjy^;D%kWCuV5Tm~ iG5iy9;j@e^sX8izVQ7YGhgSg&@OST`7iK5y5e845>0_b* literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TerminalFieldBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/TerminalFieldBuilder.java new file mode 100644 index 00000000..b9fbf7fe --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/TerminalFieldBuilder.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.FieldBuilder; + +public sealed interface TerminalFieldBuilder + extends FieldBuilder + permits DirectFieldBuilder, BufferedFieldBuilder { +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TerminalMethodBuilder.class b/tests/test_data/std/jdk/internal/classfile/impl/TerminalMethodBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..97ec7f8e8828da6cdbf5ff9a1a7c40a510f28fe1 GIT binary patch literal 449 zcmah`%TB{E5S(qHh61G$H*USb1&ecUE#lOwi1GtYya5L{L5{=6ao_{^D8!}$RS{Kt zSU*;t*_rXz_s1uIDTWFi!fkF}wJRcr!g!r}Q&pMstljF(>n9E?C;d6cm(osZ=Pd_? z1Hv#j??!u5JnKc0a~c(TgwdwEVQPU17fGFE9N11v%fFO_$E(>kZ1ZL=<;T~vT|y`S zImd+lvaCbO_u_|exz)@~GgU-AG)`k=yR4J7bgmT6_QdlywdGLZoS=7!y>meVYk?#? cLRacgzJ?@Ug(Eq2aJ*joIFY?4_frgh05xEYng9R* literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TerminalMethodBuilder.java b/tests/test_data/std/jdk/internal/classfile/impl/TerminalMethodBuilder.java new file mode 100644 index 00000000..636b12a9 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/TerminalMethodBuilder.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.classfile.CodeModel; +import java.lang.classfile.MethodBuilder; + +public sealed interface TerminalMethodBuilder + extends MethodBuilder + permits BufferedMethodBuilder, DirectMethodBuilder { + BufferedCodeBuilder bufferedCodeBuilder(CodeModel original); +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedClassTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedClassTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..767d8723f9b0dd8047eb91682af2b64dd3eb1210 GIT binary patch literal 3893 zcmb_fZFdtz6n-Xcvq`$8r9!2syjieGfCWLtrWR=cTPX$m5_yrzCYiR|Zg#`I6!0JT zU;H5FhzOkH@w0!y|Kjn^?qstiFOA}d?C#u|``kOvJacFA=ije>2T;Th86?oBpkKuR zk_;nT`i`!dy0xJ#@rvzK8Ise6Wq30TeUsTz8Y!d|WK;}7Ww^Xm-PR1t^^)N7xVPc^fwTZENWI;sUr(#%y?YH<7 zZxH)2s^A?J2XK(##NHSTio;#o+~EvslbwUk`i5EMP9fWQ$aR`!G>eI)5Vaav3JTt3 z(7Le`=R*b@#5fKscu&Rq_<-S3#~JMrogr1RE!VGchvDd?oQCfirnc@|70<9OttbZ+ zG8n^AvHHgtW_utdwwxr<1zmi1@bwVtHhzS)Zaf%_st?Ha^RZTIOvBqRVh5DAI zmrYJ{m_$}VPDLK48M57YkJd;8Vi>9jT`ox^hM7184RawTgvb_GM`RS4pH-oW%vIOZ z9Z%+-!Eu}yG=I!6Cu4LVv0boswrnXwd*Y(d|0fJQp7byPHM3N*ny@ z{}60mU|&%&iz3xQ{>ax&m!b6b$g$ziuaLc`;2Q0~-U(W@WHD>0sW-Yvp-E*d zhd1QX9Fr|ku?_hgUZC>5=-0~JSrMC#VRXT+=w?ZG4AGXxes9wtj;_4*O4C_%lY5(X z^|tQlHBLti!7AmjG*h|noPI;?R6DBnW6Sj%uGbi*I(zI-|~za*Fs(-3~8X;KxTLrC%~|F>}{@v1H)6uomjB#ZNDBr z&*bXFh?kBlB;>2ytvE*Avz@q0QQYC;28nUM6(k;gSMiQkSDm*k?gWsWcKE@zbzi|F z(m|7pZmY(yzeT%*+hPmP|3jV1sDd4alg*G_=v458;YjzPwAdl{I8TRm0(3ypb5vZT z>5Lf__gZ?V$v%MV)bka!Zi>4(y@zuzz;gNLP;#fAW9S)~5}2cBl7<6!Fi+28;ZS^y z8`L7F09y192jB@T(04jPW?=%k(!D`O`ir0j$hMmM1w;9l7)jvfYmD8^pMHr$3@>nG zk$RLfLC;kGYaG8j-XC;{*M|%=j-J2aBhfw+wCPFh7dZDb0rv&@9)UvN4=9B-9LD!J zg@?ERo&JZEu|nTs9v8zzqIs+m4U3fQAX#qVHYI!*1$;xcKJwSFM7Dk`ljj)qg`-yJ zE9_gLzE$c=phSNcrtmEx32M*NTX3V~Uf~iTQf#GE4Ts27_R|&PP8;`W;HRG4XK`1$ zPgAf2`J{6BSNO7%znBk=iI_;?9_|x@;Nm-pqy=qYKrBzUSqw-RMr+^Bd8h~Hkt^b_ z7G)(EJSXRn%;kT@g>K$S8CvLXfJh%f0Q5itU64TOT>cMyx(8Oe1&ideM!*S@)5G9B zNrD3QktN();m#@tHiiunL<$vftivK(j{H;f_ra!%`#9=wl4-iBPr{|vReF2L6ns3! HQ;h!uNuw&? literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedCodeTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedCodeTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..38a65584fa002d52df8681197e9bb5285a28f333 GIT binary patch literal 3683 zcmbtWTXz#x6#h=yW|DMDFG8_gT96i-6o?2al3JhvY_%=en*yRvlGAqD$xN7;6nygs z`5DDXfv(B)dJ+jFHKcU(LKm3XF70GZ+n26wSlOawc;1F- z$*ftfSlLzAu)Ph(Ezff|p5HP|TbA-pNj44ygfDPzVNdCvh^C7wbiC_`x>%|C8XgI0k6iy3VYw1o0$^{Zd$M&ja=?aWZhF(;C)5>mC?V@iwb~Ybg z$fYohF%|eT0=M1{Nq|TjS?P5R?+M&E$n6G1wS?FQoT4fm#&t~Kyg*9Yr8&bcS<08; zx-UU)R&CoTSduPGBCR2#V+t1p(jBW8=qsv>Tn;5Mm!k;O$+<`xG-%P>Xb_dW-!dYBaD1Rt07wTvOVk>2>XbSABjBm>r9IAGkDkPAaQ@V0GrtukdZ5iH{Dq?~B;dRX`(KmG5#4UCt`J`%Cp1|6n z1xL`mSJ;+CKbL-}AKqD_B_yWi!R9mAc^JW)yy`)RB1nzco&`=43|Sv1D1= zer|?FC0EQ%+wiL{L-AAlc-QfWwvI@+I{=_FbB;E($*?SIPxrjQv8a8Gbmt@Ns5IJZ zCgG95M3c0Lz0pUUAQYm4BiHI~9o~B?Nv$|lwyKk2g-vW}Fm-HWr>VEPRogeqG8@1Wiecmn zb;$zHqX3xpuCpVv!NuSa@WvM$XQx_;J||&tBDjZ)tIXcp(kr@V#dq8&OI`sQC4@2_ z?H3Z&-qfla!PVz&Te>xol2v^)GL$sH)xgv^zn2*;V%xYYFu3nYXU^@Tsb^l`c$==N zfzg}T(|7=w8g>On55CG!2gu_xAHx^~X8Av)rdK{FLu#PpnjpOgw|R1hyG1n;bM4Q( zgvd<2fR?%N0)5X(is3H*K>?wUg`JZ*ca(NO$c>E$0MykN>~p zeYL+>+w-6Mm-yfp3ht`eI|_|@Poh_x!U=Jj6Ur#Ah%r8MXRyj|<;T^)kcJ;?_!0{= zwwLxVVu=QyKo0jv>%w_XIrmBH##iJV=2>uSnP0)#GS60c7Q-s%^lMn7Bn9ndt_mA1 z^BNxm%EbMU>cN%JltGRY>n+%?13!1feiL7Z?9)^hBTphT^%^tn_?15@CF&7P;2S)k z1ck-JP*S$G2YOU^4)UTW6eAe>R?K}JFb~{f$~>Y~3c)L(56R5bpSbcHJ~~K1GSse8 zu!p!0aKX3S#PAs3)z(RT&-Dl?K}iG!@k5O!AQ{I53=~m{Oce7mGcmf`(c#4sK0ZuFJ2><{9 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedFieldTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedFieldTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..9f522c84d253895b3a7a8ad0826cb55cbaaf0d4a GIT binary patch literal 3704 zcmb_fTXz#x6#hKerINqOl=aQ^`Uce_Bs38dw+YMeNKP)^VxR*Ch;hZ1llyT z>*zqIK<|dJZR9M&UdzqPg5wqiI>$`g^v4C-Ml#DOB$3jP*3kuB;POUsGiTbqbZx`R z6)eN^R!vLh%+i*XTXYTETXo#hG-pGT>xOB|;tf+;#p;TH@CAluYF29)yLaZ5sk>!TMR|i!R-+i2 z4^eAzqXRxb%A8TvAuFhx&p^WqA<$7Y2{YS zcEL9tJ2x3^$fq%YV=DW{1twY`CFG<5SY}zn$$wQAd#F>zqKFvMaSFo%X=xXy47+Hl zUJLDl7agd{K?r=TLv#|oh;i&sZg zs60QbBd0vqJ>PKs$oDi(;GClQ4S}i1MgtP-8LKB#WM2?CUaw4o!xNQNnkT2fpU3@e z9T)KqtHXB|eAl$s1eWN^{*LgjQxd}Fm9e~zF}zD->xQ>J=@fb9uKf?jrWN*O9anIb ztw}y88_X)bROEC?@FU2aH+0FD=jWBa3DCjvKV2r(#l&E;DOyde7;rT;{JcO zI969PIA_-_S(3J&AE#HT1#`_d{Ibhze9=St5-!2E1G}ZJ)KxhV-4#XOdT88vJ)ddQe0#OUz1+J zHMe}njjIHN#sv|^y}clD>$|#kHM{z>ZA&+Rlswvp;%}5HyBb&=!!<7IB)7U(pl{Cw zPuxAS@Gd^wsDEl;{!Z0QHlb6)w!qQmTbb;Tdz|Cdm;ie`zy0b-%gd!-y)ii^Deu5F zu3YDAR=txs_GEV;vZGI+Wlujr_hX6@xWR8Hw*x=nJ${deTQP-c&ZrbXtM#4$Jc0N5 zJC&eVi9l7pVIxaF5~_o;rR>+}9({`51ZJOO;Lhmjr#LLIgQIg?(ar=bm)f7>#GS$R zU`Y+H3UD94-{LhjKNHOP<$MRPe?{Q7z~7_L`1@zN@C%OMR}AAfoX79{pWqKH^0$iP zLg+{}jwRg044v(w|Ff8*!$*+EEy~)cpTlj++VKH32e=mQn&+=@ZJuijTuTtYk1vrW zA}MOmaa7!B*=KkQP%iGJR1ddAuJrM3v0O*}67Xe9>R0e#q&`Mt3F;)Xqt7tjNMFUH zN}`g{BtF6&A}B8IMo76}4s@vWG>f7mf)UJpJ>~8elzXqTWbV-`#o+lUhE#U+dz}9U zZ#Dx+Mb=dbc98d84)~ap1U|w2U>w1x91lF2u{(kXoK0|aJCpEG#zPGL1-@zli~s-t literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedMethodTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ChainedMethodTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..b1d907c6c6dc49d0c2935b82ada00ad7259ec68c GIT binary patch literal 3725 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ClassMethodTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ClassMethodTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..5d801677936c38f09e5dd2d6b4ca44820788c61d GIT binary patch literal 5601 zcmb_g>v!Aa9e!TNiJU|sj#oOmbtNkXVmpn=*oES*v^A85C80EFpk-qyveGD#r69|t z-PUp0V0U1HUAhg%u6*GGoCEZ-0S(>p5AH&Iv`LStGwuHc4NhH>ofe7ugaHmhPUd}q89>#UQ0;e z&e^u}wy8}j6^Y;$6{E-!8lBO%z=1%u>6un}rD^M)>DcAdu2C~}%`++rasm(Zj`fVu zaIA|)8>oyRN5b}~xD|WpSkrZ5!xMO6Vzzg)NfcBPgZ3p)G)=2!xRpXua8<`{H0yjj zgfZMEv$s!RoM>eJI(djh3roZJBK9lzl8OVkUEq!$2p3Q^ySBJ$*aEYmeZM}oPf-YX z2dNwczO3RP?hr_OMuTj=eG}N+RY4|m-7cgd7T=wc?7IX`_C`ihM%o5tN+wWHP?RYt z37qJ?oX*;ASf_ru#JcK{WN4jYtynjuX_JtGL#(T$I`IX=8kM}1RosJVmP?3A;HfS! zHWhagh?AToQBe6UJ;|=VSK#2b&>~d{t}u+R;~NU@lLdEJV1GiNL|GBIHIDqzoKrKbVNBwiDvsg-fzfEX1p)$Val?8vFJt=217Y(NOm4AwN-7e_ zaTO;}Wq&@f4u8#I1)3ETq#Fcj_H7h(OJ_r=9~3p!(G&tEgH|wI=W^pX|5@MhY!=< zs>$Gv?KVLIdppfv-e|eV2BmshbG5p`#hLERjL zinbw!OLYDofrqAIGzz|exzbag}KiG>-FEqB>dvPwDP z=eZ#~jxc^kMhEbVA^Z}* zQt*n3SMgfMR>!n2I_pMx)-O1k)mAj!bKJ`U!}a*D|HOfWN&$*ftWwKpNN@)So(elvvE@rHums`wp#-?15Uo3>}x zjdC#Cf*`r}3@*2-K;ZqG$%f?NL8GC&<_4LMN98w0{6Wa*liN`m5)+R-n$YTuZ5ys{ z(qK4y{JS8!sBc)+TXx5?mjrIx?u?+|O@aH`D}o+vMSTadGb8g`*EI!y5xA>2ZGo{Z z;1v9g4c6B0sG-ivRPYZT@4Jh#>4P%HH2W~cbL9lTbMh|=p4oHqzXCox&HEG{<1--- zaOlGsKKU-6_3=7dyarJ$eF&vE`5{K$=c7I>@Oyyb;8a-T_jn+RvsmIUD)}zt`%&LX z3Xk(%ItZRTM&nQLelSHr`3ND3a}?oWiLWJwD$=~;`;Repu2{N(&jHu)`SYx;s;PB`MHiSq)?o^ z!N}+_|6Z|l4R=ewLF~8q+E*CS4@v0@5eF*v<2&R)f}Vj2CoTVMGIU;RIArR0(qG9zuuVjCwjBa_$hwG^&mPbv08 zNxy@1pUhpnwVsR0inn3iW!H6I&DAA`+lSj9241;T%|*|uhLkWucjwI!~LxB z$xm_ryo7Klgpey8lDWE$BYk-M9SoOLliib3* literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$MethodCodeTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$MethodCodeTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..b1a07cf5db2e4acd0b94178f7d0d51c27788cf21 GIT binary patch literal 4573 zcmb_gTXPd-7=FI=ut~bLp|oH{jt#X*3IXwernJ&>Xf!R@mLj0yCfT;zZg#_FQ@|r2 zo=?~O0&ctzN9j;z9Jug8bR2Kgf8+Rm+0ACRY(kwn)6JgVnw&Nytu(6}g*4qo$7OR~&yVVP*?G>;a*4lZ=*`sp)~tAh zQvx1i7+$->Nx7t}OLE?E$HVBPtRo^eppz1layhwZGFVD5+Gi}(4Z34E7*nyo4J0Dp*3RBYZ)AO=ci=slZ zdd0TkYA6#XF81=&q6~d@Y7G^5;C*;XKtB&W#xS~OoTH~S!{(D!SBF&$8Gqlao#k_4?C8N>NTk*s3ksyIe@?;fMxbrOp{)IijN`>9v`s=X== z9v&NEEZab3mes45p^&8$;W2g)kqonROeF^rcOf~G!Y8j3c@FhyS0Gd?};Eu$&! zYDA>LeuP}jOQm@W%aL`vN^{G{L>$K$O-}hjSyD?3)9bbCnlC4^3v!MyJxgVN|&jGmL!8Oc!iz5TG+oL4B8;dP=(i=Rb|lae77WLne6sF1bhcfBRb zOC^TTlrpDDX4#-%uluvetK!d4he8dyanOZbZH!vhs{|cN(Xw60(HhsR$(QJ~yMdD9 ziWIC@{Z2;J>C<>3YTJYZHWyrb>yTqz} zSZy$OY(8R6Vm>2{Ve%199Bog(HF87vMO3Mf%}Y^xG)MO_r2YMP>EJ@E=D}Oj*bGA; zN1LYYzQP>C%50@50tKR>|K7@LlOa5%myMjvR{$!SlQZ8l?d27uaWWy7%rU)0ENZRp z4I?AEZk9|#Dq8kR5iHi>!%RmD3VdDAM4ZQ45ftmL+TPe=GeNX@*j zT*76BT{Utk+LFE~Co>h?$$~U1N_h*nrWeIwP*~t{!cVG4oBot&QOYkygRE=-m&fnHlpY1L23iz&fS?FVp`K=qheB~ zbT(Rvd1eQ3@S)ucr!qrN-Hn`pj~Ncu(5v-d#nmJBMgl%1KCexiVZ%ew3HXBMVol$} zAulrpe8sS>u_*PZMPuxzmJ86@-A6|!|7xQzpfFw2wwa!%>28S50sb_;3>HuP2;mmp z1@JQcwvr_9GhU(JO_mfg7^gdKgwwKPR|06gT?hN05{Ms?KL0u!@##B z=0?X~{W#9p>VqWB1Exe*aI~JjRllH44dR_>{u9K}Xiv{+^$hpFOk zkaJ#=19ljpI29v)8v~6DgzPwM_8 zY#z9W0~3ioJjFYBwh518 z2hgZZSN<%AJY~Z9(u}|sfqFrv>i}jkS2=fKp3cDv_`D?*I(UIfWOD&3bi7ShL0o`= ptMo2T7J~F&f@|oZFZwQgNasE}UvCZKBYc9-T0{68U*c=@{0pyr4^{vG literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ResolvedTransformImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$ResolvedTransformImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..01495789128a35e5b2b9ade11877b0597bffa1ff GIT binary patch literal 3013 zcmb_eZBye^6n-u(O2r=O$^JO6=@_3~h4nJ?A;+Jm=;1ufNa#1W>{AG^P-f5SKBH1Vi>% zJJl3JGY^#=-nQ%xLt<4ob$5*+wp?tbkVHyCTE=UT86F;YP88jAxov8O(l#{5InWKR z=-r;7G;Pgv4lKJ{qt(I=cP!(ScgA)Zl5NX$`dw}_+^BoT`>t*%2Ys{c>XxZgf@4)! zeqBZeS%x$>J5|l>7(%V!tNA|nO;g)9xF?;L@rIC=9app6Kt6?8%t?4t##`d7_{sq= zNR91gwbpo&CQq&jzOFM=mnS+Mmh-w}=zh+I4N+JY?7-{Hsx{7DEPo zSXCH%N5&nzOU8~g=cr`W7N1Ed zGCUZS?5F@Mq7*l&6o=(@u>cuTyZWK2xqX|0zvCN-uD;dghPtLQ+@757Vv8Z}bD62@ zCU5k+``m7die$*wt+r;gG+P(zU^DI>>BP^YD`%NuZXEyT-oVD@Rlx_*FHVf!ml70Y zx43&`b)IUr*5x!CD8Q{(Pz_~xXVAw{d%{FvIijq+5mjTD4UBmsVOT5-%o14`l}m8M zaBF}ToqbCD!eog7LvsVM@oB{H%j(9;O2~9XrEVC!%S~5Z3yJwNSPkt&C{8HxfnVue zt8cftXb7TUs2~ROeZdEffd+Tns^z%UwS&o@eQa5-EyLnSe*!lWzGt{OS(MW56NwM#dYb~nGGfS!Yo6Xq zG}Nb1rZwHa^qv#OYZmy#yy!nLWW@5Aeseu#_5cMf?bd!HZ zBErE6J%w?pbdI-y-{{q6BOzcd>#Nch(Zx` zvQ$3D!ha$92}=%XOJW5oA&i_AXTn)VoU9U}i2f0+L}=5cKOjwtefmP|Vn@LF)%OL# zWUxlx|Aw8p94w=ZMZx7R2bT!^e26c}=P3&OvG<&%0stjm6iT?4{7&-wXq_ao6xmnQ jO-XFv396{!8``}_dP(}tx`TP@$X)CuQfT2jJj47yo#))n literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierClassTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierClassTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..a70df56d43cc0f7a2c9bfffee159998d28f38e52 GIT binary patch literal 2987 zcmb_eTXWk)6#mvpEZY&piCfc9nwB;Vu?-caTnY}MwVM!wo0d3rp#^4Sdy^=UB_qk1 z;g#RR1D)YA%|oZp{3wRA(pr|C*pq3RnONH0bG~!VcP^`c|2ujCpp2hVh+#s(q>3rT z8Pfaup{|*_wX1FMrtP#C;wy$_c&iK(%ei_I2_zMyR7^u|5%trlzDPRBI3Qx-zu5ktb22Mm|0zV)tWnA%R)YI=rkX+6E- zG~UFFg0zZR%rRUXBTK&Sa*yHMaxQ@M1A5Td=S{Du;2gu%ew=-;2VI*+23Zwv;R1u= zaMv~uIm6G(5yT&0xzjp zz-1!QvumDXSi1~$a`22v83-W2EedPzsFTD-@c1=AM{*^zpL?Pp$51*wM~^I-{MKN7FeGcnuBCfjhlnVTtKF4|A43JvPyK3< zGB2xZL<{8V43h!zGgZUlo85MUJKK80BoF4Qc2hU&x?_m7+?@3G4C1nM_L^YG4jTBi z(=(F3&%Hgn^-y>8Hm6xY2G_?1a!Ni#xJn~vDr(u$B=#DQ;Wug5Z}=gqds467o@4x8 zGkKd^UQuLmaO}ti^5jQ&3EFiUF zS@PcH)SB7ejp`c-6QH2RaJx^&3Hc9Yk6&C09x*JPPMcx&*u}?iVbq*e@B_p3KJ*yY z6+C5F7%xgy5~K(>=@yNFVVVBt#Pi#0UrM5WMDGGU*eTH4Eqb3~bPQ?oW7?!o4FV7bzm^6w z`9GmN#~TbUktsaK`56A7<5>@ncs`>~rUl%lwE(|KPvMJ_Kf*gW z1{j1AxT{FOS-SW?KSBKp@cWQIC#x^v3#q;$LrdffM_3%CA268+<4K^172oe^d?`uN z{5A0?NE)Uk>c*6W3CLJY-zBEMk|4LFJIQ?ECFcLe#c@DM2_&fR*upmI@g$XF8IR)$e2*vi5%d28Io&i! literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierCodeTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierCodeTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..0f5a52017e799cd0a96596d14ff88e9427c9e2e3 GIT binary patch literal 2970 zcmb_eYf~Fl7=BKGY%Z$=Qm9x06(5Vf@*Hpu}NHoI{z%=pb8 zZcA~WIaIeX6YKJW8h&i?(+$qN7#JWU~n2?diXrVwYy z9O}oqX6n|yw#{3%(`JY-8%j1rvn_A1%U3bqg zxn^{_rnckgmb+&=ohr?8b-&v+4enIzHXpoUNVsyH;cBgC-1iJq+w-lKXV{k3KUPlT zbxbSBsF=Yl!<8|6iRwQ07%t@t0c6jghs{IY^2!P>G29rsIV2rnmPQuyDlX#<2F2m7 zZ60%mr}+?I^yHdvm~HNq!zM#Jgf#a_nt|)N?EthrSRra}GF%%)O&Um11m{ z;u%q`tbK-EqIa=?MCb>wWnt`wins9&89UJ310fW{`u||8DzI;=Si-xMX#6K% zH(iFt#gRi{l5sCQR#0GAJ-HuVKW2_(NQ$skbG=pNILLI4Kzup*rkyd+E9+kPj>Ax4{Xwn-d z?{LfO1u)uaWZm>SW|d(s%x{p549phM86V#I<1K zrf#)O?&fN?edKq`p+L&`hgRgl9jcyn?zSAG>)B5DNJU5@qB!?=-{Ask@Hh@`(1T;0K1AL*y}< zD|o`NIDRYTNDv_0ri(KMhCKad#per+MY?`sC_$m;DZGaXyiY5SXe~x#s`wXJvGfO& zXEd9@E&3m)onSd=^gJKz!Uu#c{!$Y4LwXkI!Agmq?$GlTqt}ooKcYqYwjcmu@GEIB zTl^i$bG*jz64}yo%*F5)k^=L01Z1Ah`IW4XsWjW47~ zT5nD|3XxuwB}`*V!USThWL8P(dlKZ1q?0U`USi=-Tp0(Hlt40i$dGY-*%M$DYrV08 z4H`2P&R`6Xsf$#AcKVsouOA;zY literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierFieldTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierFieldTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..de5af3abe9b0b014c5a3e60b3c4a4030a6dd2b7e GIT binary patch literal 2987 zcmb_eS##S|7(LfXEH8pMacde%(}gs|HdK_d6dXcpH)#xRTH@4&7MPLkn?#8$8A;9z zulyb!=nTs=4@{r=O$@^)=~_z?dorY%iKV-p?|kQ5uKxb_@Gk&0e4jxA6A~t6Od-jT z+fxrzMOTd-Ws`SItILpF)(p*AVVGDdw$ex;Eg>T#3z^~0UUy&742N5Wsw*8`we4+9 z=Ze&lj;8uqqn_3AWQXb$>)UE|i8#`SKn#E`PZ0>h<-XMNyky0SemI*w)<%J5tz zi`OwNAtz%7vkVu<>?N){++jGkRP-S|haR@~c*m(oILB};^fP1~r}sTC_3SypP>37& zsXsK5d%&Gtv-?Q3)E=i^KnB;wI&w-qTz93mUsP1GqeUDR9>dSVu2=9!q#o}2|K&M` z_o~i&+;F@o#@mi4Ag_Pc8O}!;21&`lOgDsK<%=bT%flu%A}QP=6fT{-V+`w{6?wed zQEH)hLE}2RfRy5yra7=W+--#9a6rJlBW}3fQ+wIqwzF>9j)Z#*#Zy-*^^W14m8+Vj zV>_1G_fykOAv;aUG@Znk8GMC?gao#4}x|4;*#)~VexdQ8D@@Md<+*x^;rquGF%U# z$EYsh8N>Yet&}Bxh;Wl`(F7Ql=zrGzo}p)nZlVOrkm!91?_vV)(aa;7OVBe@`V*{F z{vFbD8cpB^{U&KA@DCLFE%>|eK4H6m8G-r%y}RiCOqt$p(fbsmWeAfW(j_XfcENAb)8!(S z4)GR_0t#1rx{?5#p^N|16OLa2eu?uLaeNVyAQ3&}$T;qJ0^CK_ zd)BZ@&m2*UC)66vx|-H0ZBi89bxJCbs*^OT;cLuc6I*B{)0B=iJV~bT4W8mV%>4(7 C;5IP; literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierMethodTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$SupplierMethodTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..c6d5dbf3fd2fbb829f40ee2fb535ecbec0fd94f5 GIT binary patch literal 3004 zcmb_eYg5}+5Ixs`<%e1fPDp7Qk~D;3yN!~jkF=(wU_x-~kQ5V=ChcTo`vL-4a`j-Q z-}`g=p_%Dp!b~#h*Z!zZSJJg48|+~kn8DJ0o!vcqcCY^V_wW^f3VzHWfe{I#GRBZ( z$nB{Is-mmLj<)Jr&de7ANI#7gMM(CSkOL%Oc*7^>r1#Kp=m2`|JPiB!>t zS6(bLToNK1Pzr@DhS7lh@tS7vb+_H%)~4Ff$%V<9*;Mr{)zZANm>hL>HKMa}3c_HR z>b3B5r)wn_#PUG3)HbKCKo;)~jpU?^cmYd|ptz`bhw#{~K!#t0Wxw|O>F#d(|Ajit z^*cImbHnjd+1rCeCHdX7%5XOBW2j9AW_o#ynt)hhxY+Gz1C-%aqloGF9mCuX+mi2i zBko(oU)aRnoI(X1gr6$t7!g9-| z>DZ2?b^?9cDP+e*HojWb9=UCn)`02980B8Kx{@F+@v~M;dax~I*w_@kNA|wCj`dRqabnXJuN&` zkX$tkZuyX$>hoOpehp5B8IVwCxD~N+i~z#DM{h9+4;ki8cA8=0$Sue)J+R?Q_@3cv zggu0J2~QbjhHoXE1WCdTx>6Hhn5X|q?*oUPMY@y{C_$q4F?@&-d_*%3Xf8p|Oz|(U zV(AY^&uKJ*YxJ9>oxn>d^g9*o!ga#-{xSmfV|w?{gP9V&-K6(1M#~T;KcPwb@*n`u z;9X%bU;G`?3%tef8u`)-oK4_2T290){~fcO4=v~MDLx~}AfC_Z6KV#xXzYRCpr_}H zR6N9cI06`i61Xb~zzO;Y_~Mx3mw;dU{5k&k9KICC7er{OV(AdGgU$y`rownqC}Y9* zJBzObNs2!v9zBx!X^FcrCSU?G7IRC)^lbrhQ@E2ZmR@7}Pn;hHlomiDd&rS-eC-pk zgk}F(!5w<$$hBTUt6FzAAB$EN*9;*(vdF`DD;U zdG<#c?`*fU!L&h5)17-~?wot>xp(*Hudm+$l<~wuf?@8MpK!^f;xar4R5L6#+o3MjMNx?`@K1zGHXV@PmeP}l88D=5SV+_Q z+>@SOW0;t)_R{TWMRBX8eG3_eV(*~g^DsQ{eBqRhwchr8SEwv(T(NM~Mh~f6o&JP(Zu6Hz7nqjt|Sr4tB05LTj3O2?Kfl;n2 z(zP%#jC;iwO(C_pcf-aMZjupuzopt~}$%nc>@SV^{f%~2--V`)dRAcRu*9S8Q`tzt-Ti%@R{A@y&C3b?e$4EC0kLPY~Bi2T%`sZW81@fN+EcjzmS zqLrqSp7+SxM3R0$<{Q|DLh=hne~_2J{WubMi6Ys>P81$snmmffL(C9{v1ajzZZPwX z(9@uG`rw19X;KNMO|Y2slK42V({^#0C9^~0-}1>+ z6YaA<%6Mj33XOtQL*UGrIrE+GeCG_`e|-K5pp0i05)4aCe#RZ2%M<5NhMjghP+GXP zwoqJqfvkLJh_+dzF~+c>6_??0pju(E)d_X6E{aNofqy1kTGIjf9VtC|k^w`?hJ`fQ zm!9R=et5>VdI8{NgFxj8Md45 zd&iSnD9L@Nf5U6FednOZa+kctL)oKf;4aS?EUx!8SDImQkXIjUAU)AE45n-pO!{%I zE7G+vJ%V_}7cC*Rxi)KK4!21N-Y{}9RQ{ZBK&h*YV%$i$yA1ihaJ702^!096iRjQe zfx4-NW3>fp9bz*u6Rq(Fj0ZEYhM37?_QD~9g`%p zA9PehnB1i8WdqD`ZkRSPr1wOqcY=_5w?PG5TVV!!S4yGECaoayvqOeG1)9P;^d#@m z(@&A5aire|{ zsR+!DO3TK?mMLbOYR!Yt3PaIu{sY<^N-?(=aVK&Sx3vr0I>$_MB){AMzX_@XQ$$|`9k literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$UnresolvedFieldTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$UnresolvedFieldTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..467c35f04f577351d30f4d905c6bafeeccc24059 GIT binary patch literal 1552 zcmbtUT~8B16g|_@ZfRFrK@h(yf>6FzAAB$v53MPCcK2Ey>Y~9W_vs2>V^2wly z^6ZZ=@x>SagYnLGOBGCEF>7FYW#>hK9>j1t_+)v zMxeBCw;Dom?FDl6eN{BfB7*^j8LhYs_XAZAi}hxxixp8+A`JW^;nJE8$ZtyN$%8By z(l#t)$UgU^rvPMhWic@w*`%`w6|J!G)B-qu`chRJSb9kgx&#ME#Y zvN3E3q_|#{u7#0)+*f^37gC#hH*AdICW*nTMpA}X7f9J9*BMeVawOkvhC)Zatx8Q) zwS~J3}x1r=6j4Q04v}SDx|X%>jMrg$ystm)C!h z8c=C9m#FqGH68#HE?Ro_4R0&MP&!}X6*FIJG+%At(jE!;TIj>TeZv*63z{mbaqEKD z&t-m^q)o>p$!-TtRTU;T$$Q!ZGo=frRScO;5$g3Ir2Z{X0T&jT!QPNks3@%<@?*WG zJ`EbiTl99`p|3!iEKMc--y?4wN%{fV&tPwdk{^-!N?ro@<4E8KinK1aqVNFY6k#s;fXe=}BTHDry#Uk)4M_)_k39%;Rx7^9OiTa=icm literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$UnresolvedMethodTransform.class b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl$UnresolvedMethodTransform.class new file mode 100644 index 0000000000000000000000000000000000000000..ccc5243763b6321b1edc9dbbe847c3bc80f55d12 GIT binary patch literal 1563 zcmb_cT~8B16g|^Ix3sIRAP9aIL7?Sh^}z>&ATx-!lgAGkl&WllLr|v zq-hIFI0Q!wzZ3IB&J9ZUN^EbY+NR3pJr!y#n_REw;1w05w~g$ zQP&pkFwFFJ&))A-VyGOrf+1J+q}XgXYeMbtnom2U)u7J(J+3_C$D2d?&6j#$?Vzpd!sI4}PupO|b;Y!cA-yR=y&iYe>ca6) zfoAe1y{Nb8gODOi!%6>l$y-N~en93c*z3{cXAFNQFM)e;B=8;uS{FJ|n8tnbC>}GI zB@DBAfH}Is%)1h!u2FQtoLz|eAwr$#ME!wENum@LwTPw2F2f;fKGZgr@i3MC1rud;X0%I3~34}hX3W{g-E;3f+P%B~{CD*?fFg_}Mlh;iEQM=G2uz=; zmulWn&6E5=?M$n?0*Q6q)ZNDdqf5D?8Lk>nVFF3^?UpI87uN&hoZt{E^aIelGVZfPLN1TvUaa3h5|%nRhs8s~Z4bT!*ljeOlu9p_j# zw7h=NH1btjHJxM2zSv_=Kq((oclXNA1ZD??CoopD8k)dVNjJ4}>!POFRhc0}Em?Kd zI8tq0_JhGO_f&TTR!Xr$CbtYwG$93e>M6v)Qeg}%{s2?>h4 zVf?RfBrv{SH-e9vtXM6(uI*4CrW6wAuKX4PlV#0u_cfWhqhLv3Gj?v-N~_s4bj_9; zcDNNRbKArxDN1#;Mjyuq0$cGpo}0GjSjJ_9=B~h#_%!W&c67~X^d!VDFoY^WLj5Ek z3v9;^rJGSd&wYW7_&ocXdusKI`^iw^wpH<|dSrPxl(>N`5tdH{it+R5>JlMZA4-^_ ztQ-B>vJ4Khb0tM2j3+~>(iYbXr$^iESJ`s?B%cjMau^(;P870)D%g3&eH#vjMSk0| zT*tN5rZ1T@jl@&}pC?(}zewRW7TMdEy>bfgcynJS@f8jgR8pwoxxixg`q0fw>s-s1 zyb?-6^;oUDmi>YS?V`8$Z*S!c7Ww{nRkLAePPSxO=dEV%l~!?W-8|_X2`#L?XohaU z_>;cNmlOBifB|z+HH?bxYP?HQd#1^HD>t6Ti|9sY`}9^|UUq|us=$2r^n}VSZ=N<$ z_(agdz-lINvrE;#B;)Jb=V89>!JqAHGWs4|83Y!(J|c@Uo(BD{XT8ygaVNX}J=xAK zGCuGugt87VQE)17C$c^LNWwc!!I{9Vmz(lg=5I?LiwvJ|;3MgE`TAk&8vA_AapWd@ z_lQD{F8>MfI~yZd;D7n<1MXuCYg`Dv!aO6qfj7O`w`k!LtkY83jxVoVK>>ba+vkuj zfQR1tIo}4iybx%Ox7iZYNqJHOCh1rHd13JDvFTG3XvX6mm~9cI!}RiBnB>#O``?W` z>NVZ*n)bcY`@0>lx4kHVi7QM2e_%#Zg}hUQEXPK02k#LVF^%_;!wNn`9;;Mv4G-`L z1#DmwTYNP?#WUK;ln*e9UF`Aaw@Pdsaqd@KCr1WfGs_(D8{!J_+r&6oGx(1EJn?(t zD)9%7-y{CW{u=Qo;sfH(#7D$mIA0*D>~9cj#7$zIxJ7Ibi$sn1lz2@06X-a{!vEbs BdhGxJ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl.java b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl.java new file mode 100644 index 00000000..1677d421 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/TransformImpl.java @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import java.lang.classfile.ClassBuilder; +import java.lang.classfile.ClassElement; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.ClassFileElement; +import java.lang.classfile.ClassFileTransform; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeModel; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.FieldBuilder; +import java.lang.classfile.FieldElement; +import java.lang.classfile.FieldModel; +import java.lang.classfile.FieldTransform; +import java.lang.classfile.MethodBuilder; +import java.lang.classfile.MethodElement; +import java.lang.classfile.MethodModel; +import java.lang.classfile.MethodTransform; + +public class TransformImpl { + // ClassTransform + + private TransformImpl() { + } + + private static Runnable chainRunnable(Runnable a, Runnable b) { + return () -> { a.run(); b.run(); }; + } + + private static final Runnable NOTHING = () -> { }; + + interface UnresolvedClassTransform extends ClassTransform { + @Override + default void accept(ClassBuilder builder, ClassElement element) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + + @Override + default void atEnd(ClassBuilder builder) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + + @Override + default void atStart(ClassBuilder builder) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + } + + public record ResolvedTransformImpl(Consumer consumer, + Runnable endHandler, + Runnable startHandler) + implements ClassFileTransform.ResolvedTransform { + + public ResolvedTransformImpl(Consumer consumer) { + this(consumer, NOTHING, NOTHING); + } + } + + public record ChainedClassTransform(ClassTransform t, + ClassTransform next) + implements UnresolvedClassTransform { + @Override + public ResolvedTransformImpl resolve(ClassBuilder builder) { + ResolvedTransform downstream = next.resolve(builder); + ClassBuilder chainedBuilder = new ChainedClassBuilder(builder, downstream.consumer()); + ResolvedTransform upstream = t.resolve(chainedBuilder); + return new ResolvedTransformImpl<>(upstream.consumer(), + chainRunnable(upstream.endHandler(), downstream.endHandler()), + chainRunnable(upstream.startHandler(), downstream.startHandler())); + } + } + + public record SupplierClassTransform(Supplier supplier) + implements UnresolvedClassTransform { + @Override + public ResolvedTransform resolve(ClassBuilder builder) { + return supplier.get().resolve(builder); + } + } + + public record ClassMethodTransform(MethodTransform transform, + Predicate filter) + implements UnresolvedClassTransform { + @Override + public ResolvedTransform resolve(ClassBuilder builder) { + return new ResolvedTransformImpl<>(ce -> { + if (ce instanceof MethodModel mm && filter.test(mm)) + builder.transformMethod(mm, transform); + else + builder.with(ce); + }); + } + + @Override + public ClassTransform andThen(ClassTransform next) { + if (next instanceof ClassMethodTransform cmt) + return new ClassMethodTransform(transform.andThen(cmt.transform), + mm -> filter.test(mm) && cmt.filter.test(mm)); + else + return UnresolvedClassTransform.super.andThen(next); + } + } + + public record ClassFieldTransform(FieldTransform transform, + Predicate filter) + implements UnresolvedClassTransform { + @Override + public ResolvedTransform resolve(ClassBuilder builder) { + return new ResolvedTransformImpl<>(ce -> { + if (ce instanceof FieldModel fm && filter.test(fm)) + builder.transformField(fm, transform); + else + builder.with(ce); + }); + } + + @Override + public ClassTransform andThen(ClassTransform next) { + if (next instanceof ClassFieldTransform cft) + return new ClassFieldTransform(transform.andThen(cft.transform), + mm -> filter.test(mm) && cft.filter.test(mm)); + else + return UnresolvedClassTransform.super.andThen(next); + } + } + + // MethodTransform + + interface UnresolvedMethodTransform extends MethodTransform { + @Override + default void accept(MethodBuilder builder, MethodElement element) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + + @Override + default void atEnd(MethodBuilder builder) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + + @Override + default void atStart(MethodBuilder builder) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + } + + public record ChainedMethodTransform(MethodTransform t, + MethodTransform next) + implements TransformImpl.UnresolvedMethodTransform { + @Override + public ResolvedTransform resolve(MethodBuilder builder) { + ResolvedTransform downstream = next.resolve(builder); + MethodBuilder chainedBuilder = new ChainedMethodBuilder(builder, downstream.consumer()); + ResolvedTransform upstream = t.resolve(chainedBuilder); + return new ResolvedTransformImpl<>(upstream.consumer(), + chainRunnable(upstream.endHandler(), downstream.endHandler()), + chainRunnable(upstream.startHandler(), downstream.startHandler())); + } + } + + public record SupplierMethodTransform(Supplier supplier) + implements TransformImpl.UnresolvedMethodTransform { + @Override + public ResolvedTransform resolve(MethodBuilder builder) { + return supplier.get().resolve(builder); + } + } + + public record MethodCodeTransform(CodeTransform xform) + implements TransformImpl.UnresolvedMethodTransform { + @Override + public ResolvedTransform resolve(MethodBuilder builder) { + return new ResolvedTransformImpl<>(me -> { + if (me instanceof CodeModel cm) { + builder.transformCode(cm, xform); + } + else { + builder.with(me); + } + }, NOTHING, NOTHING); + } + + @Override + public MethodTransform andThen(MethodTransform next) { + return (next instanceof TransformImpl.MethodCodeTransform mct) + ? new TransformImpl.MethodCodeTransform(xform.andThen(mct.xform)) + : UnresolvedMethodTransform.super.andThen(next); + + } + } + + // FieldTransform + + interface UnresolvedFieldTransform extends FieldTransform { + @Override + default void accept(FieldBuilder builder, FieldElement element) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + + @Override + default void atEnd(FieldBuilder builder) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + + @Override + default void atStart(FieldBuilder builder) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + } + + public record ChainedFieldTransform(FieldTransform t, FieldTransform next) + implements UnresolvedFieldTransform { + @Override + public ResolvedTransform resolve(FieldBuilder builder) { + ResolvedTransform downstream = next.resolve(builder); + FieldBuilder chainedBuilder = new ChainedFieldBuilder(builder, downstream.consumer()); + ResolvedTransform upstream = t.resolve(chainedBuilder); + return new ResolvedTransformImpl<>(upstream.consumer(), + chainRunnable(upstream.endHandler(), downstream.endHandler()), + chainRunnable(upstream.startHandler(), downstream.startHandler())); + } + } + + public record SupplierFieldTransform(Supplier supplier) + implements UnresolvedFieldTransform { + @Override + public ResolvedTransform resolve(FieldBuilder builder) { + return supplier.get().resolve(builder); + } + } + + // CodeTransform + + interface UnresolvedCodeTransform extends CodeTransform { + @Override + default void accept(CodeBuilder builder, CodeElement element) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + + @Override + default void atEnd(CodeBuilder builder) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + + @Override + default void atStart(CodeBuilder builder) { + throw new UnsupportedOperationException("transforms must be resolved before running"); + } + } + + public record ChainedCodeTransform(CodeTransform t, CodeTransform next) + implements UnresolvedCodeTransform { + @Override + public ResolvedTransform resolve(CodeBuilder builder) { + ResolvedTransform downstream = next.resolve(builder); + CodeBuilder chainedBuilder = new ChainedCodeBuilder(builder, downstream.consumer()); + ResolvedTransform upstream = t.resolve(chainedBuilder); + return new ResolvedTransformImpl<>(upstream.consumer(), + chainRunnable(upstream.endHandler(), downstream.endHandler()), + chainRunnable(upstream.startHandler(), downstream.startHandler())); + } + } + + public record SupplierCodeTransform(Supplier supplier) + implements UnresolvedCodeTransform { + @Override + public ResolvedTransform resolve(CodeBuilder builder) { + return supplier.get().resolve(builder); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$AdHocAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$AdHocAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..33b0bb36bdc58d48a55d6730202202bbbaa9f6bc GIT binary patch literal 1735 zcmbtU>rN9<5dKbg>C&=-BA_A{x#`jZ^@51BR@w@(2@(?uCdNP8?gER;*=D;{@d@;o z_XjZ{n)<^B@S%*e+Y6LzB7|(R=gc`X^UXIiXa4;C^&3DAY7`*|5=0qo2s2FW>Ms)} zcMXSYR-$NWaO-mOIRA;K4R8X zeWI00hLfD!>_9sr5~4CXATtaGS!F9*&m5CtV33P8FS{CdpW3#?Ft1Do;xx2Mq?O1W zG09d;ODEt6I?*NJyo?LzW=Nif=6FV5v5QSA#Cp$X!!QvTOjEN?x&uAvmCz^S5-u~0 z1yMd`!ys~Pj}qL|LU^4L&$p8u=*LwF12P6N#4sD=@P8R$h*aFI`6cc;`wWXm%U4G^ zL8dnv9w?-CT$3?^QHJPiuXrlgjW-O5qn;1@sU{uq}rf$I$Ibw@6xLs4tJ zqsW* zvuAOf%IA}5@*X=$&o-1J>*hAs+=@e#r-RdZtaEFYUhX8n6nUG06&QvCVGnD;&_?gv zq2x2QZtEJH;YBLHun=h51g=4*PnDbo!RWeOaf-$=%{YeM;{$HSds);OYev~!vC9;k zta5HRId3i+RO-&w(IAdcD~4#W0s@E;!X(`x={c?5c{mpT3HIH;pQXPyeIdLbn0;v>zs0UL{bP# SSoYTt9@82nT`$WkV&oqu&(O30 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$EmptyBootstrapAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$EmptyBootstrapAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..f9796b95a35c100a873ee67447edda25b97f68b1 GIT binary patch literal 1162 zcmb_bO>Yx15Pi;Wv*~8(M<|r?Q9fE|f~u~#z#&y62(74;_7ce5N!-?DmE*{U=Z{~T%@8_@YKLFIR;UWjif$d=id4|;!{)YPj zS4Vy);BkB?1K~f_I+E=~iGk#Lvteg4)();RJekxRK5VIeJp7vyN&Z)?9x1Mqh$6K=8o51jPGj%gQ93%U)~M3Q3sIh&e2TVGt%Y$XQN{eg}%d}o2?=cCKku5wt z1N#Q&EA4Ywq18wi);l=Xdt4{qJHLk;xJe$vEv%+FHp!YCIqS1o2k5+sSRY1^xePgj x65TS@w^F2ihD%?@u%AY-c8a|{xN`?K&UbflZxC6-`oI=&pR7w+&3hkUQE5@*{X$XXB2uZycwxLerR@rVbhjp3NB@%#IwRu@ z5B>mul;hbX&}aokd1!X`HMsiCTq>(YuVPYRlhN;!+n&k+^Jz=|6#kGC^wc~QjsnuQUnJCMK zs7@;7Ipv1p!%yGW`J$~>re&=z1sAGFY7C}|4oyUDJ1K-zwsNFsg&Nkz z1%18!CbH;a=+>~4-g2X+J&7uR$H0m`6n2k^131W#R`LnmO)N7!A1VERD1}_?>LGGL z`#WUfFpiMF72BuatDNEf-uMf`IcnkYb1ej{GLyL7NmAdgIY<@kbRX^>v#>M6Vcb|Ae+%ei%BQ$c9(p zv($d%{ny^RpgmFrE^uGXNnaVb$Z&2qB~SIWIT5<1q*T80?0QIwpT<>&fp{AiTADA* zV9>8Ko5IZw+`^cFf{Ah5W;oHL!)plT)VLMW62UWM%9|b;KE;`J#9O(>tx$2!7FCz~ z!zC%#8uj=biJCFSdt|7`$_)1_o>N!Si@Kb{af^)3nbdNUTLbHx2$X1TaYZOSEcLBfmj%e57rw2QyTO zJap3>Kl>Z=Uf{!DnIFSQWIj&L5@eIkk8YrEJNrYS&Q^eFMiGrhNLFwLlKIat zc8Vey!7!p?Gm5xz=T0$f8Ygisi1a)z1gk|n0{iKnVOGPOUJhgoH_%R*zk+MHjyoh9 d3eFZLDCB{Ok#Ny(eu%%EUVj%{hHusZcTBlBD!|tq4eZ}>G z-&Z`2_oWj4wlR_HB}T*yOI+*Fa3e$gT&VgZW|E~T|CF?22x??INp zbh#55J)E6Kj_7igh`_-WhG(<-!?V8n+c{?3)QKp6D>sLX!Zf-J#a1{F42x~4MJGAx ziRcaQDbieShkdTPJd&wARu;`$NfUkD{=a<*7`(w~HEd>Q?8j6I4AotEpt(sR%K5{E z^4gp^i}Q3i*b4p~%i!*YNz@lF=ujAzv#rS{`y`z^L!~2P^D>O-SiBvrMbt`AYb33V0Jx4-k_ejK2)SdpftzEuzLkMe^AxpXGAa-ZD3coaW!-r8UmCk9;+D0# WjWx^f;I8ErtP^+1Hm&3yR{sEv!%>O= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundCharacterRangeInfo.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundCharacterRangeInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..b64b41634c1ca561bc9e1ec98dd27bd27e58b1de GIT binary patch literal 2288 zcmb_cTT|Oc7(Huj%TQ5_!4#SsO=xQ?X_WMmHZ@I~kPzHBgb67Ry*$YBf(1fyB{?&l z>5u6T=tDD8PiJ`O59p8T^sFRf6CB2!!87Y`wY%rLpYNZ4kNyU*hG$dAU_wJyM-F*` z;=c9LGF{8tGoMS_4_X5GRmXFpdjb=c>dqtznA9+(<1Od{>-((()A1r1c$RD0t`&y6 zjw?;)u;ZHFc}>6TweCkz;556DTuBes+E!rM#5|`NS@(8*0WFNIAlkA8L|xf=Tl9UY6YzFpVa3rmdsT^$#2QJ@g{ z+jP*|6Zo;xIG=cG)y5!?iT0YZd0EF5EYoJ&3fpUbOA0(WKbv)B;;N2oSYg%V&t1z6 z1%5g=14A)AYwk-ss#U+&@PWXsL9l}su=-^;N7cJfsjFXgM`dt~suSnLHj$adbS?@JPox9t&I< zBqZp1k#i``Br&NM0+Y?YV*;;+6Xv5Y<;rlS;rj>OPHiZeDT#(oQs9eU zI`W|m?ZD|oelQGKQ`2bpAl321X(hwfPjELauYg|nJQ>6)B^zYvjiXG%6M^>!`8Xp! z4NnCwpZ%1zO_G7zoMIVJHwSe|O<$6|q=sZHIT~Zh5g1DjJIYDE&*4MjD*XDDGEcc| z`~_iL=s`0s_AqT+>Y-?qvpvii;TMuO$EhgL>yN2HFuJ}YN~$<=#-Gs6 zawC_j5lqV{@bq}#(nxS|JaBm=cy2uK;z;nqIN%&Ui3{{8K8xiYd_lR)Zb|yP-`zS- slg>{1`Yylcncn-*$citqim%w8U*j8W@TSD_6mSQ1Hqf_dU=vIK0o0uR!vFvP literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundCharacterRangeTableAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundCharacterRangeTableAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..10ad02e99d4d63df3027a79942013bbdffb2e4fe GIT binary patch literal 1467 zcmb_cU2hUW6g{&A7U&8H7OmF$(Q1KKH@-^K#9*pTu$oqRG#Qqmow}VR%dAQNk&l{a zY<%zs_@j(>mjx=VO=*1Cy|Z`co^$V+d*|2hA3p&!@F)udGbR!il1MQu9`KLccDdTK z9hdj}UFiz@nby8+2U_$QO3ps_xub=@Lz~1~-gX7UN~PL7H}Vzl^@Lx~B8`lRtc6)v z3~L9S54KbUrnq~8P#*SN`<-fgf$EIN8B*&~Nxi{Psa%My+L}cUc@qT-S5aihML7mq zx^`3cH6c1)@91@Rj2QiEc&;lPEj?9_%Nm8$Gq{F16J-n6af9K_G!-nzB{fbeLYNS&Y-H zwipr(uR|R9rc`1(IBW|)?v!HFbGX~$z6?7jb|&<`q=I*v|65JUulzURQEy24Vlwed z2@n=r9CrU$1BT60&P(Ale40v?=}02|N4-bqIaLo#L^EV}y}) literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundCompilationIDAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundCompilationIDAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..c1aa0a49a427a75cbc8019f78795e7b92a7f2f42 GIT binary patch literal 1140 zcmb_b&2G~`5dJ1j;>2}Y2((b3<)=s_0o6j{faIzY3Lt_^FD{|93iFe^4 zKmvg{@BlmjaNt=GV>h4(C50jm-q{(?eDlrh%%|@kJ_6`s-9`y>7RnAPs1nu=#dG0C zLhZZ5NTlhWj6(OGF^L>xCQJ#9p&rFD5=Ls(3kWw_ZU5MqCnAo+#IsRD-Gc349uDEw zVerhA%7lp$(L^daiX-=_8t6;~ztR$_n^H-$MQFADDqFi>#{w2DoN{m)O~T`o!FDHB9Xa1HkQqS5SD%)*^T^}3AODoHIH;^2u@F_FzMz? zmG9B&u``C-Jiav$&hXdFN0_&@#P@kD@wv=ekM$DEM&~`~9jwmHw`jaB+|Kd2fH{CZ z!=f*|Z(nhqZOcaiSiuF>IJ5vJ2CU%X7}jM;{IAk^gT^bql#s(!b0d8#V4Nd|F-#ek Y3a?eH74kB!6tae^EN%A9E4hZ1A8*Y|0ssI2 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundConstantValueAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundConstantValueAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..38405509c0c933cc1556614283c141255588b59d GIT binary patch literal 1176 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 QL|ei`OyfIjVF%Oy0b%U%2LJ#7 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundInnerClassesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundInnerClassesAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..f6c7c41f4694b393e6d7e4965e9edb35ada0bf91 GIT binary patch literal 1407 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 D-?gc$ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTypeInfo.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTypeInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..828a0f7f5be9722535a49defadfa8102e81f2afb GIT binary patch literal 2445 zcmb_dU31$+6g}(MmXj*PF-}5gXhWNVt+o-Rd;}C)+O#EZ-89gW2bck5dlM^Bc8#>| zOlSB>JkS|D%;bR|z>i|ME6KJ(TsNJ`gS4yF-h0kHd+*(U{yq8|zy`jZLIx8CvL;Cd(n_x(Ym8l;5E96uOtg~*>wFKH}Kqs&!4^M@S50_3`VHjKy5b}SWUyc zWnxBSPbO)TL(hJun$iM!Zi__8dTiwG351#3)WGEeH6fb5~+atvuonbCe$vx(( zEnC}eKuJxNL;&T=h!lwmu*NV)=QSwOfyh)fR70hczZh1Jd3&vf3{y{KH)!$)RLKPQ z|1w_H=#-^fJXD)9R0h7FQhbx@pycZ}m*QP1Rj2~D6RQvw@D;>U7@@~ZpV@(aMTMLeFh9K)6#n4 zxjf)@ym8YNEuV)gbtwJWO^a-@#9G+Y4l@# zBRO~mvnB)&BA1*}XK7rMHSn0>%21LqAsTqXaAEvbI>%TK+@Lm^0mBD$icEt-rvm^F0{WQV-MC^&X1WVz!5}HJ9sQ z;U(?Kz@m4a?2+l=D$Q@jwz!7t^hI7G4)mX9nnfm>X&w{NOf$(wGtDK3RhrM`$OyDu zQwLoXplbn`rMti;C{6MPjoPVU9pPQz51O9jV#Zq%F0;hoqY>s8fZtDLz7nBo^mPK$ zffTH(N4WGV`}ug!K#BrB#?6TLxd9O!kB%c}{Rv|nja=e}ku3cv(#F%LGcMtiM1r(& zah!fb=# zHa_?R{87fUmqLrAmL@*zo|&_I&Ue0Z`}O!W2#OYNIo zX$^;cA-Va&bsf?1Ts~wdO1o>xw&e(`Bl+&pfbaSThP6_;d9LxcH5hQGnnn^S9ccse zFc>xtdLK-oT<$1Kp28G|18MH5j_s-52%jNQ6H2&S45iYA(8}$3WRTU7GjJ7ohD;En z=L%^y#n2^>U3+l!wm11@~$gvRgGwkOsXkd!-9^Yf$O-z(3*w8N<^tSHH)W- z26?80=R%%icpWzxo=;1)by6qupYBsFv9B!GbEtB!CJ<^bf2dg+ zp{~&BAyy+ylWzV$@yb^eKGQ)9fD*n^s|5g|lXwIWhQ5YaM52UpU{%3-Ad}c2nI?Om I_9HC*0f~XU4FCWD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundMethodParameterInfo.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundMethodParameterInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..9f9377ef279abe4e861c9db27c0db643013f9dac GIT binary patch literal 2235 zcmb_eZEq7t5PsH)b9T7I!42WHB!$q%4&@q3TiQzlBq79=c@cqp00COto8*$qu6wtK z#DD4skU*7EsXw4Us_N|B**=4b8Yv&_-JRW;XXcsN+56|;gTDc+;I~oaFl1raMjj&! z6TAF1cYH3loyVf7f)>Nbq9;AQ#4t2h*({=fqJ>c#Ctx$&+imSRp41|c+;^Hj55q0b z7ml~z_MNA)p(5G3qjlglA}wZ9!F{23RO=BB_`V>`n%q(h!;)4Ell9nvNPE8Xu&q5s zc3lHHZli<=hT@jbx5N89++$$1G6hk#@dYLs3R-OtlH6u^F;_n($J|QdP|QeT-Zh|8 zHcsOVf$s2dXGOKh_4+Y_#(|x)aUK^a0pj2<3q?q^{}xkn%b>Avv84Np;rLC zbn;FLoq@S4Zg|_0>nI==mIowoF@x4K+Eg;sT`%OoFCOL{L_?lLvltP%9 zF`mOWBsHMP-VDv=XkN_GK_f!yO$8_EDXG%7@nL~RqheJLNRGEO&3%HMShZ5@lk_Oe z4^Te^{PDlk&*N&UzDQs>(kWEu4{-K#`cui7Zs-Mki)*ppC*aVYiNlH4K)(7O)?rcP zQ!`0wz9Y3#H=3-GvBP5N7|9cVhOq1SJ|1u2M;eX4{rOL_{}b(v6W}6-sa9^{7r69s ULT@{rFW?4NiGsVhhZ@fQ2U6HQVgLXD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundMethodParametersAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundMethodParametersAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..a054e07eb3b79a06bf2f6404fca50c20c582b35a GIT binary patch literal 1453 zcmb_c-A)rx5dKbSyX~^l+DZ{cL`7)}y79`35|lJ3BrTYry)-#(PvPM9>}G#VcpaZW z6OF_RAHat)&bHehE21S{?9QCoo%!aQGc(_ReEkNXiibL4n9&e7kU)}Q`GmjYrp48f z*|NCjb)+TCZQplgGw_ASknIZp*lxe%E+$y36SrV9b?4KePk4C7#o!V3?mA+(%)UlSPoc4A$gpj!kgd@7!5!SC6M07%_eeJ=e&4b*L|r9q z0rw+JlTP73iSj4pKadjZ0VP8t+vx%HgCrt=e(Dbpk4UVc*z+o(+>%Ez`<>r8eD7#fmoHp|F( z<1g@+c%d^gWxVjlJEy;?<9kk)ki@Jmi+Yp1=i`0eujib+`Qz2EzX2%V>lC^m$>>&) zKo7&UJ?%itnVPkmtD0K9zGIkrZq9WbqtbBoIz!LCz1=W%hLP-O>2EhLYqgs0?;G&F6 z3I>p7D4fOK&87p(BF2ClDKF|3ZJ#2ai1nmuTXk2n+?s8hIS*jLa-G9Gcjz?*S1`!X z=iw}x+Aigi75Uoh3NmrUOUEy~nCo7r-A?s`W0Fod^cTvKozZ!=sFm1($! znJXD}m-1M(Ylo{lr+E}>1=}?Bs!Qhb&0_j0!tHky4C5w4($Swc42ReMlIK-;-@6J% z_&!tZ6OU{b)>9Q(l7*6S&}hxcXNQSbpi zWJsSzv0CF^Y9>R<-dSmwrdHu346$OhvPZ#$A~{jZ%ec!h9>-Vhgxt-d1*+b=VeDF( z+i=KIArkj=Y;~ew>t5c9){dQ@$um6Y2xUQJ)d!jF2xOJY;6vPR3nE160>2JCvhhed z%g35mXy1>Q@uxauICz$du~`poKRpwH7z0HAuVzQf#O#8-OJP zl3mrzvgR0k+??!ozcJ`UEtLL+D~c*I7#|s52pK=DojB0UX5=d9jM+=E*4x91@O$wb zP$8C6X8G5wt@uJ5ig5ird5SQe{rlpSE_&sKig^y4Kqb$B(z=Xi0Evba zt|33@lP#K`kon-nMVCV0)4#0MpD{?;(ITDB6DUDb|AWOaAG;7=&5+&G8<1br=@1O> z2555OFO%`O(M*I{67`XTw}%rV34InjbSJ5j+_@A?Mg z8)HmSqn8B3NAyhdhMRsW(!A9bZ)$7Bn|esv^D)U?xJT>MEBfO+jj2!c$I~>XF3}%< zLSt$Y{qYQXN$$ga!kPux5WRZ|d0ssRdjVM;J3_xYbcD<5_z|wEneJn}d4wBkCLx4d zYNkgBSv4aIVNA^=g)s3m;YgUHr-~GbYmlXfP^5JXNE;ZGHgR3rLRKncN_vEQ(qj~) zCwM^nzw&&bAF6p8kvAe2Oh`N%T|(mdkc2dh1#}B(grtO!RFZmxG)|H%q)C#JSS0yQ zbJs9F^);7#&7!aQnXmadX?i&?QN{+aOwULB^sW-?aoO6UbyN$V3$6`<5V& eh)iCJALEHA=NI@=ypu#~&@rH&Ng~oyWc~z{rHy<5 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleExportInfo.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleExportInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..0ba9958f04f66c03e225d913a0a819cef323d0cb GIT binary patch literal 2661 zcmb_eOH&(15dLN*SP3skD7F+5V&?&gBy4ZUI}yP)0)i3&j*&UorzaK@}pAeeMnjfLqUauG&4QZ-Cw`=pMOtY04QU30t#X(;u^*<&X7JZ zo*BAj*e(4LZwRN!Fur8krd(!-B#=}wq2U@dhSh^+TQ_aV9ow+JD;LV3dqiwV}gI*l~8HjBN z+m(hbJ3?4`_;$^f&QZz3HKieiG}#bHbJs1S&5 zUNv1wRyIWEXnT(#pAS^~cV%H&ydh0tmkJTG$KtDeUBe9CU`U24Yh+A%^kIfPJ*(j@ z++;{du|w{#TMSP~(G_^F2h5LIAiLygd|Sgic$YNp8}5EtG|8!ztI}BU6wGOu$NS_t z{zKQWT!yDtBt8=Q?fL<^zf^dlBF}L5RXJhw(n~*`SIHf-WgD{Vkn#6N!m<=mb4G@R z0{sMAE-{qD)bL$>2G3AdRz`G|3cC#PAQ-8tY4fe_VVyfQqizwxOjR@tYu9j0?;H~2 za^EE1u3t^AFl2|79Cdn%(wkiF3#vfJIOJ5&q}2Vt_Fme@o`0_A!%~Z8wBLOy3^$^X z`q@DRPKB3=L^Ql&SR9gek)V;F9#6kNQ1Dky5ie~W!^Dp0It{)~J(6r0ZIFI`Q^js^ zS8fPbs<_W^`!Y>}s7;X)U(dpXKJmh-d^iUl&#d;3`!}Dm|O#7K=b3J&tVc1QJyK_|`+TBhm z62q{WMJOR-jk0!?yA8+eNZ~|T%H9Nu5<(eIPYa1^AL^m~)X^%o%^hDPr)tQZF}_qh zVwfLz;~eW$)EI7_|CB-)xB`nb(-bg#fEW!gnzz(+Gv0{vSDHI?SD?LuB2?OsVS!%W zCdyAli_@Ab{svZDIEGrBJ;r45&hMB$M(#OX#c+rIv&01D55$!}kyQS|l=3&S%1hj( zyJ8>$IzFTm3G*Q^f9HWv{GA6QMo>ZUg1Z^wjNv1qOvZ=>gcvj>5n}xq(=-Y{p~oK5 zMOr;JwRnOzfnR8=_{hdRvhu=55=d4P#Wu83Gh5_>oz9Lkf2cyin zi)ao~rbLln^4;|{mi_e}9?&{Vu?tcyNVMTJTcH{ZK7rfP6GGv NkV5@EcJLT8{{d#zwP^qV literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleHashInfo.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleHashInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..9f85ebe610083cc4ffbf5b2125d38f219b3cf6eb GIT binary patch literal 1989 zcmb_d+foxj5IqwTHpIn1RJ`B?6*LLRf_M+!!bPYGXbDm(Pn%?bh0RRdomj;``5;wN zR`K8m_)(TU*@Y~E6qY<>XSTQd^yPGSe*W6|0bl~tDa6obAZ{Xoc80EX`?GDiwpg{^ z@{07T4DI8NaMUw~wrp;x14(okNSQbVlcBg?-LM>?xF>Aas<^iAuQ)EZoLb$r-ifko zi0VtFJg3}HygwAo$!f#pGq%4rD^?^!s@4?D+cnNGTxvzo!mCK(D_f|#l&%%nPYLC1 z7IZwPO{CGq5MLumhS+j3L%C&4oWWU!q>>91fLLXCpDq1=yoFpO!T`CT{q>kQj|=2a zM=>F*l*_A=@i(jCFPZ4YWnzPWYS^yN@Zm(jBe}dTuk(s3$}n^o4fZaTAqOoE z$0(Y;&N&8e%f;LhF&5M*U2+7UZ`8`%TeQnARW4JK72931Jx9NX!nj&qM)J40)-BpxQ`O35FK{@;+?lYuY6Isyh zoMtfS*O_j|;}o8tU|`(DQ_xbl)}q~O2<6nc6;vR^W9TUFx?tFf7SR!(v zUGDdnq}*uK3z33`GZvAAhKrkZKFR%x=hT(-q9zl15k&?N2)4tYXgl+j>_WHsM`ME)C$qq0bZFffm1IK~OwX=XYMt9g## qE}f?-&Vbc`)3K(E;Su7*{5?FtLp�hV+sc!3#?HCH-+v;o@%vGxa3^ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleHashesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleHashesAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..65305c099cd93d3a9b9bccbdbe9f5fa31556e60f GIT binary patch literal 1700 zcmb_cT~8B16g^W4TgviP0Ywo}QQCs6=!?k`{Ae@~3qGK{PundW+|De!Qw@o~#9yI_ zMB;-#z#nD2)0R?eOK9+A=kDFTbI!Rl_x$?(<0pU|9wiaOfQ7h?K@2g>AMg*{@wwc0 ziaw8`vhY3Uxz?d5)U+2d*i}`k`Q9dvD&}=5oynhDvdx3Q3*96V7`BkKF#?-m<)HN5 z5mI}h*kdN|72}e)3Z4@W>s(6s9fA*tm*o3}f}a)wJ-PyofZZ zEUMt>P5De^{aa4?zE{*jNw?YRR*7p=Ubk@rb5vbv9?3+5)7f7Z<{2J$J0*U4uudlch%l)%Pm<}?uN_owEOY(=vN1xo7rQC=TwQfjOT^)c52mv7rx~M zpE9YuDsq31hr+x!lW|=UbV*<5|J(7Ch?&2Uj)GG(bs2SichhuZwa4`JXef2*wBYP^ zFueFD**6)6&wcgy;s9RM8a=u~7rt`sWemw(RSS#WD>5^N=}v!HHKW0h*zqF0smvtW zTT*&q&KRIExw-QU0c$jb2{7CwCrufa# literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleMainClassAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleMainClassAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..9d16cafeafb302adf3e301ff6ce460989b73abba GIT binary patch literal 1159 zcmb_b+iuf95IvKoapF3?K?~*5LO~)4mxUKzTvb95h)PLbO7jYvWLvg4>u9}3;&1o_ zkU$_F_y9f%F?ItKlu(Lz@XpS7X3p%)nJ-^IeFo6PH6I1ccqj&#MTxL}C|^nuNpm3j zkxY_(9Vzj^IjeiAQwd>V7!T4&wWT)A%z<#DR&V_=sx3z&WkVljR6O_r<`58W9S&Xy zZJe@3M#sSPa1@C>(~DCx_yJ5PZE2(3HlbGgE3|sIf_W@>SPZa)WkTyTc-O}Tw10i< zv3e@QpB=b8v7&x#5+{ut#c?F^UOhC1~=YWwODZwz7OcLv|d22LnYU3m51H8t~_o%+j-Olkjj~RfT!lP%rfD-4~ zwt5tRHC$kgL-WMM372qjoK~(~e$C!aDFc?<$n{Cq;io3#c%!Xrm-mdL% z(>~}p=3`NpUD3R!lxx?!iqA!a4cY8Ee5=DnMeIt3aY8_%*JS2}v(|Ges8p!A@tyy)4Jj_;Q!*X^k*Y>|7Vp8qd zl-JeEzz9Qb(8OVZa^rNP-4e%9n94KezS({Flm6qPZ2 zfiHDb4QybO;YPm&-L6pf0XM^RM}`>E^`32pr}2u};)!f?Gh|%1MAPBkTvf_;w^NE$ zFB)GlN+eh#ysmPu;o2P~-MC2E-!ySTq~p71mBg(NOwAL}7!@J78>r;e2facK4i_Dd z80P!AI3qS4HHPbFvr_58L|~D&mj;G+kf23HTb0Ia)?a49Njrw#3Ut>{giiMnED+~S zqWnO#B%Ra6U%-kBN6?G2M;I^O`V~`0n0`u63EZN;ITC{QCz9GOQCf=nlQWm(tf}8Jz7TkO{667k#z3^>@Bola#DB}qd0eKACh=_cBA5*mWJ|Je_ z(?vRcF}-+`q39(giFd+fvKh~EHyJeT-9K8nPb$e15SsiW9EMpc&Wbt literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModulePackagesAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModulePackagesAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..27e951c5c5365cd4abec62d767d11c496aa9f6b1 GIT binary patch literal 1452 zcmb_cU2oD*7=8{zT3Ch29CJGHYdT=lMiZ}CmKfqUOp_^>CWq4D*~)2CPEGg&>V?0- z-=K-c#S4FcKg#$P3fr)5l6cX+=REEEKJWL>U*CTKsNrS?3Cw6n8aRa%LvfeC;iki7 z$Fv;Y>+J}~Ht#9ri&miQ9z(Y4wgbn0&aFM(34zs8xqhrtgL|IsS2NI&){rqU3xi>O zx4mZyscc_z=Mb0ZdXD*0w%kCr$Gi-w4IzcvWGI#XiLKn6MHV>?a|X^JPks-443u!p zy67pgXt`eh+0KE*!MB?0IJTvPE2~jhW0h(eXR)B6U|9=#-yv|CPT93wuvlP7t-Dex-Hv(!CMX?`MPUyr^$U0-Xk!nUJGibM*Tk~l^iS_ zc%|J(ZmKo#E&!a$#ioP~Z2 zFpO-vJFe}!V#EHPH)POc7?}2ir)C)XO69cz@+g=Xv~UU*!`xPt+|3yd5nUx#=MGrvr&T`-<_n zsWA+$$|z{?`!x3`k=~(qL$@^@)g>OPc^N7b(+pF`84q*{JEM5yu9PZNf!j_L4fD7| zoSiAa=oT@+@FD#d^<7CrwWu!@ zvR$RMfom9`bw55rA4+5q`Xbi5D!+kMCZEHsO#O~`o@4A8S^H4d-;g8d-^dyNpkTbf zsPQi(?n(vCSRG{!^Jn@b#k<4 zKlMC5!KdVbQD&c|p6vJ?=&$?=^RO)XQ#W*`@HsiwS!BUuZv#%`{equa> rd_zwiZ_*A2n_-5&4N;s`k~ojsn8jT@BwLa8=i%U6(xrwatYG{lgP)oO literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleRequiresInfo.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleRequiresInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..08a5fc7e3c1868f5a477228a733781ac50a6d321 GIT binary patch literal 2587 zcmb_eTTdHD6#m8r){v#X;Ly_2&|Sw=iMj3T%e;!{(9WN-ccJJ*VOEAlP#~ z;kd^w&v_~9DwNH~TKjH2)M7qnY^rAHiRa?C(Dg-7m3xXIza)@d_rxdf^#om_;qLw5;<+x4@E;)NkT&nTLuyDgL-S6ggtK%xSDfEGAKI1+=7IY)YtsX+sm#nlY zQE_1ayxa4m%5XIqQx_(5PiYDi5^Lcbx_ zY1C0d|DSV9255ALw?v>fRG=+9V7PIa!9lmPGktR_O6frRycM-K$bd$1xiiKp9ilt& zx}12zWf?5`PSQ7@9mDDb*6_r_x{V*O!7$gm6@DnSdn}x&^07OH@p>l$hBwLPx$>1d z5>6zz!DZ7E!F)}rqp(#;G%_A<2~Mo|g0QChF)IV4t zx*W-)M3ngy+y3Z1QO0AcO&OnQED~)SU3!`#-)Y<+dNNHaAYl*_abP!*r){`I!X~WS zbQ(3Qe2S~UA4I0!i6pXY#gXJ`u{i_OXMo=?q&|mRvHCJOGihYXi>LVbEdA+7rdx;% zMg3Jf?ko5@wqyb_d5o6-gmqpPqp=zK1JTVQsXTdJ4n5^5d_z&03MQ5F7x5h7;|^it zZo6FH;$Hi_j|!c$)Vl~*5vuwzwM-H@N_2&^Gx!dV@I4-*O56g4lfixbh#5S^Cblv2 EA70C&-2eap literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleResolutionAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleResolutionAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..be760d9f596b286b627da8c4c797696275589f66 GIT binary patch literal 1048 zcmb_bO>YxH41G>E*<`zEN}z>OD1}yH6CqZdIHanCB2}!E6p2FalVlpEoyuyKv>_^e@wKQr{tNojdOvrn)(;YbqdU1j86IvL35g&1hI zG`itX=)QTN;K-xR) ze-0%$`(YXl{{Nwwm|%$alM{Gac9`~KxCfClck$YIVw-orc!gpCvNTKJ*R1HT)J zIPR-Z`j4zNs*_k56TD&6OG0@h%s^Vg-D<6MrpcZdjid=&6j5^EdRTx**gEOG@|CvI zXc10CQo~W`AL~w(=-#iWgu;%}%I*@X)xU~XYnM>LqJyQhtYt#;Jn=Ti3G7W&I+4uQ z)D*grj;+vk6h&Nt?LU01t$7nTxJY;~twZ8xQ~eon{OPsM2vlnm@{On`35zYI<$f~k zNOL4QAxkc_qOJ(r!l;xV3-k7+;(^u)j$iI z7|#3cxpLc?I+#E7IoJ*U$&BD0Mv3XlC%hqqmES?Toz9$4+?TO^8pXUSUQ=sn8tGQ0 zi?n_g%5b0YTLe#z&r*tE-qswy7jTL173P}E=a`o3pFyAC)bD*n`F*Cg%6A2G06m98 z2fT1EaG7PRrv|u!HRjkfb4={;Dz1&)`b>%c=Ib9&e#eg-n*oJXNXMBQ?^I#zCXe+@ X>pC_vdIL8zTEs1;F6*Y1+{W4u`B+KW literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundNestHostAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundNestHostAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..58ee6478df9ec862452cdef7a43ff7a4cdc20061 GIT binary patch literal 1110 zcmb_b+iuf95IvJ7apF2Hq_nhL%2jHT0t?TsDxs)ArO=nsyl;}F-QunzdtHg&;7dRP zfq38%5aOE^XD&@$2&!0A1X1QNoOavWE()gw;cNEJYyAz8D5F zj$i6PiO1GPdXQKZ6KY1q_E{KP!dk1{JJfYVPZyq7zx!4ZM5Aav|9hf*6!Cahj|AVJX}PRur&?e-8_JuJj*kI)DJl8 zEn}nCg!_e|3_}xJY3w)*1JO;(m$~~6E)hggspM&8MFHW%;)Ex$wEKi|HykO#d`}y- zlN=3H^g<2-wlsU;PzHS&=~T~+WqY8xrB8eRr9wXEIAJ0tg-odL>U|?^5^;=grix>u zum$H7)Zg@{enN0}!z3E2C%gxQ#lOe%LE2Paiqq~9ylrDtlr=wHm*q+GghxE3H4ql~ zYo?RR`&i=pEEf4(Vr`rC63a&C6X+wH&iV&5-eqo=`JBTHKwsg|H(smnSZ3SO$pft5 z3Tyl{111Kn;A##lSQ7uMbl#)!mMCW92ta1wd8+ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundNestMembersAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundNestMembersAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..56c3858575e332ca59105a632673ed3a4b222689 GIT binary patch literal 1403 zcmb_c+iuf95IvhFaV~BW5*jEiwe>vsSR+|3|{B@J;M2_zXd&dj%_;h5so zupHC(PqBzL*sa*v@>`6sk$D~lZR8VWitpvaI5YYZfJj3)Ob zWwhL0|M|%zWB9G%I*x5g?uvRuYaCKf<04ixlyzLfWrl-A7;HwAjwaHbW4GK5)qE^S zWTkLn$Z-O#;R?fpSu&fWgE3~OP9O7AVamX>86Hlh-JL0=o_YMk_^LfBr|E~WTqV0f zo>ydJWDB(c*cWKE?E#iQq4a@#OSnew99gi>(CBlX4RD=&NX`Yn}2B zJ?mrCORFOiOVf9%5plg;c zjx@v4J@1fPrnW1k%e%fbJ%+Mlx_vIC*=zgV@RtDHsMcB+dcM>ha%|*~K~_Od#UfOO zt>fN%jSFeILbuKk^1fqfZ$#JjMQ=pTklyBk%N>Slbtbl2XAyZ66ckllMu{OG=IBdq zX)W$aifGu*VE=F&G5prFEz2|{w?!kCHF9ZWaRo~XDnY%jG91jKU_F*}aK40RR2Cy` zV@d_f43DOjS05gXc5%pTn;!{X`mV|Fcq07v)KVI@@T4xJW80S23_9VdknW(d)1VfJ zt3S@L)?r9C?H+|Mw74+${C?MTU+Z0qkW$MwbgQGgJlMxzQoiHVH?La%yMB~kq zGbDX7nfScg1D&N|tB>U~?4ASX4b5;eS1qQ;pRFP26sI2gjNS~nw(Yxy`HU_HhNa0t zeGs%NLuSwP|Va9ga+Fb8-@gO&lqHF`?Hu#vq^cUA%`^f0u-*bgZ6%~M?Zj`CN+7O+b1JXx@hP}nCF*a>bCR*8IY8+T|&-Z95rTB{U4 zLRLnsYqUyXJ?7MC7yOf|e?$2TEfOJ7Isn<{kRS?@LPQXyehdpURBgWn?apy Lj{F1Jn^^t}`~jq- literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRecordAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRecordAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..5d470394461e020c4d2a8ddc847f6beb1adb7efe GIT binary patch literal 1383 zcmbVMZEq4m5Pp^d2iFr2EG@O-TeU!2FMg(JVlHZ%U`<-(qsehBb?dQrIqppQC;Tm% zXl(r85Aa7B=Z*s^MFah?H@kB?^UO0lGrxZS_zA$ku8IVf6eKmIkY=c!nIBEvHsz^q z+2&x-6E@eM`MxJQfzJmFX^&fu*JaqM)m#6){K|A)?lo0pkX4{+Scb;1bJqQ!3+Z!D zn)W3O(RXeAt?W2~?2hpWZcj+z?=#eDbD`DS%g7 z{<=5u82vLG+vb)p9NCO%jZKOtqZ8>qstrN@`)q zZ33xaond!Ydd<;W=vQ23PsFJ-{lMc4&!;@@&CK4kGh-Cfq3k)${U$>xPWvRZdYd6> zI9&qCw}j+JLBGSjH)h8sO|j)zrrkC@5uRgZ(tj_AB!#rV)BhuJ6jJ$bjB|H{b1)t2 z^+<;Vi=*P6@Md^J#zz)+!847-QqZJIj?Y|vsf5$=$zlI9)B1j$0< z0_;1K#`Xnnd_(CA>6UPpzB!U$YfxAPdA5#wq$>|?a32roMAk9JL)vTPf2i3Qqi)h} z6^~*}olfDMRO2g3pJ|hbfYPCoRU?3*lT-{a4E-^ZF^MhIBC9$Yk<4J5q)PT7?HyG9 E0HyVZ@Bjb+ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRecordComponentInfo.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRecordComponentInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..00149a8f013953e893a0277363046fecc3074ca3 GIT binary patch literal 2684 zcmcgtT~ixX7=F$sunAotjcrO1+p1KPKv~gRs~gca{UDk`EtCr#o!KM{ENsq+yCnLZQqWZFd8N9-fkz$Qp z=UWV4lBKhWR1aL3qDZ}^j9xWx4X={XZ9CYmiWbGPeuhSC%Es#kW^tVY=zQI^J#zo6 zv$K%M`)Xr{5@D4-*YPI9;&BDh&p}+JM~W%C=5BFYc72M%%_AwQBrFXotY4&+@{+Y= zG3>^*5ypAIcS0o|tMgReemz>H4XXYqW0Q54J1gCG!|~VchDYf0b*x4*Xh~HJ#yr>Xg#)l>QCx(vit4-6`G+^rNVci7`JS)E5d8Huy9D*zviB_^aKV;Ww`YMaVU3az^sX`-*g_(93}8ahvh`kUBo1srg@q3-xbrwCC;$Ap_~#ohZve233Y>HHxjlJhl4W7EChe^c$yNVR979 zW2oU19iJMg;}OHvL9hBQo=ZNwR z(b9BYD*p&pp4*3Bp5MoK`NmJk?W6FVo>G{n{{jg?`weOBcVx9cFrod4g7z0~&|5iD zfd!cKMan`5EW9ZYT6j}1Qh1B*20>6x=5!I z)5`~#2EM1O79tx}WbM}wNu*hik(|dh+&o773h>=f;j`e|N_#A+CY3OyRbk-H1OcV?wz^2_ndp~ojX5%e)|rfime0;ESQK`h+>gp?S!9l+u`ci zZaTc%J(7;FceVCp!`GtAu;Tej%eL54r?M*>j@VVo)m%$g(btVavGz}dXS~x9UL}DT z;wBOnlCT&yPg);rskHDEcg_*ZcE_<_sfO#T)+h;v#cipi-eD*dW@0PWlSmPb& z))|sNniMdD>_B3Yj|xG#XNMCot^>ovKb$jQGxX-F!*s~`&H;6DYOm)+VMrXfzSk5_ z==xw-njGP+;KVY-_C;4eb%O!4_LLG{HMnwuTc$k6gy24nVhjw+^kjo^B)dYln}Jn& zs6n_!c8xsm$Qoobr5@ND{)v`8BlnROMxSUga2jv>1Ot$0NH9o!1CdZf0mXh) S3FW?xVUuiv;se?Du>1=w(zBuf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleParameterAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleParameterAnnotationsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..3c0e913cfecd158d9f2e82e6be04d5e85295e330 GIT binary patch literal 1611 zcmcIkZEq4m5PtRwJ)kEbv}m=~H?%-&FD8DYY0_Y-jaZFUKAJ4Bty_;ha_pf^{85@{ zZ2aI4=#Mha!2uPCDJ14{H@kB?^UO0lGiSek`~*DX1-(d4n=wohIhjy(4MRb0mrjeuG?q%|}t$FYbd6FCc4aFu~i z!yq40dUb)Eo}(QTj%W#`DbMLX?@>4=t}#5DlzKk6MSDuP_<=l9T>GA2csz!;HF-Z? zK*Q1~Z_~q&4ex6dcd^D0sklwTNL8g0`+ln~yw{v6j3HBX8{DaJPX_x?8PV?~WuQ_0 z?-{3nbALu~(jG+dWSq%N841`gwkLK{X3$BaTruqarJMUkW80O!M?*Rt)Jr3H)Ow%ZVor;nThkSwD1&n2Eb*b>DaGS)%8`q7YM`jhE!5-GURe&q2((x zm_^b=%EDEo8D`rt`dT`6S++EJthvpzy`#Rz_P3JjIHDF%D~7asCdD|eVa`O>!gbtW zcs&V&<&e_L%hNf)I3^s?5K2>uQyt3vNKD*h*dCR2-mRTIK2m&N9xJYWPcS?gg4!6F z?TbxN+$=I=!n*W>%vTs9CAUsqlVz#IuHUE%?|@SiF{I0GjXM?Y$>1I;Bl?Xbx`*Ze znOTZ8dl8&EIt<|1Fo`kg2UKVH;8di$Q_;@{!_&W%WBO2pw5nm6wnIX0-TKc&g45+oEl<-QyS_(E%cPWh9*LY0h8Uw>TJ?UU% zN#3F@XkdXJDj05)TqMmQNrPmna1QnjW?}UlSH2?inRHWFqW3IG81G;j?~yb<;121s z9UI)mJ-U%~h;g6J7WwaJ7J8`5bb5e?A*M~Y;GbyW3o@VRV6=gz1Euk?4bX8C4FNi# buOJeV$RXdhDqyuOV^|}ZAp3y!Bh3E+tSrSI literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleAnnotationsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..86fea55198d55a22ee5d2e343048ed9181c8e433 GIT binary patch literal 1471 zcmcIkZEq4m5PtRw94{vzShQN}TeU!IFB<(s)7X&In$Vh9C4MqlU|Y8yd*s+N>A%vX z#>Nl+0DqKm?l_<#8u;Lcz1f|;nP;Avo%!+e+jjtUY^Gsg!9>hL90`V%6aJCg4p+x^ z+u{BGk#vN;qqQenz7~CkCC^t{c12V6Wy=veO1YYA=_oQb@J%P25p z!x()n9lIg>nmo4M-s#JuvB&VP?mCWW2h?g2t&vGBg)3MzQL=Cq*BF}fFj$Q!z4}`s zFK|r?M|6eKl-&G)>^KG!*BPEo%Qqj^%bo=zbtsP&*S;qh9#4R5P0#SC=(X({Louqu zIJ8QWAy#)gpeGUJL`o~!m9^kCYUUhnfn5dsQr?lVMMDCv>?eFG|vny)1uPg zCdn1jyd!Cl%vaCBzQU}opX1UO6hD)00k`OzB?)5}rtus(V-L4UR~p#h4(`&4tRswj zw71CrK(jnTU8UW9JcuxDItBm4t7j;FqKy#(B?6_<2muC8;t{|g^fkmH5@l3Et18w* PnZyRkG}#BVA7bejMcl1( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleParameterAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleParameterAnnotationsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..3fc521d26af01f9781729b74279c97c9d18b9b66 GIT binary patch literal 1597 zcmcIkQEw7K5dQWG9MBUGTC`fL)@p&)Ui6iwNrS02!D_7Xs99j4TaP_*?3wgmX`-?5 z!ABqbQN}qqpdwKrF_*j9o!gmjzS)`i{^QG602S;cVPL^T#6lD?hP6}vj@u4bZM)&{ zUaut`Vef10$-1vak73>Om6jb*lRa5?#B=WPj?lu}SIX5~OIOjM%|fyIM@LV2w=2AI z5^*Fo~%)($J zr1avi8NEO{E*#MjN>i3I1J>hUOk86)oR)Y#yg_>=u*9)!E3SP{Fg%(-+nv6jES*tV zl=tXi$c1+`j=ET5h*aDrVWg{4i6g&L7v4)w)y0slx()8sxF>^ssEp_nN&I>BKWCf5 z&Hsvj)*Z(1c#_9l`3Sf#b*J`FcGyGXOfek%rko3w;oD5P3qdCCcCMnLBAD8&^EqQk z9=pER5C=4;7?vl8#7@u*4Dln;(@)%>#jQi7gjWe>TQJTZ&fbG~Ks_G^!wS9Gpzldu zr)g?nm0m`(>;}m-(!3^Vkj#|M!9K$*ZJp!NC*(emZUHyxn<5FL1=DCFZJgj1>GA^` z+{QZX$U4NhLu-rt4>YSI)D2qQ#k~;Ird@C*TKb6Gds-NMpjeQVIzKmm=WRmOy+V`>Y6Ok6)iU0rr literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleTypeAnnotationsAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleTypeAnnotationsAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..c25b66607290f6299c252fa7e1153b5851f294c4 GIT binary patch literal 1511 zcmcIkTW=CU6#ixlESD7!ELv^rty-X$jW0$+)1<)|O|T}m@?ea~0Mj~knI+4tN&kTQ z;E&NnV`Gdzz#nBi3tMQBH1N=e*)wxy&-u=GF7xN_&))#5SWm*hjERVaC}IqY2mC#^ z9j^B6ro+44J?RL0OKVRyd@Z^R3!bmEY>T?=%7!C$4?AK@DOYnXT}AiH#Zv7|AJ2HF zBfLryaU@J6Eu>&EtRA%9*-~lYDejzrmhFyXzf=v^SFJ%946zNVq~2sG7AHb0)l*0# zVN<{S2GlAct$|4;flHV*QLu0sR~TMR z!(b_-^x~{!p5Pl7j%W*|DZ$x3;b9ymt};9tmveqxH+xc?#E#roT>GA2xIY54F*ehu z8=$gTVaSIy8HQM@GeoLxi@auPQi*N9-4Na`rv_rk)!Zg`>fDpTIaEgUTS;VJ*Um4i z6lvi!H1%=_|8SJTgyaLFDSmPua>w&9%m%}Q|CAH@XZST$M#j6HwlAovV{1RPABN

w8V{n4T4e+0nsX54xBkzAd`?i5rZi^;9Y0RfDG}czxEUnj74s5siakj#e%hQ!P0H1Dtc1#*jO|VoTY|T%wKVN?WzsFFk7W^FGC3>Y;beyi%6nMg z_cZSEJjjpz)(Pl4oYsqPsC~)I7WkgQ6yHDK;1nKy;vQ=Y7Ynm!X*{Hy7K$*XR^DK;)y-TAoMLfu?9^z3Zm+&}~6+B_-vTa()Q`G+e D%^y9q literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceDebugExtensionAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceDebugExtensionAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..3d5ad75f6182c264441a78a31677f31fb32d4846 GIT binary patch literal 1064 zcmb_bOK;Oa5dOwZVkdQ48rnj6l&6Ff5Ef@wl}G?lDO5s%Tyk0`OW5MBBYTbbO`Jdi zfjIC3_(8w{A;wNX6^bAg9K5qLp84jn-+cQ1;Ujx5w5D8$bx`hNi|dxLhfPbhWbktD2km6rS2VJMSF zB8=G5=*B}4^+lp`eP%3~r;1DHb^m*d0hi)62W>*Nr^Z^CEa4(v9xKt#-1k~=B*AX* zPvL~xbmaG#&4i8LiFGr7E`qZ!Q*%E~4Z+>hS|*)*19H+Y#01=8t~nr_$4>OS8lyQ{S{v<MDdAkNm8uKR^&Q>Ex%Zs;c75>`KpjgqGRRuUImn~HFxTTJ-1WIS za63K^!+q%s_mwePwj(1#20IKQ-4UH!YIZpjK@PgVtDhAe#-*@ySH=R zfwGzkpcAOjaAo>IK={r6#{AQtUY8N+s&LM58Erwh@=n@}eO{v6A zblettkGErn9yfyy_gh@c*dJWx%%LPI8_oZ;7ms0Wh!TciW+?5-1I10G3FL8>%Ab<3NjgW7rSlRNuHfK1rpTN8m4IiMCXZ5M z{Zlzcc4ko4O?)6<`;78O3d&F#P@rqzM^eT~{_}$}IXq9IX7M7ibC^$T5esB(ij5~( G#Pm<~q(CqL literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceIDAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceIDAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..909bc5cb2501c5edec346bfbdbded7dee2fe4a89 GIT binary patch literal 1105 zcmb_b&2G~`5dJ1j;>2}Y2(+~PlwXM?psu(fxvGRhfk>g3(%d)kwrp|Nk-bLZHFy$` zKp+l001pBjcm~AS38+F&MI;X1*%^N`-^}dHm!F?L1L)$WixL(bls!~XC2SnYmr{h% z9EwpWljJ~$N<6SO*2C1QgiuSOG#;s5K)Bs%_fLgCmE*CBeHS&<9k?DA;Sug01uuj) zR>ek!Cs_3HI28M47^Noo!$_!ZX`}5nq1E~)w)UWoB`iBQG>G4p-&*U&&d2@#(jA|$Ib#}TWK5{<=|dxJ8gq)T z=SpL%u>YsD)8F>zb|JWvXL-acKv?;EGB>j)<$c&yiG30!mf-b_QE@k0n`~3oW{nc= z@qpGqILBWz8&Y1y65kiG!sjY$J=RMs8=a4!4{$nn-lOq0hh5-v2@3#yg+t$XqrPK} zZL1Rptm7hU?3xEA4p_mZX;{IM_+O>-4vjZ_DIp72&5ZOT593V$(=cUR&QVvek;|*N RmdhHhvve7oRdNICzW~_pJiPz_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundStackMapTableAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute$UnboundStackMapTableAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..4fb1e029b50a20ade29e7166cd252966731d5150 GIT binary patch literal 1423 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute.class b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute.class new file mode 100644 index 0000000000000000000000000000000000000000..b936016e1a918e66d079c36ab7206efb832ba171 GIT binary patch literal 9124 zcmbtZ`+pSG75`omvLQsUh$y}hPzXX4>_dXIkOT=5h)IkH_?X?DBm=uM>+WoLXc4JW zixw3vwbW8eEw$8ArTD;B`+nK?`~80RkLai0yE8lY&So}jCO;(Kojdn_&$;KGbMCo! z-umC`Zvtq?f15A~bqUlrV=@{97Hvy!Z?$aK%-cq$HI*?6g+VK0wp!U-rgc@a;O32# z+nF)5rtJzetgvj$T`5qvVBx?NG-65uP0g5!W`S$QV!G8%Iz>CZ%60Qrvgn$m${M+x znHQM9ew#63v}O!@NRuD*>@Ia{n~G_ep1`@ycpGL2%&lRJK)r2bDQf0|g_?{$s$dV5 z2xm6qe9RJ% zM$VNZ=hZZyHI|tv4{XF$0y6^Tx5%Zqaem>B1QrOKtCr6*UlUreD1mF5u^3B2@4e-s zzYIG0tU({VK{u1Xm|G&&Lu>MTC2+04rAo9~*g#EzDSg(EZMele9j8U(i0JIO=8FFQ zwv}xH3v|7z_U0neFWb2^0@K%9wz;90O`7?BBbi~#jP*{+$P5^HOFsLJ_3p4$p#9g6 zwRDvMMuldD$#&(+gv-XoRG#1Bn&#*AmXn-rl!M)~lfc!XIIM0W=91camQ_0^5VfHc z@QG49_d8W%N(Hjiv@Tg36u3Ncu~kojWwgK;*>ZGDmlivbEC=|t;~g%rv?h@%&`T0q zYmuXk@$%hSXBNr}B|+EKASgVlMkDHpq$H^p(}e~JG`dbXckEu#zkGS*@&YG4>GnbvSsn03qQ|21(ssiU%#_1B7js&J|Fbi(CDN{iqfj)tbu{^DkWL{@B z=k8kVIBtRabuO4x0=EjZjf-hjdaaYv2yPQ-9~XhITep)gX4ICN!0iI7$3@i7gw%AVuw}eFzCx02m2Eq&;aZNJz#RfNjY}V&r`Jq5`Lt5X9&{48OJGeL zGS5oA<~>E$1BI><7rmh~K37lP8L`r)N0o|cD^IPBIn(xd=(yusyO0yCH44KX&(L`N zI>ghtGw0-8kI9O;dR{i_G4k9eSjTx}+XcGfSbWs}>d|FmE?|hxqv8%0%kZkO@ObWt z$$WnbDj>x7SWMMq z<+j!-xSDED2&|2xnpOmAY){5q;2txdwOrRs_Z5?+`qb33%7+BH?8-A7}_o=4YhSaxYE)Mos#2`Sib%;?_oxtI!e?o63E8M?Zkd_HDn7u=RJ z*Dl)~HeE|Ue|{n6Bs=!ASlM1a z>~Y>9Ds^~M+C?131TOK1jVjON2}CIvdhNX`->s-pDcr7>#cMCyAzTP~?^=B=YCUZ5 zLOwj=EQbePxrO@&1$2!iV2nR zDvARoTm`MR*{k)5-n>)MlngBQ_^BrRdG3 zeh$C3P69vR@o%R5;!3=ZpL8c-DW>rEWGv(F>)DbdP9iq7yb95>=w&2c;!_>o&i~Vh zfQfnxa?}vs!KYbXZ@d%l;uFXD>^FqoEf3x;4J5bm*9zR|%U#7M!CsSFP9yOme|RDr zN{!n~qNLL7;ER$1REregO=u;1y&E(5UruKYQI2Yov}bURKqYrh<8B(oEn6hFzY>}3q?0e=0Y~<4<^xziaAVaSg{q&|y*o>{X6L&NC(rh2bHe_HUhdf+* z(oXE=YVW~b?8Ae!-NQJ5M{y93;}D+0VLXi^cm_xDERNwh9LMuGffsO+o_-3a@d{zNbAmmNv*$66ILeVn$Z(iUhsb!4%m*l8KPBy>#66U}n;MKzlL2bmi&q&8 zhf2CP;x)`>TO-cYPvP4}yw2xM#4i#z6Td{NOC-F_<-NY{wlf)J z4impl+(!HcF+=<&(I$S2m?M6hm?wUR=n}t693j3%+)4Z%aX0b%#QTUpAnqalkhqul zBjP^dkBJWwe?r_({3-Ea;?IZ&h(9MjO8f=!An}*P$BDlp9wPpl_!RLs#KXkj5}zji zj(CLld*U<1KM;=+|44k6_$T5q;-87n5&uFwPW&tJdE(!QCy0M1zCip3@g(t|#21PG PBAz1tn|PY|AI$zg#}tBn literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute.java b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute.java new file mode 100644 index 00000000..70b58e42 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/UnboundAttribute.java @@ -0,0 +1,937 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.AnnotationValue; +import java.lang.classfile.Attribute; +import java.lang.classfile.AttributeMapper; +import java.lang.classfile.Attributes; +import java.lang.classfile.BootstrapMethodEntry; +import java.lang.classfile.BufWriter; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.Label; +import java.lang.classfile.TypeAnnotation; +import java.lang.classfile.attribute.AnnotationDefaultAttribute; +import java.lang.classfile.attribute.BootstrapMethodsAttribute; +import java.lang.classfile.attribute.CharacterRangeInfo; +import java.lang.classfile.attribute.CharacterRangeTableAttribute; +import java.lang.classfile.attribute.CompilationIDAttribute; +import java.lang.classfile.attribute.ConstantValueAttribute; +import java.lang.classfile.attribute.DeprecatedAttribute; +import java.lang.classfile.attribute.EnclosingMethodAttribute; +import java.lang.classfile.attribute.ExceptionsAttribute; +import java.lang.classfile.attribute.InnerClassInfo; +import java.lang.classfile.attribute.InnerClassesAttribute; +import java.lang.classfile.attribute.LineNumberInfo; +import java.lang.classfile.attribute.LineNumberTableAttribute; +import java.lang.classfile.attribute.LocalVariableInfo; +import java.lang.classfile.attribute.LocalVariableTableAttribute; +import java.lang.classfile.attribute.LocalVariableTypeInfo; +import java.lang.classfile.attribute.LocalVariableTypeTableAttribute; +import java.lang.classfile.attribute.MethodParameterInfo; +import java.lang.classfile.attribute.MethodParametersAttribute; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.classfile.attribute.ModuleExportInfo; +import java.lang.classfile.attribute.ModuleHashInfo; +import java.lang.classfile.attribute.ModuleHashesAttribute; +import java.lang.classfile.attribute.ModuleMainClassAttribute; +import java.lang.classfile.attribute.ModuleOpenInfo; +import java.lang.classfile.attribute.ModulePackagesAttribute; +import java.lang.classfile.attribute.ModuleProvideInfo; +import java.lang.classfile.attribute.ModuleRequireInfo; +import java.lang.classfile.attribute.ModuleResolutionAttribute; +import java.lang.classfile.attribute.ModuleTargetAttribute; +import java.lang.classfile.attribute.NestHostAttribute; +import java.lang.classfile.attribute.NestMembersAttribute; +import java.lang.classfile.attribute.PermittedSubclassesAttribute; +import java.lang.classfile.attribute.RecordAttribute; +import java.lang.classfile.attribute.RecordComponentInfo; +import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; +import java.lang.classfile.attribute.SignatureAttribute; +import java.lang.classfile.attribute.SourceDebugExtensionAttribute; +import java.lang.classfile.attribute.SourceFileAttribute; +import java.lang.classfile.attribute.SourceIDAttribute; +import java.lang.classfile.attribute.StackMapTableAttribute; +import java.lang.classfile.attribute.StackMapFrameInfo; +import java.lang.classfile.attribute.SyntheticAttribute; +import java.lang.classfile.constantpool.ConstantValueEntry; +import java.lang.classfile.constantpool.ModuleEntry; +import java.lang.classfile.constantpool.NameAndTypeEntry; +import java.lang.classfile.constantpool.PackageEntry; +import java.lang.classfile.constantpool.Utf8Entry; + +public abstract sealed class UnboundAttribute> + extends AbstractElement + implements Attribute { + protected final AttributeMapper mapper; + + public UnboundAttribute(AttributeMapper mapper) { + this.mapper = mapper; + } + + @Override + public AttributeMapper attributeMapper() { + return mapper; + } + + @Override + public String attributeName() { + return mapper.name(); + } + + @Override + @SuppressWarnings("unchecked") + public void writeTo(BufWriter buf) { + mapper.writeAttribute(buf, (T) this); + } + + @Override + public void writeTo(DirectClassBuilder builder) { + builder.writeAttribute(this); + } + + @Override + public void writeTo(DirectCodeBuilder builder) { + builder.writeAttribute(this); + } + + @Override + public void writeTo(DirectMethodBuilder builder) { + builder.writeAttribute(this); + } + + @Override + public void writeTo(DirectFieldBuilder builder) { + builder.writeAttribute(this); + } + + @Override + public String toString() { + return String.format("Attribute[name=%s]", mapper.name()); + } + public static final class UnboundConstantValueAttribute + extends UnboundAttribute + implements ConstantValueAttribute { + + private final ConstantValueEntry entry; + + public UnboundConstantValueAttribute(ConstantValueEntry entry) { + super(Attributes.constantValue()); + this.entry = entry; + } + + @Override + public ConstantValueEntry constant() { + return entry; + } + + } + + public static final class UnboundDeprecatedAttribute + extends UnboundAttribute + implements DeprecatedAttribute { + public UnboundDeprecatedAttribute() { + super(Attributes.deprecated()); + } + } + + public static final class UnboundSyntheticAttribute + extends UnboundAttribute + implements SyntheticAttribute { + public UnboundSyntheticAttribute() { + super(Attributes.synthetic()); + } + } + + public static final class UnboundSignatureAttribute + extends UnboundAttribute + implements SignatureAttribute { + private final Utf8Entry signature; + + public UnboundSignatureAttribute(Utf8Entry signature) { + super(Attributes.signature()); + this.signature = signature; + } + + @Override + public Utf8Entry signature() { + return signature; + } + } + + public static final class UnboundExceptionsAttribute + extends UnboundAttribute + implements ExceptionsAttribute { + private final List exceptions; + + public UnboundExceptionsAttribute(List exceptions) { + super(Attributes.exceptions()); + this.exceptions = List.copyOf(exceptions); + } + + @Override + public List exceptions() { + return exceptions; + } + } + + public static final class UnboundAnnotationDefaultAttribute + extends UnboundAttribute + implements AnnotationDefaultAttribute { + private final AnnotationValue annotationDefault; + + public UnboundAnnotationDefaultAttribute(AnnotationValue annotationDefault) { + super(Attributes.annotationDefault()); + this.annotationDefault = annotationDefault; + } + + @Override + public AnnotationValue defaultValue() { + return annotationDefault; + } + } + + public static final class UnboundSourceFileAttribute extends UnboundAttribute + implements SourceFileAttribute { + private final Utf8Entry sourceFile; + + public UnboundSourceFileAttribute(Utf8Entry sourceFile) { + super(Attributes.sourceFile()); + this.sourceFile = sourceFile; + } + + @Override + public Utf8Entry sourceFile() { + return sourceFile; + } + + } + + public static final class UnboundStackMapTableAttribute extends UnboundAttribute + implements StackMapTableAttribute { + private final List entries; + + public UnboundStackMapTableAttribute(List entries) { + super(Attributes.stackMapTable()); + this.entries = List.copyOf(entries); + } + + @Override + public List entries() { + return entries; + } + } + + public static final class UnboundInnerClassesAttribute + extends UnboundAttribute + implements InnerClassesAttribute { + private final List innerClasses; + + public UnboundInnerClassesAttribute(List innerClasses) { + super(Attributes.innerClasses()); + this.innerClasses = List.copyOf(innerClasses); + } + + @Override + public List classes() { + return innerClasses; + } + } + + public static final class UnboundRecordAttribute + extends UnboundAttribute + implements RecordAttribute { + private final List components; + + public UnboundRecordAttribute(List components) { + super(Attributes.record()); + this.components = List.copyOf(components); + } + + @Override + public List components() { + return components; + } + } + + public static final class UnboundEnclosingMethodAttribute + extends UnboundAttribute + implements EnclosingMethodAttribute { + private final ClassEntry classEntry; + private final NameAndTypeEntry method; + + public UnboundEnclosingMethodAttribute(ClassEntry classEntry, NameAndTypeEntry method) { + super(Attributes.enclosingMethod()); + this.classEntry = classEntry; + this.method = method; + } + + @Override + public ClassEntry enclosingClass() { + return classEntry; + } + + @Override + public Optional enclosingMethod() { + return Optional.ofNullable(method); + } + } + + public static final class UnboundMethodParametersAttribute + extends UnboundAttribute + implements MethodParametersAttribute { + private final List parameters; + + public UnboundMethodParametersAttribute(List parameters) { + super(Attributes.methodParameters()); + this.parameters = List.copyOf(parameters); + } + + @Override + public List parameters() { + return parameters; + } + } + + public static final class UnboundModuleTargetAttribute + extends UnboundAttribute + implements ModuleTargetAttribute { + final Utf8Entry moduleTarget; + + public UnboundModuleTargetAttribute(Utf8Entry moduleTarget) { + super(Attributes.moduleTarget()); + this.moduleTarget = moduleTarget; + } + + @Override + public Utf8Entry targetPlatform() { + return moduleTarget; + } + } + + public static final class UnboundModuleMainClassAttribute + extends UnboundAttribute + implements ModuleMainClassAttribute { + final ClassEntry mainClass; + + public UnboundModuleMainClassAttribute(ClassEntry mainClass) { + super(Attributes.moduleMainClass()); + this.mainClass = mainClass; + } + + @Override + public ClassEntry mainClass() { + return mainClass; + } + } + + public static final class UnboundModuleHashesAttribute + extends UnboundAttribute + implements ModuleHashesAttribute { + private final Utf8Entry algorithm; + private final List hashes; + + public UnboundModuleHashesAttribute(Utf8Entry algorithm, List hashes) { + super(Attributes.moduleHashes()); + this.algorithm = algorithm; + this.hashes = List.copyOf(hashes); + } + + @Override + public Utf8Entry algorithm() { + return algorithm; + } + + @Override + public List hashes() { + return hashes; + } + } + + public static final class UnboundModulePackagesAttribute + extends UnboundAttribute + implements ModulePackagesAttribute { + private final Collection packages; + + public UnboundModulePackagesAttribute(Collection packages) { + super(Attributes.modulePackages()); + this.packages = List.copyOf(packages); + } + + @Override + public List packages() { + return List.copyOf(packages); + } + } + + public static final class UnboundModuleResolutionAttribute + extends UnboundAttribute + implements ModuleResolutionAttribute { + private final int resolutionFlags; + + public UnboundModuleResolutionAttribute(int flags) { + super(Attributes.moduleResolution()); + resolutionFlags = flags; + } + + @Override + public int resolutionFlags() { + return resolutionFlags; + } + } + + public static final class UnboundPermittedSubclassesAttribute + extends UnboundAttribute + implements PermittedSubclassesAttribute { + private final List permittedSubclasses; + + public UnboundPermittedSubclassesAttribute(List permittedSubclasses) { + super(Attributes.permittedSubclasses()); + this.permittedSubclasses = List.copyOf(permittedSubclasses); + } + + @Override + public List permittedSubclasses() { + return permittedSubclasses; + } + } + + public static final class UnboundNestMembersAttribute + extends UnboundAttribute + implements NestMembersAttribute { + private final List memberEntries; + + public UnboundNestMembersAttribute(List memberEntries) { + super(Attributes.nestMembers()); + this.memberEntries = List.copyOf(memberEntries); + } + + @Override + public List nestMembers() { + return memberEntries; + } + } + + public static final class UnboundNestHostAttribute + extends UnboundAttribute + implements NestHostAttribute { + private final ClassEntry hostEntry; + + public UnboundNestHostAttribute(ClassEntry hostEntry) { + super(Attributes.nestHost()); + this.hostEntry = hostEntry; + } + + @Override + public ClassEntry nestHost() { + return hostEntry; + } + } + + public static final class UnboundCompilationIDAttribute + extends UnboundAttribute + implements CompilationIDAttribute { + private final Utf8Entry idEntry; + + public UnboundCompilationIDAttribute(Utf8Entry idEntry) { + super(Attributes.compilationId()); + this.idEntry = idEntry; + } + + @Override + public Utf8Entry compilationId() { + return idEntry; + } + } + + public static final class UnboundSourceIDAttribute + extends UnboundAttribute + implements SourceIDAttribute { + private final Utf8Entry idEntry; + + public UnboundSourceIDAttribute(Utf8Entry idEntry) { + super(Attributes.sourceId()); + this.idEntry = idEntry; + } + + @Override + public Utf8Entry sourceId() { + return idEntry; + } + } + + public static final class UnboundSourceDebugExtensionAttribute + extends UnboundAttribute + implements SourceDebugExtensionAttribute { + private final byte[] contents; + + public UnboundSourceDebugExtensionAttribute(byte[] contents) { + super(Attributes.sourceDebugExtension()); + this.contents = contents; + } + + @Override + public byte[] contents() { + return contents; + } + } + + public static final class UnboundCharacterRangeTableAttribute + extends UnboundAttribute + implements CharacterRangeTableAttribute { + private final List ranges; + + public UnboundCharacterRangeTableAttribute(List ranges) { + super(Attributes.characterRangeTable()); + this.ranges = List.copyOf(ranges); + } + + @Override + public List characterRangeTable() { + return ranges; + } + } + + public static final class UnboundLineNumberTableAttribute + extends UnboundAttribute + implements LineNumberTableAttribute { + private final List lines; + + public UnboundLineNumberTableAttribute(List lines) { + super(Attributes.lineNumberTable()); + this.lines = List.copyOf(lines); + } + + @Override + public List lineNumbers() { + return lines; + } + } + + public static final class UnboundLocalVariableTableAttribute + extends UnboundAttribute + implements LocalVariableTableAttribute { + private final List locals; + + public UnboundLocalVariableTableAttribute(List locals) { + super(Attributes.localVariableTable()); + this.locals = List.copyOf(locals); + } + + @Override + public List localVariables() { + return locals; + } + } + + public static final class UnboundLocalVariableTypeTableAttribute + extends UnboundAttribute + implements LocalVariableTypeTableAttribute { + private final List locals; + + public UnboundLocalVariableTypeTableAttribute(List locals) { + super(Attributes.localVariableTypeTable()); + this.locals = List.copyOf(locals); + } + + @Override + public List localVariableTypes() { + return locals; + } + } + + public static final class UnboundRuntimeVisibleAnnotationsAttribute + extends UnboundAttribute + implements RuntimeVisibleAnnotationsAttribute { + private final List elements; + + public UnboundRuntimeVisibleAnnotationsAttribute(List elements) { + super(Attributes.runtimeVisibleAnnotations()); + this.elements = List.copyOf(elements); + } + + @Override + public List annotations() { + return elements; + } + } + + public static final class UnboundRuntimeInvisibleAnnotationsAttribute + extends UnboundAttribute + implements RuntimeInvisibleAnnotationsAttribute { + private final List elements; + + public UnboundRuntimeInvisibleAnnotationsAttribute(List elements) { + super(Attributes.runtimeInvisibleAnnotations()); + this.elements = List.copyOf(elements); + } + + @Override + public List annotations() { + return elements; + } + } + + public static final class UnboundRuntimeVisibleParameterAnnotationsAttribute + extends UnboundAttribute + implements RuntimeVisibleParameterAnnotationsAttribute { + private final List> elements; + + public UnboundRuntimeVisibleParameterAnnotationsAttribute(List> elements) { + super(Attributes.runtimeVisibleParameterAnnotations()); + this.elements = List.copyOf(elements); + } + + @Override + public List> parameterAnnotations() { + return elements; + } + } + + public static final class UnboundRuntimeInvisibleParameterAnnotationsAttribute + extends UnboundAttribute + implements RuntimeInvisibleParameterAnnotationsAttribute { + private final List> elements; + + public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List> elements) { + super(Attributes.runtimeInvisibleParameterAnnotations()); + this.elements = List.copyOf(elements); + } + + @Override + public List> parameterAnnotations() { + return elements; + } + } + + public static final class UnboundRuntimeVisibleTypeAnnotationsAttribute + extends UnboundAttribute + implements RuntimeVisibleTypeAnnotationsAttribute { + private final List elements; + + public UnboundRuntimeVisibleTypeAnnotationsAttribute(List elements) { + super(Attributes.runtimeVisibleTypeAnnotations()); + this.elements = List.copyOf(elements); + } + + @Override + public List annotations() { + return elements; + } + } + + public static final class UnboundRuntimeInvisibleTypeAnnotationsAttribute + extends UnboundAttribute + implements RuntimeInvisibleTypeAnnotationsAttribute { + private final List elements; + + public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List elements) { + super(Attributes.runtimeInvisibleTypeAnnotations()); + this.elements = List.copyOf(elements); + } + + @Override + public List annotations() { + return elements; + } + } + + public record UnboundCharacterRangeInfo(int startPc, int endPc, + int characterRangeStart, + int characterRangeEnd, + int flags) + implements CharacterRangeInfo { } + + public record UnboundInnerClassInfo(ClassEntry innerClass, + Optional outerClass, + Optional innerName, + int flagsMask) + implements InnerClassInfo {} + + public record UnboundLineNumberInfo(int startPc, int lineNumber) + implements LineNumberInfo { } + + public record UnboundLocalVariableInfo(int startPc, int length, + Utf8Entry name, + Utf8Entry type, + int slot) + implements LocalVariableInfo { } + + public record UnboundLocalVariableTypeInfo(int startPc, int length, + Utf8Entry name, + Utf8Entry signature, + int slot) + implements LocalVariableTypeInfo { } + + public record UnboundMethodParameterInfo(Optional name, int flagsMask) + implements MethodParameterInfo {} + + public record UnboundModuleExportInfo(PackageEntry exportedPackage, + int exportsFlagsMask, + List exportsTo) + implements ModuleExportInfo { + public UnboundModuleExportInfo(PackageEntry exportedPackage, int exportsFlagsMask, + List exportsTo) { + this.exportedPackage = exportedPackage; + this.exportsFlagsMask = exportsFlagsMask; + this.exportsTo = List.copyOf(exportsTo); + } + } + + public record UnboundModuleHashInfo(ModuleEntry moduleName, + byte[] hash) implements ModuleHashInfo { } + + public record UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask, + List opensTo) + implements ModuleOpenInfo { + public UnboundModuleOpenInfo(PackageEntry openedPackage, int opensFlagsMask, + List opensTo) { + this.openedPackage = openedPackage; + this.opensFlagsMask = opensFlagsMask; + this.opensTo = List.copyOf(opensTo); + } + } + + public record UnboundModuleProvideInfo(ClassEntry provides, + List providesWith) + implements ModuleProvideInfo { + public UnboundModuleProvideInfo(ClassEntry provides, List providesWith) { + this.provides = provides; + this.providesWith = List.copyOf(providesWith); + } + } + + public record UnboundModuleRequiresInfo(ModuleEntry requires, int requiresFlagsMask, + Optional requiresVersion) + implements ModuleRequireInfo {} + + public record UnboundRecordComponentInfo(Utf8Entry name, + Utf8Entry descriptor, + List> attributes) + implements RecordComponentInfo { + public UnboundRecordComponentInfo(Utf8Entry name, Utf8Entry descriptor, List> attributes) { + this.name = name; + this.descriptor = descriptor; + this.attributes = List.copyOf(attributes); + } + } + + public record UnboundTypeAnnotation(TargetInfo targetInfo, + List targetPath, + Utf8Entry className, + List elements) implements TypeAnnotation { + + public UnboundTypeAnnotation(TargetInfo targetInfo, List targetPath, + Utf8Entry className, List elements) { + this.targetInfo = targetInfo; + this.targetPath = List.copyOf(targetPath); + this.className = className; + this.elements = List.copyOf(elements); + } + + private int labelToBci(LabelContext lr, Label label) { + //helper method to avoid NPE + if (lr == null) throw new IllegalArgumentException("Illegal targetType '%s' in TypeAnnotation outside of Code attribute".formatted(targetInfo.targetType())); + return lr.labelToBci(label); + } + + @Override + public void writeTo(BufWriter buf) { + LabelContext lr = ((BufWriterImpl) buf).labelContext(); + // target_type + buf.writeU1(targetInfo.targetType().targetTypeValue()); + + // target_info + switch (targetInfo) { + case TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex()); + case SupertypeTarget st -> buf.writeU2(st.supertypeIndex()); + case TypeParameterBoundTarget tpbt -> { + buf.writeU1(tpbt.typeParameterIndex()); + buf.writeU1(tpbt.boundIndex()); + } + case EmptyTarget et -> { + // nothing to write + } + case FormalParameterTarget fpt -> buf.writeU1(fpt.formalParameterIndex()); + case ThrowsTarget tt -> buf.writeU2(tt.throwsTargetIndex()); + case LocalVarTarget lvt -> { + buf.writeU2(lvt.table().size()); + for (var e : lvt.table()) { + int startPc = labelToBci(lr, e.startLabel()); + buf.writeU2(startPc); + buf.writeU2(labelToBci(lr, e.endLabel()) - startPc); + buf.writeU2(e.index()); + } + } + case CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex()); + case OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target())); + case TypeArgumentTarget tat -> { + buf.writeU2(labelToBci(lr, tat.target())); + buf.writeU1(tat.typeArgumentIndex()); + } + } + + // target_path + buf.writeU1(targetPath().size()); + for (TypePathComponent component : targetPath()) { + buf.writeU1(component.typePathKind().tag()); + buf.writeU1(component.typeArgumentIndex()); + } + + // type_index + buf.writeIndex(className); + + // element_value_pairs + buf.writeU2(elements.size()); + for (AnnotationElement pair : elements()) { + buf.writeIndex(pair.name()); + pair.value().writeTo(buf); + } + } + } + + public record TypePathComponentImpl(TypeAnnotation.TypePathComponent.Kind typePathKind, int typeArgumentIndex) + implements TypeAnnotation.TypePathComponent {} + + public static final class UnboundModuleAttribute extends UnboundAttribute implements ModuleAttribute { + private final ModuleEntry moduleName; + private final int moduleFlags; + private final Utf8Entry moduleVersion; + private final List requires; + private final List exports; + private final List opens; + private final List uses; + private final List provides; + + public UnboundModuleAttribute(ModuleEntry moduleName, + int moduleFlags, + Utf8Entry moduleVersion, + Collection requires, + Collection exports, + Collection opens, + Collection uses, + Collection provides) + { + super(Attributes.module()); + this.moduleName = moduleName; + this.moduleFlags = moduleFlags; + this.moduleVersion = moduleVersion; + this.requires = List.copyOf(requires); + this.exports = List.copyOf(exports); + this.opens = List.copyOf(opens); + this.uses = List.copyOf(uses); + this.provides = List.copyOf(provides); + } + + @Override + public ModuleEntry moduleName() { + return moduleName; + } + + @Override + public int moduleFlagsMask() { + return moduleFlags; + } + + @Override + public Optional moduleVersion() { + return Optional.ofNullable(moduleVersion); + } + + @Override + public List requires() { + return requires; + } + + @Override + public List exports() { + return exports; + } + + @Override + public List opens() { + return opens; + } + + @Override + public List uses() { + return uses; + } + + @Override + public List provides() { + return provides; + } + } + + public abstract static non-sealed class AdHocAttribute> + extends UnboundAttribute { + + public AdHocAttribute(AttributeMapper mapper) { + super(mapper); + } + + public abstract void writeBody(BufWriter b); + + @Override + public void writeTo(BufWriter b) { + b.writeIndex(b.constantPool().utf8Entry(mapper.name())); + b.writeInt(0); + int start = b.size(); + writeBody(b); + int written = b.size() - start; + b.patchInt(start - 4, 4, written); + } + } + + public static final class EmptyBootstrapAttribute + extends UnboundAttribute + implements BootstrapMethodsAttribute { + public EmptyBootstrapAttribute() { + super(Attributes.bootstrapMethods()); + } + + @Override + public int bootstrapMethodsSize() { + return 0; + } + + @Override + public List bootstrapMethods() { + return List.of(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/Util$1.class b/tests/test_data/std/jdk/internal/classfile/impl/Util$1.class new file mode 100644 index 0000000000000000000000000000000000000000..e6f155effc39f191844e0a138d14fb09beef686b GIT binary patch literal 1083 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/Util.java b/tests/test_data/std/jdk/internal/classfile/impl/Util.java new file mode 100644 index 00000000..0e969272 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/Util.java @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl; + +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.AbstractList; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; + +import java.lang.classfile.Attribute; +import java.lang.classfile.AttributeMapper; +import java.lang.classfile.Attributes; +import java.lang.classfile.BufWriter; +import java.lang.classfile.ClassFile; +import java.lang.classfile.Opcode; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ModuleEntry; +import java.lang.classfile.constantpool.NameAndTypeEntry; +import java.lang.constant.ModuleDesc; +import java.lang.reflect.AccessFlag; +import jdk.internal.access.SharedSecrets; + +import static java.lang.classfile.ClassFile.ACC_STATIC; +import java.lang.classfile.attribute.CodeAttribute; +import java.lang.classfile.components.ClassPrinter; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.nio.ByteBuffer; +import java.util.function.Consumer; + +/** + * Helper to create and manipulate type descriptors, where type descriptors are + * represented as JVM type descriptor strings and symbols are represented as + * name strings + */ +public class Util { + + private Util() { + } + + private static final int ATTRIBUTE_STABILITY_COUNT = AttributeMapper.AttributeStability.values().length; + + public static boolean isAttributeAllowed(final Attribute attr, + final ClassFile.AttributesProcessingOption processingOption) { + return attr instanceof BoundAttribute + ? ATTRIBUTE_STABILITY_COUNT - attr.attributeMapper().stability().ordinal() > processingOption.ordinal() + : true; + } + + public static int parameterSlots(MethodTypeDesc mDesc) { + int count = 0; + for (int i = 0; i < mDesc.parameterCount(); i++) { + count += slotSize(mDesc.parameterType(i)); + } + return count; + } + + public static int[] parseParameterSlots(int flags, MethodTypeDesc mDesc) { + int[] result = new int[mDesc.parameterCount()]; + int count = ((flags & ACC_STATIC) != 0) ? 0 : 1; + for (int i = 0; i < result.length; i++) { + result[i] = count; + count += slotSize(mDesc.parameterType(i)); + } + return result; + } + + public static int maxLocals(int flags, MethodTypeDesc mDesc) { + int count = ((flags & ACC_STATIC) != 0) ? 0 : 1; + for (int i = 0; i < mDesc.parameterCount(); i++) { + count += slotSize(mDesc.parameterType(i)); + } + return count; + } + + /** + * Converts a descriptor of classes or interfaces into + * a binary name. Rejects primitive types or arrays. + * This is an inverse of {@link ClassDesc#of(String)}. + */ + public static String toBinaryName(ClassDesc cd) { + return toInternalName(cd).replace('/', '.'); + } + + public static String toInternalName(ClassDesc cd) { + var desc = cd.descriptorString(); + if (desc.charAt(0) == 'L') + return desc.substring(1, desc.length() - 1); + throw new IllegalArgumentException(desc); + } + + public static ClassDesc toClassDesc(String classInternalNameOrArrayDesc) { + return classInternalNameOrArrayDesc.charAt(0) == '[' + ? ClassDesc.ofDescriptor(classInternalNameOrArrayDesc) + : ClassDesc.ofInternalName(classInternalNameOrArrayDesc); + } + + public static List mappedList(List list, Function mapper) { + return new AbstractList<>() { + @Override + public U get(int index) { + return mapper.apply(list.get(index)); + } + + @Override + public int size() { + return list.size(); + } + }; + } + + public static List entryList(List list) { + var result = new Object[list.size()]; // null check + for (int i = 0; i < result.length; i++) { + result[i] = TemporaryConstantPool.INSTANCE.classEntry(list.get(i)); + } + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result); + } + + public static List moduleEntryList(List list) { + var result = new Object[list.size()]; // null check + for (int i = 0; i < result.length; i++) { + result[i] = TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(list.get(i).name())); + } + return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result); + } + + public static void checkKind(Opcode op, Opcode.Kind k) { + if (op.kind() != k) + throw new IllegalArgumentException( + String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k)); + } + + public static int flagsToBits(AccessFlag.Location location, Collection flags) { + int i = 0; + for (AccessFlag f : flags) { + if (!f.locations().contains(location)) { + throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location); + } + i |= f.mask(); + } + return i; + } + + public static int flagsToBits(AccessFlag.Location location, AccessFlag... flags) { + int i = 0; + for (AccessFlag f : flags) { + if (!f.locations().contains(location)) { + throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location); + } + i |= f.mask(); + } + return i; + } + + public static boolean has(AccessFlag.Location location, int flagsMask, AccessFlag flag) { + return (flag.mask() & flagsMask) == flag.mask() && flag.locations().contains(location); + } + + public static ClassDesc fieldTypeSymbol(NameAndTypeEntry nat) { + return ((AbstractPoolEntry.NameAndTypeEntryImpl)nat).fieldTypeSymbol(); + } + + public static MethodTypeDesc methodTypeSymbol(NameAndTypeEntry nat) { + return ((AbstractPoolEntry.NameAndTypeEntryImpl)nat).methodTypeSymbol(); + } + + public static int slotSize(ClassDesc desc) { + return switch (desc.descriptorString().charAt(0)) { + case 'V' -> 0; + case 'D','J' -> 2; + default -> 1; + }; + } + + public static boolean isDoubleSlot(ClassDesc desc) { + char ch = desc.descriptorString().charAt(0); + return ch == 'D' || ch == 'J'; + } + + public static void dumpMethod(SplitConstantPool cp, + ClassDesc cls, + String methodName, + MethodTypeDesc methodDesc, + int acc, + ByteBuffer bytecode, + Consumer dump) { + + // try to dump debug info about corrupted bytecode + try { + var cc = ClassFile.of(); + var clm = cc.parse(cc.build(cp.classEntry(cls), cp, clb -> + clb.withMethod(methodName, methodDesc, acc, mb -> + ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { + @Override + public void writeBody(BufWriter b) { + b.writeU2(-1);//max stack + b.writeU2(-1);//max locals + b.writeInt(bytecode.limit()); + b.writeBytes(bytecode.array(), 0, bytecode.limit()); + b.writeU2(0);//exception handlers + b.writeU2(0);//attributes + } + })))); + ClassPrinter.toYaml(clm.methods().get(0).code().get(), ClassPrinter.Verbosity.TRACE_ALL, dump); + } catch (Error | Exception _) { + // fallback to bytecode hex dump + bytecode.rewind(); + while (bytecode.position() < bytecode.limit()) { + dump.accept("%n%04x:".formatted(bytecode.position())); + for (int i = 0; i < 16 && bytecode.position() < bytecode.limit(); i++) { + dump.accept(" %02x".formatted(bytecode.get())); + } + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier$1.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier$1.class new file mode 100644 index 0000000000000000000000000000000000000000..d6d35c5fd69f4c995e5c7cc5d8a5f8b445dc4858 GIT binary patch literal 1177 zcmbVK+fEZf82*NqZo4c}0R<5eq;l{;MGhVS6$-?LQivt>f*Y6Jfi5gN&FmJ#orykx zi9UddFL3lgIac>$JQ)25AzRe}~ta^}J2F62sSva<` zYnWh2M@_D6?Q$!ic(a!4cuw#jyo)kJJSS|r&9;K$@nUU%i^~m@s$*y`2+MTKrgRiP z5?f1wY3KlCrqKC7?wE6&E( zJ|eyn(k`OS5$z$Gi0CDvT15MaCL=mXG~M7HQoO-Fs(6F{hT^H{|E%JA$Ui|x3Z3Y} zIdo$XLxjWB-W1_9=CMe)gmsh%H}DJ=p^Ykh!T>MulJFH?;|<|kyu*9K817K}iSQDB x<1U?>Xx*bViO#1QIaW{Dib^|aLmczFfdu!96}L84u)NP0#{&ux3%Y~(8wtC1FsqQalEYp z>8bs8;2p?FZ7Ughzxq)uqs{bne6B8#5B+^9Fx}|+>sdE-7#lw{ZLI_Eh1p(M2~BiZ zv%W96C|SpObJ&(;rf}Is8Dj!Pqc=>X!dC)~$wq%+)hd~A611B2an;2&d`cfXe!R1! zTMWF`zmHW5dELbgd`@!Z?;Ssg1=jio%*6c5)~;-tTIDx^m&AKt%8yd}e{?IGq(5Py z)KH;Z@9b~M=()cYke6~pH~nDKkCc5+g?Y21nBqdeWno*cNwcF{Y$Ub~yNzg9CeNr= zw@Ft8u4c2(up+b#u}4h$Nnqv_+DG{k7~asGs4460c7d_e9X?|n2$WXBW}svCWD>oD zZw2o4(V8wi%nG>OfjX=!8MH{iSej$UsK9Hen004mit92qPjzhATkj@#^oiCcHj&>> z0*Q;bFEC_Bux96|B;fEjQYzqwVf=`igGCn)!I{6^<0|TeM(s;4;VeZW%+@<_fuk(# zDm>78(n}Pd`e7@O@pwb)y-vH9DM31C8A)pRoRKZdxEZOo(NWf9$?ln~AjNq3AxPHy zsqubad3QAoWz>a~WL4B1JQ0}a<$X>b4weOOov+F|BuQhI`zy!U&v9dMd-7Jc%Zz7% zzd?M#FE@Exvn!crsrna0b?O*Sb@~`1M-=67i_ZcCpRaM7&o2{Io?r2eMqOz8z0?KI z;cMQ9auiz;7bd-aLjdb(j;B?1swWr){^a#T4{oB8dbrG0IDUrt72uBxncu)fYQ9Kk zmXBg}>I9$tm;JRwCv{J4+`(NU2xc^yB6;0+a#(!>=e#TiQy32CnZ_d*F)pCe&9sUs zo_S1ThD=)OrtuxmOS~oZO{#mZE93s7ZV}&O9uM%CvNH9GJbz;HKl8tM1=rsKaqrsS literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier$1M.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier$1M.class new file mode 100644 index 0000000000000000000000000000000000000000..210d68760184af5da6c8e43b0c14668058910b09 GIT binary patch literal 1945 zcmbVN+fvg|6kVs5ro~{fc*VP-(t^Y*UW!-1k(pK12ep3(Ar0eKWG^xN1ATVQgzx#D<%mSN!fPQ!PjXwmbfLt}=Be8ARZA3dTx=pn@O*$uVFr9sh z6`@RsU1E|?0ux)%{>hg>|4Y>l8}c!`U0`Tyhff#>0>#;&;j4%}8Aos7lEAedTGNJu z%K`(Pfm)Bj$iPsNWLtZ_Q}ZGgo~6k@m63j;BF*OdJ;H;Jl+uw7-Bx0p#|?pknZc?V zq@sYu-#{^k+x@tMs)Z>Vcfp}Q)g>!z2ijYePE6Wn7=?x3-~yl1ynDf#T9Hny_{0sG zzKlj{O0Be8)l?0VK}$&z!&i)KMn;X$YiSjxO{UGFNedE;w||19y>FTC&C=U*K_J5p zq$I1NZsC!@`EK4jm=@}jSIL)1i_3(6C|heP7W(yVC|GeUjoDF+}3ztH^w=XJDFB6#xsj?Opr-K-8ioD n+{as7-?+NhIx;Rm>gI7Blemfdl$EHL=lOuiKjfeBEROyH!us3Q literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier.class new file mode 100644 index 0000000000000000000000000000000000000000..315ca38e97d5c3b037120a8e8e0f23c707ca0f50 GIT binary patch literal 37876 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 LBjyZqCWZeW_dm%) literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier.java b/tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier.java new file mode 100644 index 00000000..4a2ffd3f --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/verifier/ParserVerifier.java @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl.verifier; + +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationValue; +import java.lang.constant.ClassDesc; +import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.lang.classfile.Attribute; +import java.lang.classfile.AttributedElement; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassModel; +import java.lang.classfile.ClassFileElement; +import java.lang.classfile.CodeModel; +import java.lang.classfile.CompoundElement; +import java.lang.classfile.CustomAttribute; +import java.lang.classfile.FieldModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.TypeAnnotation; +import java.lang.classfile.TypeKind; +import java.lang.classfile.attribute.*; +import java.lang.classfile.constantpool.*; +import java.lang.constant.ConstantDescs; +import java.lang.reflect.AccessFlag; +import java.util.Collection; +import java.util.function.Function; +import java.util.function.ToIntFunction; +import jdk.internal.classfile.impl.BoundAttribute; +import jdk.internal.classfile.impl.Util; + +/** + * ParserVerifier performs selected checks of the class file format according to + * {@jvms 4.8 Format Checking} + * + * @see hotspot/share/classfile/classFileParser.cpp + */ +public record ParserVerifier(ClassModel classModel) { + + List verify() { + var errors = new ArrayList(); + verifyConstantPool(errors); + verifyInterfaces(errors); + verifyFields(errors); + verifyMethods(errors); + verifyAttributes(classModel, errors); + return errors; + } + + private void verifyConstantPool(List errors) { + for (var cpe : classModel.constantPool()) { + Consumer check = c -> { + try { + c.run(); + } catch (VerifyError|Exception e) { + errors.add(new VerifyError("%s at constant pool index %d in %s".formatted(e.getMessage(), cpe.index(), toString(classModel)))); + } + }; + check.accept(switch (cpe) { + case DoubleEntry de -> de::doubleValue; + case FloatEntry fe -> fe::floatValue; + case IntegerEntry ie -> ie::intValue; + case LongEntry le -> le::longValue; + case Utf8Entry ue -> ue::stringValue; + case ConstantDynamicEntry cde -> cde::asSymbol; + case InvokeDynamicEntry ide -> ide::asSymbol; + case ClassEntry ce -> ce::asSymbol; + case StringEntry se -> se::stringValue; + case MethodHandleEntry mhe -> mhe::asSymbol; + case MethodTypeEntry mte -> mte::asSymbol; + case FieldRefEntry fre -> { + check.accept(fre.owner()::asSymbol); + check.accept(fre::typeSymbol); + yield () -> verifyFieldName(fre.name().stringValue()); + } + case InterfaceMethodRefEntry imre -> { + check.accept(imre.owner()::asSymbol); + check.accept(imre::typeSymbol); + yield () -> verifyMethodName(imre.name().stringValue()); + } + case MethodRefEntry mre -> { + check.accept(mre.owner()::asSymbol); + check.accept(mre::typeSymbol); + yield () -> verifyMethodName(mre.name().stringValue()); + } + case ModuleEntry me -> me::asSymbol; + case NameAndTypeEntry nate -> { + check.accept(nate.name()::stringValue); + yield () -> nate.type().stringValue(); + } + case PackageEntry pe -> pe::asSymbol; + }); + } + } + + private void verifyFieldName(String name) { + if (name.length() == 0 || name.chars().anyMatch(ch -> switch(ch) { + case '.', ';', '[', '/' -> true; + default -> false; + })) { + throw new VerifyError("Illegal field name %s in %s".formatted(name, toString(classModel))); + } + } + + private void verifyMethodName(String name) { + if (!name.equals(INIT_NAME) + && !name.equals(CLASS_INIT_NAME) + && (name.length() == 0 || name.chars().anyMatch(ch -> switch(ch) { + case '.', ';', '[', '/', '<', '>' -> true; + default -> false; + }))) { + throw new VerifyError("Illegal method name %s in %s".formatted(name, toString(classModel))); + } + } + + private void verifyInterfaces(List errors) { + var intfs = new HashSet(); + for (var intf : classModel.interfaces()) { + if (!intfs.add(intf)) { + errors.add(new VerifyError("Duplicate interface %s in %s".formatted(intf.asSymbol().displayName(), toString(classModel)))); + } + } + } + + private void verifyFields(List errors) { + record F(Utf8Entry name, Utf8Entry type) {}; + var fields = new HashSet(); + for (var f : classModel.fields()) try { + if (!fields.add(new F(f.fieldName(), f.fieldType()))) { + errors.add(new VerifyError("Duplicate field name %s with signature %s in %s".formatted(f.fieldName().stringValue(), f.fieldType().stringValue(), toString(classModel)))); + } + verifyFieldName(f.fieldName().stringValue()); + } catch (VerifyError ve) { + errors.add(ve); + } + } + + private void verifyMethods(List errors) { + record M(Utf8Entry name, Utf8Entry type) {}; + var methods = new HashSet(); + for (var m : classModel.methods()) try { + if (!methods.add(new M(m.methodName(), m.methodType()))) { + errors.add(new VerifyError("Duplicate method name %s with signature %s in %s".formatted(m.methodName().stringValue(), m.methodType().stringValue(), toString(classModel)))); + } + if (m.methodName().equalsString(CLASS_INIT_NAME) + && !m.flags().has(AccessFlag.STATIC)) { + errors.add(new VerifyError("Method is not static in %s".formatted(toString(classModel)))); + } + if (classModel.flags().has(AccessFlag.INTERFACE) + && m.methodName().equalsString(INIT_NAME)) { + errors.add(new VerifyError("Interface cannot have a method named in %s".formatted(toString(classModel)))); + } + verifyMethodName(m.methodName().stringValue()); + } catch (VerifyError ve) { + errors.add(ve); + } + } + + private void verifyAttributes(ClassFileElement cfe, List errors) { + if (cfe instanceof AttributedElement ae) { + var attrNames = new HashSet(); + for (var a : ae.attributes()) { + if (!a.attributeMapper().allowMultiple() && !attrNames.add(a.attributeName())) { + errors.add(new VerifyError("Multiple %s attributes in %s".formatted(a.attributeName(), toString(ae)))); + } + verifyAttribute(ae, a, errors); + } + } + switch (cfe) { + case CompoundElement comp -> { + for (var e : comp) verifyAttributes(e, errors); + } + case RecordAttribute ra -> { + for(var rc : ra.components()) verifyAttributes(rc, errors); + } + default -> {} + } + } + + private void verifyAttribute(AttributedElement ae, Attribute a, List errors) { + int size = switch (a) { + case AnnotationDefaultAttribute aa -> + valueSize(aa.defaultValue()); + case BootstrapMethodsAttribute bma -> + 2 + bma.bootstrapMethods().stream().mapToInt(bm -> 4 + 2 * bm.arguments().size()).sum(); + case CharacterRangeTableAttribute cra -> + 2 + 14 * cra.characterRangeTable().size(); + case CodeAttribute ca -> { + MethodModel mm = (MethodModel)ae; + if (mm.flags().has(AccessFlag.NATIVE) || mm.flags().has(AccessFlag.ABSTRACT)) { + errors.add(new VerifyError("Code attribute in native or abstract %s".formatted(toString(ae)))); + } + if (ca.maxLocals() < Util.maxLocals(mm.flags().flagsMask(), mm.methodTypeSymbol())) { + errors.add(new VerifyError("Arguments can't fit into locals in %s".formatted(toString(ae)))); + } + yield 10 + ca.codeLength() + 8 * ca.exceptionHandlers().size() + attributesSize(ca.attributes()); + } + case CompilationIDAttribute cida -> { + cida.compilationId(); + yield 2; + } + case ConstantValueAttribute cva -> { + ClassDesc type = ((FieldModel)ae).fieldTypeSymbol(); + ConstantValueEntry cve = cva.constant(); + if (!switch (TypeKind.from(type)) { + case BooleanType, ByteType, CharType, IntType, ShortType -> cve instanceof IntegerEntry; + case DoubleType -> cve instanceof DoubleEntry; + case FloatType -> cve instanceof FloatEntry; + case LongType -> cve instanceof LongEntry; + case ReferenceType -> type.equals(ConstantDescs.CD_String) && cve instanceof StringEntry; + case VoidType -> false; + }) { + errors.add(new VerifyError("Bad constant value type in %s".formatted(toString(ae)))); + } + yield 2; + } + case DeprecatedAttribute _ -> + 0; + case EnclosingMethodAttribute ema -> { + ema.enclosingClass(); + ema.enclosingMethod(); + yield 4; + } + case ExceptionsAttribute ea -> + 2 + 2 * ea.exceptions().size(); + case InnerClassesAttribute ica -> { + for (var ici : ica.classes()) { + if (ici.outerClass().isPresent() && ici.outerClass().get().equals(ici.innerClass())) { + errors.add(new VerifyError("Class is both outer and inner class in %s".formatted(toString(ae)))); + } + } + yield 2 + 8 * ica.classes().size(); + } + case LineNumberTableAttribute lta -> + 2 + 4 * lta.lineNumbers().size(); + case LocalVariableTableAttribute lvta -> + 2 + 10 * lvta.localVariables().size(); + case LocalVariableTypeTableAttribute lvta -> + 2 + 10 * lvta.localVariableTypes().size(); + case MethodParametersAttribute mpa -> + 1 + 4 * mpa.parameters().size(); + case ModuleAttribute ma -> + 16 + subSize(ma.exports(), ModuleExportInfo::exportsTo, 6, 2) + + subSize(ma.opens(), ModuleOpenInfo::opensTo, 6, 2) + + subSize(ma.provides(), ModuleProvideInfo::providesWith, 4, 2) + + 6 * ma.requires().size() + + 2 * ma.uses().size(); + case ModuleHashesAttribute mha -> + 2 + moduleHashesSize(mha.hashes()); + case ModuleMainClassAttribute mmca -> { + mmca.mainClass(); + yield 2; + } + case ModulePackagesAttribute mpa -> + 2 + 2 * mpa.packages().size(); + case ModuleResolutionAttribute mra -> + 2; + case ModuleTargetAttribute mta -> { + mta.targetPlatform(); + yield 2; + } + case NestHostAttribute nha -> { + nha.nestHost(); + yield 2; + } + case NestMembersAttribute nma -> { + if (ae.findAttribute(Attributes.nestHost()).isPresent()) { + errors.add(new VerifyError("Conflicting NestHost and NestMembers attributes in %s".formatted(toString(ae)))); + } + yield 2 + 2 * nma.nestMembers().size(); + } + case PermittedSubclassesAttribute psa -> { + if (classModel.flags().has(AccessFlag.FINAL)) { + errors.add(new VerifyError("PermittedSubclasses attribute in final %s".formatted(toString(ae)))); + } + yield 2 + 2 * psa.permittedSubclasses().size(); + } + case RecordAttribute ra -> + componentsSize(ra.components()); + case RuntimeVisibleAnnotationsAttribute aa -> + annotationsSize(aa.annotations()); + case RuntimeInvisibleAnnotationsAttribute aa -> + annotationsSize(aa.annotations()); + case RuntimeVisibleTypeAnnotationsAttribute aa -> + typeAnnotationsSize(aa.annotations()); + case RuntimeInvisibleTypeAnnotationsAttribute aa -> + typeAnnotationsSize(aa.annotations()); + case RuntimeVisibleParameterAnnotationsAttribute aa -> + parameterAnnotationsSize(aa.parameterAnnotations()); + case RuntimeInvisibleParameterAnnotationsAttribute aa -> + parameterAnnotationsSize(aa.parameterAnnotations()); + case SignatureAttribute sa -> { + sa.signature(); + yield 2; + } + case SourceDebugExtensionAttribute sda -> + sda.contents().length; + case SourceFileAttribute sfa -> { + sfa.sourceFile(); + yield 2; + } + case SourceIDAttribute sida -> { + sida.sourceId(); + yield 2; + } + case StackMapTableAttribute smta -> + 2 + subSize(smta.entries(), frame -> stackMapFrameSize(frame)); + case SyntheticAttribute _ -> + 0; + case UnknownAttribute _ -> + -1; + case CustomAttribute _ -> + -1; + default -> // should not happen if all known attributes are verified + throw new AssertionError(a); + }; + if (size >= 0 && size != ((BoundAttribute)a).payloadLen()) { + errors.add(new VerifyError("Wrong %s attribute length in %s".formatted(a.attributeName(), toString(ae)))); + } + } + + private static > int subSize(Collection entries, Function subMH, int entrySize, int subSize) { + return subSize(entries, (ToIntFunction) t -> entrySize + subSize * subMH.apply(t).size()); + } + + private static int subSize(Collection entries, ToIntFunction subMH) { + int l = 0; + for (T entry : entries) { + l += subMH.applyAsInt(entry); + } + return l; + } + + private static int componentsSize(List comps) { + int l = 2; + for (var rc : comps) { + l += 4 + attributesSize(rc.attributes()); + } + return l; + } + + private static int attributesSize(List> attrs) { + int l = 2; + for (var a : attrs) { + l += 6 + ((BoundAttribute)a).payloadLen(); + } + return l; + } + + private static int parameterAnnotationsSize(List> pans) { + int l = 1; + for (var ans : pans) { + l += annotationsSize(ans); + } + return l; + } + + private static int annotationsSize(List ans) { + int l = 2; + for (var an : ans) { + l += annotationSize(an); + } + return l; + } + + private static int typeAnnotationsSize(List ans) { + int l = 2; + for (var an : ans) { + l += 2 + an.targetInfo().size() + 2 * an.targetPath().size() + annotationSize(an); + } + return l; + } + + private static int annotationSize(Annotation an) { + int l = 4; + for (var el : an.elements()) { + l += 2 + valueSize(el.value()); + } + return l; + } + + private static int valueSize(AnnotationValue val) { + return 1 + switch (val) { + case AnnotationValue.OfAnnotation oan -> + annotationSize(oan.annotation()); + case AnnotationValue.OfArray oar -> { + int l = 2; + for (var v : oar.values()) { + l += valueSize(v); + } + yield l; + } + case AnnotationValue.OfConstant _, AnnotationValue.OfClass _ -> 2; + case AnnotationValue.OfEnum _ -> 4; + }; + } + + private static int moduleHashesSize(List hashes) { + int l = 2; + for (var h : hashes) { + h.moduleName(); + l += 4 + h.hash().length; + } + return l; + } + + private int stackMapFrameSize(StackMapFrameInfo frame) { + int ft = frame.frameType(); + if (ft < 64) return 1; + if (ft < 128) return 1 + verificationTypeSize(frame.stack().getFirst()); + if (ft > 246) { + if (ft == 247) return 3 + verificationTypeSize(frame.stack().getFirst()); + if (ft < 252) return 3; + if (ft < 255) { + var loc = frame.locals(); + int l = 3; + for (int i = loc.size() + 251 - ft; i < loc.size(); i++) { + l += verificationTypeSize(loc.get(i)); + } + return l; + } + if (ft == 255) { + int l = 7; + for (var vt : frame.stack()) { + l += verificationTypeSize(vt); + } + for (var vt : frame.locals()) { + l += verificationTypeSize(vt); + } + return l; + } + } + throw new IllegalArgumentException("Invalid stack map frame type " + ft); + } + + private static int verificationTypeSize(StackMapFrameInfo.VerificationTypeInfo vti) { + return switch (vti) { + case StackMapFrameInfo.SimpleVerificationTypeInfo _ -> 1; + case StackMapFrameInfo.ObjectVerificationTypeInfo ovti -> { + ovti.classSymbol(); + yield 3; + } + case StackMapFrameInfo.UninitializedVerificationTypeInfo _ -> 3; + }; + } + + private String className() { + return classModel.thisClass().asSymbol().displayName(); + } + + private String toString(AttributedElement ae) { + return switch (ae) { + case CodeModel m -> "Code attribute for " + toString(m.parent().get()); + case FieldModel m -> "field %s.%s".formatted( + className(), + m.fieldName().stringValue()); + case MethodModel m -> "method %s::%s(%s)".formatted( + className(), + m.methodName().stringValue(), + m.methodTypeSymbol().parameterList().stream().map(ClassDesc::displayName).collect(Collectors.joining(","))); + case RecordComponentInfo i -> "Record component %s of class %s".formatted( + i.name().stringValue(), + className()); + default -> "class " + className(); + }; + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationBytecodes.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationBytecodes.class new file mode 100644 index 0000000000000000000000000000000000000000..50ecd5540dbc4ccef34a455539a71efb24b2525d GIT binary patch literal 12824 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 NaHx1ryfA8${{bhotspot/share/interpreter/bytecodes.hpp + * @see hotspot/share/interpreter/bytecodes.cpp + */ +final class VerificationBytecodes { + + static final int _breakpoint = 202, + _fast_agetfield = 203, + _fast_bgetfield = 204, + _fast_cgetfield = 205, + _fast_dgetfield = 206, + _fast_fgetfield = 207, + _fast_igetfield = 208, + _fast_lgetfield = 209, + _fast_sgetfield = 210, + _fast_aputfield = 211, + _fast_bputfield = 212, + _fast_zputfield = 213, + _fast_cputfield = 214, + _fast_dputfield = 215, + _fast_fputfield = 216, + _fast_iputfield = 217, + _fast_lputfield = 218, + _fast_sputfield = 219, + _fast_aload_0 = 220, + _fast_iaccess_0 = 221, + _fast_aaccess_0 = 222, + _fast_faccess_0 = 223, + _fast_iload = 224, + _fast_iload2 = 225, + _fast_icaload = 226, + _fast_invokevfinal = 227, + _fast_linearswitch = 228, + _fast_binaryswitch = 229, + _fast_aldc = 230, + _fast_aldc_w = 231, + _return_register_finalizer = 232, + _invokehandle = 233, + _nofast_getfield = 234, + _nofast_putfield = 235, + _nofast_aload_0 = 236, + _nofast_iload = 237, + _shouldnotreachhere = 238, + number_of_codes = 239; + + static int code_or_bp_at(byte[] code, int bci) { + return code[bci] & 0xff; + } + + static boolean is_valid(int code) { + return 0 <= code && code < number_of_codes; + } + + static int wide_length_for(int code) { + return is_valid(code) ? _lengths[code] >> 4 : -1; + } + + static boolean is_store_into_local(int code) { + return (ClassFile.ISTORE <= code && code <= ClassFile.ASTORE_3); + } + + static final int _lengths[] = new int[number_of_codes]; + + static int special_length_at(int code, byte bytecode[], int bci, int end) { + switch (code) { + case ClassFile.WIDE: + if (bci + 1 >= end) { + return -1; + } + return wide_length_for(bytecode[bci + 1] & 0xff); + case ClassFile.TABLESWITCH: + int aligned_bci = align(bci + 1); + if (aligned_bci + 3 * 4 >= end) { + return -1; + } + ByteBuffer bb = ByteBuffer.wrap(bytecode, aligned_bci + 1 * 4, 2 * 4); + int lo = bb.getInt(); + int hi = bb.getInt(); + int len = aligned_bci - bci + (3 + hi - lo + 1) * 4; + return len > 0 ? len : -1; + case ClassFile.LOOKUPSWITCH: + case _fast_binaryswitch: + case _fast_linearswitch: + aligned_bci = align(bci + 1); + if (aligned_bci + 2 * 4 >= end) { + return -1; + } + int npairs = ByteBuffer.wrap(bytecode, aligned_bci + 4, 4).getInt(); + len = aligned_bci - bci + (2 + 2 * npairs) * 4; + return len > 0 ? len : -1; + default: + return 0; + } + } + + static int align(int n) { + return (n + 3) & ~3; + } + + static void def(int code, String name, String format, String wide_format, BasicType result_type, int depth) { + def(code, name, format, wide_format, result_type, depth, code); + } + + static void def(int code, String name, String format, String wide_format, BasicType result_type, int depth, int java_code) { + if (wide_format != null && format == null) throw new IllegalArgumentException("short form must exist if there's a wide form"); + int len = format != null ? format.length() : 0; + int wlen = wide_format != null ? wide_format.length() : 0; + _lengths[code] = (wlen << 4) | (len & 0xf); + } + + static { + def(ClassFile.NOP, "nop", "b", null, T_VOID, 0); + def(ClassFile.ACONST_NULL, "aconst_null", "b", null, T_OBJECT, 1); + def(ClassFile.ICONST_M1, "iconst_m1", "b", null, T_INT, 1); + def(ClassFile.ICONST_0, "iconst_0", "b", null, T_INT, 1); + def(ClassFile.ICONST_1, "iconst_1", "b", null, T_INT, 1); + def(ClassFile.ICONST_2, "iconst_2", "b", null, T_INT, 1); + def(ClassFile.ICONST_3, "iconst_3", "b", null, T_INT, 1); + def(ClassFile.ICONST_4, "iconst_4", "b", null, T_INT, 1); + def(ClassFile.ICONST_5, "iconst_5", "b", null, T_INT, 1); + def(ClassFile.LCONST_0, "lconst_0", "b", null, T_LONG, 2); + def(ClassFile.LCONST_1, "lconst_1", "b", null, T_LONG, 2); + def(ClassFile.FCONST_0, "fconst_0", "b", null, T_FLOAT, 1); + def(ClassFile.FCONST_1, "fconst_1", "b", null, T_FLOAT, 1); + def(ClassFile.FCONST_2, "fconst_2", "b", null, T_FLOAT, 1); + def(ClassFile.DCONST_0, "dconst_0", "b", null, T_DOUBLE, 2); + def(ClassFile.DCONST_1, "dconst_1", "b", null, T_DOUBLE, 2); + def(ClassFile.BIPUSH, "bipush", "bc", null, T_INT, 1); + def(ClassFile.SIPUSH, "sipush", "bcc", null, T_INT, 1); + def(ClassFile.LDC, "ldc", "bk", null, T_ILLEGAL, 1); + def(ClassFile.LDC_W, "ldc_w", "bkk", null, T_ILLEGAL, 1); + def(ClassFile.LDC2_W, "ldc2_w", "bkk", null, T_ILLEGAL, 2); + def(ClassFile.ILOAD, "iload", "bi", "wbii", T_INT, 1); + def(ClassFile.LLOAD, "lload", "bi", "wbii", T_LONG, 2); + def(ClassFile.FLOAD, "fload", "bi", "wbii", T_FLOAT, 1); + def(ClassFile.DLOAD, "dload", "bi", "wbii", T_DOUBLE, 2); + def(ClassFile.ALOAD, "aload", "bi", "wbii", T_OBJECT, 1); + def(ClassFile.ILOAD_0, "iload_0", "b", null, T_INT, 1); + def(ClassFile.ILOAD_1, "iload_1", "b", null, T_INT, 1); + def(ClassFile.ILOAD_2, "iload_2", "b", null, T_INT, 1); + def(ClassFile.ILOAD_3, "iload_3", "b", null, T_INT, 1); + def(ClassFile.LLOAD_0, "lload_0", "b", null, T_LONG, 2); + def(ClassFile.LLOAD_1, "lload_1", "b", null, T_LONG, 2); + def(ClassFile.LLOAD_2, "lload_2", "b", null, T_LONG, 2); + def(ClassFile.LLOAD_3, "lload_3", "b", null, T_LONG, 2); + def(ClassFile.FLOAD_0, "fload_0", "b", null, T_FLOAT, 1); + def(ClassFile.FLOAD_1, "fload_1", "b", null, T_FLOAT, 1); + def(ClassFile.FLOAD_2, "fload_2", "b", null, T_FLOAT, 1); + def(ClassFile.FLOAD_3, "fload_3", "b", null, T_FLOAT, 1); + def(ClassFile.DLOAD_0, "dload_0", "b", null, T_DOUBLE, 2); + def(ClassFile.DLOAD_1, "dload_1", "b", null, T_DOUBLE, 2); + def(ClassFile.DLOAD_2, "dload_2", "b", null, T_DOUBLE, 2); + def(ClassFile.DLOAD_3, "dload_3", "b", null, T_DOUBLE, 2); + def(ClassFile.ALOAD_0, "aload_0", "b", null, T_OBJECT, 1); + def(ClassFile.ALOAD_1, "aload_1", "b", null, T_OBJECT, 1); + def(ClassFile.ALOAD_2, "aload_2", "b", null, T_OBJECT, 1); + def(ClassFile.ALOAD_3, "aload_3", "b", null, T_OBJECT, 1); + def(ClassFile.IALOAD, "iaload", "b", null, T_INT, -1); + def(ClassFile.LALOAD, "laload", "b", null, T_LONG, 0); + def(ClassFile.FALOAD, "faload", "b", null, T_FLOAT, -1); + def(ClassFile.DALOAD, "daload", "b", null, T_DOUBLE, 0); + def(ClassFile.AALOAD, "aaload", "b", null, T_OBJECT, -1); + def(ClassFile.BALOAD, "baload", "b", null, T_INT, -1); + def(ClassFile.CALOAD, "caload", "b", null, T_INT, -1); + def(ClassFile.SALOAD, "saload", "b", null, T_INT, -1); + def(ClassFile.ISTORE, "istore", "bi", "wbii", T_VOID, -1); + def(ClassFile.LSTORE, "lstore", "bi", "wbii", T_VOID, -2); + def(ClassFile.FSTORE, "fstore", "bi", "wbii", T_VOID, -1); + def(ClassFile.DSTORE, "dstore", "bi", "wbii", T_VOID, -2); + def(ClassFile.ASTORE, "astore", "bi", "wbii", T_VOID, -1); + def(ClassFile.ISTORE_0, "istore_0", "b", null, T_VOID, -1); + def(ClassFile.ISTORE_1, "istore_1", "b", null, T_VOID, -1); + def(ClassFile.ISTORE_2, "istore_2", "b", null, T_VOID, -1); + def(ClassFile.ISTORE_3, "istore_3", "b", null, T_VOID, -1); + def(ClassFile.LSTORE_0, "lstore_0", "b", null, T_VOID, -2); + def(ClassFile.LSTORE_1, "lstore_1", "b", null, T_VOID, -2); + def(ClassFile.LSTORE_2, "lstore_2", "b", null, T_VOID, -2); + def(ClassFile.LSTORE_3, "lstore_3", "b", null, T_VOID, -2); + def(ClassFile.FSTORE_0, "fstore_0", "b", null, T_VOID, -1); + def(ClassFile.FSTORE_1, "fstore_1", "b", null, T_VOID, -1); + def(ClassFile.FSTORE_2, "fstore_2", "b", null, T_VOID, -1); + def(ClassFile.FSTORE_3, "fstore_3", "b", null, T_VOID, -1); + def(ClassFile.DSTORE_0, "dstore_0", "b", null, T_VOID, -2); + def(ClassFile.DSTORE_1, "dstore_1", "b", null, T_VOID, -2); + def(ClassFile.DSTORE_2, "dstore_2", "b", null, T_VOID, -2); + def(ClassFile.DSTORE_3, "dstore_3", "b", null, T_VOID, -2); + def(ClassFile.ASTORE_0, "astore_0", "b", null, T_VOID, -1); + def(ClassFile.ASTORE_1, "astore_1", "b", null, T_VOID, -1); + def(ClassFile.ASTORE_2, "astore_2", "b", null, T_VOID, -1); + def(ClassFile.ASTORE_3, "astore_3", "b", null, T_VOID, -1); + def(ClassFile.IASTORE, "iastore", "b", null, T_VOID, -3); + def(ClassFile.LASTORE, "lastore", "b", null, T_VOID, -4); + def(ClassFile.FASTORE, "fastore", "b", null, T_VOID, -3); + def(ClassFile.DASTORE, "dastore", "b", null, T_VOID, -4); + def(ClassFile.AASTORE, "aastore", "b", null, T_VOID, -3); + def(ClassFile.BASTORE, "bastore", "b", null, T_VOID, -3); + def(ClassFile.CASTORE, "castore", "b", null, T_VOID, -3); + def(ClassFile.SASTORE, "sastore", "b", null, T_VOID, -3); + def(ClassFile.POP, "pop", "b", null, T_VOID, -1); + def(ClassFile.POP2, "pop2", "b", null, T_VOID, -2); + def(ClassFile.DUP, "dup", "b", null, T_VOID, 1); + def(ClassFile.DUP_X1, "dup_x1", "b", null, T_VOID, 1); + def(ClassFile.DUP_X2, "dup_x2", "b", null, T_VOID, 1); + def(ClassFile.DUP2, "dup2", "b", null, T_VOID, 2); + def(ClassFile.DUP2_X1, "dup2_x1", "b", null, T_VOID, 2); + def(ClassFile.DUP2_X2, "dup2_x2", "b", null, T_VOID, 2); + def(ClassFile.SWAP, "swap", "b", null, T_VOID, 0); + def(ClassFile.IADD, "iadd", "b", null, T_INT, -1); + def(ClassFile.LADD, "ladd", "b", null, T_LONG, -2); + def(ClassFile.FADD, "fadd", "b", null, T_FLOAT, -1); + def(ClassFile.DADD, "dadd", "b", null, T_DOUBLE, -2); + def(ClassFile.ISUB, "isub", "b", null, T_INT, -1); + def(ClassFile.LSUB, "lsub", "b", null, T_LONG, -2); + def(ClassFile.FSUB, "fsub", "b", null, T_FLOAT, -1); + def(ClassFile.DSUB, "dsub", "b", null, T_DOUBLE, -2); + def(ClassFile.IMUL, "imul", "b", null, T_INT, -1); + def(ClassFile.LMUL, "lmul", "b", null, T_LONG, -2); + def(ClassFile.FMUL, "fmul", "b", null, T_FLOAT, -1); + def(ClassFile.DMUL, "dmul", "b", null, T_DOUBLE, -2); + def(ClassFile.IDIV, "idiv", "b", null, T_INT, -1); + def(ClassFile.LDIV, "ldiv", "b", null, T_LONG, -2); + def(ClassFile.FDIV, "fdiv", "b", null, T_FLOAT, -1); + def(ClassFile.DDIV, "ddiv", "b", null, T_DOUBLE, -2); + def(ClassFile.IREM, "irem", "b", null, T_INT, -1); + def(ClassFile.LREM, "lrem", "b", null, T_LONG, -2); + def(ClassFile.FREM, "frem", "b", null, T_FLOAT, -1); + def(ClassFile.DREM, "drem", "b", null, T_DOUBLE, -2); + def(ClassFile.INEG, "ineg", "b", null, T_INT, 0); + def(ClassFile.LNEG, "lneg", "b", null, T_LONG, 0); + def(ClassFile.FNEG, "fneg", "b", null, T_FLOAT, 0); + def(ClassFile.DNEG, "dneg", "b", null, T_DOUBLE, 0); + def(ClassFile.ISHL, "ishl", "b", null, T_INT, -1); + def(ClassFile.LSHL, "lshl", "b", null, T_LONG, -1); + def(ClassFile.ISHR, "ishr", "b", null, T_INT, -1); + def(ClassFile.LSHR, "lshr", "b", null, T_LONG, -1); + def(ClassFile.IUSHR, "iushr", "b", null, T_INT, -1); + def(ClassFile.LUSHR, "lushr", "b", null, T_LONG, -1); + def(ClassFile.IAND, "iand", "b", null, T_INT, -1); + def(ClassFile.LAND, "land", "b", null, T_LONG, -2); + def(ClassFile.IOR, "ior", "b", null, T_INT, -1); + def(ClassFile.LOR, "lor", "b", null, T_LONG, -2); + def(ClassFile.IXOR, "ixor", "b", null, T_INT, -1); + def(ClassFile.LXOR, "lxor", "b", null, T_LONG, -2); + def(ClassFile.IINC, "iinc", "bic", "wbiicc", T_VOID, 0); + def(ClassFile.I2L, "i2l", "b", null, T_LONG, 1); + def(ClassFile.I2F, "i2f", "b", null, T_FLOAT, 0); + def(ClassFile.I2D, "i2d", "b", null, T_DOUBLE, 1); + def(ClassFile.L2I, "l2i", "b", null, T_INT, -1); + def(ClassFile.L2F, "l2f", "b", null, T_FLOAT, -1); + def(ClassFile.L2D, "l2d", "b", null, T_DOUBLE, 0); + def(ClassFile.F2I, "f2i", "b", null, T_INT, 0); + def(ClassFile.F2L, "f2l", "b", null, T_LONG, 1); + def(ClassFile.F2D, "f2d", "b", null, T_DOUBLE, 1); + def(ClassFile.D2I, "d2i", "b", null, T_INT, -1); + def(ClassFile.D2L, "d2l", "b", null, T_LONG, 0); + def(ClassFile.D2F, "d2f", "b", null, T_FLOAT, -1); + def(ClassFile.I2B, "i2b", "b", null, T_BYTE, 0); + def(ClassFile.I2C, "i2c", "b", null, T_CHAR, 0); + def(ClassFile.I2S, "i2s", "b", null, T_SHORT, 0); + def(ClassFile.LCMP, "lcmp", "b", null, T_VOID, -3); + def(ClassFile.FCMPL, "fcmpl", "b", null, T_VOID, -1); + def(ClassFile.FCMPG, "fcmpg", "b", null, T_VOID, -1); + def(ClassFile.DCMPL, "dcmpl", "b", null, T_VOID, -3); + def(ClassFile.DCMPG, "dcmpg", "b", null, T_VOID, -3); + def(ClassFile.IFEQ, "ifeq", "boo", null, T_VOID, -1); + def(ClassFile.IFNE, "ifne", "boo", null, T_VOID, -1); + def(ClassFile.IFLT, "iflt", "boo", null, T_VOID, -1); + def(ClassFile.IFGE, "ifge", "boo", null, T_VOID, -1); + def(ClassFile.IFGT, "ifgt", "boo", null, T_VOID, -1); + def(ClassFile.IFLE, "ifle", "boo", null, T_VOID, -1); + def(ClassFile.IF_ICMPEQ, "if_icmpeq", "boo", null, T_VOID, -2); + def(ClassFile.IF_ICMPNE, "if_icmpne", "boo", null, T_VOID, -2); + def(ClassFile.IF_ICMPLT, "if_icmplt", "boo", null, T_VOID, -2); + def(ClassFile.IF_ICMPGE, "if_icmpge", "boo", null, T_VOID, -2); + def(ClassFile.IF_ICMPGT, "if_icmpgt", "boo", null, T_VOID, -2); + def(ClassFile.IF_ICMPLE, "if_icmple", "boo", null, T_VOID, -2); + def(ClassFile.IF_ACMPEQ, "if_acmpeq", "boo", null, T_VOID, -2); + def(ClassFile.IF_ACMPNE, "if_acmpne", "boo", null, T_VOID, -2); + def(ClassFile.GOTO, "goto", "boo", null, T_VOID, 0); + def(ClassFile.JSR, "jsr", "boo", null, T_INT, 0); + def(ClassFile.RET, "ret", "bi", "wbii", T_VOID, 0); + def(ClassFile.TABLESWITCH, "tableswitch", "", null, T_VOID, -1); // may have backward branches + def(ClassFile.LOOKUPSWITCH, "lookupswitch", "", null, T_VOID, -1); // rewriting in interpreter + def(ClassFile.IRETURN, "ireturn", "b", null, T_INT, -1); + def(ClassFile.LRETURN, "lreturn", "b", null, T_LONG, -2); + def(ClassFile.FRETURN, "freturn", "b", null, T_FLOAT, -1); + def(ClassFile.DRETURN, "dreturn", "b", null, T_DOUBLE, -2); + def(ClassFile.ARETURN, "areturn", "b", null, T_OBJECT, -1); + def(ClassFile.RETURN, "return", "b", null, T_VOID, 0); + def(ClassFile.GETSTATIC, "getstatic", "bJJ", null, T_ILLEGAL, 1); + def(ClassFile.PUTSTATIC, "putstatic", "bJJ", null, T_ILLEGAL, -1); + def(ClassFile.GETFIELD, "getfield", "bJJ", null, T_ILLEGAL, 0); + def(ClassFile.PUTFIELD, "putfield", "bJJ", null, T_ILLEGAL, -2); + def(ClassFile.INVOKEVIRTUAL, "invokevirtual", "bJJ", null, T_ILLEGAL, -1); + def(ClassFile.INVOKESPECIAL, "invokespecial", "bJJ", null, T_ILLEGAL, -1); + def(ClassFile.INVOKESTATIC, "invokestatic", "bJJ", null, T_ILLEGAL, 0); + def(ClassFile.INVOKEINTERFACE, "invokeinterface", "bJJ__", null, T_ILLEGAL, -1); + def(ClassFile.INVOKEDYNAMIC, "invokedynamic", "bJJJJ", null, T_ILLEGAL, 0); + def(ClassFile.NEW, "new", "bkk", null, T_OBJECT, 1); + def(ClassFile.NEWARRAY, "newarray", "bc", null, T_OBJECT, 0); + def(ClassFile.ANEWARRAY, "anewarray", "bkk", null, T_OBJECT, 0); + def(ClassFile.ARRAYLENGTH, "arraylength", "b", null, T_VOID, 0); + def(ClassFile.ATHROW, "athrow", "b", null, T_VOID, -1); + def(ClassFile.CHECKCAST, "checkcast", "bkk", null, T_OBJECT, 0); + def(ClassFile.INSTANCEOF, "instanceof", "bkk", null, T_INT, 0); + def(ClassFile.MONITORENTER, "monitorenter", "b", null, T_VOID, -1); + def(ClassFile.MONITOREXIT, "monitorexit", "b", null, T_VOID, -1); + def(ClassFile.WIDE, "wide", "", null, T_VOID, 0); + def(ClassFile.MULTIANEWARRAY, "multianewarray", "bkkc", null, T_OBJECT, 1); + def(ClassFile.IFNULL, "ifnull", "boo", null, T_VOID, -1); + def(ClassFile.IFNONNULL, "ifnonnull", "boo", null, T_VOID, -1); + def(ClassFile.GOTO_W, "goto_w", "boooo", null, T_VOID, 0); + def(ClassFile.JSR_W, "jsr_w", "boooo", null, T_INT, 0); + def(_breakpoint, "breakpoint", "", null, T_VOID, 0); + def(_fast_agetfield, "fast_agetfield", "bJJ", null, T_OBJECT, 0, ClassFile.GETFIELD); + def(_fast_bgetfield, "fast_bgetfield", "bJJ", null, T_INT, 0, ClassFile.GETFIELD); + def(_fast_cgetfield, "fast_cgetfield", "bJJ", null, T_CHAR, 0, ClassFile.GETFIELD); + def(_fast_dgetfield, "fast_dgetfield", "bJJ", null, T_DOUBLE, 0, ClassFile.GETFIELD); + def(_fast_fgetfield, "fast_fgetfield", "bJJ", null, T_FLOAT, 0, ClassFile.GETFIELD); + def(_fast_igetfield, "fast_igetfield", "bJJ", null, T_INT, 0, ClassFile.GETFIELD); + def(_fast_lgetfield, "fast_lgetfield", "bJJ", null, T_LONG, 0, ClassFile.GETFIELD); + def(_fast_sgetfield, "fast_sgetfield", "bJJ", null, T_SHORT, 0, ClassFile.GETFIELD); + def(_fast_aputfield, "fast_aputfield", "bJJ", null, T_OBJECT, 0, ClassFile.PUTFIELD); + def(_fast_bputfield, "fast_bputfield", "bJJ", null, T_INT, 0, ClassFile.PUTFIELD); + def(_fast_zputfield, "fast_zputfield", "bJJ", null, T_INT, 0, ClassFile.PUTFIELD); + def(_fast_cputfield, "fast_cputfield", "bJJ", null, T_CHAR, 0, ClassFile.PUTFIELD); + def(_fast_dputfield, "fast_dputfield", "bJJ", null, T_DOUBLE, 0, ClassFile.PUTFIELD); + def(_fast_fputfield, "fast_fputfield", "bJJ", null, T_FLOAT, 0, ClassFile.PUTFIELD); + def(_fast_iputfield, "fast_iputfield", "bJJ", null, T_INT, 0, ClassFile.PUTFIELD); + def(_fast_lputfield, "fast_lputfield", "bJJ", null, T_LONG, 0, ClassFile.PUTFIELD); + def(_fast_sputfield, "fast_sputfield", "bJJ", null, T_SHORT, 0, ClassFile.PUTFIELD); + def(_fast_aload_0, "fast_aload_0", "b", null, T_OBJECT, 1, ClassFile.ALOAD_0); + def(_fast_iaccess_0, "fast_iaccess_0", "b_JJ", null, T_INT, 1, ClassFile.ALOAD_0); + def(_fast_aaccess_0, "fast_aaccess_0", "b_JJ", null, T_OBJECT, 1, ClassFile.ALOAD_0); + def(_fast_faccess_0, "fast_faccess_0", "b_JJ", null, T_OBJECT, 1, ClassFile.ALOAD_0); + def(_fast_iload, "fast_iload", "bi", null, T_INT, 1, ClassFile.ILOAD); + def(_fast_iload2, "fast_iload2", "bi_i", null, T_INT, 2, ClassFile.ILOAD); + def(_fast_icaload, "fast_icaload", "bi_", null, T_INT, 0, ClassFile.ILOAD); + def(_fast_invokevfinal, "fast_invokevfinal", "bJJ", null, T_ILLEGAL, -1, ClassFile.INVOKEVIRTUAL); + def(_fast_linearswitch, "fast_linearswitch", "", null, T_VOID, -1, ClassFile.LOOKUPSWITCH); + def(_fast_binaryswitch, "fast_binaryswitch", "", null, T_VOID, -1, ClassFile.LOOKUPSWITCH); + def(_return_register_finalizer, "return_register_finalizer", "b", null, T_VOID, 0, ClassFile.RETURN); + def(_invokehandle, "invokehandle", "bJJ", null, T_ILLEGAL, -1, ClassFile.INVOKEVIRTUAL); + def(_fast_aldc, "fast_aldc", "bj", null, T_OBJECT, 1, ClassFile.LDC); + def(_fast_aldc_w, "fast_aldc_w", "bJJ", null, T_OBJECT, 1, ClassFile.LDC_W); + def(_nofast_getfield, "nofast_getfield", "bJJ", null, T_ILLEGAL, 0, ClassFile.GETFIELD); + def(_nofast_putfield, "nofast PUTFIELD", "bJJ", null, T_ILLEGAL, -2, ClassFile.PUTFIELD); + def(_nofast_aload_0, "nofast_aload_0", "b", null, T_ILLEGAL, 1, ClassFile.ALOAD_0); + def(_nofast_iload, "nofast_iload", "bi", null, T_ILLEGAL, 1, ClassFile.ILOAD); + def(_shouldnotreachhere, "_shouldnotreachhere", "b", null, T_VOID, 0); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationFrame$1.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationFrame$1.class new file mode 100644 index 0000000000000000000000000000000000000000..1ae112e5f8b2e67e9edb9eb5bc519df5d96a0c74 GIT binary patch literal 1456 zcmb_cTTc@~7(D}}OUoh^xrsNFm5UcDsK`yFEiF__*R*R5;Q^QJ01L}5+1+A%GtnPl zqCdby6JJ%LF~;x%{6Rh%zu6SZgT`Rk?9Q2U^36AMX6D-;zrO7PNMSaLI@C)D$!I{B zVP?I&5jSn0yS8q{4NLdD71QEzb92jzZ*$jNF}WKr1sy~8O~)>ptG4b}T&^T_&os2B zTbv=hty>lDF=Ph@7js9Eb25TPL?lFIG(lzjB`Q>YfH%mEiI(;GA>l5)LfzYOdm(S_nq=%NP(^ghr}rE}h7W$V)OV zS0ghyH4#K!l`$kV+MyZsVKNuYa!tmt5NYC^nx7S8ugkbml}c)MM#3mVtY%VOUgw5S zX{HRzv`zm`uooqUP|7LO^=rwQHqTc!m$|Fy%N8lEImghglJ1&`vL7F+EAn2M8h?DhNx7dJwzL8w3le?Ky;tr2f_yhKM;RK@JMZZT<~a( zj|kor@Q-9Ef;M!b9bM=}A7MX6$Z$JGk-!XL8V^t;)bJPvVHsQS2z@-mbHW#RiC2WL z@dj@R-{Avx2;FFcz!e< zO)pe%O`E=<1U{5_;WtnUL!oVJWLrx#o;H*5aIB>(7EYzQqcO83+Seazx!O!dyQ5~Z zWrKd`3a6uq__AcU&s6Y+65ZV?ljK#0&>Ur8v=B5xu|!ummI|e!*O<~V#z2L1l!j92 zaMw1ceXN11-1fe3a+{1FXJEY5-WT3s6O;A{25P0YsY*q78qEF^D-VckdDS$ z&QB)8J5$13YE?8v-0xP{(WneYdD4aba7okILN%Rb)LTUPo!a0R_ zffZ2N(fs7)A_Jem#pFAh3U&3GUE6fTZuViFLgng#R64N541@zoGaL)ZYJP0MMlUWg zunC(L&MJU^%m1i4?Y}#hCX13C`<|CAJIOR~QHh+g`FA zOT>GmEo@+mw3VHLz70{SJ**A7bP( z50MbN;tZt^b2$)a7+Gxk&~M->P)J`kWX~3_`0MkZ9kjw*+Q0y=R;VCvOqtQ1c$hMV zx|4}Mg+8kBucw;h1cgkqnVG)X&lI)8z)oDlzE|L81G{hwN6`EOajCA+ zaE$dX5=!?*IkT-G#XF|-;#P%u1^Z5?xLE1-deq#hi%v4u0+MiCaDDB3l#lm+gbmU1Fn@6br+wfTfpR;p7XPQW(%Lk7Lbhm-O z6KULW)<8eLfE&CR%v7D6lHh||Omnwn^)DItvZVBJryED-X_4Yy1N&t?Bb>h2r1s*H zhb5(c#lTnbHHC>?y+lza0ZUIPov zfrgH7O^d^+XqPBd0E6cDkb#GAnEXoRQdnMC>K&%MEPY~!hjGMLcGHn>JGEZoXG^vV1 zf7ihG#GwtbM~|7*%Sgu$4E#_!O1A7wTZ>EU(*};|R=RL@?6U^`Sz7(6-b6C(koXq^ z|Eg(kNhD%sIPP@($iTnp@hqX??D+pM@SoCLYSnLN_zMPpBJCwo!F8(-|HT~H*_#-M zMFR0eTA)i;Z=jc|l1lNCftST*r8zqWY5#8nKf|j`#2NTLZ`$;cMvEV>E~1HaJ&vs)S;en(ikO7E2dvR4Z9MN@rYhMwf0-wUSuUxiz88M44^dm$OtiW?o> zBc3;%2=I@@Zp_ME+lI61!~Yw2AIGWM4@04JLLn{ae?&-Vr1O{@eKTWJF|rST zGH^qOtaI0yn)Qrl)bg`sZ!RPysJ1E)~Cu8#`iKrQ-KTu);kX^C-uK< z)%h2O)-CVo46R?&v8IEYhO#AzIDIgl-Vlxrm@b|dP;~c_M1%==^r~pwTr<$O#Z0af zafoI0`WtK^?MAl+Xyz7fN6YCL#hG)05@+AeGXrAhGVM?-H1<+{o+dbl3U2OAH_%Sf zrtL(I)zA=^KY>b2$)a*d#n zOL1!#7L6>WP^-dKBc)Zih8-3>Qd3#H^_@JFINJb)b4OBWHD%VmbfTa8y41iHS%5m^ zF0<63Ez-IwAS>lykyucE<`+)e!D!@slo-y+1EKf; zc`cRNZ6^ltio(fTJ|V&EN+rAa8#Cif5t^<}FLY~bYhNT~?PDy#04h$?cO)YjnSw98 zQ%`KPq>v<1P{ia|cBCMa$s@|sk{wj1!-oWTa>SezZU)PxGg)6}dL88-gHovzw<3(c zGcl0tGMDjynpRb^d2a-bjqA9=7{0wrx_;gl1RsG4)*gX3Sbqd%!7BF=ln0BBpfXtH zIfCk7Rq+wj1nZ8VE?DC|f`(v??+6-$H6=$d`@X43uoy?7Mp2-cv*}gLGWNv2jOfDb3awP9$ zZh7-eZXCXHZ{Eq=9p{-`J$&U@zR9Wq7u%DU(rv`f<+O91`+E1i@VXDe?Gieq^y_E;|k^uvHp>b-G4u@J~p15=lhvjgepaUL9^$9Y_ z8<{=BVfI#=S;=CRMf)&a?(T@@ynMgrJj38Aavo%NIpZtK=mecWuVX&C9^-HWnYtcR za1)dH&6-KcDx-5)Ysq2F57!Bd7M_@TRikRMHMonhFB)u{F@&{)Fu3THiq0Xdm(_XI z?6=!4wb~kko7l10eI>(wMrW3{YSIBuKFe_{{}Q|hO}L$f-p@7c1c1jvtUUN0c5lRYVbX)igd8X`v{pgmXD-ll0F{}$jAzTU9*eiXJ z)1>&$mX!vzmo>_xJJPy(Mssioi6NvG)(>K|Hl;hlRhth5spjq3wJlxj_h&%{B^3yUQCCa4)AH%FAKW;IjuY{!H!kz;CdI+L8v%2=8cT{`skaBVRu zZ;nZAON#^0(vAaUEbZBk<=T{%U~6W~v;}K(XPP~c)_I=h8c(L9xXL|<%Btc)jM9R8 zMDT~S+#7>jWBbOeH@BgT%->H}cz~|(b%LR9U@;!#pP~<8GezpgVf5ph)cM1>mS@{H zF+<*pZ)vqGr%a3a$M_bi#l;!3)R~mq&3Tj5S#0xgc9m*no4}zxjw|g^8CTkq<4Rs} zr4O)*Lp^G?Wnz+X>2OPESm+X1$e%L#DVLv0fgjZZ2W#ZDE;y4gFj)IIRtPk#)AvSK zo4d+gdw_$PF{|7j9v~j0`hqf9q~Tp5nMaGMn11Owh-JDhr1~b>T1jQH(sKdBoa5d7S;># z1CU!oeJdUP`auh|);D+Va#8EAS!2qrF^#!n8l5pSgry<;%^-Z*u33Z3qDa6CtYJT) z)4s^BZeCyteu>WeGV|CgbjX*8tY1YZUZZ+{u0@deC3B7lo76dUPf_qDHCM-U5jJX* zSPC}a6>Zjf_&>Kl>RdI?_Q#j#jpEEFAH(iV6mE|MA$9kuHS{IEe`YV*cez!?=lOis z5dMA;lPmTz0Qm8g#G*WqP|L#oGJRNau4Cam2GbJ z{KLUhuj|cF*-ya;pH)q{PPJnH^L>AFYyM0~A`$}GGd3EyI$m>#GAzod)dPw41 z^E@@4qxklr!+4U{_jx_V>lt3p@p_)uzw`PruZ}|^X2pxl;_^ZQ7NFRQ34Hz~#^4QZ zuij)me2WHon_1*nbkKJg%)jRHzhg#t4}JJOA;%w>N&d*#InMa_0MFqheuO{q4>_ms zB4v1)2g9$bBK$(R@TPL(9p%Aq>EiDzpA$V#@z0IzYQ9bjCmoZXR14HXt%j58JZ;i3 zoV`e$PtP2Sx71?Bky}U4c#JxURbK2?#eom7vecFNM=dT<7ub<=1L;d`maO?x3SV{r zetA5|48*qubzjC9zP}=|)ZnT+ir2C(s>_)wBR(0$ud_yL&IMMHn!|5UE#(%I2ll8` z%Ou7%ZzXV5EKw&=L0zZ|^D^@W7i8=RGjCYTlxLWETbOCg%S;8CsU$OFN5)K%{B6b7 z%srGu5YSYeJ?jr(Vsn+dbp|iH{_I8ZL6k5G=(1JrEaugqjtR}B#-oJd)~X4Z$mb?* z-voKivB)|qnyQvFy^3c~RULeiL^f3`%S9HNlps{gq&|UsE;T{edS9)uW3`%5FG|0Q zTB)YG-rdJ~C~o{)G3tAwM^R#?^$%7nn;Y2t3a_6I;r|xY$wOw$2hNyAHoq+-^cZ;< zHiq%dAt!H?pL^kPKfp0lD*3lPHoTX!6PU-60?JaV&R{WUV(FZWW|qYT1UgFzsxDH^ z2(yGn)hwi04|l0ny6zl&PPOIO@-9bfcd3=yu@*3+t#Ta84^K5KM5AgPLyhnw9ov}q zQ%8~;+eL!E1lDo^)m|20EliPs)ND4;P>QM2tJ(>X7EqLh{IKvmw5UZy35zwmRw{0H z*lo996CqayUd_nBD;*I$Pbfc$XWH#bt);%jUzcj3iYQc*g%q_Y^wNqGsAE!qx=4M(_EPSowBPS$l^Biz1sXC@3u5HW zL5$lna>x$AHihpr!3Ff})jJ!yorr!AO}eU3@{Dqv=x5 zf!{@5!cSE;(X%%5GrG(8<=N%9R$akQkit0;yxY;pZbu`#HRO{B-mM{@i+klcS~pe% z(?7>mSDv7r1JusNTvwY}nYNjaQ9B>nw4H8t%aj^HkIp<_K8Q0YE?>(WO^J)>e)pAv z1T#aaU1yp(i27RhfsAhb&WwmNqq)=eq%(#1!g|8X1|e17${}CN%rrPtgPzxIf6MB3 zF?Tvp5jwkx@v56&_V!|)it@{atwbd;T&4POql$B5+0R(N3VT%&UsWkQ%KMXQ08gv! zju-Bu-Xt4Jwmar%|CpowW0pT^FRX-7K4x5{f7~el3D%wo$KfHMQR^IsypLogksdGH zA**v7GDpp=+9+derSnaj#q$wn@q9e9*sIL6>>~`x_OQ&}0tBR+rRp>zNws=4SnH9b zkTsG<|LPhB!Lzdzr(o=q+ zV|51+$nAJfeTqftPA5Q~XBO6_OLXiQ>$qdA<4&j?w?ajmZ7j+dAhovL8dROOn~Q-d l2Z0-u06f`u-^UOIQJD+3sZB~Cp9YELKJMRktIHOR|1;p)aqa*B literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationFrame.java b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationFrame.java new file mode 100644 index 00000000..13aac2c9 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationFrame.java @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl.verifier; + +import java.util.Arrays; + +/** + * @see hotspot/share/classfile/stackMapFrame.hpp + * @see hotspot/share/classfile/stackMapFrame.cpp + */ +class VerificationFrame { + + public static final int FLAG_THIS_UNINIT = 0x01; + + private int _offset; + private int _locals_size, _stack_size; + private int _stack_mark; + private final int _max_locals, _max_stack; + private int _flags; + private final VerificationType[] _locals, _stack; + private final VerifierImpl _verifier; + + public VerificationFrame(int offset, int flags, int locals_size, int stack_size, int max_locals, int max_stack, VerificationType[] locals, VerificationType[] stack, VerifierImpl v) { + this._offset = offset; + this._locals_size = locals_size; + this._stack_size = stack_size; + this._stack_mark = -1; + this._max_locals = max_locals; + this._max_stack = max_stack; + this._flags = flags; + this._locals = locals; + this._stack = stack; + this._verifier = v; + } + + @Override + public String toString() { + return "frame @" + _offset + " with locals " + (_locals == null ? "[]" : Arrays.asList(_locals)) + " and stack " + (_stack == null ? "[]" : Arrays.asList(_stack)); + } + + void set_offset(int offset) { + this._offset = offset; + } + + void set_flags(int flags) { + _flags = flags; + } + + void set_locals_size(int locals_size) { + _locals_size = locals_size; + } + + void set_stack_size(int stack_size) { + _stack_size = _stack_mark = stack_size; + } + + int offset() { + return _offset; + } + + VerifierImpl verifier() { + return _verifier; + } + + int flags() { + return _flags; + } + + int locals_size() { + return _locals_size; + } + + VerificationType[] locals() { + return _locals; + } + + int stack_size() { + return _stack_size; + } + + VerificationType[] stack() { + return _stack; + } + + int max_locals() { + return _max_locals; + } + + boolean flag_this_uninit() { + return (_flags & FLAG_THIS_UNINIT) == FLAG_THIS_UNINIT; + } + + void reset() { + for (int i = 0; i < _max_locals; i++) { + _locals[i] = VerificationType.bogus_type; + } + for (int i = 0; i < _max_stack; i++) { + _stack[i] = VerificationType.bogus_type; + } + } + + void set_mark() { + if (_stack_mark != -1) { + for (int i = _stack_mark - 1; i >= _stack_size; --i) { + _stack[i] = VerificationType.bogus_type; + } + _stack_mark = _stack_size; + } + } + + void push_stack(VerificationType type) { + if (type.is_check()) _verifier.verifyError("Must be a real type"); + if (_stack_size >= _max_stack) { + _verifier.verifyError("Operand stack overflow"); + } + _stack[_stack_size++] = type; + } + + void push_stack_2(VerificationType type1, VerificationType type2) { + if (!(type1.is_long() || type1.is_double())) _verifier.verifyError("must be long/double"); + if (!(type2.is_long2() || type2.is_double2())) _verifier.verifyError("must be long/double_2"); + if (_stack_size >= _max_stack - 1) { + _verifier.verifyError("Operand stack overflow"); + } + _stack[_stack_size++] = type1; + _stack[_stack_size++] = type2; + } + + VerificationType pop_stack() { + if (_stack_size <= 0) { + _verifier.verifyError("Operand stack underflow"); + } + return _stack[--_stack_size]; + } + + VerificationType pop_stack(VerificationType type) { + if (_stack_size != 0) { + VerificationType top = _stack[_stack_size - 1]; + boolean subtype = type.is_assignable_from(top, verifier()); + if (subtype) { + --_stack_size; + return top; + } + } + return pop_stack_ex(type); + } + + void pop_stack_2(VerificationType type1, VerificationType type2) { + if (!(type1.is_long2() || type1.is_double2())) _verifier.verifyError("must be long/double"); + if (!(type2.is_long() || type2.is_double())) _verifier.verifyError("must be long/double_2"); + if (_stack_size >= 2) { + VerificationType top1 = _stack[_stack_size - 1]; + boolean subtype1 = type1.is_assignable_from(top1, verifier()); + VerificationType top2 = _stack[_stack_size - 2]; + boolean subtype2 = type2.is_assignable_from(top2, verifier()); + if (subtype1 && subtype2) { + _stack_size -= 2; + return; + } + } + pop_stack_ex(type1); + pop_stack_ex(type2); + } + + VerificationFrame(int max_locals, int max_stack, VerifierImpl verifier) { + _offset = 0; + _locals_size = 0; + _stack_size = 0; + _stack_mark = 0; + _max_locals = max_locals; + _max_stack = max_stack; + _flags = 0; + _verifier = verifier; + _locals = new VerificationType[max_locals]; + _stack = new VerificationType[max_stack]; + for (int i = 0; i < max_locals; i++) { + _locals[i] = VerificationType.bogus_type; + } + for (int i = 0; i < max_stack; i++) { + _stack[i] = VerificationType.bogus_type; + } + } + + VerificationFrame frame_in_exception_handler(int flags) { + return new VerificationFrame(_offset, flags, _locals_size, 0, + _max_locals, _max_stack, _locals, new VerificationType[1], + _verifier); + } + + void initialize_object(VerificationType old_object, VerificationType new_object) { + int i; + for (i = 0; i < _max_locals; i++) { + if (_locals[i].equals(old_object)) { + _locals[i] = new_object; + } + } + for (i = 0; i < _stack_size; i++) { + if (_stack[i].equals(old_object)) { + _stack[i] = new_object; + } + } + if (old_object.is_uninitialized_this(_verifier)) { + _flags = 0; + } + } + + VerificationType set_locals_from_arg(VerificationWrapper.MethodWrapper m, VerificationType thisKlass) { + var ss = new VerificationSignature(m.descriptor(), true, _verifier); + int init_local_num = 0; + if (!m.isStatic()) { + init_local_num++; + if (VerifierImpl.object_initializer_name.equals(m.name()) && !VerifierImpl.java_lang_Object.equals(thisKlass.name())) { + _locals[0] = VerificationType.uninitialized_this_type; + _flags |= FLAG_THIS_UNINIT; + } else { + _locals[0] = thisKlass; + } + } + while (!ss.atReturnType()) { + init_local_num += _verifier.change_sig_to_verificationType(ss, _locals, init_local_num); + ss.next(); + } + _locals_size = init_local_num; + switch (ss.type()) { + case T_OBJECT: + case T_ARRAY: + { + String sig = ss.asSymbol(); + return VerificationType.reference_type(sig); + } + case T_INT: return VerificationType.integer_type; + case T_BYTE: return VerificationType.byte_type; + case T_CHAR: return VerificationType.char_type; + case T_SHORT: return VerificationType.short_type; + case T_BOOLEAN: return VerificationType.boolean_type; + case T_FLOAT: return VerificationType.float_type; + case T_DOUBLE: return VerificationType.double_type; + case T_LONG: return VerificationType.long_type; + case T_VOID: return VerificationType.bogus_type; + default: + _verifier.verifyError("Should not reach here"); + return VerificationType.bogus_type; + } + } + + void copy_locals(VerificationFrame src) { + int len = src.locals_size() < _locals_size ? src.locals_size() : _locals_size; + if (len > 0) System.arraycopy(src.locals(), 0, _locals, 0, len); + } + + void copy_stack(VerificationFrame src) { + int len = src.stack_size() < _stack_size ? src.stack_size() : _stack_size; + if (len > 0) System.arraycopy(src.stack(), 0, _stack, 0, len); + } + + private int is_assignable_to(VerificationType[] from, VerificationType[] to, int len) { + int i = 0; + for (; i < len; i++) { + if (!to[i].is_assignable_from(from[i], verifier())) { + break; + } + } + return i; + } + + boolean is_assignable_to(VerificationFrame target) { + if (_max_locals != target.max_locals()) { + _verifier.verifyError("Locals size mismatch", this, target); + } + if (_stack_size != target.stack_size()) { + _verifier.verifyError("Stack size mismatch", this, target); + } + int mismatch_loc; + mismatch_loc = is_assignable_to(_locals, target.locals(), target.locals_size()); + if (mismatch_loc != target.locals_size()) { + _verifier.verifyError("Bad type", this, target); + } + mismatch_loc = is_assignable_to(_stack, target.stack(), _stack_size); + if (mismatch_loc != _stack_size) { + _verifier.verifyError("Bad type", this, target); + } + + if ((_flags | target.flags()) == target.flags()) { + return true; + } else { + _verifier.verifyError("Bad flags", this, target); + } + return false; + } + + VerificationType pop_stack_ex(VerificationType type) { + if (_stack_size <= 0) { + _verifier.verifyError("Operand stack underflow"); + } + VerificationType top = _stack[--_stack_size]; + boolean subtype = type.is_assignable_from(top, verifier()); + if (!subtype) { + _verifier.verifyError("Bad type on operand stack"); + } + return top; + } + + VerificationType get_local(int index, VerificationType type) { + if (index >= _max_locals) { + _verifier.verifyError("Local variable table overflow"); + } + boolean subtype = type.is_assignable_from(_locals[index], + verifier()); + if (!subtype) { + _verifier.verifyError("Bad local variable type"); + } + if(index >= _locals_size) { _locals_size = index + 1; } + return _locals[index]; + } + + void get_local_2(int index, VerificationType type1, VerificationType type2) { + if (!(type1.is_long() || type1.is_double())) _verifier.verifyError("must be long/double"); + if (!(type2.is_long2() || type2.is_double2())) _verifier.verifyError("must be long/double_2"); + if (index >= _locals_size - 1) { + _verifier.verifyError("get long/double overflows locals"); + } + boolean subtype = type1.is_assignable_from(_locals[index], verifier()); + if (!subtype) { + _verifier.verifyError("Bad local variable type"); + } else { + subtype = type2.is_assignable_from(_locals[index + 1], verifier()); + if (!subtype) { + _verifier.verifyError("Bad local variable type"); + } + } + } + + void set_local(int index, VerificationType type) { + if (type.is_check()) _verifier.verifyError("Must be a real type"); + if (index >= _max_locals) { + _verifier.verifyError("Local variable table overflow"); + } + if (_locals[index].is_double() || _locals[index].is_long()) { + if ((index + 1) >= _locals_size) _verifier.verifyError("Local variable table overflow"); + _locals[index + 1] = VerificationType.bogus_type; + } + if (_locals[index].is_double2() || _locals[index].is_long2()) { + if (index < 1) _verifier.verifyError("Local variable table underflow"); + _locals[index - 1] = VerificationType.bogus_type; + } + _locals[index] = type; + if (index >= _locals_size) { + for (int i=_locals_size; i= _max_locals - 1) { + _verifier.verifyError("Local variable table overflow"); + } + if (_locals[index+1].is_double() || _locals[index+1].is_long()) { + if ((index + 2) >= _locals_size) _verifier.verifyError("Local variable table overflow"); + _locals[index + 2] = VerificationType.bogus_type; + } + if (_locals[index].is_double2() || _locals[index].is_long2()) { + if (index < 1) _verifier.verifyError("Local variable table underflow"); + _locals[index - 1] = VerificationType.bogus_type; + } + _locals[index] = type1; + _locals[index+1] = type2; + if (index >= _locals_size - 1) { + for (int i=_locals_size; i#V(2e){v9 z?*PQ`UI0x7`cF-rj=05&Q!d(tNWNgt&riDrC*sb|6(VPxvODcM<;bLd$lDdSRJ7cg zqFq@iI{`Es825FAB`rJnSOx*3^IA$lhNeS zxMg7U`0{+M5DwtB00spPBFb#$3#FoCU{z0V@|1nXjuhpV^x9C<5 z7+BM2s=hPPJE^iVE|5anKy!svZNNwbaJzvmi*6+f1!u-CM9VV^vre%RKbv>v)TIi5 z8C<)lS2H`b;1;HwatISRs=Syq;Ops~G;z$p%2cV+Wp^<^cdAPr*Wa~WDc&h?9Cy)O zdv4AtP8ry_gu9J_UUd{Bp1?iIM9#p5p4fjYny?w5J~A&b1%_)@N;PBu{95%Sg>VEj zDvpx|RxjlhBMXF>#?wlvz=SNJlwhh&w3=u)vBJbE6KhR$n%HQf%fwa_+f4MDxZXs> z#EmBQnYcySd{p2uoKpp>YhvC&qNjJ6N|xEaVzfC{nqn$Cl5WvSEzF*9${G7afs#9y zh=tkx-`#hydkz=~Crf#|Flm=vby)qx=Au2zgTw!>a|3eRshliL9kI*QVe@A?nky$= zLh$eYPEik&%~mm8F3mQG6S^*z$MdEmF6o3M50)9%DRa-Dr0}ov4gu=XfaOL zl?Sg;(+nVT>}cey(a8Ctkt0PT=ZHqm4vm}`8aXC3ax!S-G|4{VgiO{LqHMt)_JdSfP@C4ZwqWTMY*na`H{(u9YlNorD|NZ*iM(U5?DKu&Q zy+pMm6!!I9!q5-!DgCCa^q;0g)U@yno+W#ZtA*RnDOFxY=5IoQGf)Sr4KL%R@&M;~v6QjCxpIMbyK(Dh52PuVSBvO;toZY_6i$Lw6NhFXKq| zGA6PYkqO^%0ol$AxI26=A1>g;MNEIMK8H^`-_IX6z|A;|{dklg|0&$cq}+zr5XCzz z(hm^FM;OJ&NZ>OZ#+Mk!H_YZQ+_U%zf5j_0HLuauDzyE9vn`8%xd41Jq}pmN!PHdW zlflXr-@=#mFb?usX9h3F1e;O^yH>2Y+T?@Ouz(t%oj~2~l zn@!DvniX55UsIuJ$uDcVwViVTSyK+{xA&PcsFhc1T9$qp(tMrf^D-b?HD9lJMVeA* zzDe^18I*0BZ`S;b49RxQyEVUGw#p98w`+b@3Mn=3)BFM1CRb>_Q}YL9y9{f-Tl0rx zhg_-o9?c(?Qsy@ zZ`*dfhaOf=FD{`EKT`8&{s#RGJMlYq8JxwegW3gr18>r16W)Tl9IAP|LktmpT<;!S F_ZLnA;?n>C literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationSignature.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationSignature.class new file mode 100644 index 0000000000000000000000000000000000000000..21314aee3d54ec6f7811c895bafc7aeb813be114 GIT binary patch literal 6442 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 Cz literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationSignature.java b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationSignature.java new file mode 100644 index 00000000..9fa4a377 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationSignature.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl.verifier; + +final class VerificationSignature { + + enum BasicType { + T_BOOLEAN(4), + T_CHAR(5), + T_FLOAT(6), + T_DOUBLE(7), + T_BYTE(8), + T_SHORT(9), + T_INT(10), + T_LONG(11), + T_OBJECT(12), + T_ARRAY(13), + T_VOID(14), + T_ADDRESS(15), + T_NARROWOOP(16), + T_METADATA(17), + T_NARROWKLASS(18), + T_CONFLICT(19), + T_ILLEGAL(99); + + final int type; + + BasicType(int type) { + this.type = type; + } + + static BasicType fromSignature(char ch) { + return switch (ch) { + case JVM_SIGNATURE_BOOLEAN -> + T_BOOLEAN; + case JVM_SIGNATURE_CHAR -> + T_CHAR; + case JVM_SIGNATURE_FLOAT -> + T_FLOAT; + case JVM_SIGNATURE_DOUBLE -> + T_DOUBLE; + case JVM_SIGNATURE_BYTE -> + T_BYTE; + case JVM_SIGNATURE_SHORT -> + T_SHORT; + case JVM_SIGNATURE_INT -> + T_INT; + case JVM_SIGNATURE_LONG -> + T_LONG; + case JVM_SIGNATURE_CLASS -> + T_OBJECT; + case JVM_SIGNATURE_ARRAY -> + T_ARRAY; + case JVM_SIGNATURE_VOID -> + T_VOID; + default -> + throw new IllegalArgumentException("Not a valid type: '" + ch + "'"); + }; + } + } + + static final char JVM_SIGNATURE_DOT = '.', + JVM_SIGNATURE_ARRAY = '[', + JVM_SIGNATURE_BYTE = 'B', + JVM_SIGNATURE_CHAR = 'C', + JVM_SIGNATURE_CLASS = 'L', + JVM_SIGNATURE_ENDCLASS = ';', + JVM_SIGNATURE_FLOAT = 'F', + JVM_SIGNATURE_DOUBLE = 'D', + JVM_SIGNATURE_FUNC = '(', + JVM_SIGNATURE_ENDFUNC = ')', + JVM_SIGNATURE_INT = 'I', + JVM_SIGNATURE_LONG = 'J', + JVM_SIGNATURE_SHORT = 'S', + JVM_SIGNATURE_VOID = 'V', + JVM_SIGNATURE_BOOLEAN = 'Z'; + + static boolean isReferenceType(BasicType t) { + return t == BasicType.T_OBJECT || t == BasicType.T_ARRAY; + } + + private static final char TYPE2CHAR_TAB[] = new char[]{ + 0, 0, 0, 0, + JVM_SIGNATURE_BOOLEAN, JVM_SIGNATURE_CHAR, + JVM_SIGNATURE_FLOAT, JVM_SIGNATURE_DOUBLE, + JVM_SIGNATURE_BYTE, JVM_SIGNATURE_SHORT, + JVM_SIGNATURE_INT, JVM_SIGNATURE_LONG, + JVM_SIGNATURE_CLASS, JVM_SIGNATURE_ARRAY, + JVM_SIGNATURE_VOID, 0, + 0, 0, 0, 0 + }; + + static boolean hasEnvelope(char signature_char) { + return signature_char == JVM_SIGNATURE_CLASS; + } + + private BasicType type; + private final String signature; + private final int limit; + private int begin, end, arrayPrefix, state; + + private static final int S_FIELD = 0, S_METHOD = 1, S_METHOD_RETURN = 3; + + boolean atReturnType() { + return state == S_METHOD_RETURN; + } + + boolean isReference() { + return isReferenceType(type); + } + + BasicType type() { + return type; + } + + private int rawSymbolBegin() { + return begin + (hasEnvelope() ? 1 : 0); + } + + private int rawSymbolEnd() { + return end - (hasEnvelope() ? 1 : 0); + } + + private boolean hasEnvelope() { + return hasEnvelope(signature.charAt(begin)); + } + + String asSymbol() { + int begin = rawSymbolBegin(); + int end = rawSymbolEnd(); + return signature.substring(begin, end); + } + + int skipArrayPrefix(int max_skip_length) { + if (type != BasicType.T_ARRAY) { + return 0; + } + if (arrayPrefix > max_skip_length) { + // strip some but not all levels of T_ARRAY + arrayPrefix -= max_skip_length; + begin += max_skip_length; + return max_skip_length; + } + return skipWholeArrayPrefix(); + } + + static BasicType decodeSignatureChar(char ch) { + return BasicType.fromSignature(ch); + } + + private final VerifierImpl context; + + VerificationSignature(String signature, boolean is_method, VerifierImpl context) { + this.signature = signature; + this.limit = signature.length(); + int oz = is_method ? S_METHOD : S_FIELD; + this.state = oz; + this.begin = this.end = oz; + this.arrayPrefix = 0; + this.context = context; + next(); + } + + private int scanType(BasicType type) { + int e = end; + int tem; + switch (type) { + case T_OBJECT: + tem = signature.indexOf(JVM_SIGNATURE_ENDCLASS, e); + return tem < 0 ? limit : tem + 1; + case T_ARRAY: + while (e < limit && signature.charAt(e) == JVM_SIGNATURE_ARRAY) { + e++; + } + arrayPrefix = e - end; + if (hasEnvelope(signature.charAt(e))) { + tem = signature.indexOf(JVM_SIGNATURE_ENDCLASS, e); + return tem < 0 ? limit : tem + 1; + } + return e + 1; + default: + return e + 1; + } + } + + void next() { + final String sig = signature; + int len = limit; + testLen(len); + begin = end; + char ch = sig.charAt(begin); + if (ch == JVM_SIGNATURE_ENDFUNC) { + state = S_METHOD_RETURN; + begin = ++end; + testLen(len); + ch = sig.charAt(begin); + } + try { + BasicType bt = decodeSignatureChar(ch); + type = bt; + end = scanType(bt); + } catch (IllegalArgumentException iae) { + throw new IllegalArgumentException("Not a valid signature: '" + signature + "'", iae); + } + } + + private void testLen(int len) { + if (end >= len) { + if (context == null) { + throw new IllegalArgumentException("Invalid signature " + signature); + } else { + context.verifyError("Invalid signature " + signature); + } + } + } + + int skipWholeArrayPrefix() { + int whole_array_prefix = arrayPrefix; + int new_begin = begin + whole_array_prefix; + begin = new_begin; + char ch = signature.charAt(new_begin); + BasicType bt = decodeSignatureChar(ch); + type = bt; + return whole_array_prefix; + } + + @SuppressWarnings("fallthrough") + static int isValidType(String type, int limit) { + int index = 0; + + // Iterate over any number of array dimensions + while (index < limit && type.charAt(index) == JVM_SIGNATURE_ARRAY) { + ++index; + } + if (index >= limit) { + return -1; + } + switch (type.charAt(index)) { + case JVM_SIGNATURE_BYTE: + case JVM_SIGNATURE_CHAR: + case JVM_SIGNATURE_FLOAT: + case JVM_SIGNATURE_DOUBLE: + case JVM_SIGNATURE_INT: + case JVM_SIGNATURE_LONG: + case JVM_SIGNATURE_SHORT: + case JVM_SIGNATURE_BOOLEAN: + case JVM_SIGNATURE_VOID: + return index + 1; + case JVM_SIGNATURE_CLASS: + for (index = index + 1; index < limit; ++index) { + char c = type.charAt(index); + switch (c) { + case JVM_SIGNATURE_ENDCLASS: + return index + 1; + case '\0': + case JVM_SIGNATURE_DOT: + case JVM_SIGNATURE_ARRAY: + return -1; + default: ; // fall through + } + } + // fall through + default: ; // fall through + } + return -1; + } + + static boolean isValidMethodSignature(String method_sig) { + if (method_sig != null) { + int len = method_sig.length(); + int index = 0; + if (len > 1 && method_sig.charAt(index) == JVM_SIGNATURE_FUNC) { + ++index; + while (index < len && method_sig.charAt(index) != JVM_SIGNATURE_ENDFUNC) { + int res = isValidType(method_sig.substring(index), len - index); + if (res == -1) { + return false; + } else { + index += res; + } + } + if (index < len && method_sig.charAt(index) == JVM_SIGNATURE_ENDFUNC) { + // check the return type + ++index; + return (isValidType(method_sig.substring(index), len - index) == (len - index)); + } + } + } + return false; + } + + static boolean isValidTypeSignature(String sig) { + if (sig == null) return false; + int len = sig.length(); + return (len >= 1 && (isValidType(sig, len) == len)); + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable$StackMapReader.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable$StackMapReader.class new file mode 100644 index 0000000000000000000000000000000000000000..1cec8a2e9ac774758a4a623e8b8a3aec065b1967 GIT binary patch literal 7982 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 Lxs+x5&*1wX?WN3s literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable$StackMapStream.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable$StackMapStream.class new file mode 100644 index 0000000000000000000000000000000000000000..b599486c04a06e3df165f55a4f753aada6806fff GIT binary patch literal 1292 zcmbVMK~vLE5dK~hnzRNA1*!;YRn#^hwW5fE4g(@~rosWIGs2<1rVj|T36s7ucyatG zdh+7M8NnG396k7>)O~4@&Nv?GA=%C5?S9|xe#wuY-%bE5;eH$uXa;l(J%}>&@A3nl zt8s5Tw^rE|j%0|=yPhkbFld=}#TF$BQMq|sZiJV*C zujLLz;BL7h$dy9J;nMZJm%LIFx zDh?S~L4}hR1~J4CE1#BTm@alfK?DUNHfJKmaE&{TXf)Cl@y7S6X}KfPf~>!l=28Z3 zr71-m7cgSrqJ>e6G32{OVu*(`Sq=g}U>MF6&&ErwyWaL(wiKt%E?c;QG&Q^}WVx9S zXI)^J&1^3IM}OH8gTCZf1w*3fdSbO%uZSR=JVUbRJG@rnfvYyr4(f8pZ7{5K1NQHI z&e0M zR}Zd&Bt>3DeNSYE?5|+<#1RZzJ3_BLd4z$_6p!FK-BXkS%uwzF#4w9KJfv!mFiz2Q zD<3y-lb)y&ZV@gEy$n4mHYAodUY#nbcX|5@jPFR0=~eE@2UuhWlEcS1uLAZfdb6Rw zCNk3l`1SS^C21j0iXxM+k8!ErJe(g@ z&O24O)usBk08eRx%VE(}>v+4U2?G-}NyUB=x7+=!(HRvPQJg#bc@IPX2wgkl9Ssi_ iI{1!s@Qp$n)D}ommG literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable.class new file mode 100644 index 0000000000000000000000000000000000000000..91681415e19cb39ac690c71bc4f7b7e7f0711944 GIT binary patch literal 4631 zcmd5{BU`p~q#hkR zhPJdMq;Wz*dT%jpnvl-qB`@t1C(};)(zpJQ{)f(l(r@h}2}39|a$Y(fYv0#i>s#Mi zYoCAq=dXVUa2OxO5J1pC$V3C7 zUtwDvXN`K=cHOc&l%BR`(msje*oEB&224DOJqml8@TL!wLPE3X{1FkYkff~*3XXej z!I>TIoe)s=nfQiKG?tsQa|>D9nTeB(gC?HBex4H;3(kzaOfbu(Y@Oqwo{W$@fFTpZ zIH1s4vb@|}mLAS6l&p%vGaE)XlbM|Cos5F9vHQq!h0#K7(^k4JJFT-q+VaxVuI1$B z(w^l~&Gh5c{8@ayg$|mq4wTvsrh}t6X5cv! z89aYiI@woH1d`g>ikMUK2fLP0Wc+ z;e64Wt;)>2i3O1n6B)JH07^nsM`2{c*w$!CZamkC?>mF!K}v z9W6Na*kWngc56khZB%?TVYvlye{C}4%@wK&`1M~ zN_^5}9LIJK%QM+#4rs0W#($C-_<+oB;yrNJBTS+FKF_dqm-tE`&C1@!$9#ytd}p!O zCU1G&^7XA-K33Tp{O5xU3g2UIfURO1?)wYWC+q~^@;9Ozo15~V)vR3;(#pb?L^d`3a4V`ED zQ{iMJWu&5?qI)RTmyFy*x-S)5!(%t0`b6o^Vcvuxz4tM>b0{7hOe7OBynz=|u~a;n zScMV#7@=TyGPH&#hD^~mnMj%ADU&J>wj^7UksCAez7Pm7zH;GG_ z!rM5Dt6cjf&fyv?jn7qDK8>9?j|)WGrMykVr-g5#7x8`e5|nltKj5l3aWG5m&_*tN1Zb1ajr+p7_d4f<7OS|7H#8Ym@e>jw%3CkuO|0-^?JchV z0g>BOz%&pr@U{U{DYpE-VqlknPMHC2^Hbx&TX5`OwV+^SKS;X#|I=CK8{ z{F<||4fEP3X+RYnEEC)zJ_%@)q6mJ0fa(xz`B|g#-q*E;Zw`k0`n!^0 z&AzAa1cyoMp}=NjOR$|83xTfUPA@1bN6MgzQMmYHDY<% zc#KKtXS6oT6Hnpi?8U_H28t^U6jvH3uHYBkCwy7acuI(@XgtHz=PX0>0@rslV1Gr7 z4ejWM5ivV%VT(}n7Ir8V{5Nwh@N4|0=5)DRB<-QML%}r^N4l?JQx_c|luXwhQ2vqw z?&Os=E#L}Gc!ykkm!FdFX+!&b!40GKG>qC)Gb+aKWS<%myNsGIkWwAA@wXfXm}pkn e3TZoW9lvLPE7v+XexJx)VX%M5_BzKm5dAM2sj3wK literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable.java b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable.java new file mode 100644 index 00000000..db07e0aa --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationTable.java @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl.verifier; + +import static jdk.internal.classfile.impl.verifier.VerificationType.*; + +/** + * @see hotspot/share/classfile/stackMapTable.hpp + * @see hotspot/share/classfile/stackMapTable.cpp + */ +class VerificationTable { + + private final int _code_length; + private final int _frame_count; + private final VerificationFrame[] _frame_array; + private final VerifierImpl _verifier; + + int get_frame_count() { + return _frame_count; + } + + int get_offset(int index) { + return _frame_array[index].offset(); + } + + static class StackMapStream { + + private final byte[] _data; + private int _index; + private final VerifierImpl _verifier; + + StackMapStream(byte[] ah, VerifierImpl context) { + _data = ah; + _index = 0; + _verifier = context; + } + + int get_u1() { + if (_data == null || _index >= _data.length) { + _verifier.classError("access beyond the end of attribute"); + } + return _data[_index++] & 0xff; + } + + int get_u2() { + int res = get_u1() << 8; + return res | get_u1(); + } + + boolean at_end() { + return (_data == null) || (_index == _data.length); + } + } + + VerificationTable(byte[] stackmap_data, VerificationFrame init_frame, int max_locals, int max_stack, byte[] code_data, int code_len, + VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl v) { + _verifier = v; + var reader = new StackMapReader(stackmap_data, code_data, code_len, cp, v); + _code_length = code_len; + _frame_count = reader.get_frame_count(); + _frame_array = new VerificationFrame[_frame_count]; + if (_frame_count > 0) { + VerificationFrame pre_frame = init_frame; + for (int i = 0; i < _frame_count; i++) { + VerificationFrame frame = reader.next(pre_frame, i == 0, max_locals, max_stack); + _frame_array[i] = frame; + int offset = frame.offset(); + if (offset >= code_len || code_data[offset] == 0) { + _verifier.verifyError("StackMapTable error: bad offset"); + } + pre_frame = frame; + } + } + reader.check_end(); + } + + int get_index_from_offset(int offset) { + int i = 0; + for (; i < _frame_count; i++) { + if (_frame_array[i].offset() == offset) { + return i; + } + } + return i; + } + + boolean match_stackmap(VerificationFrame frame, int target, boolean match, boolean update) { + int index = get_index_from_offset(target); + return match_stackmap(frame, target, index, match, update); + } + + boolean match_stackmap(VerificationFrame frame, int target, int frame_index, boolean match, boolean update) { + if (frame_index < 0 || frame_index >= _frame_count) { + _verifier.verifyError(String.format("Expecting a stackmap frame at branch target %d", target)); + } + VerificationFrame stackmap_frame = _frame_array[frame_index]; + boolean result = true; + if (match) { + result = frame.is_assignable_to(stackmap_frame); + } + if (update) { + int lsize = stackmap_frame.locals_size(); + int ssize = stackmap_frame.stack_size(); + if (frame.locals_size() > lsize || frame.stack_size() > ssize) { + frame.reset(); + } + frame.set_locals_size(lsize); + frame.copy_locals(stackmap_frame); + frame.set_stack_size(ssize); + frame.copy_stack(stackmap_frame); + frame.set_flags(stackmap_frame.flags()); + } + return result; + } + + void check_jump_target(VerificationFrame frame, int target) { + boolean match = match_stackmap(frame, target, true, false); + if (!match || (target < 0 || target >= _code_length)) { + _verifier.verifyError(String.format("Inconsistent stackmap frames at branch target %d", target)); + } + } + + static class StackMapReader { + + private final VerificationWrapper.ConstantPoolWrapper _cp; + private final StackMapStream _stream; + private final byte[] _code_data; + private final int _code_length; + private final int _frame_count; + + void check_verification_type_array_size(int size, int max_size) { + if (size < 0 || size > max_size) { + _verifier.classError("StackMapTable format error: bad type array size"); + } + } + + private static final int + SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, + SAME_EXTENDED = 251, + FULL = 255; + + public int get_frame_count() { + return _frame_count; + } + + public void check_end() { + if (!_stream.at_end()) { + _verifier.classError("wrong attribute size"); + } + } + + private final VerifierImpl _verifier; + + public StackMapReader(byte[] stackmapData, byte[] code_data, int code_len, VerificationWrapper.ConstantPoolWrapper cp, VerifierImpl context) { + this._verifier = context; + _stream = new StackMapStream(stackmapData, _verifier); + if (stackmapData != null) { + _frame_count = _stream.get_u2(); + } else { + _frame_count = 0; + } + _code_data = code_data; + _code_length = code_len; + _cp = cp; + } + + int chop(VerificationType[] locals, int length, int chops) { + if (locals == null) return -1; + int pos = length - 1; + for (int i=0; i= nconstants || _cp.tagAt(class_index) != VerifierImpl.JVM_CONSTANT_Class) { + _verifier.classError("bad class index"); + } + return VerificationType.reference_type(_cp.classNameAt(class_index)); + } + if (tag == ITEM_UninitializedThis) { + if (flags != null) { + flags[0] |= VerificationFrame.FLAG_THIS_UNINIT; + } + return VerificationType.uninitialized_this_type; + } + if (tag == ITEM_Uninitialized) { + int offset = _stream.get_u2(); + if (offset >= _code_length || _code_data[offset] != VerifierImpl.NEW_OFFSET) { + _verifier.classError("StackMapTable format error: bad offset for Uninitialized"); + } + return VerificationType.uninitialized_type(offset); + } + _verifier.classError("bad verification type"); + return VerificationType.bogus_type; + } + + public VerificationFrame next(VerificationFrame pre_frame, boolean first, int max_locals, int max_stack) { + VerificationFrame frame; + int offset; + VerificationType[] locals = null; + int frame_type = _stream.get_u1(); + if (frame_type < 64) { + if (first) { + offset = frame_type; + if (pre_frame.locals_size() > 0) { + locals = new VerificationType[pre_frame.locals_size()]; + } + } else { + offset = pre_frame.offset() + frame_type + 1; + locals = pre_frame.locals(); + } + frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), 0, max_locals, max_stack, locals, null, _verifier); + if (first && locals != null) { + frame.copy_locals(pre_frame); + } + return frame; + } + if (frame_type < 128) { + if (first) { + offset = frame_type - 64; + if (pre_frame.locals_size() > 0) { + locals = new VerificationType[pre_frame.locals_size()]; + } + } else { + offset = pre_frame.offset() + frame_type - 63; + locals = pre_frame.locals(); + } + VerificationType[] stack = new VerificationType[2]; + int stack_size = 1; + stack[0] = parse_verification_type(null); + if (stack[0].is_category2()) { + stack[1] = stack[0].to_category2_2nd(_verifier); + stack_size = 2; + } + check_verification_type_array_size(stack_size, max_stack); + frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), stack_size, max_locals, max_stack, locals, stack, _verifier); + if (first && locals != null) { + frame.copy_locals(pre_frame); + } + return frame; + } + int offset_delta = _stream.get_u2(); + if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) { + _verifier.classError("reserved frame type"); + } + if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { + if (first) { + offset = offset_delta; + if (pre_frame.locals_size() > 0) { + locals = new VerificationType[pre_frame.locals_size()]; + } + } else { + offset = pre_frame.offset() + offset_delta + 1; + locals = pre_frame.locals(); + } + VerificationType[] stack = new VerificationType[2]; + int stack_size = 1; + stack[0] = parse_verification_type(null); + if (stack[0].is_category2()) { + stack[1] = stack[0].to_category2_2nd(_verifier); + stack_size = 2; + } + check_verification_type_array_size(stack_size, max_stack); + frame = new VerificationFrame(offset, pre_frame.flags(), pre_frame.locals_size(), stack_size, max_locals, max_stack, locals, stack, _verifier); + if (first && locals != null) { + frame.copy_locals(pre_frame); + } + return frame; + } + if (frame_type <= SAME_EXTENDED) { + locals = pre_frame.locals(); + int length = pre_frame.locals_size(); + int chops = SAME_EXTENDED - frame_type; + int new_length = length; + int flags = pre_frame.flags(); + if (chops != 0) { + new_length = chop(locals, length, chops); + check_verification_type_array_size(new_length, max_locals); + flags = 0; + for (int i=0; i 0) { + locals = new VerificationType[new_length]; + } else { + locals = null; + } + } else { + offset = pre_frame.offset() + offset_delta + 1; + } + frame = new VerificationFrame(offset, flags, new_length, 0, max_locals, max_stack, locals, null, _verifier); + if (first && locals != null) { + frame.copy_locals(pre_frame); + } + return frame; + } else if (frame_type < SAME_EXTENDED + 4) { + int appends = frame_type - SAME_EXTENDED; + int real_length = pre_frame.locals_size(); + int new_length = real_length + appends*2; + locals = new VerificationType[new_length]; + VerificationType[] pre_locals = pre_frame.locals(); + int i; + for (i=0; i 0) { + locals = new VerificationType[locals_size*2]; + } + int i; + for (i=0; i 0) { + stack = new VerificationType[stack_size*2]; + } + for (i=0; iG<2r}`8Qn`3xqFj`Vva3wTYPO0Ye3+#xP$=!vb{M~z=npW_ zA7Da^pVh<|WB397DC2vY!S=z#U})O&oaf1V-gBP5=l%8j$3B1zvM~e@6c7^8fiOdM ztG1mqEKheV)l6!p>bmQOsV9w{x|!V79b?_lo#e7V(Nxc{t%|W>sb0g;rL^iAn)0%) zGlX|lv!S~Tg^|(K;&J4hjUs}mfS8CA5E-VAoRptT8fTED$_vBOHkZ`8L`kFrx6+|o ziMy2!+)Dp+8(1ww={KGf(S$AxtL3p81lzso>!?`#A);}2)0u*s5%V6kaLnJRcj+zvMUX3GjHf-E$2A4!w;4aah4w}Ob1(0a$Gtm;(SxeET+m_x+vlj zmjtC+S(M8P*Di~=!nF>iS}6I7B;smwVNotUQgG^d${Wq9{}-^&c4j9sIv z)>Sktz0}xQ(;Y=!GfC+#+L~%EtB%2WQ|zpGsrtKQm#**%B+BE^R`{aM!JTg$yU2oBL$%|O9EZxcQ?$TWWX@;32Cq3*tx^Rb` z7ayQ5xlNtT;tAd-d`8LyCJCpA$OzI5`1l=c|7YwggfIN<{DxB@`4d8qecDH~qec6P zhFkOkQK3Z#h(=m;kZ8OudWiG3@KMg&;%{&sZLLpo9`pHU#1KUf`p}C61~Ei9O!g)T zr;tLHFo!3o5Gr^Mjj)C~TtW}8@S5-q-r^nMdwjqiVGz?~Kg@pu+rwR&2k5&;-voM| t2^6vPm!ZV9zYPds#?LW}Il>U;X?)--^H?D4ru+dqYi1!qg`g)M`2*ESTZRAt literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationType.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationType.class new file mode 100644 index 0000000000000000000000000000000000000000..94398480db463c60c70ef22f954cc5b94cdc3898 GIT binary patch literal 13089 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 X({JzwPr>6+Qkf5*`Bd;n^G5wYKGbqY literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationType.java b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationType.java new file mode 100644 index 00000000..a2ecda88 --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationType.java @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.classfile.impl.verifier; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Objects; +import jdk.internal.classfile.impl.ClassHierarchyImpl; +import jdk.internal.classfile.impl.Util; +import static jdk.internal.classfile.impl.verifier.VerifierImpl.*; +import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*; + +/** + * @see hotspot/share/classfile/verificationType.hpp + * @see hotspot/share/classfile/verificationType.cpp + */ +class VerificationType { + + private static final int BitsPerByte = 8; + + static final int + ITEM_Top = 0, + ITEM_Integer = 1, + ITEM_Float = 2, + ITEM_Double = 3, + ITEM_Long = 4, + ITEM_Null = 5, + ITEM_UninitializedThis = 6, + ITEM_Object = 7, + ITEM_Uninitialized = 8, + ITEM_Bogus = -1; + + VerificationType(String sym) { + _data = 0x100; + _sym = sym; + } + public VerificationType(int data, String sym) { + _data = data; + _sym = sym; + } + private final int _data; + private final String _sym; + + @Override + public int hashCode() { + return _sym == null ? _data : _sym.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof VerificationType ? (_data == ((VerificationType)obj)._data) && Objects.equals(_sym, ((VerificationType)obj)._sym) : false; + } + + private static final Map _constantsMap = new IdentityHashMap<>(18); + + @Override + public String toString() { + if (_constantsMap.isEmpty()) { + for (Field f : VerificationType.class.getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers()) && f.getType() == VerificationType.class) try { + _constantsMap.put((VerificationType)f.get(null), f.getName()); + } catch (IllegalAccessException ignore) {} + } + } + if (_sym != null) return _sym; + if ((_data & 0xff) == Uninitialized) return "uninit@" + (_data >> 8); + return _constantsMap.getOrDefault(this, java.lang.Integer.toHexString(_data)); + } + + String name() { + return _sym; + } + private static final int + ITEM_Boolean = 9, ITEM_Byte = 10, ITEM_Short = 11, ITEM_Char = 12, + ITEM_Long_2nd = 13, ITEM_Double_2nd = 14; + + private static final int + TypeMask = 0x00000003, + // Topmost types encoding + Reference = 0x0, // _sym contains the name + Primitive = 0x1, // see below for primitive list + Uninitialized = 0x2, // 0x00ffff00 contains bci + TypeQuery = 0x3, // Meta-types used for category testing + // Utility flags + ReferenceFlag = 0x00, // For reference query types + Category1Flag = 0x01, // One-word values + Category2Flag = 0x02, // First word of a two-word value + Category2_2ndFlag = 0x04, // Second word of a two-word value + // special reference values + Null = 0x00000000, // A reference with a 0 sym is null + // Primitives categories (the second byte determines the category) + Category1 = (Category1Flag << BitsPerByte) | Primitive, + Category2 = (Category2Flag << BitsPerByte) | Primitive, + Category2_2nd = (Category2_2ndFlag << BitsPerByte) | Primitive, + // Primitive values (type discriminator stored in most-significant bytes) + // Bogus needs the " | Primitive". Else, isReference(Bogus) returns TRUE. + Bogus = (ITEM_Bogus << 2 * BitsPerByte) | Primitive, + Boolean = (ITEM_Boolean << 2 * BitsPerByte) | Category1, + Byte = (ITEM_Byte << 2 * BitsPerByte) | Category1, + Short = (ITEM_Short << 2 * BitsPerByte) | Category1, + Char = (ITEM_Char << 2 * BitsPerByte) | Category1, + Integer = (ITEM_Integer << 2 * BitsPerByte) | Category1, + Float = (ITEM_Float << 2 * BitsPerByte) | Category1, + Long = (ITEM_Long << 2 * BitsPerByte) | Category2, + Double = (ITEM_Double << 2 * BitsPerByte) | Category2, + Long_2nd = (ITEM_Long_2nd << 2 * BitsPerByte) | Category2_2nd, + Double_2nd = (ITEM_Double_2nd << 2 * BitsPerByte) | Category2_2nd, + // Used by Uninitialized (second and third bytes hold the bci) + BciMask = 0xffff << BitsPerByte, + // A bci of -1 is an Uninitialized-This + BciForThis = 0xffff, + // Query values + ReferenceQuery = (ReferenceFlag << BitsPerByte) | TypeQuery, + Category1Query = (Category1Flag << BitsPerByte) | TypeQuery, + Category2Query = (Category2Flag << BitsPerByte) | TypeQuery, + Category2_2ndQuery = (Category2_2ndFlag << BitsPerByte) | TypeQuery; + + VerificationType(int raw_data) { + this._data = raw_data; + this._sym = null; + } + + static final VerificationType bogus_type = new VerificationType(Bogus), + null_type = new VerificationType(Null), + integer_type = new VerificationType(Integer), + float_type = new VerificationType(Float), + long_type = new VerificationType(Long), + long2_type = new VerificationType(Long_2nd), + double_type = new VerificationType(Double), + boolean_type = new VerificationType(Boolean), + byte_type = new VerificationType(Byte), + char_type = new VerificationType(Char), + short_type = new VerificationType(Short), + double2_type = new VerificationType(Double_2nd), + // "check" types are used for queries. A "check" type is not assignable + // to anything, but the specified types are assignable to a "check". For + // example, any category1 primitive is assignable to category1_check and + // any reference is assignable to reference_check. + reference_check = new VerificationType(ReferenceQuery), + category1_check = new VerificationType(Category1Query), + category2_check = new VerificationType(Category2Query); + + static VerificationType reference_type(String sh) { + return new VerificationType(sh); + } + + static VerificationType uninitialized_type(int bci) { + return new VerificationType(bci << 1 * BitsPerByte | Uninitialized); + } + + static final VerificationType uninitialized_this_type = uninitialized_type(BciForThis); + + boolean is_bogus() { + return (_data == Bogus); + } + + boolean is_null() { + return (_data == Null); + } + + boolean is_integer() { + return (_data == Integer); + } + + boolean is_long() { + return (_data == Long); + } + + boolean is_double() { + return (_data == Double); + } + + boolean is_long2() { + return (_data == Long_2nd ); + } + + boolean is_double2() { + return (_data == Double_2nd); + } + + boolean is_reference() { + return ((_data & TypeMask) == Reference); + } + + boolean is_category1(VerifierImpl context) { + // This should return true for all one-word types, which are category1 + // primitives, and references (including uninitialized refs). Though + // the 'query' types should technically return 'false' here, if we + // allow this to return true, we can perform the test using only + // 2 operations rather than 8 (3 masks, 3 compares and 2 logical 'ands'). + // Since no one should call this on a query type anyway, this is ok. + if(is_check()) context.verifyError("Must not be a check type (wrong value returned)"); + // should only return false if it's a primitive, and the category1 flag + // is not set. + return ((_data & Category1) != Primitive); + } + + boolean is_category2() { + return ((_data & Category2) == Category2); + } + + boolean is_category2_2nd() { + return ((_data & Category2_2nd) == Category2_2nd); + } + + boolean is_check() { + return (_data & TypeQuery) == TypeQuery; + } + + boolean is_x_array(char sig) { + return is_null() || (is_array() &&(name().charAt(1) == sig)); + } + + boolean is_int_array() { + return is_x_array(JVM_SIGNATURE_INT); + } + + boolean is_byte_array() { + return is_x_array(JVM_SIGNATURE_BYTE); + } + + boolean is_bool_array() { + return is_x_array(JVM_SIGNATURE_BOOLEAN); + } + + boolean is_char_array() { + return is_x_array(JVM_SIGNATURE_CHAR); + } + + boolean is_short_array() { + return is_x_array(JVM_SIGNATURE_SHORT); + } + + boolean is_long_array() { + return is_x_array(JVM_SIGNATURE_LONG); + } + + boolean is_float_array() { + return is_x_array(JVM_SIGNATURE_FLOAT); + } + + boolean is_double_array() { + return is_x_array(JVM_SIGNATURE_DOUBLE); + } + + boolean is_object_array() { + return is_x_array(JVM_SIGNATURE_CLASS); + } + + boolean is_array_array() { + return is_x_array(JVM_SIGNATURE_ARRAY); + } + + boolean is_reference_array() { + return is_object_array() || is_array_array(); + } + + boolean is_object() { + return (is_reference() && !is_null() && name().length() >= 1 && name().charAt(0) != JVM_SIGNATURE_ARRAY); + } + + boolean is_array() { + return (is_reference() && !is_null() && name().length() >= 2 && name().charAt(0) == JVM_SIGNATURE_ARRAY); + } + + boolean is_uninitialized() { + return ((_data & Uninitialized) == Uninitialized); + } + + boolean is_uninitialized_this(VerifierImpl context) { + return is_uninitialized() && bci(context) == BciForThis; + } + + VerificationType to_category2_2nd(VerifierImpl context) { + if (!(is_category2())) context.verifyError("Must be a double word"); + return is_long() ? long2_type : double2_type; + } + + int bci(VerifierImpl context) { + if (!(is_uninitialized())) context.verifyError("Must be uninitialized type"); + return ((_data & BciMask) >> 1 * BitsPerByte); + } + + boolean is_assignable_from(VerificationType from, VerifierImpl context) { + boolean ret = _is_assignable_from(from, context); + context.errorContext = ret ? "" : String.format("(%s is not assignable from %s)", this, from); + return ret; + } + + private boolean _is_assignable_from(VerificationType from, VerifierImpl context) { + if (equals(from) || is_bogus()) { + return true; + } else { + switch(_data) { + case Category1Query: + return from.is_category1(context); + case Category2Query: + return from.is_category2(); + case Category2_2ndQuery: + return from.is_category2_2nd(); + case ReferenceQuery: + return from.is_reference() || from.is_uninitialized(); + case Boolean: + case Byte: + case Char: + case Short: + return from.is_integer(); + default: + if (is_reference() && from.is_reference()) { + return is_reference_assignable_from(from, context); + } else { + return false; + } + } + } + } + + // Check to see if one array component type is assignable to another. + // Same as is_assignable_from() except int primitives must be identical. + boolean is_component_assignable_from(VerificationType from, VerifierImpl context) { + if (equals(from) || is_bogus()) { + return true; + } else { + switch (_data) { + case Boolean: + case Byte: + case Char: + case Short: + return false; + default: + return is_assignable_from(from, context); + } + } + } + + int dimensions(VerifierImpl context) { + if (!(is_array())) context.verifyError("Must be an array"); + int index = 0; + while (name().charAt(index) == JVM_SIGNATURE_ARRAY) index++; + return index; + } + + static VerificationType from_tag(int tag, VerifierImpl context) { + switch (tag) { + case ITEM_Top: return bogus_type; + case ITEM_Integer: return integer_type; + case ITEM_Float: return float_type; + case ITEM_Double: return double_type; + case ITEM_Long: return long_type; + case ITEM_Null: return null_type; + default: + context.verifyError("Should not reach here"); + return bogus_type; + } + } + + boolean resolve_and_check_assignability(ClassHierarchyImpl assignResolver, String name, String from_name, boolean from_is_array, boolean from_is_object) { + //let's delegate assignability to SPI + var desc = Util.toClassDesc(name); + if (assignResolver.isInterface(desc)) { + return !from_is_array || "java/lang/Cloneable".equals(name) || "java/io/Serializable".equals(name); + } else if (from_is_object) { + return assignResolver.isAssignableFrom(desc, Util.toClassDesc(from_name)); + } + return false; + } + + boolean is_reference_assignable_from(VerificationType from, VerifierImpl context) { + ClassHierarchyImpl clsTree = context.class_hierarchy(); + if (from.is_null()) { + return true; + } else if (is_null()) { + return false; + } else if (name().equals(from.name())) { + return true; + } else if (is_object()) { + if (VerifierImpl.java_lang_Object.equals(name())) { + return true; + } + return resolve_and_check_assignability(clsTree, name(), from.name(), from.is_array(), from.is_object()); + } else if (is_array() && from.is_array()) { + VerificationType comp_this = get_component(context); + VerificationType comp_from = from.get_component(context); + if (!comp_this.is_bogus() && !comp_from.is_bogus()) { + return comp_this.is_component_assignable_from(comp_from, context); + } + } + return false; + } + + VerificationType get_component(VerifierImpl context) { + if (!(is_array() && name().length() >= 2)) context.verifyError("Must be a valid array"); + var ss = new VerificationSignature(name(), false, context); + ss.skipArrayPrefix(1); + switch (ss.type()) { + case T_BOOLEAN: return VerificationType.boolean_type; + case T_BYTE: return VerificationType.byte_type; + case T_CHAR: return VerificationType.char_type; + case T_SHORT: return VerificationType.short_type; + case T_INT: return VerificationType.integer_type; + case T_LONG: return VerificationType.long_type; + case T_FLOAT: return VerificationType.float_type; + case T_DOUBLE: return VerificationType.double_type; + case T_ARRAY: + case T_OBJECT: { + if (!(ss.isReference())) context.verifyError("Unchecked verifier input"); + String component = ss.asSymbol(); + return VerificationType.reference_type(component); + } + default: + return VerificationType.bogus_type; + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationWrapper$ConstantPoolWrapper.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationWrapper$ConstantPoolWrapper.class new file mode 100644 index 0000000000000000000000000000000000000000..057649cde081bb1a7d0dbd8e2893ff2d7b3fe75b GIT binary patch literal 2688 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationWrapper.java b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationWrapper.java new file mode 100644 index 00000000..d34f579b --- /dev/null +++ b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerificationWrapper.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.internal.classfile.impl.verifier; + +import java.lang.constant.ClassDesc; +import java.util.LinkedList; +import java.util.List; + +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.DynamicConstantPoolEntry; +import java.lang.classfile.constantpool.MemberRefEntry; +import java.lang.classfile.constantpool.NameAndTypeEntry; +import java.lang.reflect.AccessFlag; +import java.util.stream.Collectors; +import java.lang.classfile.ClassModel; +import java.lang.classfile.constantpool.ConstantPool; +import java.lang.classfile.MethodModel; +import java.lang.classfile.attribute.LocalVariableInfo; +import java.lang.classfile.Attributes; +import jdk.internal.classfile.impl.BoundAttribute; +import jdk.internal.classfile.impl.CodeImpl; +import jdk.internal.classfile.impl.Util; + +public final class VerificationWrapper { + private final ClassModel clm; + private final ConstantPoolWrapper cp; + + public VerificationWrapper(ClassModel clm) { + this.clm = clm; + this.cp = new ConstantPoolWrapper(clm.constantPool()); + } + + String thisClassName() { + return clm.thisClass().asInternalName(); + } + + int majorVersion() { + return clm.majorVersion(); + } + + String superclassName() { + return clm.superclass().map(ClassEntry::asInternalName).orElse(null); + } + + Iterable interfaceNames() { + return Util.mappedList(clm.interfaces(), ClassEntry::asInternalName); + } + + Iterable methods() { + return clm.methods().stream().map(m -> new MethodWrapper(m)).toList(); + } + + boolean findField(String name, String sig) { + for (var f : clm.fields()) + if (f.fieldName().stringValue().equals(name) && f.fieldType().stringValue().equals(sig)) + return true; + return false; + } + + class MethodWrapper { + + final MethodModel m; + private final CodeImpl c; + private final List exc; + + MethodWrapper(MethodModel m) { + this.m = m; + this.c = (CodeImpl)m.code().orElse(null); + exc = new LinkedList<>(); + if (c != null) c.iterateExceptionHandlers((start, end, handler, catchType) -> { + exc.add(new int[] {start, end, handler, catchType}); + }); + } + + ConstantPoolWrapper constantPool() { + return cp; + } + + boolean isNative() { + return m.flags().has(AccessFlag.NATIVE); + } + + boolean isAbstract() { + return m.flags().has(AccessFlag.ABSTRACT); + } + + boolean isBridge() { + return m.flags().has(AccessFlag.BRIDGE); + } + + boolean isStatic() { + return m.flags().has(AccessFlag.STATIC); + } + + String name() { + return m.methodName().stringValue(); + } + + int maxStack() { + return c == null ? 0 : c.maxStack(); + } + + int maxLocals() { + return c == null ? 0 : c.maxLocals(); + } + + String descriptor() { + return m.methodType().stringValue(); + } + + String parameters() { + return m.methodTypeSymbol().parameterList().stream().map(ClassDesc::displayName).collect(Collectors.joining(",")); + } + + int codeLength() { + return c == null ? 0 : c.codeLength(); + } + + byte[] codeArray() { + return c == null ? null : c.codeArray(); + } + + List exceptionTable() { + return exc; + } + + List localVariableTable() { + var attro = c.findAttribute(Attributes.localVariableTable()); + return attro.map(lvta -> lvta.localVariables()).orElse(List.of()); + } + + byte[] stackMapTableRawData() { + var attro = c.findAttribute(Attributes.stackMapTable()); + return attro.map(attr -> ((BoundAttribute) attr).contents()).orElse(null); + } + + } + + static class ConstantPoolWrapper { + + private final ConstantPool cp; + + ConstantPoolWrapper(ConstantPool cp) { + this.cp = cp; + } + + int entryCount() { + return cp.size(); + } + + String classNameAt(int index) { + return cp.entryByIndex(index, ClassEntry.class).asInternalName(); + } + + String dynamicConstantSignatureAt(int index) { + return cp.entryByIndex(index, DynamicConstantPoolEntry.class).type().stringValue(); + } + + int tagAt(int index) { + return cp.entryByIndex(index).tag(); + } + + private NameAndTypeEntry _refNameType(int index) { + var e = cp.entryByIndex(index); + return (e instanceof DynamicConstantPoolEntry de) ? de.nameAndType() : + e != null ? ((MemberRefEntry)e).nameAndType() : null; + } + + String refNameAt(int index) { + return _refNameType(index).name().stringValue(); + } + + String refSignatureAt(int index) { + return _refNameType(index).type().stringValue(); + } + + int refClassIndexAt(int index) { + return cp.entryByIndex(index, MemberRefEntry.class).owner().index(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl$1.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..0f8584c2f2d1608285b1ff6b92394e931dc53f2c GIT binary patch literal 1393 zcmb_bZBNrs6n?smb(=*7qD*{4sl52YL|#-tWv?`UAgoM+)E>W$f%H`A|*Um^d%eAmtEh?o4 zTskk|LbLp=@+4i%aq*&rOI&PItA&!v6JWpq0mf_v=jV}lY zW$YSVvyP%+u~K7mnK`PqY?9Jdv~|r~&>VyFrr2KbG<}15-sG{0-Eef4r;9D1bEm~S zcVvWroATx?-Lzf9TAgR!nq3n?UmiX5jibU#%=PAMmpn)X%VJK3PZV=Sqy+#!Z@LA)er~!FQyLV}fv!h=L&PfREoHZ2ydXh4_X4+rObRqTn4?yu>TQ*LZ`sgzxYk9|(iEMfSt~A^gT|+6U;l yL(e$6pNbSQf51}W+Cd9KnDTQ>V}>wp4phnOy9{CFa?pA#O literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl$sig_as_verification_types.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl$sig_as_verification_types.class new file mode 100644 index 0000000000000000000000000000000000000000..88c5be3a34e37fa68ff2728a0ed3024e9b083d60 GIT binary patch literal 1282 zcmbVMTWb?R6#gcc&Be5d(WZ@6>!sBsf{V{70SSn~7?qa1E|YW`CvG-nc2nq&@d7?5 z=!1eq@WCJ8j}p(!t}*H=v@GnLIcLuKzH{c={r3IKR{(9)^GG0>L8^c>EQZpUA9CB} z-pGD57>i-RU~NlJ1}%nUt=`Wei(Cfz0?weo@L;_6%$8mtl*e6r=yKoRm#(noDqUd;zwQS2Tjdl zxqu={3^~V}O&qR9RDgA8zavK;4`xa*^y0F&yC)zW65J(z%~q3Ptrl0YS?@EX+S5IP zEOwYYk-yC(W#M$!IRil zPCpzygY2)XAhFP86nqgZ+)t|3(Z^P6_1G~oJdTf?o)trWXF5|uagSulaCT9Ox3#p0 zbWixf{iz>haD(B_3B(az2zA-h)cBBur{swOuF$2OYg}@7%b@E8=W5)+4H6 zw*J!qZ>YPs3lyz+1&auj3__LW6!yPJB=g}9BJW~|gk!u))466&U&p3dw{VlzJeAL4 I3pHea091uL82|tP literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl.class b/tests/test_data/std/jdk/internal/classfile/impl/verifier/VerifierImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..81fa76d6c00e2adcd515f651239c067f1d60bca0 GIT binary patch literal 47281 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.base/share/native/include/classfile_constants.h.template + * @see hotspot/share/classfile/verifier.hpp + * @see hotspot/share/classfile/verifier.cpp + */ +public final class VerifierImpl { + static final int + JVM_CONSTANT_Utf8 = 1, + JVM_CONSTANT_Unicode = 2, + JVM_CONSTANT_Integer = 3, + JVM_CONSTANT_Float = 4, + JVM_CONSTANT_Long = 5, + JVM_CONSTANT_Double = 6, + JVM_CONSTANT_Class = 7, + JVM_CONSTANT_String = 8, + JVM_CONSTANT_Fieldref = 9, + JVM_CONSTANT_Methodref = 10, + JVM_CONSTANT_InterfaceMethodref = 11, + JVM_CONSTANT_NameAndType = 12, + JVM_CONSTANT_MethodHandle = 15, + JVM_CONSTANT_MethodType = 16, + JVM_CONSTANT_Dynamic = 17, + JVM_CONSTANT_InvokeDynamic = 18, + JVM_CONSTANT_Module = 19, + JVM_CONSTANT_Package = 20, + JVM_CONSTANT_ExternalMax = 20; + + static final char JVM_SIGNATURE_SPECIAL = '<', + JVM_SIGNATURE_ARRAY = '[', + JVM_SIGNATURE_BYTE = 'B', + JVM_SIGNATURE_CHAR = 'C', + JVM_SIGNATURE_CLASS = 'L', + JVM_SIGNATURE_FLOAT = 'F', + JVM_SIGNATURE_DOUBLE = 'D', + JVM_SIGNATURE_INT = 'I', + JVM_SIGNATURE_LONG = 'J', + JVM_SIGNATURE_SHORT = 'S', + JVM_SIGNATURE_BOOLEAN = 'Z'; + + static final String java_lang_String = "java/lang/String"; + static final String object_initializer_name = ""; + static final String java_lang_invoke_MethodHandle = "java/lang/invoke/MethodHandle"; + static final String java_lang_Object = "java/lang/Object"; + static final String java_lang_invoke_MethodType = "java/lang/invoke/MethodType"; + static final String java_lang_Throwable = "java/lang/Throwable"; + static final String java_lang_Class = "java/lang/Class"; + + String errorContext = ""; + private int bci; + + static void log_info(Consumer logger, String messageFormat, Object... args) { + if (logger != null) logger.accept(String.format(messageFormat + "%n", args)); + } + private final Consumer _logger; + void log_info(String messageFormat, Object... args) { + log_info(_logger, messageFormat, args); + } + + + static final int STACKMAP_ATTRIBUTE_MAJOR_VERSION = 50; + static final int INVOKEDYNAMIC_MAJOR_VERSION = 51; + static final int NOFAILOVER_MAJOR_VERSION = 51; + static final int MAX_CODE_SIZE = 65535; + + public static List verify(ClassModel classModel, Consumer logger) { + return verify(classModel, ClassHierarchyResolver.defaultResolver(), logger); + } + + public static List verify(ClassModel classModel, ClassHierarchyResolver classHierarchyResolver, Consumer logger) { + var klass = new VerificationWrapper(classModel); + log_info(logger, "Start class verification for: %s", klass.thisClassName()); + try { + var errors = new ArrayList(); + errors.addAll(new ParserVerifier(classModel).verify()); + if (is_eligible_for_verification(klass)) { + if (klass.majorVersion() >= STACKMAP_ATTRIBUTE_MAJOR_VERSION) { + var verifierErrors = new VerifierImpl(klass, classHierarchyResolver, logger).verify_class(); + if (!verifierErrors.isEmpty() && klass.majorVersion() < NOFAILOVER_MAJOR_VERSION) { + log_info(logger, "Fail over class verification to old verifier for: %s", klass.thisClassName()); + errors.addAll(inference_verify(klass)); + } else { + errors.addAll(verifierErrors); + } + } else { + errors.addAll(inference_verify(klass)); + } + } + return errors; + } finally { + log_info(logger, "End class verification for: %s", klass.thisClassName()); + } + } + + public static boolean is_eligible_for_verification(VerificationWrapper klass) { + String name = klass.thisClassName(); + return !java_lang_Object.equals(name) && + !java_lang_Class.equals(name) && + !java_lang_String.equals(name) && + !java_lang_Throwable.equals(name); + } + + static List inference_verify(VerificationWrapper klass) { + return List.of(new VerifyError("Inference verification is not supported")); + } + + static class sig_as_verification_types { + private int _num_args; + private ArrayList _sig_verif_types; + + sig_as_verification_types(ArrayList sig_verif_types) { + this._sig_verif_types = sig_verif_types; + this._num_args = 0; + } + + int num_args() { + return _num_args; + } + + void set_num_args(int num_args) { + _num_args = num_args; + } + + ArrayList sig_verif_types() { + return _sig_verif_types; + } + } + + VerificationType cp_ref_index_to_type(int index, ConstantPoolWrapper cp) { + return cp_index_to_type(cp.refClassIndexAt(index), cp); + } + + final VerificationWrapper _klass; + final ClassHierarchyImpl _class_hierarchy; + VerificationWrapper.MethodWrapper _method; + VerificationType _this_type; + + static final int BYTECODE_OFFSET = 1, NEW_OFFSET = 2; + + VerificationWrapper current_class() { + return _klass; + } + + ClassHierarchyImpl class_hierarchy() { + return _class_hierarchy; + } + + VerificationType current_type() { + return _this_type; + } + + VerificationType cp_index_to_type(int index, ConstantPoolWrapper cp) { + return VerificationType.reference_type(cp.classNameAt(index)); + } + + int change_sig_to_verificationType(VerificationSignature sig_type, VerificationType inference_types[], int inference_type_index) { + BasicType bt = sig_type.type(); + switch (bt) { + case T_OBJECT: + case T_ARRAY: + String name = sig_type.asSymbol(); + inference_types[inference_type_index] = VerificationType.reference_type(name); + return 1; + case T_LONG: + inference_types[inference_type_index] = VerificationType.long_type; + inference_types[++inference_type_index] = VerificationType.long2_type; + return 2; + case T_DOUBLE: + inference_types[inference_type_index] = VerificationType.double_type; + inference_types[++inference_type_index] = VerificationType.double2_type; + return 2; + case T_INT: + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + inference_types[inference_type_index] = VerificationType.integer_type; + return 1; + case T_FLOAT: + inference_types[inference_type_index] = VerificationType.float_type; + return 1; + default: + verifyError("Should not reach here"); + return 1; + } + } + + private static final int NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION = 51; + private static final int STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION = 52; + private static final int MAX_ARRAY_DIMENSIONS = 255; + + VerifierImpl(VerificationWrapper klass, ClassHierarchyResolver classHierarchyResolver, Consumer logger) { + _klass = klass; + _class_hierarchy = new ClassHierarchyImpl(classHierarchyResolver); + _this_type = VerificationType.reference_type(klass.thisClassName()); + _logger = logger; + } + + private VerificationType object_type() { + return VerificationType.reference_type(java_lang_Object); + } + + List verify_class() { + log_info("Verifying class %s with new format", _klass.thisClassName()); + var errors = new ArrayList(); + for (VerificationWrapper.MethodWrapper m : _klass.methods()) { + if (m.isNative() || m.isAbstract() || m.isBridge()) { + continue; + } + verify_method(m, errors); + } + return errors; + } + + void translate_signature(String method_sig, sig_as_verification_types sig_verif_types) { + var sig_stream = new VerificationSignature(method_sig, true, this); + VerificationType[] sig_type = new VerificationType[2]; + int sig_i = 0; + ArrayList verif_types = sig_verif_types.sig_verif_types(); + while (!sig_stream.atReturnType()) { + int n = change_sig_to_verificationType(sig_stream, sig_type, 0); + if (n > 2) verifyError("Unexpected signature type"); + for (int x = 0; x < n; x++) { + verif_types.add(sig_type[x]); + } + sig_i += n; + sig_stream.next(); + } + sig_verif_types.set_num_args(sig_i); + if (sig_stream.type() != BasicType.T_VOID) { + int n = change_sig_to_verificationType(sig_stream, sig_type, 0); + if (n > 2) verifyError("Unexpected signature return type"); + for (int y = 0; y < n; y++) { + verif_types.add(sig_type[y]); + } + } + } + + void create_method_sig_entry(sig_as_verification_types sig_verif_types, String method_sig) { + translate_signature(method_sig, sig_verif_types); + } + + void verify_method(VerificationWrapper.MethodWrapper m, List errorsCollector) { + try { + verify_method(m); + } catch (VerifyError err) { + errorsCollector.add(err); + } catch (Error | Exception e) { + errorsCollector.add(new VerifyError(e.toString())); + } + } + + @SuppressWarnings("fallthrough") + void verify_method(VerificationWrapper.MethodWrapper m) { + _method = m; + log_info(_logger, "Verifying method %s%s", m.name(), m.descriptor()); + byte[] codeArray = m.codeArray(); + if (codeArray == null) verifyError("Missing Code attribute"); + int max_locals = m.maxLocals(); + int max_stack = m.maxStack(); + byte[] stackmap_data = m.stackMapTableRawData(); + var cp = m.constantPool(); + if (!VerificationSignature.isValidMethodSignature(m.descriptor())) verifyError("Invalid method signature"); + VerificationFrame current_frame = new VerificationFrame(max_locals, max_stack, this); + VerificationType return_type = current_frame.set_locals_from_arg(m, current_type()); + int stackmap_index = 0; + int code_length = m.codeLength(); + if (code_length < 1 || code_length > MAX_CODE_SIZE) { + verifyError(String.format("Invalid method Code length %d", code_length)); + } + var code = ByteBuffer.wrap(codeArray, 0, _method.codeLength()); + byte[] code_data = generate_code_data(code, code_length); + int ex_minmax[] = new int[] {code_length, -1}; + verify_exception_handler_table(code_length, code_data, ex_minmax); + verify_local_variable_table(code_length, code_data); + + VerificationTable stackmap_table = new VerificationTable(stackmap_data, current_frame, max_locals, max_stack, code_data, code_length, cp, this); + + var bcs = new RawBytecodeHelper(code); + boolean no_control_flow = false; + int opcode; + while (!bcs.isLastBytecode()) { + opcode = bcs.rawNext(); + bci = bcs.bci; + current_frame.set_offset(bci); + current_frame.set_mark(); + stackmap_index = verify_stackmap_table(stackmap_index, bci, current_frame, stackmap_table, no_control_flow); + boolean this_uninit = false; + boolean verified_exc_handlers = false; + { + int index; + int target; + VerificationType type, type2 = null; + VerificationType atype; + if (bcs.isWide) { + if (opcode != ClassFile.IINC && opcode != ClassFile.ILOAD + && opcode != ClassFile.ALOAD && opcode != ClassFile.LLOAD + && opcode != ClassFile.ISTORE && opcode != ClassFile.ASTORE + && opcode != ClassFile.LSTORE && opcode != ClassFile.FLOAD + && opcode != ClassFile.DLOAD && opcode != ClassFile.FSTORE + && opcode != ClassFile.DSTORE) { + verifyError("Bad wide instruction"); + } + } + if (VerificationBytecodes.is_store_into_local(opcode) && bci >= ex_minmax[0] && bci < ex_minmax[1]) { + verify_exception_handler_targets(bci, this_uninit, current_frame, stackmap_table); + verified_exc_handlers = true; + } + switch (opcode) { + case ClassFile.NOP : + no_control_flow = false; break; + case ClassFile.ACONST_NULL : + current_frame.push_stack( + VerificationType.null_type); + no_control_flow = false; break; + case ClassFile.ICONST_M1 : + case ClassFile.ICONST_0 : + case ClassFile.ICONST_1 : + case ClassFile.ICONST_2 : + case ClassFile.ICONST_3 : + case ClassFile.ICONST_4 : + case ClassFile.ICONST_5 : + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.LCONST_0 : + case ClassFile.LCONST_1 : + current_frame.push_stack_2( + VerificationType.long_type, + VerificationType.long2_type); + no_control_flow = false; break; + case ClassFile.FCONST_0 : + case ClassFile.FCONST_1 : + case ClassFile.FCONST_2 : + current_frame.push_stack( + VerificationType.float_type); + no_control_flow = false; break; + case ClassFile.DCONST_0 : + case ClassFile.DCONST_1 : + current_frame.push_stack_2( + VerificationType.double_type, + VerificationType.double2_type); + no_control_flow = false; break; + case ClassFile.SIPUSH : + case ClassFile.BIPUSH : + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.LDC : + verify_ldc( + opcode, bcs.getIndexU1(), current_frame, + cp, bci); + no_control_flow = false; break; + case ClassFile.LDC_W : + case ClassFile.LDC2_W : + verify_ldc( + opcode, bcs.getIndexU2(), current_frame, + cp, bci); + no_control_flow = false; break; + case ClassFile.ILOAD : + verify_iload(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.ILOAD_0 : + case ClassFile.ILOAD_1 : + case ClassFile.ILOAD_2 : + case ClassFile.ILOAD_3 : + index = opcode - ClassFile.ILOAD_0; + verify_iload(index, current_frame); + no_control_flow = false; break; + case ClassFile.LLOAD : + verify_lload(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.LLOAD_0 : + case ClassFile.LLOAD_1 : + case ClassFile.LLOAD_2 : + case ClassFile.LLOAD_3 : + index = opcode - ClassFile.LLOAD_0; + verify_lload(index, current_frame); + no_control_flow = false; break; + case ClassFile.FLOAD : + verify_fload(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.FLOAD_0 : + case ClassFile.FLOAD_1 : + case ClassFile.FLOAD_2 : + case ClassFile.FLOAD_3 : + index = opcode - ClassFile.FLOAD_0; + verify_fload(index, current_frame); + no_control_flow = false; break; + case ClassFile.DLOAD : + verify_dload(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.DLOAD_0 : + case ClassFile.DLOAD_1 : + case ClassFile.DLOAD_2 : + case ClassFile.DLOAD_3 : + index = opcode - ClassFile.DLOAD_0; + verify_dload(index, current_frame); + no_control_flow = false; break; + case ClassFile.ALOAD : + verify_aload(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.ALOAD_0 : + case ClassFile.ALOAD_1 : + case ClassFile.ALOAD_2 : + case ClassFile.ALOAD_3 : + index = opcode - ClassFile.ALOAD_0; + verify_aload(index, current_frame); + no_control_flow = false; break; + case ClassFile.IALOAD : + type = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_int_array()) { + verifyError("Bad type"); + } + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.BALOAD : + type = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_bool_array() && !atype.is_byte_array()) { + verifyError("Bad type"); + } + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.CALOAD : + type = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_char_array()) { + verifyError("Bad type"); + } + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.SALOAD : + type = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_short_array()) { + verifyError("Bad type"); + } + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.LALOAD : + type = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_long_array()) { + verifyError("Bad type"); + } + current_frame.push_stack_2( + VerificationType.long_type, + VerificationType.long2_type); + no_control_flow = false; break; + case ClassFile.FALOAD : + type = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_float_array()) { + verifyError("Bad type"); + } + current_frame.push_stack( + VerificationType.float_type); + no_control_flow = false; break; + case ClassFile.DALOAD : + type = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_double_array()) { + verifyError("Bad type"); + } + current_frame.push_stack_2( + VerificationType.double_type, + VerificationType.double2_type); + no_control_flow = false; break; + case ClassFile.AALOAD : { + type = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_reference_array()) { + verifyError("Bad type"); + } + if (atype.is_null()) { + current_frame.push_stack( + VerificationType.null_type); + } else { + VerificationType component = + atype.get_component(this); + current_frame.push_stack(component); + } + no_control_flow = false; break; + } + case ClassFile.ISTORE : + verify_istore(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.ISTORE_0 : + case ClassFile.ISTORE_1 : + case ClassFile.ISTORE_2 : + case ClassFile.ISTORE_3 : + index = opcode - ClassFile.ISTORE_0; + verify_istore(index, current_frame); + no_control_flow = false; break; + case ClassFile.LSTORE : + verify_lstore(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.LSTORE_0 : + case ClassFile.LSTORE_1 : + case ClassFile.LSTORE_2 : + case ClassFile.LSTORE_3 : + index = opcode - ClassFile.LSTORE_0; + verify_lstore(index, current_frame); + no_control_flow = false; break; + case ClassFile.FSTORE : + verify_fstore(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.FSTORE_0 : + case ClassFile.FSTORE_1 : + case ClassFile.FSTORE_2 : + case ClassFile.FSTORE_3 : + index = opcode - ClassFile.FSTORE_0; + verify_fstore(index, current_frame); + no_control_flow = false; break; + case ClassFile.DSTORE : + verify_dstore(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.DSTORE_0 : + case ClassFile.DSTORE_1 : + case ClassFile.DSTORE_2 : + case ClassFile.DSTORE_3 : + index = opcode - ClassFile.DSTORE_0; + verify_dstore(index, current_frame); + no_control_flow = false; break; + case ClassFile.ASTORE : + verify_astore(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.ASTORE_0 : + case ClassFile.ASTORE_1 : + case ClassFile.ASTORE_2 : + case ClassFile.ASTORE_3 : + index = opcode - ClassFile.ASTORE_0; + verify_astore(index, current_frame); + no_control_flow = false; break; + case ClassFile.IASTORE : + type = current_frame.pop_stack( + VerificationType.integer_type); + type2 = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_int_array()) { + verifyError("Bad type"); + } + no_control_flow = false; break; + case ClassFile.BASTORE : + type = current_frame.pop_stack( + VerificationType.integer_type); + type2 = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_bool_array() && !atype.is_byte_array()) { + verifyError("Bad type"); + } + no_control_flow = false; break; + case ClassFile.CASTORE : + current_frame.pop_stack( + VerificationType.integer_type); + current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_char_array()) { + verifyError("Bad type"); + } + no_control_flow = false; break; + case ClassFile.SASTORE : + current_frame.pop_stack( + VerificationType.integer_type); + current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_short_array()) { + verifyError("Bad type"); + } + no_control_flow = false; break; + case ClassFile.LASTORE : + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_long_array()) { + verifyError("Bad type"); + } + no_control_flow = false; break; + case ClassFile.FASTORE : + current_frame.pop_stack( + VerificationType.float_type); + current_frame.pop_stack + (VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_float_array()) { + verifyError("Bad type"); + } + no_control_flow = false; break; + case ClassFile.DASTORE : + current_frame.pop_stack_2( + VerificationType.double2_type, + VerificationType.double_type); + current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + if (!atype.is_double_array()) { + verifyError("Bad type"); + } + no_control_flow = false; break; + case ClassFile.AASTORE : + type = current_frame.pop_stack(object_type()); + type2 = current_frame.pop_stack( + VerificationType.integer_type); + atype = current_frame.pop_stack( + VerificationType.reference_check); + // more type-checking is done at runtime + if (!atype.is_reference_array()) { + verifyError("Bad type"); + } + // 4938384: relaxed constraint in JVMS 3nd edition. + no_control_flow = false; break; + case ClassFile.POP : + current_frame.pop_stack( + VerificationType.category1_check); + no_control_flow = false; break; + case ClassFile.POP2 : + type = current_frame.pop_stack(); + if (type.is_category1(this)) { + current_frame.pop_stack( + VerificationType.category1_check); + } else if (type.is_category2_2nd()) { + current_frame.pop_stack( + VerificationType.category2_check); + } else { + verifyError("Bad type"); + } + no_control_flow = false; break; + case ClassFile.DUP : + type = current_frame.pop_stack( + VerificationType.category1_check); + current_frame.push_stack(type); + current_frame.push_stack(type); + no_control_flow = false; break; + case ClassFile.DUP_X1 : + type = current_frame.pop_stack( + VerificationType.category1_check); + type2 = current_frame.pop_stack( + VerificationType.category1_check); + current_frame.push_stack(type); + current_frame.push_stack(type2); + current_frame.push_stack(type); + no_control_flow = false; break; + case ClassFile.DUP_X2 : + { + VerificationType type3 = null; + type = current_frame.pop_stack( + VerificationType.category1_check); + type2 = current_frame.pop_stack(); + if (type2.is_category1(this)) { + type3 = current_frame.pop_stack( + VerificationType.category1_check); + } else if (type2.is_category2_2nd()) { + type3 = current_frame.pop_stack( + VerificationType.category2_check); + } else { + verifyError("Bad type"); + } + current_frame.push_stack(type); + current_frame.push_stack(type3); + current_frame.push_stack(type2); + current_frame.push_stack(type); + no_control_flow = false; break; + } + case ClassFile.DUP2 : + type = current_frame.pop_stack(); + if (type.is_category1(this)) { + type2 = current_frame.pop_stack( + VerificationType.category1_check); + } else if (type.is_category2_2nd()) { + type2 = current_frame.pop_stack( + VerificationType.category2_check); + } else { + verifyError("Bad type"); + } + current_frame.push_stack(type2); + current_frame.push_stack(type); + current_frame.push_stack(type2); + current_frame.push_stack(type); + no_control_flow = false; break; + case ClassFile.DUP2_X1 : + { + VerificationType type3; + type = current_frame.pop_stack(); + if (type.is_category1(this)) { + type2 = current_frame.pop_stack( + VerificationType.category1_check); + } else if (type.is_category2_2nd()) { + type2 = current_frame.pop_stack( + VerificationType.category2_check); + } else { + verifyError("Bad type"); + } + type3 = current_frame.pop_stack( + VerificationType.category1_check); + current_frame.push_stack(type2); + current_frame.push_stack(type); + current_frame.push_stack(type3); + current_frame.push_stack(type2); + current_frame.push_stack(type); + no_control_flow = false; break; + } + case ClassFile.DUP2_X2 : + VerificationType type3, type4 = null; + type = current_frame.pop_stack(); + if (type.is_category1(this)) { + type2 = current_frame.pop_stack( + VerificationType.category1_check); + } else if (type.is_category2_2nd()) { + type2 = current_frame.pop_stack( + VerificationType.category2_check); + } else { + verifyError("Bad type"); + } + type3 = current_frame.pop_stack(); + if (type3.is_category1(this)) { + type4 = current_frame.pop_stack( + VerificationType.category1_check); + } else if (type3.is_category2_2nd()) { + type4 = current_frame.pop_stack( + VerificationType.category2_check); + } else { + verifyError("Bad type"); + } + current_frame.push_stack(type2); + current_frame.push_stack(type); + current_frame.push_stack(type4); + current_frame.push_stack(type3); + current_frame.push_stack(type2); + current_frame.push_stack(type); + no_control_flow = false; break; + case ClassFile.SWAP : + type = current_frame.pop_stack( + VerificationType.category1_check); + type2 = current_frame.pop_stack( + VerificationType.category1_check); + current_frame.push_stack(type); + current_frame.push_stack(type2); + no_control_flow = false; break; + case ClassFile.IADD : + case ClassFile.ISUB : + case ClassFile.IMUL : + case ClassFile.IDIV : + case ClassFile.IREM : + case ClassFile.ISHL : + case ClassFile.ISHR : + case ClassFile.IUSHR : + case ClassFile.IOR : + case ClassFile.IXOR : + case ClassFile.IAND : + current_frame.pop_stack( + VerificationType.integer_type); + // fall through + case ClassFile.INEG : + current_frame.pop_stack( + VerificationType.integer_type); + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.LADD : + case ClassFile.LSUB : + case ClassFile.LMUL : + case ClassFile.LDIV : + case ClassFile.LREM : + case ClassFile.LAND : + case ClassFile.LOR : + case ClassFile.LXOR : + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + // fall through + case ClassFile.LNEG : + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + current_frame.push_stack_2( + VerificationType.long_type, + VerificationType.long2_type); + no_control_flow = false; break; + case ClassFile.LSHL : + case ClassFile.LSHR : + case ClassFile.LUSHR : + current_frame.pop_stack( + VerificationType.integer_type); + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + current_frame.push_stack_2( + VerificationType.long_type, + VerificationType.long2_type); + no_control_flow = false; break; + case ClassFile.FADD : + case ClassFile.FSUB : + case ClassFile.FMUL : + case ClassFile.FDIV : + case ClassFile.FREM : + current_frame.pop_stack( + VerificationType.float_type); + // fall through + case ClassFile.FNEG : + current_frame.pop_stack( + VerificationType.float_type); + current_frame.push_stack( + VerificationType.float_type); + no_control_flow = false; break; + case ClassFile.DADD : + case ClassFile.DSUB : + case ClassFile.DMUL : + case ClassFile.DDIV : + case ClassFile.DREM : + current_frame.pop_stack_2( + VerificationType.double2_type, + VerificationType.double_type); + // fall through + case ClassFile.DNEG : + current_frame.pop_stack_2( + VerificationType.double2_type, + VerificationType.double_type); + current_frame.push_stack_2( + VerificationType.double_type, + VerificationType.double2_type); + no_control_flow = false; break; + case ClassFile.IINC : + verify_iinc(bcs.getIndex(), current_frame); + no_control_flow = false; break; + case ClassFile.I2L : + type = current_frame.pop_stack( + VerificationType.integer_type); + current_frame.push_stack_2( + VerificationType.long_type, + VerificationType.long2_type); + no_control_flow = false; break; + case ClassFile.L2I : + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.I2F : + current_frame.pop_stack( + VerificationType.integer_type); + current_frame.push_stack( + VerificationType.float_type); + no_control_flow = false; break; + case ClassFile.I2D : + current_frame.pop_stack( + VerificationType.integer_type); + current_frame.push_stack_2( + VerificationType.double_type, + VerificationType.double2_type); + no_control_flow = false; break; + case ClassFile.L2F : + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + current_frame.push_stack( + VerificationType.float_type); + no_control_flow = false; break; + case ClassFile.L2D : + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + current_frame.push_stack_2( + VerificationType.double_type, + VerificationType.double2_type); + no_control_flow = false; break; + case ClassFile.F2I : + current_frame.pop_stack( + VerificationType.float_type); + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.F2L : + current_frame.pop_stack( + VerificationType.float_type); + current_frame.push_stack_2( + VerificationType.long_type, + VerificationType.long2_type); + no_control_flow = false; break; + case ClassFile.F2D : + current_frame.pop_stack( + VerificationType.float_type); + current_frame.push_stack_2( + VerificationType.double_type, + VerificationType.double2_type); + no_control_flow = false; break; + case ClassFile.D2I : + current_frame.pop_stack_2( + VerificationType.double2_type, + VerificationType.double_type); + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.D2L : + current_frame.pop_stack_2( + VerificationType.double2_type, + VerificationType.double_type); + current_frame.push_stack_2( + VerificationType.long_type, + VerificationType.long2_type); + no_control_flow = false; break; + case ClassFile.D2F : + current_frame.pop_stack_2( + VerificationType.double2_type, + VerificationType.double_type); + current_frame.push_stack( + VerificationType.float_type); + no_control_flow = false; break; + case ClassFile.I2B : + case ClassFile.I2C : + case ClassFile.I2S : + current_frame.pop_stack( + VerificationType.integer_type); + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.LCMP : + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.FCMPL : + case ClassFile.FCMPG : + current_frame.pop_stack( + VerificationType.float_type); + current_frame.pop_stack( + VerificationType.float_type); + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.DCMPL : + case ClassFile.DCMPG : + current_frame.pop_stack_2( + VerificationType.double2_type, + VerificationType.double_type); + current_frame.pop_stack_2( + VerificationType.double2_type, + VerificationType.double_type); + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.IF_ICMPEQ: + case ClassFile.IF_ICMPNE: + case ClassFile.IF_ICMPLT: + case ClassFile.IF_ICMPGE: + case ClassFile.IF_ICMPGT: + case ClassFile.IF_ICMPLE: + current_frame.pop_stack( + VerificationType.integer_type); + // fall through + case ClassFile.IFEQ: + case ClassFile.IFNE: + case ClassFile.IFLT: + case ClassFile.IFGE: + case ClassFile.IFGT: + case ClassFile.IFLE: + current_frame.pop_stack( + VerificationType.integer_type); + target = bcs.dest(); + stackmap_table.check_jump_target( + current_frame, target); + no_control_flow = false; break; + case ClassFile.IF_ACMPEQ : + case ClassFile.IF_ACMPNE : + current_frame.pop_stack( + VerificationType.reference_check); + // fall through + case ClassFile.IFNULL : + case ClassFile.IFNONNULL : + current_frame.pop_stack( + VerificationType.reference_check); + target = bcs.dest(); + stackmap_table.check_jump_target + (current_frame, target); + no_control_flow = false; break; + case ClassFile.GOTO : + target = bcs.dest(); + stackmap_table.check_jump_target( + current_frame, target); + no_control_flow = true; break; + case ClassFile.GOTO_W : + target = bcs.destW(); + stackmap_table.check_jump_target( + current_frame, target); + no_control_flow = true; break; + case ClassFile.TABLESWITCH : + case ClassFile.LOOKUPSWITCH : + verify_switch( + bcs, code_length, code_data, current_frame, + stackmap_table); + no_control_flow = true; break; + case ClassFile.IRETURN : + type = current_frame.pop_stack( + VerificationType.integer_type); + verify_return_value(return_type, type, bci, + current_frame); + no_control_flow = true; break; + case ClassFile.LRETURN : + type2 = current_frame.pop_stack( + VerificationType.long2_type); + type = current_frame.pop_stack( + VerificationType.long_type); + verify_return_value(return_type, type, bci, + current_frame); + no_control_flow = true; break; + case ClassFile.FRETURN : + type = current_frame.pop_stack( + VerificationType.float_type); + verify_return_value(return_type, type, bci, + current_frame); + no_control_flow = true; break; + case ClassFile.DRETURN : + type2 = current_frame.pop_stack( + VerificationType.double2_type); + type = current_frame.pop_stack( + VerificationType.double_type); + verify_return_value(return_type, type, bci, + current_frame); + no_control_flow = true; break; + case ClassFile.ARETURN : + type = current_frame.pop_stack( + VerificationType.reference_check); + verify_return_value(return_type, type, bci, + current_frame); + no_control_flow = true; break; + case ClassFile.RETURN: + if (!return_type.is_bogus()) { + verifyError("Method expects a return value"); + } + if (object_initializer_name.equals(_method.name()) && + current_frame.flag_this_uninit()) { + verifyError("Constructor must call super() or this() before return"); + } + no_control_flow = true; break; + case ClassFile.GETSTATIC : + case ClassFile.PUTSTATIC : + verify_field_instructions(bcs, current_frame, cp, true); + no_control_flow = false; break; + case ClassFile.GETFIELD : + case ClassFile.PUTFIELD : + verify_field_instructions(bcs, current_frame, cp, false); + no_control_flow = false; break; + case ClassFile.INVOKEVIRTUAL : + case ClassFile.INVOKESPECIAL : + case ClassFile.INVOKESTATIC : + this_uninit = verify_invoke_instructions(bcs, code_length, current_frame, (bci >= ex_minmax[0] && bci < ex_minmax[1]), this_uninit, return_type, cp, stackmap_table); + no_control_flow = false; break; + case ClassFile.INVOKEINTERFACE : + case ClassFile.INVOKEDYNAMIC : + this_uninit = verify_invoke_instructions(bcs, code_length, current_frame, (bci >= ex_minmax[0] && bci < ex_minmax[1]), this_uninit, return_type, cp, stackmap_table); + no_control_flow = false; break; + case ClassFile.NEW : + { + index = bcs.getIndexU2(); + verify_cp_class_type(bci, index, cp); + VerificationType new_class_type = + cp_index_to_type(index, cp); + if (!new_class_type.is_object()) { + verifyError("Illegal new instruction"); + } + type = VerificationType.uninitialized_type(bci); + current_frame.push_stack(type); + no_control_flow = false; break; + } + case ClassFile.NEWARRAY : + type = get_newarray_type(bcs.getIndex(), bci); + current_frame.pop_stack( + VerificationType.integer_type); + current_frame.push_stack(type); + no_control_flow = false; break; + case ClassFile.ANEWARRAY : + verify_anewarray(bci, bcs.getIndexU2(), cp, current_frame); + no_control_flow = false; break; + case ClassFile.ARRAYLENGTH : + type = current_frame.pop_stack( + VerificationType.reference_check); + if (!(type.is_null() || type.is_array())) { + verifyError("Bad type"); + } + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + case ClassFile.CHECKCAST : + { + index = bcs.getIndexU2(); + verify_cp_class_type(bci, index, cp); + current_frame.pop_stack(object_type()); + VerificationType klass_type = cp_index_to_type( + index, cp); + current_frame.push_stack(klass_type); + no_control_flow = false; break; + } + case ClassFile.INSTANCEOF : { + index = bcs.getIndexU2(); + verify_cp_class_type(bci, index, cp); + current_frame.pop_stack(object_type()); + current_frame.push_stack( + VerificationType.integer_type); + no_control_flow = false; break; + } + case ClassFile.MONITORENTER : + case ClassFile.MONITOREXIT : + current_frame.pop_stack( + VerificationType.reference_check); + no_control_flow = false; break; + case ClassFile.MULTIANEWARRAY : + { + index = bcs.getIndexU2(); + int dim = _method.codeArray()[bcs.bci+3] & 0xff; + verify_cp_class_type(bci, index, cp); + VerificationType new_array_type = + cp_index_to_type(index, cp); + if (!new_array_type.is_array()) { + verifyError("Illegal constant pool index in multianewarray instruction"); + } + if (dim < 1 || new_array_type.dimensions(this) < dim) { + verifyError(String.format("Illegal dimension in multianewarray instruction: %d", dim)); + } + for (int i = 0; i < dim; i++) { + current_frame.pop_stack( + VerificationType.integer_type); + } + current_frame.push_stack(new_array_type); + no_control_flow = false; break; + } + case ClassFile.ATHROW : + type = VerificationType.reference_type(java_lang_Throwable); + current_frame.pop_stack(type); + no_control_flow = true; break; + default: + verifyError(String.format("Bad instruction: %02x", opcode)); + } + } + if (verified_exc_handlers && this_uninit) verifyError("Exception handler targets got verified before this_uninit got set"); + if (!verified_exc_handlers && bci >= ex_minmax[0] && bci < ex_minmax[1]) { + verify_exception_handler_targets(bci, this_uninit, current_frame, stackmap_table); + } + } + if (!no_control_flow) { + verifyError("Control flow falls through code end"); + } + } + + private byte[] generate_code_data(ByteBuffer code, int code_length) { + byte code_data[] = new byte[code_length]; + var bcs = new RawBytecodeHelper(code); + while (!bcs.isLastBytecode()) { + if (bcs.rawNext() != ILLEGAL) { + int bci = bcs.bci; + if (bcs.rawCode == ClassFile.NEW) { + code_data[bci] = NEW_OFFSET; + } else { + code_data[bci] = BYTECODE_OFFSET; + } + } else { + verifyError("Bad instruction"); + } + } + return code_data; + } + + void verify_exception_handler_table(int code_length, byte[] code_data, int[] minmax) { + var cp = _method.constantPool(); + for (var exhandler : _method.exceptionTable()) { + int start_pc = exhandler[0]; + int end_pc = exhandler[1]; + int handler_pc = exhandler[2]; + if (start_pc >= code_length || code_data[start_pc] == 0) { + classError(String.format("Illegal exception table start_pc %d", start_pc)); + } + if (end_pc != code_length) { + if (end_pc > code_length || code_data[end_pc] == 0) { + classError(String.format("Illegal exception table end_pc %d", end_pc)); + } + } + if (handler_pc >= code_length || code_data[handler_pc] == 0) { + classError(String.format("Illegal exception table handler_pc %d", handler_pc)); + } + int catch_type_index = exhandler[3]; + if (catch_type_index != 0) { + VerificationType catch_type = cp_index_to_type(catch_type_index, cp); + VerificationType throwable = VerificationType.reference_type(java_lang_Throwable); + boolean is_subclass = throwable.is_assignable_from(catch_type, this); + if (!is_subclass) { + verifyError(String.format("Catch type is not a subclass of Throwable in exception handler %d", handler_pc)); + } + } + if (start_pc < minmax[0]) minmax[0] = start_pc; + if (end_pc > minmax[1]) minmax[1] = end_pc; + } + } + + void verify_local_variable_table(int code_length, byte[] code_data) { + for (var lvte : _method.localVariableTable()) { + int start_bci = lvte.startPc(); + int length = lvte.length(); + if (start_bci >= code_length || code_data[start_bci] == 0) { + classError(String.format("Illegal local variable table start_pc %d", start_bci)); + } + int end_bci = start_bci + length; + if (end_bci != code_length) { + if (end_bci >= code_length || code_data[end_bci] == 0) { + classError(String.format("Illegal local variable table length %d", length)); + } + } + } + } + + int verify_stackmap_table(int stackmap_index, int bci, VerificationFrame current_frame, VerificationTable stackmap_table, boolean no_control_flow) { + if (stackmap_index < stackmap_table.get_frame_count()) { + int this_offset = stackmap_table.get_offset(stackmap_index); + if (no_control_flow && this_offset > bci) { + verifyError("Expecting a stack map frame"); + } + if (this_offset == bci) { + boolean matches = stackmap_table.match_stackmap(current_frame, this_offset, stackmap_index, !no_control_flow, true); + if (!matches) { + verifyError("Instruction type does not match stack map"); + } + stackmap_index++; + } else if (this_offset < bci) { + classError(String.format("Bad stack map offset %d", this_offset)); + } + } else if (no_control_flow) { + verifyError("Expecting a stack map frame"); + } + return stackmap_index; + } + + void verify_exception_handler_targets(int bci, boolean this_uninit, VerificationFrame current_frame, VerificationTable stackmap_table) { + var cp = _method.constantPool(); + for(var exhandler : _method.exceptionTable()) { + int start_pc = exhandler[0]; + int end_pc = exhandler[1]; + int handler_pc = exhandler[2]; + int catch_type_index = exhandler[3]; + if(bci >= start_pc && bci < end_pc) { + int flags = current_frame.flags(); + if (this_uninit) { flags |= FLAG_THIS_UNINIT; } + VerificationFrame new_frame = current_frame.frame_in_exception_handler(flags); + if (catch_type_index != 0) { + VerificationType catch_type = cp_index_to_type(catch_type_index, cp); + new_frame.push_stack(catch_type); + } else { + VerificationType throwable = VerificationType.reference_type(java_lang_Throwable); + new_frame.push_stack(throwable); + } + boolean matches = stackmap_table.match_stackmap(new_frame, handler_pc, true, false); + if (!matches) { + verifyError(String.format("Stack map does not match the one at exception handler %d", handler_pc)); + } + } + } + } + + void verify_cp_index(int bci, ConstantPoolWrapper cp, int index) { + int nconstants = cp.entryCount(); + if ((index <= 0) || (index >= nconstants)) { + verifyError(String.format("Illegal constant pool index %d", index)); + } + } + + void verify_cp_type(int bci, int index, ConstantPoolWrapper cp, int types) { + verify_cp_index(bci, cp, index); + int tag = cp.tagAt(index); + if ((types & (1 << tag))== 0) { + verifyError(String.format("Illegal type at constant pool entry %d", index)); + } + } + + void verify_cp_class_type(int bci, int index, ConstantPoolWrapper cp) { + verify_cp_index(bci, cp, index); + int tag = cp.tagAt(index); + if (tag != JVM_CONSTANT_Class) { + verifyError(String.format("Illegal type at constant pool entry %d", index)); + } + } + + void verify_ldc(int opcode, int index, VerificationFrame current_frame, ConstantPoolWrapper cp, int bci) { + verify_cp_index(bci, cp, index); + int tag = cp.tagAt(index); + int types = 0; + if (opcode == ClassFile.LDC || opcode == ClassFile.LDC_W) { + types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) + | (1 << JVM_CONSTANT_String) | (1 << JVM_CONSTANT_Class) + | (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType) + | (1 << JVM_CONSTANT_Dynamic); + verify_cp_type(bci, index, cp, types); + } else { + if (opcode != ClassFile.LDC2_W) verifyError("must be ldc2_w"); + types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long) | (1 << JVM_CONSTANT_Dynamic); + verify_cp_type(bci, index, cp, types); + } + switch (tag) { + case JVM_CONSTANT_Utf8 -> current_frame.push_stack(object_type()); + case JVM_CONSTANT_String -> current_frame.push_stack(VerificationType.reference_type(java_lang_String)); + case JVM_CONSTANT_Class -> current_frame.push_stack(VerificationType.reference_type(java_lang_Class)); + case JVM_CONSTANT_Integer -> current_frame.push_stack(VerificationType.integer_type); + case JVM_CONSTANT_Float -> current_frame.push_stack(VerificationType.float_type); + case JVM_CONSTANT_Double -> current_frame.push_stack_2(VerificationType.double_type, VerificationType.double2_type); + case JVM_CONSTANT_Long -> current_frame.push_stack_2(VerificationType.long_type, VerificationType.long2_type); + case JVM_CONSTANT_MethodHandle -> current_frame.push_stack(VerificationType.reference_type(java_lang_invoke_MethodHandle)); + case JVM_CONSTANT_MethodType -> current_frame.push_stack(VerificationType.reference_type(java_lang_invoke_MethodType)); + case JVM_CONSTANT_Dynamic -> { + String constant_type = cp.dynamicConstantSignatureAt(index); + if (!VerificationSignature.isValidTypeSignature(constant_type)) verifyError("Invalid type for dynamic constant"); + VerificationType[] v_constant_type = new VerificationType[2]; + var sig_stream = new VerificationSignature(constant_type, false, this); + int n = change_sig_to_verificationType(sig_stream, v_constant_type, 0); + int opcode_n = (opcode == ClassFile.LDC2_W ? 2 : 1); + if (n != opcode_n) { + types &= ~(1 << JVM_CONSTANT_Dynamic); + verify_cp_type(bci, index, cp, types); + } + for (int i = 0; i < n; i++) { + current_frame.push_stack(v_constant_type[i]); + } + } + default -> verifyError("Invalid index in ldc"); + } + } + + void verify_switch(RawBytecodeHelper bcs, int code_length, byte[] code_data, VerificationFrame current_frame, VerificationTable stackmap_table) { + int bci = bcs.bci; + int aligned_bci = VerificationBytecodes.align(bci + 1); + // 4639449 & 4647081: padding bytes must be 0 + if (_klass.majorVersion() < NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION) { + int padding_offset = 1; + while ((bci + padding_offset) < aligned_bci) { + if (_method.codeArray()[bci + padding_offset] != 0) { + verifyError("Nonzero padding byte in lookupswitch or tableswitch"); + } + padding_offset++; + } + } + int default_ofset = bcs.getInt(aligned_bci); + int keys, delta; + current_frame.pop_stack(VerificationType.integer_type); + if (bcs.rawCode == ClassFile.TABLESWITCH) { + int low = bcs.getInt(aligned_bci + 4); + int high = bcs.getInt(aligned_bci + 2*4); + if (low > high) { + verifyError("low must be less than or equal to high in tableswitch"); + } + keys = high - low + 1; + if (keys < 0) { + verifyError("too many keys in tableswitch"); + } + delta = 1; + } else { + // Make sure that the lookupswitch items are sorted + keys = bcs.getInt(aligned_bci + 4); + if (keys < 0) { + verifyError("number of keys in lookupswitch less than 0"); + } + delta = 2; + for (int i = 0; i < (keys - 1); i++) { + int this_key = bcs.getInt(aligned_bci + (2+2*i)*4); + int next_key = bcs.getInt(aligned_bci + (2+2*i+2)*4); + if (this_key >= next_key) { + verifyError("Bad lookupswitch instruction"); + } + } + } + int target = bci + default_ofset; + stackmap_table.check_jump_target(current_frame, target); + for (int i = 0; i < keys; i++) { + aligned_bci = VerificationBytecodes.align(bcs.bci + 1); + target = bci + bcs.getInt(aligned_bci + (3+i*delta)*4); + stackmap_table.check_jump_target(current_frame, target); + } + } + + void verify_field_instructions(RawBytecodeHelper bcs, VerificationFrame current_frame, ConstantPoolWrapper cp, boolean allow_arrays) { + int index = bcs.getIndexU2(); + verify_cp_type(bcs.bci, index, cp, 1 << JVM_CONSTANT_Fieldref); + String field_name = cp.refNameAt(index); + String field_sig = cp.refSignatureAt(index); + if (!VerificationSignature.isValidTypeSignature(field_sig)) verifyError("Invalid field signature"); + VerificationType ref_class_type = cp_ref_index_to_type(index, cp); + if (!ref_class_type.is_object() && + (!allow_arrays || !ref_class_type.is_array())) { + verifyError(String.format("Expecting reference to class in class %s at constant pool index %d", _klass.thisClassName(), index)); + } + VerificationType target_class_type = ref_class_type; + VerificationType[] field_type = new VerificationType[2]; + var sig_stream = new VerificationSignature(field_sig, false, this); + VerificationType stack_object_type = null; + int n = change_sig_to_verificationType(sig_stream, field_type, 0); + boolean is_assignable; + switch (bcs.rawCode) { + case ClassFile.GETSTATIC -> { + for (int i = 0; i < n; i++) { + current_frame.push_stack(field_type[i]); + } + } + case ClassFile.PUTSTATIC -> { + for (int i = n - 1; i >= 0; i--) { + current_frame.pop_stack(field_type[i]); + } + } + case ClassFile.GETFIELD -> { + stack_object_type = current_frame.pop_stack( + target_class_type); + for (int i = 0; i < n; i++) { + current_frame.push_stack(field_type[i]); + } + } + case ClassFile.PUTFIELD -> { + for (int i = n - 1; i >= 0; i--) { + current_frame.pop_stack(field_type[i]); + } + stack_object_type = current_frame.pop_stack(); + if (stack_object_type.is_uninitialized_this(this) && + target_class_type.equals(current_type()) && + _klass.findField(field_name, field_sig)) { + stack_object_type = current_type(); + } + is_assignable = target_class_type.is_assignable_from(stack_object_type, this); + if (!is_assignable) { + verifyError("Bad type on operand stack in putfield"); + } + } + default -> verifyError("Should not reach here"); + } + } + + // Return TRUE if all code paths starting with start_bc_offset end in + // bytecode athrow or loop. + boolean ends_in_athrow(int start_bc_offset) { + log_info("unimplemented VerifierImpl.ends_in_athrow"); + return true; + } + + boolean verify_invoke_init(RawBytecodeHelper bcs, int ref_class_index, VerificationType ref_class_type, + VerificationFrame current_frame, int code_length, boolean in_try_block, + boolean this_uninit, ConstantPoolWrapper cp, VerificationTable stackmap_table) { + int bci = bcs.bci; + VerificationType type = current_frame.pop_stack(VerificationType.reference_check); + if (type.is_uninitialized_this(this)) { + String superk_name = current_class().superclassName(); + if (!current_class().thisClassName().equals(ref_class_type.name()) && + !superk_name.equals(ref_class_type.name())) { + verifyError("Bad method call"); + } + if (in_try_block) { + for(var exhandler : _method.exceptionTable()) { + int start_pc = exhandler[0]; + int end_pc = exhandler[1]; + + if (bci >= start_pc && bci < end_pc) { + if (!ends_in_athrow(exhandler[2])) { + verifyError("Bad method call from after the start of a try block"); + } + } + } + verify_exception_handler_targets(bci, true, current_frame, stackmap_table); + } + current_frame.initialize_object(type, current_type()); + this_uninit = true; + } else if (type.is_uninitialized()) { + int new_offset = type.bci(this); + if (new_offset > (code_length - 3) || (_method.codeArray()[new_offset] & 0xff) != ClassFile.NEW) { + verifyError("Expecting new instruction"); + } + int new_class_index = bcs.getIndexU2Raw(new_offset + 1); + verify_cp_class_type(bci, new_class_index, cp); + VerificationType new_class_type = cp_index_to_type( + new_class_index, cp); + if (!new_class_type.equals(ref_class_type)) { + verifyError("Call to wrong method"); + } + if (in_try_block) { + verify_exception_handler_targets(bci, this_uninit, current_frame, + stackmap_table); + } + current_frame.initialize_object(type, new_class_type); + } else { + verifyError("Bad operand type when invoking "); + } + return this_uninit; + } + + static boolean is_same_or_direct_interface(VerificationWrapper klass, VerificationType klass_type, VerificationType ref_class_type) { + if (ref_class_type.equals(klass_type)) return true; + for (String k_name : klass.interfaceNames()) { + if (ref_class_type.equals(VerificationType.reference_type(k_name))) { + return true; + } + } + return false; + } + + boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, VerificationFrame current_frame, boolean in_try_block, boolean this_uninit, VerificationType return_type, ConstantPoolWrapper cp, VerificationTable stackmap_table) { + // Make sure the constant pool item is the right type + int index = bcs.getIndexU2(); + int opcode = bcs.rawCode; + int types = 0; + switch (opcode) { + case ClassFile.INVOKEINTERFACE: + types = 1 << JVM_CONSTANT_InterfaceMethodref; + break; + case ClassFile.INVOKEDYNAMIC: + types = 1 << JVM_CONSTANT_InvokeDynamic; + break; + case ClassFile.INVOKESPECIAL: + case ClassFile.INVOKESTATIC: + types = (_klass.majorVersion() < STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION) ? + (1 << JVM_CONSTANT_Methodref) : + ((1 << JVM_CONSTANT_InterfaceMethodref) | (1 << JVM_CONSTANT_Methodref)); + break; + default: + types = 1 << JVM_CONSTANT_Methodref; + } + verify_cp_type(bcs.bci, index, cp, types); + String method_name = cp.refNameAt(index); + String method_sig = cp.refSignatureAt(index); + if (!VerificationSignature.isValidMethodSignature(method_sig)) verifyError("Invalid method signature"); + VerificationType ref_class_type = null; + if (opcode == ClassFile.INVOKEDYNAMIC) { + if (_klass.majorVersion() < INVOKEDYNAMIC_MAJOR_VERSION) { + classError(String.format("invokedynamic instructions not supported by this class file version (%d), class %s", _klass.majorVersion(), _klass.thisClassName())); + } + } else { + ref_class_type = cp_ref_index_to_type(index, cp); + } + String sig = cp.refSignatureAt(index); + sig_as_verification_types mth_sig_verif_types; + ArrayList verif_types = new ArrayList<>(10); + mth_sig_verif_types = new sig_as_verification_types(verif_types); + create_method_sig_entry(mth_sig_verif_types, sig); + int nargs = mth_sig_verif_types.num_args(); + int bci = bcs.bci; + if (opcode == ClassFile.INVOKEINTERFACE) { + if ((_method.codeArray()[bci+3] & 0xff) != (nargs+1)) { + verifyError("Inconsistent args count operand in invokeinterface"); + } + if ((_method.codeArray()[bci+4] & 0xff) != 0) { + verifyError("Fourth operand byte of invokeinterface must be zero"); + } + } + if (opcode == ClassFile.INVOKEDYNAMIC) { + if ((_method.codeArray()[bci+3] & 0xff) != 0 || (_method.codeArray()[bci+4] & 0xff) != 0) { + verifyError("Third and fourth operand bytes of invokedynamic must be zero"); + } + } + if (method_name.charAt(0) == JVM_SIGNATURE_SPECIAL) { + if (opcode != ClassFile.INVOKESPECIAL || + !object_initializer_name.equals(method_name)) { + verifyError("Illegal call to internal method"); + } + } else if (opcode == ClassFile.INVOKESPECIAL + && !is_same_or_direct_interface(current_class(), current_type(), ref_class_type) + && !ref_class_type.equals(VerificationType.reference_type( + current_class().superclassName()))) { + boolean have_imr_indirect = cp.tagAt(index) == JVM_CONSTANT_InterfaceMethodref; + boolean subtype = ref_class_type.is_assignable_from(current_type(), this); + if (!subtype) { + verifyError("Bad invokespecial instruction: current class isn't assignable to reference class."); + } else if (have_imr_indirect) { + verifyError("Bad invokespecial instruction: interface method reference is in an indirect superinterface."); + } + + } + ArrayList sig_verif_types = mth_sig_verif_types.sig_verif_types(); + if (sig_verif_types == null) verifyError("Missing signature's array of verification types"); + for (int i = nargs - 1; i >= 0; i--) { // Run backwards + current_frame.pop_stack(sig_verif_types.get(i)); + } + if (opcode != ClassFile.INVOKESTATIC && + opcode != ClassFile.INVOKEDYNAMIC) { + if (object_initializer_name.equals(method_name)) { // method + this_uninit = verify_invoke_init(bcs, index, ref_class_type, current_frame, + code_length, in_try_block, this_uninit, cp, stackmap_table); + } else { + switch (opcode) { + case ClassFile.INVOKESPECIAL -> + current_frame.pop_stack(current_type()); + case ClassFile.INVOKEVIRTUAL -> { + VerificationType stack_object_type = + current_frame.pop_stack(ref_class_type); + if (current_type() != stack_object_type) { + cp.classNameAt(cp.refClassIndexAt(index)); + } + } + default -> { + if (opcode != ClassFile.INVOKEINTERFACE) + verifyError("Unexpected opcode encountered"); + current_frame.pop_stack(ref_class_type); + } + } + } + } + int sig_verif_types_len = sig_verif_types.size(); + if (sig_verif_types_len > nargs) { // There's a return type + if (object_initializer_name.equals(method_name)) { + verifyError("Return type must be void in method"); + } + + if (sig_verif_types_len > nargs + 2) verifyError("Signature verification types array return type is bogus"); + for (int i = nargs; i < sig_verif_types_len; i++) { + if (!(i == nargs || sig_verif_types.get(i).is_long2() || sig_verif_types.get(i).is_double2())) verifyError("Unexpected return verificationType"); + current_frame.push_stack(sig_verif_types.get(i)); + } + } + return this_uninit; + } + + VerificationType get_newarray_type(int index, int bci) { + String[] from_bt = new String[] { + null, null, null, null, "[Z", "[C", "[F", "[D", "[B", "[S", "[I", "[J", + }; + if (index < T_BOOLEAN.type || index > T_LONG.type) { + verifyError("Illegal newarray instruction"); + } + String sig = from_bt[index]; + return VerificationType.reference_type(sig); + } + + void verify_anewarray(int bci, int index, ConstantPoolWrapper cp, VerificationFrame current_frame) { + verify_cp_class_type(bci, index, cp); + current_frame.pop_stack(VerificationType.integer_type); + VerificationType component_type = cp_index_to_type(index, cp); + int length; + String arr_sig_str; + if (component_type.is_array()) { // it's an array + String component_name = component_type.name(); + length = component_name.length(); + if (length > MAX_ARRAY_DIMENSIONS && + component_name.charAt(MAX_ARRAY_DIMENSIONS - 1) == JVM_SIGNATURE_ARRAY) { + verifyError("Illegal anewarray instruction, array has more than 255 dimensions"); + } + length++; + arr_sig_str = String.format("%c%s", JVM_SIGNATURE_ARRAY, component_name); + if (arr_sig_str.length() != length) verifyError("Unexpected number of characters in string"); + } else { // it's an object or interface + String component_name = component_type.name(); + length = component_name.length() + 3; + arr_sig_str = String.format("%c%c%s;", JVM_SIGNATURE_ARRAY, JVM_SIGNATURE_CLASS, component_name); + if (arr_sig_str.length() != length) verifyError("Unexpected number of characters in string"); + } + VerificationType new_array_type = VerificationType.reference_type(arr_sig_str); + current_frame.push_stack(new_array_type); + } + + void verify_iload(int index, VerificationFrame current_frame) { + current_frame.get_local( + index, VerificationType.integer_type); + current_frame.push_stack( + VerificationType.integer_type); + } + + void verify_lload(int index, VerificationFrame current_frame) { + current_frame.get_local_2( + index, VerificationType.long_type, + VerificationType.long2_type); + current_frame.push_stack_2( + VerificationType.long_type, + VerificationType.long2_type); + } + + void verify_fload(int index, VerificationFrame current_frame) { + current_frame.get_local( + index, VerificationType.float_type); + current_frame.push_stack( + VerificationType.float_type); + } + + void verify_dload(int index, VerificationFrame current_frame) { + current_frame.get_local_2( + index, VerificationType.double_type, + VerificationType.double2_type); + current_frame.push_stack_2( + VerificationType.double_type, + VerificationType.double2_type); + } + + void verify_aload(int index, VerificationFrame current_frame) { + VerificationType type = current_frame.get_local( + index, VerificationType.reference_check); + current_frame.push_stack(type); + } + + void verify_istore(int index, VerificationFrame current_frame) { + current_frame.pop_stack( + VerificationType.integer_type); + current_frame.set_local( + index, VerificationType.integer_type); + } + + void verify_lstore(int index, VerificationFrame current_frame) { + current_frame.pop_stack_2( + VerificationType.long2_type, + VerificationType.long_type); + current_frame.set_local_2( + index, VerificationType.long_type, + VerificationType.long2_type); + } + + void verify_fstore(int index, VerificationFrame current_frame) { + current_frame.pop_stack( + VerificationType.float_type); + current_frame.set_local( + index, VerificationType.float_type); + } + + void verify_dstore(int index, VerificationFrame current_frame) { + current_frame.pop_stack_2( + VerificationType.double2_type, + VerificationType.double_type); + current_frame.set_local_2( + index, VerificationType.double_type, + VerificationType.double2_type); + } + + void verify_astore(int index, VerificationFrame current_frame) { + VerificationType type = current_frame.pop_stack( + VerificationType.reference_check); + current_frame.set_local(index, type); + } + + void verify_iinc(int index, VerificationFrame current_frame) { + VerificationType type = current_frame.get_local( + index, VerificationType.integer_type); + current_frame.set_local(index, type); + } + + void verify_return_value(VerificationType return_type, VerificationType type, int bci, VerificationFrame current_frame) { + if (return_type.is_bogus()) { + verifyError("Method expects a return value"); + } + boolean match = return_type.is_assignable_from(type, this); + if (!match) { + verifyError("Bad return type"); + } + } + + private void dumpMethod() { + if (_logger != null) ClassPrinter.toTree(_method.m, ClassPrinter.Verbosity.CRITICAL_ATTRIBUTES).toYaml(_logger); + } + + void verifyError(String msg) { + dumpMethod(); + throw new VerifyError(String.format("%s in %s::%s(%s) @%d %s", msg, _klass.thisClassName(), _method.name(), _method.parameters(), bci, errorContext).trim()); + } + + void verifyError(String msg, VerificationFrame from, VerificationFrame target) { + dumpMethod(); + throw new VerifyError(String.format("%s in %s::%s(%s) @%d %s%n while assigning %s%n to %s", msg, _klass.thisClassName(), _method.name(), _method.parameters(), bci, errorContext, from, target)); + } + + void classError(String msg) { + dumpMethod(); + throw new VerifyError(String.format("%s in %s::%s(%s)", msg, _klass.thisClassName(), _method.name(), _method.parameters())); + } +} diff --git a/tests/test_data/std/jdk/internal/constant/ConstantUtils.class b/tests/test_data/std/jdk/internal/constant/ConstantUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..798c24a5bc5d7b18d41573be0c5d4c18974b7668 GIT binary patch literal 6839 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 Hg17zy_P=u8 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/constant/ConstantUtils.java b/tests/test_data/std/jdk/internal/constant/ConstantUtils.java new file mode 100644 index 00000000..7c676a44 --- /dev/null +++ b/tests/test_data/std/jdk/internal/constant/ConstantUtils.java @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.constant; + +import sun.invoke.util.Wrapper; + +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDesc; +import java.lang.constant.ConstantDescs; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Helper methods for the implementation of {@code java.lang.constant}. + */ +public final class ConstantUtils { + /** an empty constant descriptor */ + public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0]; + public static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0]; + public static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255; + + private static final Set pointyNames = Set.of(ConstantDescs.INIT_NAME, ConstantDescs.CLASS_INIT_NAME); + + /** No instantiation */ + private ConstantUtils() {} + + /** + * Validates the correctness of a binary class name. In particular checks for the presence of + * invalid characters in the name. + * + * @param name the class name + * @return the class name passed if valid + * @throws IllegalArgumentException if the class name is invalid + * @throws NullPointerException if class name is {@code null} + */ + public static String validateBinaryClassName(String name) { + for (int i = 0; i < name.length(); i++) { + char ch = name.charAt(i); + if (ch == ';' || ch == '[' || ch == '/') + throw new IllegalArgumentException("Invalid class name: " + name); + } + return name; + } + + /** + * Validates the correctness of an internal class name. + * In particular checks for the presence of invalid characters in the name. + * + * @param name the class name + * @return the class name passed if valid + * @throws IllegalArgumentException if the class name is invalid + * @throws NullPointerException if class name is {@code null} + */ + public static String validateInternalClassName(String name) { + for (int i = 0; i < name.length(); i++) { + char ch = name.charAt(i); + if (ch == ';' || ch == '[' || ch == '.') + throw new IllegalArgumentException("Invalid class name: " + name); + } + return name; + } + + /** + * Validates the correctness of a binary package name. + * In particular checks for the presence of invalid characters in the name. + * Empty package name is allowed. + * + * @param name the package name + * @return the package name passed if valid + * @throws IllegalArgumentException if the package name is invalid + * @throws NullPointerException if the package name is {@code null} + */ + public static String validateBinaryPackageName(String name) { + for (int i = 0; i < name.length(); i++) { + char ch = name.charAt(i); + if (ch == ';' || ch == '[' || ch == '/') + throw new IllegalArgumentException("Invalid package name: " + name); + } + return name; + } + + /** + * Validates the correctness of an internal package name. + * In particular checks for the presence of invalid characters in the name. + * Empty package name is allowed. + * + * @param name the package name + * @return the package name passed if valid + * @throws IllegalArgumentException if the package name is invalid + * @throws NullPointerException if the package name is {@code null} + */ + public static String validateInternalPackageName(String name) { + for (int i = 0; i < name.length(); i++) { + char ch = name.charAt(i); + if (ch == ';' || ch == '[' || ch == '.') + throw new IllegalArgumentException("Invalid package name: " + name); + } + return name; + } + + /** + * Validates the correctness of a module name. + * In particular checks for the presence of invalid characters in the name. + * Empty module name is allowed. + * + * {@jvms 4.2.3} Module and Package Names + * + * @param name the module name + * @return the module name passed if valid + * @throws IllegalArgumentException if the module name is invalid + * @throws NullPointerException if the module name is {@code null} + */ + public static String validateModuleName(String name) { + for (int i = name.length() - 1; i >= 0; i--) { + char ch = name.charAt(i); + if ((ch >= '\u0000' && ch <= '\u001F') + || ((ch == '\\' || ch == ':' || ch =='@') && (i == 0 || name.charAt(--i) != '\\'))) + throw new IllegalArgumentException("Invalid module name: " + name); + } + return name; + } + + /** + * Validates a member name + * + * @param name the name of the member + * @return the name passed if valid + * @throws IllegalArgumentException if the member name is invalid + * @throws NullPointerException if the member name is {@code null} + */ + public static String validateMemberName(String name, boolean method) { + int len = name.length(); + if (len == 0) + throw new IllegalArgumentException("zero-length member name"); + for (int i = 0; i < len; i++) { + char ch = name.charAt(i); + // common case fast-path + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) + continue; + if (ch == '.' || ch == ';' || ch == '[' || ch == '/') + throw new IllegalArgumentException("Invalid member name: " + name); + if (method && (ch == '<' || ch == '>')) { + if (!pointyNames.contains(name)) + throw new IllegalArgumentException("Invalid member name: " + name); + } + } + return name; + } + + public static void validateClassOrInterface(ClassDesc classDesc) { + if (!classDesc.isClassOrInterface()) + throw new IllegalArgumentException("not a class or interface type: " + classDesc); + } + + public static int arrayDepth(String descriptorString) { + int depth = 0; + while (descriptorString.charAt(depth) == '[') + depth++; + return depth; + } + + public static String binaryToInternal(String name) { + return name.replace('.', '/'); + } + + public static String internalToBinary(String name) { + return name.replace('/', '.'); + } + + public static String dropFirstAndLastChar(String s) { + return s.substring(1, s.length() - 1); + } + + /** + * Parses a method descriptor string, and return a list of field descriptor + * strings, return type first, then parameter types + * + * @param descriptor the descriptor string + * @return the list of types + * @throws IllegalArgumentException if the descriptor string is not valid + */ + public static List parseMethodDescriptor(String descriptor) { + int cur = 0, end = descriptor.length(); + ArrayList ptypes = new ArrayList<>(); + ptypes.add(null); // placeholder for return type + + if (cur >= end || descriptor.charAt(cur) != '(') + throw new IllegalArgumentException("Bad method descriptor: " + descriptor); + + ++cur; // skip '(' + while (cur < end && descriptor.charAt(cur) != ')') { + int len = skipOverFieldSignature(descriptor, cur, end, false); + if (len == 0) + throw new IllegalArgumentException("Bad method descriptor: " + descriptor); + ptypes.add(resolveClassDesc(descriptor, cur, len)); + cur += len; + } + if (cur >= end) + throw new IllegalArgumentException("Bad method descriptor: " + descriptor); + ++cur; // skip ')' + + int rLen = skipOverFieldSignature(descriptor, cur, end, true); + if (rLen == 0 || cur + rLen != end) + throw new IllegalArgumentException("Bad method descriptor: " + descriptor); + ptypes.set(0, resolveClassDesc(descriptor, cur, rLen)); + return ptypes; + } + + private static ClassDesc resolveClassDesc(String descriptor, int start, int len) { + if (len == 1) { + return Wrapper.forPrimitiveType(descriptor.charAt(start)).classDescriptor(); + } + // Pre-verified in parseMethodDescriptor; avoid redundant verification + return ReferenceClassDescImpl.ofValidated(descriptor.substring(start, start + len)); + } + + private static final char JVM_SIGNATURE_ARRAY = '['; + private static final char JVM_SIGNATURE_BYTE = 'B'; + private static final char JVM_SIGNATURE_CHAR = 'C'; + private static final char JVM_SIGNATURE_CLASS = 'L'; + private static final char JVM_SIGNATURE_ENDCLASS = ';'; + private static final char JVM_SIGNATURE_ENUM = 'E'; + private static final char JVM_SIGNATURE_FLOAT = 'F'; + private static final char JVM_SIGNATURE_DOUBLE = 'D'; + private static final char JVM_SIGNATURE_FUNC = '('; + private static final char JVM_SIGNATURE_ENDFUNC = ')'; + private static final char JVM_SIGNATURE_INT = 'I'; + private static final char JVM_SIGNATURE_LONG = 'J'; + private static final char JVM_SIGNATURE_SHORT = 'S'; + private static final char JVM_SIGNATURE_VOID = 'V'; + private static final char JVM_SIGNATURE_BOOLEAN = 'Z'; + + /** + * Validates that the characters at [start, end) within the provided string + * describe a valid field type descriptor. + * @param descriptor the descriptor string + * @param start the starting index into the string + * @param end the ending index within the string + * @param voidOK is void acceptable? + * @return the length of the descriptor, or 0 if it is not a descriptor + * @throws IllegalArgumentException if the descriptor string is not valid + */ + @SuppressWarnings("fallthrough") + static int skipOverFieldSignature(String descriptor, int start, int end, boolean voidOK) { + int arrayDim = 0; + int index = start; + while (index < end) { + switch (descriptor.charAt(index)) { + case JVM_SIGNATURE_VOID: if (!voidOK) { return 0; } + case JVM_SIGNATURE_BOOLEAN: + case JVM_SIGNATURE_BYTE: + case JVM_SIGNATURE_CHAR: + case JVM_SIGNATURE_SHORT: + case JVM_SIGNATURE_INT: + case JVM_SIGNATURE_FLOAT: + case JVM_SIGNATURE_LONG: + case JVM_SIGNATURE_DOUBLE: + return index - start + 1; + case JVM_SIGNATURE_CLASS: + // state variable for detection of illegal states, such as: + // empty unqualified name, '//', leading '/', or trailing '/' + boolean legal = false; + while (++index < end) { + switch (descriptor.charAt(index)) { + case ';' -> { + // illegal state on parser exit indicates empty unqualified name or trailing '/' + return legal ? index - start + 1 : 0; + } + case '.', '[' -> { + // do not permit '.' or '[' + return 0; + } + case '/' -> { + // illegal state when received '/' indicates '//' or leading '/' + if (!legal) return 0; + legal = false; + } + default -> + legal = true; + } + } + return 0; + case JVM_SIGNATURE_ARRAY: + arrayDim++; + if (arrayDim > MAX_ARRAY_TYPE_DESC_DIMENSIONS) { + throw new IllegalArgumentException(String.format("Cannot create an array type descriptor with more than %d dimensions", + ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS)); + } + // The rest of what's there better be a legal descriptor + index++; + voidOK = false; + break; + default: + return 0; + } + } + return 0; + } +} diff --git a/tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl$1.class b/tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..59841e1e2ddab509c09ef5048550bb78dda8974d GIT binary patch literal 1387 zcmb7EZBNrs6n?smbsI$n^6m>L6PPcI7ex_7X4#-|FJvwFfe%=^1`4GmZHHe?^aq&e z4=~ZhuPV_PWB397DC4;u*u{W`roGR7o_o)|=bW9hpTE8z0uZs7KnP(T5dlqzav0rK z_tlK4TALZowp>rOyv%~(=$cp5y)C=Cq*_%|U(j7G_1Lhg9HRTGS<_t(lOyT1!r826 z;)o&6BO#y}0*8t1>Q2V6Jl(NW^MChCyL)D8oWpcVer9;uR#DwcvFlUJ`P8xVsed{j zT9e`w|2YAzNOEWv%OzQzNIJU!_=n>G%oQN*w6eU+-(ggt*eM$Z!T^7*Kq!wApDw4P!Y`!AkYU4^^ zlM--^t?;W-MOn!f*wMoRMtn_P&WTc8yDs1c)7qpGIgrnax%CE%TLMP^T5Yf$6EMzJ zqjkU76_WyPGbtGyS6}2YMQV_Z^2RpR7l+uaW*U~^&G|`N-5+uvg9nn->S9f{jIHZH9k1O<)_M+%ngCz&3Meb0ma>*Xn zBy2{?UECv_CSoE?GvLcNaECt<2jD-mx8*C^BIOTsh)=tTHU+egXf&Xgi1Gm)AQ}tk zAkk#Q?jgn-wx=0y*ngApcwnDlJQ45-#+!Zqi9(8_1KsFE4+b$rIE)DjxD!*zVu3J+ zWypjIoS8TMles~BVU=PKU1KcE(wv_`T1V@mFP*vegk|^LU;fG literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl.class b/tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..df50669a962bd0294119c472905c613ac5bd9c69 GIT binary patch literal 7349 zcmcIp349z?8UMfRCbLPVX_6igN@+?Hnrzahl*=|yi|G|;(~_iVlX7jd({|`)H|%Z- zm0J-}R0O$#LW@Y3qbgLIHWVl*pn?}3;DHySpm-o2D2Mg`y_wye-E0N)XMVrgdGpQt zj`#nr_a;yN>w$*>w5cg&D1y&`-$XG=6e`aNZ3(qRLeY&aE7zZ6^(PfdPPC(Ta)E-c zp|PhF0hAgjGf@sxVRm+Ue=M3vhN8)qMRuHgE3D+ESa?||8je_ttVDm^sdhB1P~Nt( zqpQ1fbzAq!PK7zk-yMHz0L5h(k4ghoCaN((p-M{_O4Oo9Yc|b z!ch$#Mb5ff8^@B$FbR_l9Ae^7)F{k2C%n1EjwY>mG!$vctgp>o=xXYuvO~9oB6c{G zwAvz}L}F#UT^Kfm`Yna&UbR_%nJ196Hui|dDJBlbRE6rapcU4@dMn-$8lZ@oUJ+f% zxE7e18Mg$EsnP|o=di~uRr!XOnjRrqH)SryS z^W2)Yv&D(L?yZA5?lj1aXfZJdTw_&Q&=T86IU5wIySV=g=M~pR-8x~QSIYu4~Oec1I)L>3nWKIP&pRj zWCQOr(S}6~wE}Z13!HhynC}3lU ziIrHTP!{)CSKCl#h@fMNI;dgx)K#ziAimyelfj$%K zaC%OGO>>v9T7{&PO!9)1E>nGi?3pIclDw)IOgpbFHWW?DtB{HH=vNq*dF3EJy`lXb zEXp#m0UKGD?Zm3MJzyv8EzAg3`n~{cg+N1nqCU}Bp9o+x7tk*h!D(-*UFaV$@j+a!LG^S4r9F9ti4WsS zR{L-~HkhA^GaK3qJFP$tOaisJtx75non*8vI%`YJ4jcHS z!nEvs7wN7fyI2NhDd*Rk_>_cvAQ^MuD#O*-D#>tzi5qbf3v=8`#3EZPuO@~0-XM@n z-E6sK+1U^z>Xyf1n}-H-(q3mLOFC$w?|W)^*qiJh|Ia#=}_9Z#|_2^e26@kQKAdPMt8FNe<0@lV=+ z+p){UmvFx;rHgrL%T6HvKLg@H%Te}r2$f<4dkpL~F^UIRJ+lb)Fb&v%yL(qH=B8kb zV1f2Q>1GeHG>o@%tMbW(zM*Ig;O{KcEX81 zg;G1=)EF6i;18W#@NV8zS5Ra=*HA(2DDmKxQ&`r`(}>&sA>1 z)9GPGCyR#Ux)W)w-pDUtMFu8sCC`EO z=&%y}Tq2Q9X0ts?Z)=3)aORhNrJ?vW;)v|h3mHkbJ9{b|&3aM_AENxQ?d1s94jy7ZYds_u{ZM zHT=cfu@%x?8MACek zRz{kPf=#_RW_`9++8S19>d2Uq+VukwiqYrn`^ zUecZ^(j)PWPmlgWZGQZf<7Fs6Ky!)>G#UsPILW|TgZ+eq($dnB*Ki8obn=q>0dZ&k z%py%#h%)&C;(GcSdb)(thl8V7p}0Fbjp?#_1Zx&d8HV9c!S6dfJvjS#|I{hlF`ZM- z;2Fxl9h3Pk6!eYa>>{#qA2p25>P;mNp{Q5b0@ddb;p#|NubNVuEUayl&ui(lz=HofGIMO*c?e7}v@6$CTh2w=l5xO+6s-#dSlytGsl(2)lp@F?e|0UYG`5?HTN zEb=~oErnydEblk?Oc{?t^ z9Rzy^&t566?M@zD@50l#n{DhK!n;kw9dyuh;U!KVag zagTndiuq35a|p`b!s&)8F|fm|np81ap#n+@yr0s_$-boIgXXSf{lWmx^ba^RGF!99kNUcsxzF*OS`4%(dMpRDVp=TdP~GocERWJ>(>*W zps#aHQ1W?>5(Tb4b~}+hr}`ITq>tixgX3ys R{FfI0Dg)TA4poPt=HI!Vjwt{D literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl.java b/tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl.java new file mode 100644 index 00000000..0097ed6b --- /dev/null +++ b/tests/test_data/std/jdk/internal/constant/DirectMethodHandleDescImpl.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.constant; + +import java.lang.constant.ClassDesc; +import java.lang.constant.DirectMethodHandleDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Objects; + +import static java.lang.constant.ConstantDescs.CD_void; +import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR; +import static java.util.Objects.requireNonNull; +import static jdk.internal.constant.ConstantUtils.validateClassOrInterface; +import static jdk.internal.constant.ConstantUtils.validateMemberName; + +/** + * A nominal descriptor for a direct + * {@link MethodHandle}. A {@linkplain DirectMethodHandleDescImpl} corresponds to + * a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile. + */ +public final class DirectMethodHandleDescImpl implements DirectMethodHandleDesc { + + private final Kind kind; + private final ClassDesc owner; + private final String name; + private final MethodTypeDesc invocationType; + + /** + * Constructs a {@linkplain DirectMethodHandleDescImpl} for a method or field + * from a kind, owner, name, and type + * + * @param kind the kind of the method handle + * @param owner the declaring class or interface for the method + * @param name the unqualified name of the method (ignored if {@code kind} is {@code CONSTRUCTOR}) + * @param type the lookup type of the method + * @throws NullPointerException if any non-ignored argument is null + * @throws IllegalArgumentException if {@code kind} describes a field accessor, + * and {@code type} is not consistent with that kind of field accessor, or if + * {@code kind} describes a constructor, and the return type of {@code type} + * is not {@code void} + * @jvms 4.2.2 Unqualified Names + */ + public DirectMethodHandleDescImpl(Kind kind, ClassDesc owner, String name, MethodTypeDesc type) { + if (kind == CONSTRUCTOR) + name = ""; + + requireNonNull(kind); + validateClassOrInterface(owner); + validateMemberName(name, true); + requireNonNull(type); + + switch (kind) { + case CONSTRUCTOR -> validateConstructor(type); + case GETTER -> validateFieldType(type, false, true); + case SETTER -> validateFieldType(type, true, true); + case STATIC_GETTER -> validateFieldType(type, false, false); + case STATIC_SETTER -> validateFieldType(type, true, false); + } + + this.kind = kind; + this.owner = owner; + this.name = name; + this.invocationType = switch (kind) { + case VIRTUAL, SPECIAL, INTERFACE_VIRTUAL, INTERFACE_SPECIAL -> type.insertParameterTypes(0, owner); + case CONSTRUCTOR -> type.changeReturnType(owner); + default -> type; + }; + } + + private static void validateFieldType(MethodTypeDesc type, boolean isSetter, boolean isVirtual) { + boolean isVoid = type.returnType().descriptorString().equals("V"); + int expectedParams = (isSetter ? 1 : 0) + (isVirtual ? 1 : 0); + if (isVoid != isSetter + || type.parameterCount() != expectedParams + || (isVirtual && type.parameterType(0).isPrimitive())) { + String expectedType = String.format("(%s%s)%s", (isVirtual ? "R" : ""), + (isSetter ? "T" : ""), (isSetter ? "V" : "T")); + throw new IllegalArgumentException(String.format("Expected type of %s for getter, found %s", expectedType, type)); + } + } + + private static void validateConstructor(MethodTypeDesc type) { + if (!type.returnType().descriptorString().equals("V")) { + throw new IllegalArgumentException(String.format("Expected type of (T*)V for constructor, found %s", type)); + } + } + + @Override + public Kind kind() { return kind; } + + @Override + public int refKind() { return kind.refKind; } + + @Override + public boolean isOwnerInterface() { return kind.isInterface; } + + @Override + public ClassDesc owner() { + return owner; + } + + @Override + public String methodName() { + return name; + } + + @Override + public MethodTypeDesc invocationType() { + return invocationType; + } + + @Override + public String lookupDescriptor() { + return switch (kind) { + case VIRTUAL, + SPECIAL, + INTERFACE_VIRTUAL, + INTERFACE_SPECIAL -> invocationType.dropParameterTypes(0, 1).descriptorString(); + case STATIC, + INTERFACE_STATIC -> invocationType.descriptorString(); + case CONSTRUCTOR -> invocationType.changeReturnType(CD_void).descriptorString(); + case GETTER, + STATIC_GETTER -> invocationType.returnType().descriptorString(); + case SETTER -> invocationType.parameterType(1).descriptorString(); + case STATIC_SETTER -> invocationType.parameterType(0).descriptorString(); + default -> throw new IllegalStateException(kind.toString()); + }; + } + + public MethodHandle resolveConstantDesc(MethodHandles.Lookup lookup) + throws ReflectiveOperationException { + Class resolvedOwner = owner.resolveConstantDesc(lookup); + MethodType invocationType = this.invocationType().resolveConstantDesc(lookup); + return switch (kind) { + case STATIC, + INTERFACE_STATIC -> lookup.findStatic(resolvedOwner, name, invocationType); + case VIRTUAL, + INTERFACE_VIRTUAL -> lookup.findVirtual(resolvedOwner, name, invocationType.dropParameterTypes(0, 1)); + case SPECIAL, + INTERFACE_SPECIAL -> lookup.findSpecial(resolvedOwner, name, invocationType.dropParameterTypes(0, 1), lookup.lookupClass()); + case CONSTRUCTOR -> lookup.findConstructor(resolvedOwner, invocationType.changeReturnType(void.class)); + case GETTER -> lookup.findGetter(resolvedOwner, name, invocationType.returnType()); + case STATIC_GETTER -> lookup.findStaticGetter(resolvedOwner, name, invocationType.returnType()); + case SETTER -> lookup.findSetter(resolvedOwner, name, invocationType.parameterType(1)); + case STATIC_SETTER -> lookup.findStaticSetter(resolvedOwner, name, invocationType.parameterType(0)); + default -> throw new IllegalStateException(kind.name()); + }; + } + + /** + * Returns {@code true} if this {@linkplain DirectMethodHandleDescImpl} is + * equal to another {@linkplain DirectMethodHandleDescImpl}. Equality is + * determined by the two descriptors having equal kind, owner, name, and type + * descriptor. + * @param o a {@code DirectMethodHandleDescImpl} to compare to this + * {@code DirectMethodHandleDescImpl} + * @return {@code true} if the specified {@code DirectMethodHandleDescImpl} + * is equal to this {@code DirectMethodHandleDescImpl}. + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DirectMethodHandleDescImpl desc = (DirectMethodHandleDescImpl) o; + return kind == desc.kind && + Objects.equals(owner, desc.owner) && + Objects.equals(name, desc.name) && + Objects.equals(invocationType, desc.invocationType); + } + + @Override + public int hashCode() { + return Objects.hash(kind, owner, name, invocationType); + } + + @Override + public String toString() { + return String.format("MethodHandleDesc[%s/%s::%s%s]", kind, owner.displayName(), name, invocationType.displayDescriptor()); + } +} diff --git a/tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl$1.class b/tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..67199a47caace852fb59f37bac95d3f2fa18cedb GIT binary patch literal 1615 zcma)7?M@Rx6g^W~mX?*4@(n7eMcRTC{MI6hMTDdx2EzYkJC=p*ZZo@W!apBL6RE}@ zK7emvg0Et{vs=?$8VF6gcY9~kDmZaSdSxu9tBYqG4wLzk1EFn!*aQ> zG_#=Fmg8!cTX@IaL%XtfQs?X3(YI=KGqcQ)XliE0wC&?Yonfwgq&2mIsaaJ5XxhiT z9kr=h6_Y!evbV7)3HwyUkznX`4-F@?M6~6r@)i?NaZSO1iX>7DsSfM=gCnlHgt}r_ zhP%qplg;fXkj9XLVHG17WyoHYhmb3DRAJOzTkN{Ru&NBh*<9e1zLx}zV?x2CiYZ)Y znC%FRqlGPWm~Io!7$N{;x7?a z2D1w8s+dETVXA`_5-BUpF!@o~HNWJt+~FK-X1h}m@C5V}gURZmAxRPBRm@|7DkT~g z!*ob~cZ7mPhMS&rhwBYtxF>}jVKfbsS9xVkcMY3R_DJ9ro46Pd9-=$fv$=hSXvwZn zZjxog;@ged0T+APfk~cp+1534UlWG>-F8N0XEQ8ZSxRQPNG<0leMb{ojnf?@gmBCG zElxY*yGGU0+=d_l9|EUnZ}2@ACTS%Q5jwZ5e{q%Y6T5ap=zN1x%P`h`{TF2wC>w7q z-LxIL9R3y+FF+S>NN~qCo4nMXAF_)WHiDfKqCKDPOXV^2ZF9%nv>m$Z>Xv13;WZt1 z6ukc59~X`x8V~*;!VLAF3Wj@#q*8MF0c2?|(O~SMZxRLCvE+?Onvv3zUpNKJ&!0lc ze?$Klaz(IA&t8H7e&aqpN69CHAK)Qb`6eM59?^T8mOiCC9wr-~+!FsSg-C#r{8uO~ z43c3jjJ0s%JMMg@1)pWW6LE%q{J|j3JT`d%3iR1hYXthZ4O$>8*JAk=avhMMR6jV@ omKwtokLoF&dGt<8 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl.class b/tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..a0e6349dfaa5c904bd68386b93fd15d149ed9a44 GIT binary patch literal 8414 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 SzDzAwmxt=r3VyE&)&CF7K2mo8 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl.java b/tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl.java new file mode 100644 index 00000000..0a75416f --- /dev/null +++ b/tests/test_data/std/jdk/internal/constant/MethodTypeDescImpl.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.constant; + +import jdk.internal.vm.annotation.Stable; + +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import static java.util.Objects.requireNonNull; + +/** + * A nominal descriptor for a + * {@link MethodType}. A {@linkplain MethodTypeDescImpl} corresponds to a + * {@code Constant_MethodType_info} entry in the constant pool of a classfile. + */ +public final class MethodTypeDescImpl implements MethodTypeDesc { + private final ClassDesc returnType; + private final @Stable ClassDesc[] argTypes; + private @Stable String cachedDescriptorString; + + /** + * Constructs a {@linkplain MethodTypeDesc} with the specified return type + * and a trusted and already-validated parameter types array. + * + * @param returnType a {@link ClassDesc} describing the return type + * @param validatedArgTypes {@link ClassDesc}s describing the trusted and validated parameter types + */ + private MethodTypeDescImpl(ClassDesc returnType, ClassDesc[] validatedArgTypes) { + this.returnType = returnType; + this.argTypes = validatedArgTypes; + } + + /** + * Constructs a {@linkplain MethodTypeDesc} with the specified return type + * and a trusted parameter types array, which will be validated. + * + * @param returnType a {@link ClassDesc} describing the return type + * @param trustedArgTypes {@link ClassDesc}s describing the trusted parameter types + */ + public static MethodTypeDescImpl ofTrusted(ClassDesc returnType, ClassDesc[] trustedArgTypes) { + requireNonNull(returnType); + // implicit null checks of trustedArgTypes and all elements + for (ClassDesc cd : trustedArgTypes) { + validateArgument(cd); + } + return ofValidated(returnType, trustedArgTypes); + } + + private static ClassDesc validateArgument(ClassDesc arg) { + if (arg.descriptorString().charAt(0) == 'V') // implicit null check + throw new IllegalArgumentException("Void parameters not permitted"); + return arg; + } + + /** + * Constructs a {@linkplain MethodTypeDesc} with the specified pre-validated return type + * and a pre-validated trusted parameter types array. + * + * @param returnType a {@link ClassDesc} describing the return type + * @param trustedArgTypes {@link ClassDesc}s describing the trusted parameter types + */ + public static MethodTypeDescImpl ofValidated(ClassDesc returnType, ClassDesc... trustedArgTypes) { + if (trustedArgTypes.length == 0) + return new MethodTypeDescImpl(returnType, ConstantUtils.EMPTY_CLASSDESC); + return new MethodTypeDescImpl(returnType, trustedArgTypes); + } + + /** + * Creates a {@linkplain MethodTypeDescImpl} given a method descriptor string. + * + * @param descriptor the method descriptor string + * @return a {@linkplain MethodTypeDescImpl} describing the desired method type + * @throws IllegalArgumentException if the descriptor string is not a valid + * method descriptor + * @jvms 4.3.3 Method Descriptors + */ + public static MethodTypeDescImpl ofDescriptor(String descriptor) { + // Implicit null-check of descriptor + List ptypes = ConstantUtils.parseMethodDescriptor(descriptor); + int args = ptypes.size() - 1; + ClassDesc[] paramTypes = args > 0 + ? ptypes.subList(1, args + 1).toArray(ConstantUtils.EMPTY_CLASSDESC) + : ConstantUtils.EMPTY_CLASSDESC; + + MethodTypeDescImpl result = ofValidated(ptypes.get(0), paramTypes); + result.cachedDescriptorString = descriptor; + return result; + } + + + @Override + public ClassDesc returnType() { + return returnType; + } + + @Override + public int parameterCount() { + return argTypes.length; + } + + @Override + public ClassDesc parameterType(int index) { + return argTypes[index]; + } + + @Override + public List parameterList() { + return List.of(argTypes); + } + + @Override + public ClassDesc[] parameterArray() { + return argTypes.clone(); + } + + @Override + public MethodTypeDesc changeReturnType(ClassDesc returnType) { + return ofValidated(requireNonNull(returnType), argTypes); + } + + @Override + public MethodTypeDesc changeParameterType(int index, ClassDesc paramType) { + ClassDesc[] newArgs = argTypes.clone(); + newArgs[index] = validateArgument(paramType); + return ofValidated(returnType, newArgs); + } + + @Override + public MethodTypeDesc dropParameterTypes(int start, int end) { + Objects.checkIndex(start, argTypes.length); + Objects.checkFromToIndex(start, end, argTypes.length); + + ClassDesc[] newArgs = new ClassDesc[argTypes.length - (end - start)]; + if (start > 0) { + System.arraycopy(argTypes, 0, newArgs, 0, start); + } + if (end < argTypes.length) { + System.arraycopy(argTypes, end, newArgs, start, argTypes.length - end); + } + return ofValidated(returnType, newArgs); + } + + @Override + public MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes) { + if (pos < 0 || pos > argTypes.length) + throw new IndexOutOfBoundsException(pos); + + ClassDesc[] newArgs = new ClassDesc[argTypes.length + paramTypes.length]; + if (pos > 0) { + System.arraycopy(argTypes, 0, newArgs, 0, pos); + } + System.arraycopy(paramTypes, 0, newArgs, pos, paramTypes.length); + int destPos = pos + paramTypes.length; + if (pos < argTypes.length) { + System.arraycopy(argTypes, pos, newArgs, destPos, argTypes.length - pos); + } + // Validate after copying to avoid TOCTOU + for (int i = pos; i < destPos; i++) { + validateArgument(newArgs[i]); + } + + return ofValidated(returnType, newArgs); + } + + @Override + public String descriptorString() { + var desc = this.cachedDescriptorString; + if (desc != null) + return desc; + + int len = 2 + returnType.descriptorString().length(); + for (ClassDesc argType : argTypes) { + len += argType.descriptorString().length(); + } + StringBuilder sb = new StringBuilder(len).append('('); + for (ClassDesc argType : argTypes) { + sb.append(argType.descriptorString()); + } + desc = sb.append(')').append(returnType.descriptorString()).toString(); + cachedDescriptorString = desc; + return desc; + } + + @Override + public MethodType resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException { + @SuppressWarnings("removal") + MethodType mtype = AccessController.doPrivileged(new PrivilegedAction<>() { + @Override + public MethodType run() { + return MethodType.fromMethodDescriptorString(descriptorString(), + lookup.lookupClass().getClassLoader()); + } + }); + + // let's check that the lookup has access to all the types in the method type + lookup.accessClass(mtype.returnType()); + for (Class paramType: mtype.parameterArray()) { + lookup.accessClass(paramType); + } + return mtype; + } + + /** + * Returns {@code true} if this {@linkplain MethodTypeDescImpl} is + * equal to another {@linkplain MethodTypeDescImpl}. Equality is + * determined by the two descriptors having equal return types and argument + * types. + * + * @param o the {@code MethodTypeDescImpl} to compare to this + * {@code MethodTypeDescImpl} + * @return {@code true} if the specified {@code MethodTypeDescImpl} + * is equal to this {@code MethodTypeDescImpl}. + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MethodTypeDescImpl constant = (MethodTypeDescImpl) o; + + return returnType.equals(constant.returnType) + && Arrays.equals(argTypes, constant.argTypes); + } + + @Override + public int hashCode() { + int result = returnType.hashCode(); + result = 31 * result + Arrays.hashCode(argTypes); + return result; + } + + @Override + public String toString() { + return String.format("MethodTypeDesc[%s]", displayDescriptor()); + } +} diff --git a/tests/test_data/std/jdk/internal/constant/ModuleDescImpl.class b/tests/test_data/std/jdk/internal/constant/ModuleDescImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..7a8346b44571d6f73498e18fcdc853726e847eae GIT binary patch literal 1551 zcma)6YflqV5IvVZc3D|>+Y7s|KtZr ze1$}RfIrGO`zYN)HGJ5|%+8!SXJ+pH{&VyTKnW!UeTYejt4JWpFto=HxMpy3S9>F> zmR(~=F6*Z5t}w)M`K^A)=$D|V7=X$!yI0%Sbkh~K$qlV)nU2d%S6jDgEkisLPPN=< z8VqrhHv~gwt%JVd+Pb-0lrhLK*ooiCI`1S5brE@0*%MV)p~@Mr>@dSfE`J(I!6?Qg zoL6xH<6QtjEmHE{vK!oGSjwGF--)<_ip3s9GSsz8DlTJ!L9TPBUb1SWEKh)E=tMDJ z_5h|-Ok;-lhz~7pI1I%zruU$@E#WG|M5nPmhQKh|LvVhJ1{2Uvt?8zC*=kgTy~!(v zKPs!rjV*5Lo*g>lZe1s~b7#{^BUl%1-KxFjHjSTlgmPuqYEOgKseFQ2yYJf!%XihdZ0&ZQ6p@2I^~jb%$0h%XM6vHv=Y)jDZw`luF{hf(KZV@K8k& z%M4SU4%#i#)f++!N`{#X{gpNt!(p_ax_Myj3oQtI!OfZ>oY^(Y+HWIgBSyV|3A*Ww;GPA!|Juzg73NO;VU?P%_S($*m1DZ}Ld zL#gM1U@X!x?E}LVx-#BRg7!T@?+MJ3KTFmMJ^SdX6uyHM=D$KZB&!c|bWc(wFoSD! z9}A+8L!K;(_t6*%^qyd3fP&{SOm`2q=$8S~nRD@qpNyEqsA=Qbm+TB7}+KrcZVew>$y_6ZHQ!Ssvkgh>`aW?&1-76!NU#305)w E7i4;DegFUf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/constant/ModuleDescImpl.java b/tests/test_data/std/jdk/internal/constant/ModuleDescImpl.java new file mode 100644 index 00000000..89310c13 --- /dev/null +++ b/tests/test_data/std/jdk/internal/constant/ModuleDescImpl.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.constant; + +import java.lang.constant.ModuleDesc; + +/* + * Implementation of {@code ModuleDesc} + * @param name must have been validated + */ +public record ModuleDescImpl(String name) implements ModuleDesc { + + @Override + public String toString() { + return String.format("ModuleDesc[%s]", name()); + } +} diff --git a/tests/test_data/std/jdk/internal/constant/PackageDescImpl.class b/tests/test_data/std/jdk/internal/constant/PackageDescImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..e12bea51c6fa762a675304b7c53297a6d84cf0d2 GIT binary patch literal 1573 zcma)7YfsZq7=F$!w2bQ594KBul*v|7;}t68Swa?{n;d9BHJ#forh zl~&teP`WW|yd@a2t4C=zTw6DHOES(fq$9wcyz^edXrH7v)jd&jQ=}oQ;2d%c3DYOc z6^bV*Qy9m22^SPh;9?(7kdsRLVA(D1GAtHO!gnHDLE_SYBw4cYvVtp^WRM%&X)IfH zs!%1u(^yj~Ry>BQ3Z`+51c{FwZa56()8Yq++?FuIFnMJ0puRAS4XC-eMV1B?q*rxQ ztaVydVQ=!P;djldabt_yy0;ED6K+E%y|bq*m)h`JxDBhm&TZ-(4Gw{2*XnkJW~_2d zTG#t+24?loPWXx;wPAJans}*uI&+aJ^2Tr8bAr6>4)o}fWx0-P^L8M`kuj2HkkUhV zl)@q&ODHKQ;|asmk%@N4boG|df}A0eVYu2QV>pO9s+;>(Q)ofpD{j^e;moXBRxdxnnnt&nJe?w$%sJ;Wv8^D%fJE`Uot_%!B2c$t!U<;m*YA*TL^ z4~mm}#mUfc+fO{wt4IrlB-O8wj#m+tkql`P`jCKHY8A^;Zj0l5iLC=hcGaiNhcGQy!D6l zp=p1KdS9MGcg$;(p4WaIdjfFdw<`zFZ0*mzy1y&1EU9B@G0=C=th7c zvcvayQs+h`Su%~f%?&%5X)dy&UaB(;&K4FnmRE8Mxz${8ZX=UV7YYoCe21G^%@QSh zLD<`7`2jb|x{y9nAq3H*Af)09RE7cPX2aI>4e$iX_>uVgO-=U?#hf(RrPMT=Cp*vz2EKOa(&>SKGeYCLTdT z7{NIO=T%(5MS|JEJiBl3s#fyK$Pk#)49%Wl_|8kL72++*c>uf2Ql6dGWrvxVCNGQ--0axBgpq(wJ3{QIW+Q!?}9HAVhoSu1Go! z_SoXJny?sD(r1>}wbCl7%WyfGiRIs7O#Pb1=PDi`$I#o#i+geK2nvT`Du_o6BPVIE zkJg`sNU{YLi;~otvR1F@e1DNwh1_3O@dZ|B!dRki>U-j7$4q)t(B$MDE%h6D)7)*; zj*JBtkb+gB*sj8pokHcBG0P-GUtTlBVxzh#tX00L(@r>VmbhNzmL}hun|^y+qX{yW z|34|G66r12ytKQ(YfV1^-NDRo%ai}p$WccYw2Hy)hDF$>-&vEX_zb}b+UA>bO1+D# zX7f-jw>p`6vvgz*u81w2hB|ff5>+0T-QF^$!gf=*%q=Pc>KqdFsYi-draBDKDUY3# zXUS>iKPDnUEtn0fB<3}l+)F2`R5s_BtQBgKoM8yd@hyng4#Q}>h)&6p0&4For<>A< za_g1m)i`}b7z*?Y%Sl3C=5AWk;GyT2^!6hZ`ho#-@fTo;Lnwcu_XYZVuQB)v!-)f2 z^8bMT@YRIx0M`yM`aRD7hS*v-;eU+})_jS=A(F4~@gMQTFSz?NIr5=M&x;7q^B#sV zfol{vPNDB(iblsY9@EK)8x&t*jov7{1CHSdt^3jS4_)X|Fs{(p#SlTIN!0|Lq<=nominal descriptor for the class + * constant corresponding to a primitive type (e.g., {@code int.class}). + */ +public final class PrimitiveClassDescImpl + extends DynamicConstantDesc> implements ClassDesc { + + private final String descriptor; + + /** + * Creates a {@linkplain ClassDesc} given a descriptor string for a primitive + * type. + * + * @param descriptor the descriptor string, which must be a one-character + * string corresponding to one of the nine base types + * @throws IllegalArgumentException if the descriptor string does not + * describe a valid primitive type + * @jvms 4.3 Descriptors + */ + public PrimitiveClassDescImpl(String descriptor) { + super(ConstantDescs.BSM_PRIMITIVE_CLASS, requireNonNull(descriptor), ConstantDescs.CD_Class); + if (descriptor.length() != 1 + || "VIJCSBFDZ".indexOf(descriptor.charAt(0)) < 0) + throw new IllegalArgumentException(String.format("not a valid primitive type descriptor: %s", descriptor)); + this.descriptor = descriptor; + } + + @Override + public String descriptorString() { + return descriptor; + } + + @Override + public Class resolveConstantDesc(MethodHandles.Lookup lookup) { + return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveType(); + } + + @Override + public String toString() { + return String.format("PrimitiveClassDesc[%s]", displayName()); + } +} diff --git a/tests/test_data/std/jdk/internal/constant/ReferenceClassDescImpl.class b/tests/test_data/std/jdk/internal/constant/ReferenceClassDescImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..3816499c943d08ea72f2ec50da2ffec0756a54b9 GIT binary patch literal 3454 zcmbVOTT>jz75;j6mRVKL*YBP60tR)`oxf@DP+b{iNm%&cc- zu~DwR)`Fdv99i%N)l84=%>FGY_JKuNC z>HgdOKYa#Z3b%4dA+19*kU^V3{)V|>j@qWPGJ0|8hO7hvZKo{93Qh~8hlUs0kwv?X zoPj+s1diOOu8mqwAU(&lM=P%52c{E@zABfcC!LC%vQ6JVEB#7oy=DvKs(kdUTHtyD zg>uu^T;N&G%6JZ)cuYs$Ko<(Tz(flO#+J@Xuo{9X<X0dI$gfnc*H2b$534Gj7!*vAbV!~nxucD;3zWS?vS z;z|NnB+B@3VyeO20UTB;J|VETg_Yrj9JM>F<0*mOW-!t2Gj+?ZN-u{&q_Y?n5M}i| zV&Djl5}sMBNvA4sw3Xq9u*B9VXAedVJcHxZa>;T`Z*$%)#n~e8)PH4cJd03?u_M)7t0%ki`U&#e{*=cv(QV{7KI< zH^Y3qtiDVdIHSJgEq~Ut)~&$Wkl~UX&f=VoX#-!td4a*E1eUYmuF260GFWx1=S`<- zOaIBT>#o&n0`1F|Qw__Ads>5URBX5`Wc`ZE_y3{*gs z+vMwYQx*HJkauc_I(1^%z>4ZI*;UhDopP%(3rnCQgrOSNl|lci(sRv#tx|4J)$(h$ zxjAF5OEvEpa6x^#J?XplhTQ2gYOlapQmIGiyQ`2R3UshH_BWYpG}Q()2CM*+-?HV% znfm&Y^ybYan=^&7TQThg)3eljJgEh%7P&Z9ZrvYSH)~c-%3Y?bYFRq0zYTL?bR`;5#3eJqj_c^@#K%Vo!o=UrApyma_9RS%_D>a06LYR{0QfpSU|VZy zM`~@Jp=<#cYtl2-A<4kGm(oQo5XV_4?MmvhA^KDDJr670{X`};n|{(CsESm@I}MQSl!oZH6d z@8Zy(?;*QL3{T#n(RAp3A7O%rRt7Jk126HSa*{{tSO{YvauA1<;W@d9n{?knxL@Z} z3g6&f2LCVg3eiJ&JkVlz&vLKe*Y>2#DB`y8!@1Cf5iN>cwBwujR&1a|^UA=%dl+22 zi>C`iTPPN{ag0OZ1pl`1+%{fPktEH|Cd?khw?i=mzQgDuDMmRevzg)_pg*|zQetx^ zW?!f_%3zd^_eqnY>l&S(x`i@_S8l-=QMR@)bw`ccC{2VD{o3_tzC){S;leh)%q27F z7qq=v|8LNFbPMw{?`qOO#+AqMcBs=BQ|cYO8|rzjkyh96U3`yhe4jp)5Yeh1 zaFx=v3tI1e3<@2W#6OY$2N%2-0uy*2Kjc#iKjM#<34T%R%*K-Usjw5FU(Jty3|;#K zTKYDZMR^w`K`lXeUyMun&LDN*6(tl;%h-CIzEq_gDvtaP8SVDSUy;3qo{_&GdqFun z5^7-HPWUL015kUNd~}nEgJeLJm&)sIM*JbmOO@rJ1|x^?WBh~;6$T9{y_e5Cg<}XO zII7&qM!`uHO)~f1OGJ}xqz^BI@&0kfrS^9fR^z(d!VOiL59Z;A2}50xq5LHC@FN0O zOg}@n3V2&_WDDyL?jB6+Zi`_wmHR38Wr!lLu>XuNDf}G2;Fu$}v-l-`jRXGy%;GX{ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/constant/ReferenceClassDescImpl.java b/tests/test_data/std/jdk/internal/constant/ReferenceClassDescImpl.java new file mode 100644 index 00000000..b4ec9c13 --- /dev/null +++ b/tests/test_data/std/jdk/internal/constant/ReferenceClassDescImpl.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.constant; + +import java.lang.constant.ClassDesc; +import java.lang.invoke.MethodHandles; + +import static jdk.internal.constant.ConstantUtils.*; + +/** + * A nominal descriptor for a class, + * interface, or array type. A {@linkplain ReferenceClassDescImpl} corresponds to a + * {@code Constant_Class_info} entry in the constant pool of a classfile. + */ +public final class ReferenceClassDescImpl implements ClassDesc { + private final String descriptor; + + private ReferenceClassDescImpl(String descriptor) { + this.descriptor = descriptor; + } + + /** + * Creates a {@linkplain ClassDesc} from a descriptor string for a class or + * interface type or an array type. + * + * @param descriptor a field descriptor string for a class or interface type + * @throws IllegalArgumentException if the descriptor string is not a valid + * field descriptor string, or does not describe a class or interface type + * @jvms 4.3.2 Field Descriptors + */ + public static ReferenceClassDescImpl of(String descriptor) { + int dLen = descriptor.length(); + int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen, false); + if (len <= 1 || len != dLen) + throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor)); + return new ReferenceClassDescImpl(descriptor); + } + + /** + * Creates a {@linkplain ClassDesc} from a pre-validated descriptor string + * for a class or interface type or an array type. + * + * @param descriptor a field descriptor string for a class or interface type + * @jvms 4.3.2 Field Descriptors + */ + public static ReferenceClassDescImpl ofValidated(String descriptor) { + return new ReferenceClassDescImpl(descriptor); + } + + /** + * Creates a {@linkplain ClassDesc} from a pre-validated descriptor string + * for a class or interface type or an array type. + * + * @param descriptor a field descriptor string for a class or interface type + * @jvms 4.3.2 Field Descriptors + */ + public static ClassDesc ofValidatedBinaryName(String typeSwitchClassName) { + return ofValidated("L" + binaryToInternal(typeSwitchClassName) + ";"); + } + + @Override + public String descriptorString() { + return descriptor; + } + + @Override + public Class resolveConstantDesc(MethodHandles.Lookup lookup) + throws ReflectiveOperationException { + if (isArray()) { + if (isPrimitiveArray()) { + return lookup.findClass(descriptor); + } + // Class.forName is slow on class or interface arrays + int depth = ConstantUtils.arrayDepth(descriptor); + Class clazz = lookup.findClass(internalToBinary(descriptor.substring(depth + 1, descriptor.length() - 1))); + for (int i = 0; i < depth; i++) + clazz = clazz.arrayType(); + return clazz; + } + return lookup.findClass(internalToBinary(dropFirstAndLastChar(descriptor))); + } + + /** + * Whether the descriptor is one of a primitive array, given this is + * already a valid reference type descriptor. + */ + private boolean isPrimitiveArray() { + // All L-type descriptors must end with a semicolon; same for reference + // arrays, leaving primitive arrays the only ones without a final semicolon + return descriptor.charAt(descriptor.length() - 1) != ';'; + } + + /** + * Returns {@code true} if this {@linkplain ReferenceClassDescImpl} is + * equal to another {@linkplain ReferenceClassDescImpl}. Equality is + * determined by the two class descriptors having equal class descriptor + * strings. + * + * @param o the {@code ClassDesc} to compare to this + * {@code ClassDesc} + * @return {@code true} if the specified {@code ClassDesc} + * is equal to this {@code ClassDesc}. + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof ReferenceClassDescImpl constant) { + return descriptor.equals(constant.descriptor); + } + return false; + } + + @Override + public int hashCode() { + return descriptor.hashCode(); + } + + @Override + public String toString() { + return String.format("ClassDesc[%s]", displayName()); + } +} diff --git a/tests/test_data/std/jdk/internal/event/DeserializationEvent.class b/tests/test_data/std/jdk/internal/event/DeserializationEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..1f8b52c17d67ab12b6090b1098b05951fe4619d8 GIT binary patch literal 636 zcma)3%T60X5UeqN#Et>u0D&YtZafaGI0tbtAb~bHV8kJ}@w&Ypv&^E|F^c)CoFZ}H z1M*Q3wPuA7;=rY=ySlo2y64~j`v(9WY&KBBObz8GDyS-~jQUrBv0j|jNg%gkeQ=yx zh3bK^#vdxoZ0}sw@Ihhg4e^m=;*3tro%SZRMQv+f687w*c3|SMlfHubrOps3B|^K z$eE`Kt+Y3i$e+tVoY+V>SDh(T`f`&?>b;4V>|8XTI4i#+vRvb0`i9nX{6n%##~fSk zq type; + public int arrayLength; + public long objectReferences; + public long depth; + public long bytesRead; + public Class exceptionType; + public String exceptionMessage; +} diff --git a/tests/test_data/std/jdk/internal/event/ErrorThrownEvent.class b/tests/test_data/std/jdk/internal/event/ErrorThrownEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..8f2ceec966681aa90fd15b74d0f7d780123d82e5 GIT binary patch literal 793 zcma)4O>fgc5Pe%aF$tw#w51d%mD-9l5?Gw6dWp)RijYvM9Jp;0E8SwRtM#Uc|I{8h zA#vab@S_lKHUUD!p^?_nNuN^zoslsOW9|@nY ze#>azg--4#j7etY2E(xa4_t~j+^g5cRmgBovsaGYAbV@%-Ww-#@9;`ikJm`}-rykv znvD1WSfqUrvP*~=^Gl#zW+tUq^tJX^s4oGsLMvrp2dlKwOaRvKkiLO+Y>-}>-}A&g zp)tbW#{JN^i%5#t#3Oo%M3JbQXo|4KctS6kCE_P49}~HaC&bB^ZF>1FL^rf*W=@N^ Wr+D@UC)~s}Zs%|>iP(_}p8o=qnxfVK literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/ErrorThrownEvent.java b/tests/test_data/std/jdk/internal/event/ErrorThrownEvent.java new file mode 100644 index 00000000..c9f4ff3b --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/ErrorThrownEvent.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +/** + * Event recording error exceptions. + */ +public final class ErrorThrownEvent extends Event { + public String message; + public Class thrownClass; + + public static void commit(long start, String message, Class thrownClass) { + // Generated by JFR + } + + public static boolean enabled() { + // Generated by JFR + return false; + } + + public static long timestamp() { + // Generated by JFR + return 0; + } +} diff --git a/tests/test_data/std/jdk/internal/event/Event.class b/tests/test_data/std/jdk/internal/event/Event.class new file mode 100644 index 0000000000000000000000000000000000000000..e34dd0187a3b16b2d23d19d3b4d92064f7d5f53e GIT binary patch literal 774 zcma)4O;5r=5PeGvXhlI({5Noj3F5Wk0{(KLAv*V;})74LyS-QVhASJ+MvJmTmK<+2yT(A$2OG z2+kO^VyThF9K%M}c`}6zxG!zjT=+~rbMM)y|z>w*8ywG*3ae>z7 zR8}a~t=}tEN)2i&q{E*XSe^WV?S>J@iBbmR&I|n(zZ7Z + * If the event starts with an invocation of the {@code begin} method, but does + * not end with an explicit invocation of the {@code end} method, then the event + * ends when the {@code commit} method is invoked. + */ + public void commit() { + } + + /** + * Returns {@code true} if the event is enabled, {@code false} otherwise + * + * @return {@code true} if event is enabled, {@code false} otherwise + */ + public boolean isEnabled() { + return false; + } + + /** + * Returns {@code true} if the event is enabled and if the duration is within + * the threshold for the event, {@code false} otherwise. + * + * @return {@code true} if the event can be written, {@code false} otherwise + */ + public boolean shouldCommit() { + return false; + } + + /** + * Sets a field value. + * + * @param index the index of the field to set + * @param value value to set, can be {@code null} + * @throws UnsupportedOperationException if functionality is not supported + * @throws IndexOutOfBoundsException if {@code index} is less than {@code 0} or + * greater than or equal to the number of fields specified for the event + */ + public void set(int index, Object value) { + } +} diff --git a/tests/test_data/std/jdk/internal/event/EventHelper$ThreadTrackHolder.class b/tests/test_data/std/jdk/internal/event/EventHelper$ThreadTrackHolder.class new file mode 100644 index 0000000000000000000000000000000000000000..3fca626f47b93b3d40a20f6868b84f4740a59f49 GIT binary patch literal 604 zcma)3TT22_5dMys2tg*uu7DEn?pCwLUIi83Jt5|#jr*bM0x{Tqz%f-ki8A# E7li(fXaE2J literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/EventHelper.class b/tests/test_data/std/jdk/internal/event/EventHelper.class new file mode 100644 index 0000000000000000000000000000000000000000..7f2abf88a1df99680457f57e6c0bcabb751c531c GIT binary patch literal 6427 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 YgLqZ!eDcf{#Pc7&@!G_wnGSY80K7bEqW}N^ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/ExceptionStatisticsEvent.java b/tests/test_data/std/jdk/internal/event/ExceptionStatisticsEvent.java new file mode 100644 index 00000000..4ab58b7c --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/ExceptionStatisticsEvent.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +/** + * Event recording number of exceptions that has been created. + */ +public class ExceptionStatisticsEvent extends Event { + + public long throwables; + + public static void commit(long timestamp, long throwables) { + // Generated by JFR + } + + public static boolean enabled() { + // Generated by JFR + return false; + } + + public static long timestamp() { + // Generated by JFR + return 0; + } +} diff --git a/tests/test_data/std/jdk/internal/event/ExceptionThrownEvent.class b/tests/test_data/std/jdk/internal/event/ExceptionThrownEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..85269edb527f7f7b656631f59592556dd508fb63 GIT binary patch literal 805 zcma)4K~ED=5dI#!?b?bUhzO{_!GyMnZaho4G!=eg6TVi~S~+5G9D0QA1r}>tggVwa%N;=`1yu z#`*MEq(c4BI_r-VqE>s5;GV+4ZQ!e+nRr{c)AO?UvcW}9``L}eSFJ4UdamZ8VPp~ z9#%n<78ikK$_K%_f|xd61?4I|DYc@mb-qD;4UmVF5(aj$Mk&bzU>%RB8`!{OmY3xB zJTXs5jPNh thrownClass; + + public static void commit(long start, String message, Class thrownClass) { + // Generated by JFR + } + + public static boolean enabled() { + // Generated by JFR + return false; + } + + public static long timestamp() { + // Generated by JFR + return 0; + } +} diff --git a/tests/test_data/std/jdk/internal/event/FileForceEvent.class b/tests/test_data/std/jdk/internal/event/FileForceEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..244d8567095504f63260d352f4c149ec352ca0f2 GIT binary patch literal 926 zcmah|%W@Jy6g>?C1Try(C>f(cW1>PT2&_z${p zCFQ~o@S7~l)6G;0U*#PoM7j_T$S}04+2s$RS^Xx`j7iJYG?gw$8p9$m}&29w?D3?%iu?SaS^Dk`&L8uOrw6C)MvJN6O)-oDdh_->a z;$j(B1>Es4nS_H@5=8+=IgNI+XYy4StGLG5{Vd}(+U?GnypVn<<5T}gr$KzW*K2m! zG?IEKQ2jG4un;LNpGz$TM31GdWS|6=J3*{oO`>C!zLv)!Bh^mQmtj|?f!Sw4M-PLs zz*gtKhujk=Bqt{-66dCiTDAm;?r{+wt^d5`#nzOqx#frhpTf8b9`j1h<6JGLD zQrWlIJ2vj&4hfsjvt$i%&(h7aV+D7ab+E-KX@AF>Ll%4r8H+<3=K+7Ge>gWnT#gVH z&WxBTV~EYPDG-(~FoWHtwF>4xuwq`8H*>P&ESiyJ8~3u#bz1Y~Y^RtL^eyZ7k6hLn SeAbmea-FXWxw~&Nc<>W*7nXSd literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/FileForceEvent.java b/tests/test_data/std/jdk/internal/event/FileForceEvent.java new file mode 100644 index 00000000..f6dec6c8 --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/FileForceEvent.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.event; + +/** + * A JFR event for forced updates written to files. This event is mirrored in + * {@code jdk.jfr.events.FileForceEvent } where the event annotations are + * provided. Some of the methods are replaced by generated + * methods when jfr is enabled. Note that the order of the arguments of the + * {@link #commit(long, long, String, boolean)} method + * must be the same as the order of the fields. + */ +public class FileForceEvent extends Event { + + // THE ORDER OF THE FOLLOWING FIELDS IS IMPORTANT! + // The order must match the argument order of the generated commit method. + public String path; + public boolean metaData; + + /** + * Helper method to offer the data needed to potentially commit an event. + * The duration of the operation is computed using the current + * timestamp and the given start time. If the duration is meets + * or exceeds the configured value (determined by calling the generated method + * {@link #shouldCommit(long)}), an event will be emitted by calling + * {@link #commit(long, long, String, boolean)}. + * + * @param start timestamp of the start of the operation + * @param path the full pathname of the file + * @param metaData true if the file metadata is updated + */ + public static void offer(long start, String path, boolean metaData) { + long duration = timestamp() - start; + if (shouldCommit(duration)) { + commit(start, duration, path, metaData); + } + } + + /** + * Actually commit an event. The implementation is generated automatically. + * The order of the fields must be the same as the parameters in this method. + * + * @param start timestamp of the start of the operation + * @param duration time in nanoseconds to complete the operation + * @param path the full pathname of the file + * @param metaData true if the file metadata is updated + */ + public static void commit(long start, long duration, String path, boolean metaData) { + // Generated by JFR + } + + /** + * Determine if an event should be emitted. The duration of the operation + * must exceed some threshold in order to commit the event. The implementation + * of this method is generated automatically if jfr is enabled. + * + * @param duration time in nanoseconds to complete the operation + * @return true if the event should be commited + */ + public static boolean shouldCommit(long duration) { + // Generated by JFR + return false; + } + + /** + * Determine if this kind of event is enabled. The implementation + * of this method is generated automatically if jfr is enabled. + * + * @return true if this type of event is enabled, false otherwise + */ + public static boolean enabled() { + // Generated by JFR + return false; + } + + /** + * Fetch the current timestamp in nanoseconds. This method is used + * to determine the start and end of an operation. The implementation + * of this method is generated automatically if jfr is enabled. + * + * @return the current timestamp value + */ + public static long timestamp() { + // Generated by JFR + return 0L; + } +} diff --git a/tests/test_data/std/jdk/internal/event/FileReadEvent.class b/tests/test_data/std/jdk/internal/event/FileReadEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..24eb6b85bef199f2ad13e9997654db52f85c4622 GIT binary patch literal 741 zcmah`%Wl&^6g`tTbsPeP@M?LKs;d;yS|B7AAT|*!tOz86vgmFS56!gpxN;_y_$OGf zLSn%O@KK0!Z3~5h#Afb2_nvcK^W*2Y?*K;F?V*Ksh@g)SHWao_($m;FZ%U`L*qj^Z z<5%)3Y`n0}`j-mr;r=v4S7G-b`eI`a-9Lt9&I5?BE*Teoept*NGzBz)eO(e5cA#)BZ%H)|5l?ZsGQCo{U6Z^!Wns zfV?eiH@ru*!mR79Px54Kk{0{QLJ{ubUZb24ccu2l6`obXr`%Wuyk7~$lM>RZzEV(m Ra;KUnmkOENVZ4P0zW^DSeYOAq literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/FileReadEvent.java b/tests/test_data/std/jdk/internal/event/FileReadEvent.java new file mode 100644 index 00000000..34ff4e9d --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/FileReadEvent.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +/** + * Event recording file reads. + */ +public final class FileReadEvent extends Event { + + // The order of these fields must be the same as the parameters in + // commit(..., String, long, boolean) + public String path; + public long bytesRead; + public boolean endOfFile; + + public static boolean enabled() { + // Generated by JFR + return false; + } + + public static long timestamp() { + // Generated by JFR + return 0L; + } + + public static boolean shouldCommit(long duration) { + // Generated by JFR + return false; + } + + public static void commit(long start, long duration, String path, long bytesRead, boolean endOfFile) { + // Generated by JFR + } +} diff --git a/tests/test_data/std/jdk/internal/event/FileWriteEvent.class b/tests/test_data/std/jdk/internal/event/FileWriteEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..2be7d1d0310e410c4f96375fc2b5bf0731f26fcb GIT binary patch literal 712 zcmah`O-~y^41G>ESrWF;h8EHfkPwF^2zAAUORHWYkXS{%Pz8zGBs(GlyR&FBLF#{M z4?R`tfgiw+LbWFm3KWUMc*gd7_Os{q?(YqN9=4jOpc*2GP(z*2zDO@)W1TLo%3^)3 zt&0!E66#-!HSQ~++UX8LED^S!03Vr5pO(hyIV-qQZcJ$PFVwY)GiA@?6IU90{+SRB ze>go6w9}SA2_fhesV1!Ujn&_#`B0bN)iC2ot6z*%Hc+Jze;y3n*h~mJ{bz-6w@_Q5 zrhb4kLc^I{Pn^oHe1w}vlW{T4(q570h6fHhNtba;>9kbN6s)j5ny1>GB>8`$q&pzg zxMa!f=1DOvM_TqlSbMmZPqGZ`Bjn|S4~s#QUxZ~ueAoEJ-@*0;dokZ6(cM3w-~6ax zg{`E4Ev&MQW&pgzEA|>_VT~g~e&;jHss3b-7MLFy_Zn~RaUz9rjbD#&dyHGh#vHfD zw-@c}Eh^bxP*OqL57NL}uRxR>^9iN);}H%#aTkGa{N58qs+5pcv+c~XvLD&b2aZ>; F`496rd>H@$ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/FileWriteEvent.java b/tests/test_data/std/jdk/internal/event/FileWriteEvent.java new file mode 100644 index 00000000..7a39f93b --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/FileWriteEvent.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +/** + * Event recording file writes. + */ +public final class FileWriteEvent extends Event { + + // The order of these fields must be the same as the parameters in + // commit(..., String, long) + public String path; + public long bytesWritten; + + public static boolean enabled() { + // Generated by JFR + return false; + } + + public static long timestamp() { + // Generated by JFR + return 0L; + } + + public static boolean shouldCommit(long duration) { + // Generated by JFR + return false; + } + + public static void commit(long start, long duration, String path, long bytesWritten) { + // Generated by JFR + } +} diff --git a/tests/test_data/std/jdk/internal/event/JFRTracing.class b/tests/test_data/std/jdk/internal/event/JFRTracing.class new file mode 100644 index 0000000000000000000000000000000000000000..6a974714a91d7d67553782f4ca0ffe4779e6b6ae GIT binary patch literal 1173 zcmaJ>T~pIQ6g}IP25PX-))YZL$XpmG%(4KAA=5hp8J^}Ns&PY*9@2@rg5ENq2KvrIVupI;?fc)LIu`` z=Kg`lZAW#9R4CoWP^h%VYz@hMzpi(gVVDcwJFeAqq}WlzQP2)N!3PF%4D<2g-YAGw z3k+p{q%1|Pb}#I1^te(&?hJ;~Krz<6&sE1Ays>TJ`+A#6%rj*A$KJWn49d7^;FgI6 zEHY&OkxG7bMet78l6#`lbcF0Mti>lH$uw`h8XM9R$C8XCVFa&du#DRV?wGiXdly58 z{$If{O#32;ggT*dsmjOdq3*tK;sGion*eWJR|>8eig6Lqm#h<>A=Pj@WP7&dD6u;l z90~6r`VhI6Yjb(XJxAx~FH=F!@fns{|NWeG+Wh?&TMProRlb1@hQ+Z{yKZ}A_rhr} zK?XJ%mdBVKDMgpdXueAn!vr~ddde^x^DjCiR6CCRF2!nBJR@1ft3!PqUJO=IX>3wdLTTan~%I4zoJsb+|!6GqRAe zOkF^Qwyu(t8nVP)AkGr8u2V>A@t3sw7hL3wmnN`C4x745ij;>I_S(jN*zWPKLxe zq-ebXgPKijB8SJJ>|)eP*%PYMPXJHxjKn;rEE*|KwHK7dw|_}_0H4_8}%0b*tm AH~;_u literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/JFRTracing.java b/tests/test_data/std/jdk/internal/event/JFRTracing.java new file mode 100644 index 00000000..5882b2dd --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/JFRTracing.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +import sun.nio.ch.FileChannelImpl; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.RandomAccessFile; +import java.lang.Throwable; +import java.lang.reflect.Field; + +/** + * Helper class to enable JFR tracing. + */ +public final class JFRTracing { + + public static void enable() throws NoSuchFieldException, IllegalAccessException { + enable(Throwable.class); + enable(FileInputStream.class); + enable(FileOutputStream.class); + enable(FileChannelImpl.class); + enable(RandomAccessFile.class); + } + + private static void enable(Class clazz) throws NoSuchFieldException, IllegalAccessException { + Field field = clazz.getDeclaredField("jfrTracing"); + field.setAccessible(true); + field.setBoolean(null, true); + } +} diff --git a/tests/test_data/std/jdk/internal/event/ProcessStartEvent.class b/tests/test_data/std/jdk/internal/event/ProcessStartEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..4ba52d514cb5ee6eb032179de570309f62c728b4 GIT binary patch literal 399 zcma)2yH3ME5S+E07>prc9-^c`2q-vFgJ>cskcE(p(qHUTxL}{rBei9!aZx--(fX)HA|S{+~p=Cn?&wE!B|XuV(y*3f?l`?Fktj!-~gM9>5lAu3=pA#JQ zjpG;*uMT_&tBCnVSR0rJLC88`S1=QEaQF&(`TnrZ*gpfi*kDY40x-rVE5a7z2d^hlR*E;jS3bN`~W{n zyc2`C5W&qoGxy9n_i*R^JUUlVDgv%tu2SLi+^y8^wNJYY_0B(~4U0xk z*_g%*Lq!bR(z^do;Qo}KnxiyG3+Kv^59I8S{-cOhy-zyPT+C;k20-&Puk7$0o7NOFUFXCf~n{I6ztG# Joq7dqd;;hjf7k#3 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/SecurityProviderServiceEvent.java b/tests/test_data/std/jdk/internal/event/SecurityProviderServiceEvent.java new file mode 100644 index 00000000..8dca527c --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/SecurityProviderServiceEvent.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.event; + +/** + * Event recording details of Provider.getService(String type, String algorithm) calls + */ + +public final class SecurityProviderServiceEvent extends Event { + private static final SecurityProviderServiceEvent EVENT = new SecurityProviderServiceEvent(); + + /** + * Returns {@code true} if event is enabled, {@code false} otherwise. + */ + public static boolean isTurnedOn() { + return EVENT.isEnabled(); + } + + public String type; + public String algorithm; + public String provider; +} diff --git a/tests/test_data/std/jdk/internal/event/SerializationMisdeclarationEvent.class b/tests/test_data/std/jdk/internal/event/SerializationMisdeclarationEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..d3bd1921def3189a821095912bd0d3cae74a58a6 GIT binary patch literal 937 zcmbVKTWb?R6#gc=NxCuGi?!BzYrS9+#C?!HSqc*LA*_N#g7j^g9nz_LDSIjCZ_)>! z1RwkX{wVRA*{!Zx5L}pZ{mwbxnb~jOzkCHS#@!xTaJq2&Xrm*rc^tm=byBD-k&&-X zRZ{rRj1=hX=|mU%0?uGK>tadZ@j2kB%CwC1ds*l-d7<-A%_EsvukN!FpG8$Tj%1z- ztOm#ORQi!j7QPKV5%8vZk;tOVl)(C*`MuFTA>CNzxm*yi)&NY4OeYJb-EkT+w;bq1 zy)5HHmA#gSkwvF-8O misdeclaredClass; + public String message; + + /** + * Commit a serialization misdeclaration event. + * The implementation of this method is generated automatically if jfr is enabled. + * The order of the fields must be the same as the parameters in this method. + * {@code commit(long,Class,String)} + * + * @param start timestamp of the start of the operation + * @param misdeclaredClass the affected class + * @param message the specific event message + */ + public static void commit(long start, Class misdeclaredClass, String message) { + // Generated by JFR + } + + /** + * Determine if an event should be emitted. The duration of the operation + * must exceed some threshold in order to commit the event. The implementation + * of this method is generated automatically if jfr is enabled. + * + * @param duration time in nanoseconds to complete the operation + * @return true if the event should be commited + */ + public static boolean shouldCommit(long duration) { + // Generated by JFR + return false; + } + + /** + * Determine if this kind of event is enabled. The implementation + * of this method is generated automatically if jfr is enabled. + * + * @return whether serialization misdeclaration events are enabled + */ + public static boolean enabled() { + // Generated by JFR + return false; + } + + /** + * Fetch the current timestamp in nanoseconds. This method is used + * to determine the start and end of an operation. The implementation + * of this method is generated automatically if jfr is enabled. + * + * @return the current timestamp value + */ + public static long timestamp() { + // Generated by JFR + return 0L; + } + +} diff --git a/tests/test_data/std/jdk/internal/event/SocketReadEvent.class b/tests/test_data/std/jdk/internal/event/SocketReadEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..a4b2c23574ee6a0045929209801e744c81d96209 GIT binary patch literal 2096 zcmah~-&0#f6#h23$tB4JYJ`-KnxjRWD?LTatTYa?`Oo zI^%;+{y;}xnDLz#eei{%&N%w&zog^%?dCRssbd~?&+dNbobP;l_U4bjfBqG~6xQMh zA#B315J6O+?|x~c;JCi5xpuiAA4u0POsi2Kdd6`b|C~TLKe!l22Vy4T780-o2A<%y z;H_*(e_q<9AVAD_Dzfg|m8yO5)TY4mVI z>iwhnVzD@T-+o{hT0XB9LqG zxaB(UU-T-r;~tR4L_y%NM(q>eLc=MSWG#+SggfxEfViXVQx;yqX)>~_Rq2)lM)K|1 z+vN%FUH@y}7z>Np{mZ@11AuoXN*-wi8iReG6iSo2qra27N?PAh!I_ zmvz@|n{{>A5MEHDEXLOVrHQRSQms^?)DN0v`B_*~EX+*r$Raq0rwtD4>FNSyM1`(n) zS@C=l?Q81Nj_0FU@a>h2t9CV@A9m`tz>z(NwkJo{MpfUh(I_eKz#jNNT9Gbc>8L;7e+@YwLqDsu}^u_&!4Xltm#hjZ3ry-U#N)n9=JZuIPC-n6Kg**Cvtt z=5f5vRe`hM92t59@gt28<~XWjU=TMrT1^1vvA|VKy-DsU=lAp}Q~%p>T072@qvCZ_ z=U3J(T8ed(v!N};I-)JbJE|?k+|<@0t(dkH`vh%%H-q%UoK>_?_euuX`#kRw$4`3;r{WVA`+?(r+&Xc$u@vAwz@Ho>CHpb)qCx;SX8h2Q218^y4E<_mq|)(~>KLJAqso+{HcZm4T8bLf;-; zmWj6+i?{U``VCUxpGK3C7-tckJljkev2VYFX>7v?pN<8q*ft_5W6VfLe@E{YhSJgB z&^sQ_=F;&U99BbS2S?R>JY}Yg-q6B(|ZcB?b^oO6mH$($Y#PAdLYlg;t7Hx5;h0ZL*u$Y>>SB zb9nWoGrsep55APDGmgIcH!+Uq++EVt;Eellf1LZBd%p9XbN8>mfBhZ6Jk|}w5Z9rZ zNMJx$Q2W(Qqi3RxFoR`8;FdMGTTbDto?I zE|)9Y_5<5;WnhId=4v%xwp!DrWgS_8k?!#VVGcnI3}M(r4kH3bHf3pZ;bHEhQ{ zB#aJA;Dkc;q<^LD)N9f=FoAdyZwQF{ynf5X+jxig*v+PNYXTRF{jvMSjBX=M$MLR- zinD4x~!~%5*yK)uh0&isQ;# z?Z&$F@7U{gvScb=)vhnwzQg;-s0CY2OW{_Efdst~u79%D_U*v&C}u)YAb!&2 zdr5O@j#aXI8ynIWIN9xp=RFH5l`k7!K>UWotou>)AeI8Vx^vTRMy%sb%N7_taOitZ z#8qpm>S^s7gHIoT|D(~!#aQy%epOzl8Vd}CZFumTnBWTI6t#Vf{!khOuHibZ1m2J4 z8(2{LGCrVLrxW^h(O99KMYEteG4=%FXIjK?lSV!UO1MR%83OPj7HOB_r$rWaUQ>Gt z^>4?^%5j#iVICi;xV*YeD`pvT)YOVuCe(^~h8|0V(7r2MG_z+c{v(e)Br826 zV=4lZyo0-u=LpUGg`T3vbA@p9H}2y2e!``GqOliOCEPMrB3y@<>4eDbL(j{}L^iRH zBfBv3*+e0y?c+F$5m#X{R1Tm;@PJZjV;Em3vSZ4g>k5+tmxjaV@G0EO&gBOFz|d4GU&y8QaDs=I z_V6;#uVnRo6dz-bq2s%_$k6dA<2Ov)dxF<8ukYc_oUw<=UqH=Ao6Kbz_Hbn?oiAkO zbLqIc;2_Ps(&I}?@hjxKD16q1cdx~*whJ^W?EHT*s0PcR7{{R30 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/SocketWriteEvent.java b/tests/test_data/std/jdk/internal/event/SocketWriteEvent.java new file mode 100644 index 00000000..7c56ef82 --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/SocketWriteEvent.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.event; + + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; + +/** + * A JFR event for socket write operations. This event is mirrored in + * {@code jdk.jfr.events.SocketWriteEvent } where the metadata for the event is + * provided with annotations. Some of the methods are replaced by generated + * methods when jfr is enabled. Note that the order of the arguments of the + * {@link #commit(long, long, String, String, int, long)} method + * must be the same as the order of the fields. + */ +public class SocketWriteEvent extends Event { + + // THE ORDER OF THE FOLLOWING FIELDS IS IMPORTANT! + // The order must match the argument order of the generated commit method. + public String host; + public String address; + public int port; + public long bytesWritten; + + /** + * Actually commit a socket write event. This is generated automatically. + * The order of the fields must be the same as the parameters in this method. + * {@code commit(..., String, String, int, long)} + * + * @param start timestamp of the start of the operation + * @param duration time in nanoseconds to complete the operation + * @param host remote host of the transfer + * @param address remote address of the transfer + * @param port remote port of the transfer + * @param bytes number of bytes that were transferred + */ + public static void commit(long start, long duration, String host, String address, int port, long bytes) { + // Generated by JFR + } + + /** + * Determine if an event should be emitted. The duration of the operation + * must exceed some threshold in order to commit the event. The implementation + * of this method is generated automatically if jfr is enabled. + * + * @param duration time in nanoseconds to complete the operation + * @return true if the event should be commited + */ + public static boolean shouldCommit(long duration) { + // Generated by JFR + return false; + } + + /** + * Determine if this kind of event is enabled. The implementation + * of this method is generated automatically if jfr is enabled. + * + * @return true if socket write events are enabled, false otherwise + */ + public static boolean enabled() { + // Generated by JFR + return false; + } + + /** + * Fetch the current timestamp in nanoseconds. This method is used + * to determine the start and end of an operation. The implementation + * of this method is generated automatically if jfr is enabled. + * + * @return the current timestamp value + */ + public static long timestamp() { + // Generated by JFR + return 0L; + } + + /** + * Helper method to offer the data needed to potentially commit an event. + * The duration of the operation is computed using the current + * timestamp and the given start time. If the duration is meets + * or exceeds the configured value (determined by calling the generated method + * {@link #shouldCommit(long)}), an event will be emitted by calling + * {@link #emit(long, long, long, SocketAddress)}. + * + * @param start the start time + * @param bytesWritten how many bytes were sent + * @param remote the address of the remote socket being written to + */ + public static void offer(long start, long bytesWritten, SocketAddress remote) { + long duration = timestamp() - start; + if (shouldCommit(duration)) { + emit(start, duration, bytesWritten, remote); + } + } + + /** + * Helper method to perform a common task of getting event data ready and + * then emitting the event by calling + * {@link #commit(long, long, String, String, int, long)}. + * + * @param start the start time + * @param duration the duration + * @param bytesWritten how many bytes were sent + * @param remote the address of the remote socket being written to + */ + public static void emit(long start, long duration, long bytesWritten, SocketAddress remote) { + long bytes = bytesWritten < 0 ? 0 : bytesWritten; + if (remote instanceof InetSocketAddress isa) { + commit(start, duration, isa.getHostString(), isa.getAddress().getHostAddress(), isa.getPort(), bytes); + } else if (remote instanceof UnixDomainSocketAddress udsa) { + String path = "[" + udsa.getPath().toString() + "]"; + commit(start, duration, "Unix domain socket", path, 0, bytes); + } + } +} diff --git a/tests/test_data/std/jdk/internal/event/TLSHandshakeEvent.class b/tests/test_data/std/jdk/internal/event/TLSHandshakeEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..0b2f7be230f5d62d8a633593872766f8bbcb95b9 GIT binary patch literal 461 zcma)2yG{c^3>@c8NC<>iN(zL4f)h1}CIS(3LP!^--`tsGlVdm9+vLBfkSO>7J__Lr z*Fixut`J+&x1sI9tf4bO~mSi+VJD@Wz24<#;Ihwp^a5K zQcmZ(NLKt*XM~gRKl{sq&B!iY%y&AUc<}4Oi~J^BqAst5ypgbhrbMzhT5E0>daK|L rw%2*epDuMfq5@$OuAaYvUL`1@E128B5q1SzKLyysz9?Bmu!O^J9_DI| literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/TLSHandshakeEvent.java b/tests/test_data/std/jdk/internal/event/TLSHandshakeEvent.java new file mode 100644 index 00000000..f763a0e4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/TLSHandshakeEvent.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.event; + +/** + * Event recording details of successful TLS handshakes. + */ + +public final class TLSHandshakeEvent extends Event { + public String peerHost; + public int peerPort; + public String protocolVersion; + public String cipherSuite; + public long certificateId; +} diff --git a/tests/test_data/std/jdk/internal/event/ThreadSleepEvent.class b/tests/test_data/std/jdk/internal/event/ThreadSleepEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..7dad7373f1bee9e533484fb64454f67e8004ef7d GIT binary patch literal 515 zcma)2O-lk%6g_W79cP@Vu;ajhX(8hxiyT8`5Z-xGB_dWl^2AiA#Pc;W5hDu_={kO@>_&2fChNwK?kXsKaBa{Y5a7^yQerk>g+z zD-m8RhJ3vjEiQE0qe&dn%xaxB zx$9%(G1AT?o@S;G(1+^u?8+E5Fq83E+JEPq-}%m2{qyf%e*@UUu8jhU7D^7raEW2+ zICvKLy&&%Tj}MP|s2DD-i&&@)hGN4#urSUrmpjx~kAKIG>^0YutLQ_+os!yey}NyJcVbly4Ebbq!ng=q^j4n9DQ;o9-hQ(wf2%Q)!y z{27mxZvyT=k;$*|wq9VcxN&=ASdELigUgs@C@T^1R0YwA*=uX}a}GYnCzN2AM3Er# z>y37fWKT&EcbmBtlS0!yuyIART_uZ)uzm~qi4sYiL(>*@{g^A`8Wt@qIatPZhJ_0p z7&|S`z6?Sx87AX?G+HDLhkEsu==ot1hkYrv9)U_C5&A9j>LkQ&!-Z#I#lh!Vgk>Z1 zd(Eh9A`T^w$Z0D+dcc*9Rn#r`3@aD#Zl5N+rvfEXCBoFyLq}h8a8rjab~7(uY0Ymj zj5XSAEu@PgLuo5H;uN(bV*W!vI^=R+r_V6cNy4Ca5J+L<$QDcLi69XcI~SmgRLZ1l zGT2IsXj+8?INxcx@(v5`9x$*rA%?x+#S4b%+>xvUsL`mI(x7V)&w6+0fT8|>?&l|b zm{9FqU+dlmK~9o#;nUsVWO%H+r!R==OA6qgW7ak~KRN7*Np>UxLxodgpOuASd_C+9 zud}_E^kv9*gjTvXGRl-&)mdSUnzcaR3A*ySU1>B%WBO3g^A62?dNaN1y#aegg95&$ zr``tUahIM>b^!O#q*)p3_=Zktor#2Kdy> z=d<}|e_-J?8b9htB@@Y`&ke9dewS(F(xvuL!wTWvp!lm;Bt(zWSfeh~G#=U2i0?8s zh+=UxA_{EcKAq5`7QQ9wEgEO^dha`$ZPR}YMY~$X4h;)*NNw zMd5D~_8r2$OGx(&;yjA9c8Unhj=*Nmf$6+T7zw`^ z;LEdeRVX4TixP=aA&;kJD`CP21&pITa+h@kF!2`dPj7JhPb_FxELZsjnte}e1$6!c D4U1`Y literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/ThrowableTracer.java b/tests/test_data/std/jdk/internal/event/ThrowableTracer.java new file mode 100644 index 00000000..f7076b44 --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/ThrowableTracer.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * Helper class for exception events. + */ +public final class ThrowableTracer { + + private static final AtomicLong numThrowables = new AtomicLong(); + + public static void traceError(Class clazz, String message) { + if (OutOfMemoryError.class.isAssignableFrom(clazz)) { + return; + } + + if (ErrorThrownEvent.enabled()) { + long timestamp = ErrorThrownEvent.timestamp(); + ErrorThrownEvent.commit(timestamp, message, clazz); + } + if (ExceptionThrownEvent.enabled()) { + long timestamp = ExceptionThrownEvent.timestamp(); + ExceptionThrownEvent.commit(timestamp, message, clazz); + } + numThrowables.incrementAndGet(); + } + + public static void traceThrowable(Class clazz, String message) { + if (ExceptionThrownEvent.enabled()) { + long timestamp = ExceptionThrownEvent.timestamp(); + ExceptionThrownEvent.commit(timestamp, message, clazz); + } + numThrowables.incrementAndGet(); + } + + public static void emitStatistics() { + long timestamp = ExceptionStatisticsEvent.timestamp(); + ExceptionStatisticsEvent.commit(timestamp, numThrowables.get()); + } +} diff --git a/tests/test_data/std/jdk/internal/event/VirtualThreadEndEvent.class b/tests/test_data/std/jdk/internal/event/VirtualThreadEndEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..06e53ccecc5a4d0873739efff9cee098b7eaf5ed GIT binary patch literal 538 zcma)2%SyvQ6g`u)rb(l%?^;C>5o#Ca11xSz1f|r4A)vcyGtjAV3Te`>a-)I;1wX)# z67Qr%y6D2qea?Bz{r>s*0?@{R0|Taof{P+n7;3}l(UU3_iQ=&*CPJm2uOq`sODdUO zGMJ6C&_)Ti1;<4hE<lffPG37<(_(}vwJ6xyRmFjP8HiEj4P6G@%$MpT{9jr0(a#LOPIR z21kyAEKwr5RScz8Kc4^Dxf^9kUtCE|P+$7Bb8P{~S8n zoky8bE;grNFH{)Vrl{AzA$BObvj^DCX>8O`rHKX~CPBR1hzm-aBCjbBd literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/VirtualThreadEndEvent.java b/tests/test_data/std/jdk/internal/event/VirtualThreadEndEvent.java new file mode 100644 index 00000000..6920eb03 --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/VirtualThreadEndEvent.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +/** + * Event recording that a virtual thread has terminated. + */ +public class VirtualThreadEndEvent extends Event { + private static final VirtualThreadEndEvent EVENT = new VirtualThreadEndEvent(); + + /** + * Returns {@code true} if event is enabled, {@code false} otherwise. + */ + public static boolean isTurnedOn() { + return EVENT.isEnabled(); + } + + public long javaThreadId; +} diff --git a/tests/test_data/std/jdk/internal/event/VirtualThreadPinnedEvent.class b/tests/test_data/std/jdk/internal/event/VirtualThreadPinnedEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..440c1b581b94232e1b4f483b5caf5eaa45d56354 GIT binary patch literal 343 zcmb7{Xgv7uD@KC7d zsv``XrO*EVJKJ~PKc8O!W;n|bp_3x+BSDvNv94Zov7VhZboUa=Ve(6HDbBa1p06C6>RGJi>To}vH5C&Eg;;)SHw$)iv#8ZMFPf#POXDQygBkmk zyb*4SfBbPr$X=S(E%{Nx!PlV(fvdf;Zzx6umc#JRS5t9 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/VirtualThreadPinnedEvent.java b/tests/test_data/std/jdk/internal/event/VirtualThreadPinnedEvent.java new file mode 100644 index 00000000..73746dc4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/VirtualThreadPinnedEvent.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +/** + * Event recording that a virtual thread has parked on its carrier thread. + */ +public class VirtualThreadPinnedEvent extends Event { +} diff --git a/tests/test_data/std/jdk/internal/event/VirtualThreadStartEvent.class b/tests/test_data/std/jdk/internal/event/VirtualThreadStartEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..a189b825a34f1f48251e2c63f8db9c71ff190875 GIT binary patch literal 544 zcma)2+e!jK82)BgTX)^k&Sp|X1SQcvK+=tDP>5Z)EY#iT4mh^0Fs?pTHx(ol^Z-3n z^v^2cML{?JalXU+pI>hu0Gg;dFko89xyWOQp)!c>J(;9JB|P@TL?o%_>&URwkcmt$ z7|i37&_)5a1;<4ZE<^nnSSVFG=5f$hf=8W{t8`A3_d~xOFr2pjk2-fqaK%LlWd>W0 z{DgO75oKoX^v+~(2YkY3a#yrr*9^JlFcJ)H|?ll31r~Qbm`h zxIvvqnNiNyr(jQ17}%t!*T5dOD7v!;*v@EdR8Xdg2JdGZzq(T^B-U!m3uUFMT&rbHY{f?~wdd znAVLg~z2zZm=L)b*f6=4g}lBwM->upvsGckA1-$8F&c-UcV+rSa} RjM2(~0d`sOG8jGV{{RnbZqfh% literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/event/VirtualThreadSubmitFailedEvent.java b/tests/test_data/std/jdk/internal/event/VirtualThreadSubmitFailedEvent.java new file mode 100644 index 00000000..e12e4008 --- /dev/null +++ b/tests/test_data/std/jdk/internal/event/VirtualThreadSubmitFailedEvent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.event; + +/** + * Event recording when an attempt to submit the task for a virtual thread failed. + */ +public class VirtualThreadSubmitFailedEvent extends Event { + public long javaThreadId; + public String exceptionMessage; +} diff --git a/tests/test_data/std/jdk/internal/event/X509CertificateEvent.class b/tests/test_data/std/jdk/internal/event/X509CertificateEvent.class new file mode 100644 index 0000000000000000000000000000000000000000..37529650800c6729c3dc6c6ff29056821bec9e2d GIT binary patch literal 718 zcma)4OHUL*5dLZ(%&TzX^qgaoJ!;3 zu9t+FZDo{uOQ>&b4%%p;9UzP_i-@p(McKjYmv1`KI`vs4!pW*jvpeYS^$DB3|18-G znd(}Ec`OjxD(@OG)G{r{_~c`Cb_+eqta9Tc!j0ZUOhv4P8O8g~Dl^(5M7gv|=)K}- zC@mq#i{V5jekqmbMd><}C;gLS$<0{nNi%X|0__s!l7CC=GB3U3oT<<%-LV-HhNb?& zIHd`VPL^_y`JOWJg01hz^_Rrh@1cf~8dLXDp@#Ik=5)|d}BOT1O#?F#Qyc(=kuER}i7xL4x+3LlhM=T7`D zSU%)v%t(yQ=ck~rtkkf=(uaY^c*HWgNMOs4(Z(tk*yD>=$_NmAL+}H0U)V*L$~Sn2 fwZBYjHJ^JP98B06$8c z)gT^v@bccgH#5uZ`}ll&2asSpLzzSh^$?*O0;YlV+RS2t$Zdd!ctgL!axv+9t5a^1q`Nz943+2YSGbIe0-~GhY z?iPZdm_iZ;snYVgexAwdPRvSnMybg~nTbj{-I~6AR13l+{ojG7gz(nXRW2`;dvm&uEE;<-6x;C(b4aVqa07Hye KaW0G}$M!k}70oRpm58EJM=Xvd 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, RuntimeException> + permits HeapMemorySegmentImpl, NativeMemorySegmentImpl { + + private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess(); + + static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); + + final long length; + final boolean readOnly; + final MemorySessionImpl scope; + + @ForceInline + AbstractMemorySegmentImpl(long length, boolean readOnly, MemorySessionImpl scope) { + this.length = length; + this.readOnly = readOnly; + this.scope = scope; + } + + abstract AbstractMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySessionImpl scope); + + abstract ByteBuffer makeByteBuffer(); + + @Override + public AbstractMemorySegmentImpl asReadOnly() { + return dup(0, length, true, scope); + } + + @Override + public boolean isReadOnly() { + return readOnly; + } + + @Override + public AbstractMemorySegmentImpl asSlice(long offset, long newSize) { + checkBounds(offset, newSize); + return asSliceNoCheck(offset, newSize); + } + + @Override + public AbstractMemorySegmentImpl asSlice(long offset) { + checkBounds(offset, 0); + return asSliceNoCheck(offset, length - offset); + } + + @Override + public MemorySegment asSlice(long offset, long newSize, long byteAlignment) { + checkBounds(offset, newSize); + Utils.checkAlign(byteAlignment); + + if (!isAlignedForElement(offset, byteAlignment)) { + throw new IllegalArgumentException("Target offset incompatible with alignment constraints"); + } + return asSliceNoCheck(offset, newSize); + } + + @Override + public MemorySegment asSlice(long offset, MemoryLayout layout) { + Objects.requireNonNull(layout); + return asSlice(offset, layout.byteSize(), layout.byteAlignment()); + } + + @Override + @CallerSensitive + public final MemorySegment reinterpret(long newSize, Arena arena, Consumer cleanup) { + Objects.requireNonNull(arena); + return reinterpretInternal(Reflection.getCallerClass(), newSize, + MemorySessionImpl.toMemorySession(arena), cleanup); + } + + @Override + @CallerSensitive + public final MemorySegment reinterpret(long newSize) { + return reinterpretInternal(Reflection.getCallerClass(), newSize, scope, null); + } + + @Override + @CallerSensitive + public final MemorySegment reinterpret(Arena arena, Consumer cleanup) { + Objects.requireNonNull(arena); + return reinterpretInternal(Reflection.getCallerClass(), byteSize(), + MemorySessionImpl.toMemorySession(arena), cleanup); + } + + public MemorySegment reinterpretInternal(Class callerClass, long newSize, Scope scope, Consumer cleanup) { + Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret"); + Utils.checkNonNegativeArgument(newSize, "newSize"); + if (!isNative()) throw new UnsupportedOperationException("Not a native segment"); + Runnable action = cleanup != null ? + () -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) : + null; + return SegmentFactories.makeNativeSegmentUnchecked(address(), newSize, + (MemorySessionImpl)scope, readOnly, action); + } + + private AbstractMemorySegmentImpl asSliceNoCheck(long offset, long newSize) { + return dup(offset, newSize, readOnly, scope); + } + + @Override + public Spliterator spliterator(MemoryLayout elementLayout) { + Objects.requireNonNull(elementLayout); + if (elementLayout.byteSize() == 0) { + throw new IllegalArgumentException("Element layout size cannot be zero"); + } + Utils.checkElementAlignment(elementLayout, "Element layout size is not multiple of alignment"); + if (!isAlignedForElement(0, elementLayout)) { + throw new IllegalArgumentException("Incompatible alignment constraints"); + } + if ((byteSize() % elementLayout.byteSize()) != 0) { + throw new IllegalArgumentException("Segment size is not a multiple of layout size"); + } + return new SegmentSplitter(elementLayout.byteSize(), byteSize() / elementLayout.byteSize(), + this); + } + + @Override + public Stream elements(MemoryLayout elementLayout) { + return StreamSupport.stream(spliterator(elementLayout), false); + } + + @Override + public final MemorySegment fill(byte value){ + checkAccess(0, length, false); + SCOPED_MEMORY_ACCESS.setMemory(sessionImpl(), unsafeGetBase(), unsafeGetOffset(), length, value); + return this; + } + + @Override + public MemorySegment allocate(long byteSize, long byteAlignment) { + Utils.checkAllocationSizeAndAlign(byteSize, byteAlignment); + return asSlice(0, byteSize, byteAlignment); + } + + /** + * Mismatch over long lengths. + */ + public static long vectorizedMismatchLargeForBytes(MemorySessionImpl aSession, MemorySessionImpl bSession, + Object a, long aOffset, + Object b, long bOffset, + long length) { + long off = 0; + long remaining = length; + int i, size; + boolean lastSubRange = false; + while (remaining > 7 && !lastSubRange) { + if (remaining > Integer.MAX_VALUE) { + size = Integer.MAX_VALUE; + } else { + size = (int) remaining; + lastSubRange = true; + } + i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(aSession, bSession, + a, aOffset + off, + b, bOffset + off, + size, ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE); + if (i >= 0) + return off + i; + + i = size - ~i; + off += i; + remaining -= i; + } + return ~remaining; + } + + @Override + public final ByteBuffer asByteBuffer() { + checkArraySize("ByteBuffer", 1); + ByteBuffer _bb = makeByteBuffer(); + if (readOnly) { + //session is IMMUTABLE - obtain a RO byte buffer + _bb = _bb.asReadOnlyBuffer(); + } + return _bb; + } + + @Override + public final long byteSize() { + return length; + } + + @Override + public boolean isMapped() { + return false; + } + + @Override + public boolean isNative() { + return false; + } + + @Override + public final Optional asOverlappingSlice(MemorySegment other) { + AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other); + if (unsafeGetBase() == that.unsafeGetBase()) { // both either native or heap + final long thisStart = this.unsafeGetOffset(); + final long thatStart = that.unsafeGetOffset(); + final long thisEnd = thisStart + this.byteSize(); + final long thatEnd = thatStart + that.byteSize(); + + if (thisStart < thatEnd && thisEnd > thatStart) { //overlap occurs + long offsetToThat = that.address() - this.address(); + long newOffset = offsetToThat >= 0 ? offsetToThat : 0; + return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat))); + } + } + return Optional.empty(); + } + + @Override + public MemorySegment copyFrom(MemorySegment src) { + MemorySegment.copy(src, 0, this, 0, src.byteSize()); + return this; + } + + @Override + public long mismatch(MemorySegment other) { + Objects.requireNonNull(other); + return MemorySegment.mismatch(this, 0, byteSize(), other, 0, other.byteSize()); + } + + @Override + public void load() { + throw notAMappedSegment(); + } + + @Override + public void unload() { + throw notAMappedSegment(); + } + + @Override + public boolean isLoaded() { + throw notAMappedSegment(); + } + + @Override + public void force() { + throw notAMappedSegment(); + } + + private static UnsupportedOperationException notAMappedSegment() { + throw new UnsupportedOperationException("Not a mapped segment"); + } + + @Override + public final byte[] toArray(ValueLayout.OfByte elementLayout) { + return toArray(byte[].class, elementLayout, byte[]::new, MemorySegment::ofArray); + } + + @Override + public final short[] toArray(ValueLayout.OfShort elementLayout) { + return toArray(short[].class, elementLayout, short[]::new, MemorySegment::ofArray); + } + + @Override + public final char[] toArray(ValueLayout.OfChar elementLayout) { + return toArray(char[].class, elementLayout, char[]::new, MemorySegment::ofArray); + } + + @Override + public final int[] toArray(ValueLayout.OfInt elementLayout) { + return toArray(int[].class, elementLayout, int[]::new, MemorySegment::ofArray); + } + + @Override + public final float[] toArray(ValueLayout.OfFloat elementLayout) { + return toArray(float[].class, elementLayout, float[]::new, MemorySegment::ofArray); + } + + @Override + public final long[] toArray(ValueLayout.OfLong elementLayout) { + return toArray(long[].class, elementLayout, long[]::new, MemorySegment::ofArray); + } + + @Override + public final double[] toArray(ValueLayout.OfDouble elementLayout) { + return toArray(double[].class, elementLayout, double[]::new, MemorySegment::ofArray); + } + + private Z toArray(Class arrayClass, ValueLayout elemLayout, IntFunction arrayFactory, Function segmentFactory) { + int size = checkArraySize(arrayClass.getSimpleName(), (int)elemLayout.byteSize()); + Z arr = arrayFactory.apply(size); + MemorySegment arrSegment = segmentFactory.apply(arr); + MemorySegment.copy(this, elemLayout, 0, arrSegment, elemLayout.withOrder(ByteOrder.nativeOrder()), 0, size); + return arr; + } + + @ForceInline + public void checkReadOnly(boolean readOnly) { + if (!readOnly && this.readOnly) { + throw new IllegalArgumentException("Attempt to write a read-only segment"); + } + } + + @ForceInline + public void checkAccess(long offset, long length, boolean readOnly) { + checkReadOnly(readOnly); + checkBounds(offset, length); + } + + public void checkValidState() { + sessionImpl().checkValidState(); + } + + public abstract long unsafeGetOffset(); + + public abstract Object unsafeGetBase(); + + // Helper methods + + public abstract long maxAlignMask(); + + @ForceInline + public final boolean isAlignedForElement(long offset, MemoryLayout layout) { + return isAlignedForElement(offset, layout.byteAlignment()); + } + + @ForceInline + public final boolean isAlignedForElement(long offset, long byteAlignment) { + return (((unsafeGetOffset() + offset) | maxAlignMask()) & (byteAlignment - 1)) == 0; + } + + private int checkArraySize(String typeName, int elemSize) { + // elemSize is guaranteed to be a power of two, so we can use an alignment check + if (!Utils.isAligned(length, elemSize)) { + throw new IllegalStateException(String.format("Segment size is not a multiple of %d. Size: %d", elemSize, length)); + } + long arraySize = length / elemSize; + if (arraySize > (Integer.MAX_VALUE - 8)) { //conservative check + throw new IllegalStateException(String.format("Segment is too large to wrap as %s. Size: %d", typeName, length)); + } + return (int)arraySize; + } + + @ForceInline + void checkBounds(long offset, long length) { + if (length > 0) { + Preconditions.checkIndex(offset, this.length - length + 1, this); + } else if (length < 0 || offset < 0 || + offset > this.length - length) { + throw outOfBoundException(offset, length); + } + } + + @Override + public RuntimeException apply(String s, List numbers) { + long offset = numbers.get(0).longValue(); + long length = byteSize() - numbers.get(1).longValue() + 1; + return outOfBoundException(offset, length); + } + + @Override + public Scope scope() { + return scope; + } + + @Override + public boolean isAccessibleBy(Thread thread) { + return sessionImpl().isAccessibleBy(thread); + } + + @ForceInline + public final MemorySessionImpl sessionImpl() { + return scope; + } + + private IndexOutOfBoundsException outOfBoundException(long offset, long length) { + return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d", + this, offset, length)); + } + + static class SegmentSplitter implements Spliterator { + AbstractMemorySegmentImpl segment; + long elemCount; + final long elementSize; + long currentIndex; + + SegmentSplitter(long elementSize, long elemCount, AbstractMemorySegmentImpl segment) { + this.segment = segment; + this.elementSize = elementSize; + this.elemCount = elemCount; + } + + @Override + public SegmentSplitter trySplit() { + if (currentIndex == 0 && elemCount > 1) { + AbstractMemorySegmentImpl parent = segment; + long rem = elemCount % 2; + long split = elemCount / 2; + long lobound = split * elementSize; + long hibound = lobound + (rem * elementSize); + elemCount = split + rem; + segment = parent.asSliceNoCheck(lobound, hibound); + return new SegmentSplitter(elementSize, split, parent.asSliceNoCheck(0, lobound)); + } else { + return null; + } + } + + @Override + public boolean tryAdvance(Consumer action) { + Objects.requireNonNull(action); + if (currentIndex < elemCount) { + AbstractMemorySegmentImpl acquired = segment; + try { + action.accept(acquired.asSliceNoCheck(currentIndex * elementSize, elementSize)); + } finally { + currentIndex++; + if (currentIndex == elemCount) { + segment = null; + } + } + return true; + } else { + return false; + } + } + + @Override + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + if (currentIndex < elemCount) { + AbstractMemorySegmentImpl acquired = segment; + try { + for (long i = currentIndex ; i < elemCount ; i++) { + action.accept(acquired.asSliceNoCheck(i * elementSize, elementSize)); + } + } finally { + currentIndex = elemCount; + segment = null; + } + } + } + + @Override + public long estimateSize() { + return elemCount; + } + + @Override + public int characteristics() { + return NONNULL | SUBSIZED | SIZED | IMMUTABLE | ORDERED; + } + } + + // Object methods + + @Override + public String toString() { + return "MemorySegment{ " + + heapBase().map(hb -> "heapBase: " + hb + ", ").orElse("") + + "address: " + Utils.toHexString(address()) + + ", byteSize: " + length + + " }"; + } + + @Override + public boolean equals(Object o) { + return o instanceof AbstractMemorySegmentImpl that && + unsafeGetBase() == that.unsafeGetBase() && + unsafeGetOffset() == that.unsafeGetOffset(); + } + + @Override + public int hashCode() { + return Objects.hash( + unsafeGetOffset(), + unsafeGetBase()); + } + + public static AbstractMemorySegmentImpl ofBuffer(Buffer bb) { + Objects.requireNonNull(bb); + Object base = NIO_ACCESS.getBufferBase(bb); + if (!bb.isDirect() && base == null) { + throw new IllegalArgumentException("The provided heap buffer is not backed by an array."); + } + long bbAddress = NIO_ACCESS.getBufferAddress(bb); + UnmapperProxy unmapper = NIO_ACCESS.unmapper(bb); + + int pos = bb.position(); + int limit = bb.limit(); + int size = limit - pos; + + AbstractMemorySegmentImpl bufferSegment = (AbstractMemorySegmentImpl) NIO_ACCESS.bufferSegment(bb); + boolean readOnly = bb.isReadOnly(); + int scaleFactor = getScaleFactor(bb); + final MemorySessionImpl bufferScope; + if (bufferSegment != null) { + bufferScope = bufferSegment.scope; + } else { + bufferScope = MemorySessionImpl.createHeap(bufferRef(bb)); + } + long off = bbAddress + ((long)pos << scaleFactor); + long len = (long)size << scaleFactor; + if (base != null) { + return switch (base) { + case byte[] _ -> new HeapMemorySegmentImpl.OfByte(off, base, len, readOnly, bufferScope); + case short[] _ -> new HeapMemorySegmentImpl.OfShort(off, base, len, readOnly, bufferScope); + case char[] _ -> new HeapMemorySegmentImpl.OfChar(off, base, len, readOnly, bufferScope); + case int[] _ -> new HeapMemorySegmentImpl.OfInt(off, base, len, readOnly, bufferScope); + case float[] _ -> new HeapMemorySegmentImpl.OfFloat(off, base, len, readOnly, bufferScope); + case long[] _ -> new HeapMemorySegmentImpl.OfLong(off, base, len, readOnly, bufferScope); + case double[] _ -> new HeapMemorySegmentImpl.OfDouble(off, base, len, readOnly, bufferScope); + default -> throw new AssertionError("Cannot get here"); + }; + } else if (unmapper == null) { + return new NativeMemorySegmentImpl(off, len, readOnly, bufferScope); + } else { + return new MappedMemorySegmentImpl(off, unmapper, len, readOnly, bufferScope); + } + } + + private static Object bufferRef(Buffer buffer) { + if (buffer instanceof DirectBuffer directBuffer) { + // direct buffer, return either the buffer attachment (for slices and views), or the buffer itself + return directBuffer.attachment() != null ? + directBuffer.attachment() : directBuffer; + } else { + // heap buffer, return the underlying array + return NIO_ACCESS.getBufferBase(buffer); + } + } + + @ForceInline + public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long srcOffset, + MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset, + long elementCount) { + + Utils.checkNonNegativeIndex(elementCount, "elementCount"); + AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment; + AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)dstSegment; + if (srcElementLayout.byteSize() != dstElementLayout.byteSize()) { + throw new IllegalArgumentException("Source and destination layouts must have same size"); + } + Utils.checkElementAlignment(srcElementLayout, "Source layout alignment greater than its size"); + Utils.checkElementAlignment(dstElementLayout, "Destination layout alignment greater than its size"); + if (!srcImpl.isAlignedForElement(srcOffset, srcElementLayout)) { + throw new IllegalArgumentException("Source segment incompatible with alignment constraints"); + } + if (!dstImpl.isAlignedForElement(dstOffset, dstElementLayout)) { + throw new IllegalArgumentException("Destination segment incompatible with alignment constraints"); + } + long size = elementCount * srcElementLayout.byteSize(); + srcImpl.checkAccess(srcOffset, size, true); + dstImpl.checkAccess(dstOffset, size, false); + if (srcElementLayout.byteSize() == 1 || srcElementLayout.order() == dstElementLayout.order()) { + ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), dstImpl.sessionImpl(), + srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, + dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstOffset, size); + } else { + ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), dstImpl.sessionImpl(), + srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, + dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstOffset, size, srcElementLayout.byteSize()); + } + } + + @ForceInline + public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset, + Object dstArray, int dstIndex, + int elementCount) { + Utils.checkNonNegativeIndex(elementCount, "elementCount"); + var dstInfo = Utils.BaseAndScale.of(dstArray); + if (dstArray.getClass().componentType() != srcLayout.carrier()) { + throw new IllegalArgumentException("Incompatible value layout: " + srcLayout); + } + AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment; + Utils.checkElementAlignment(srcLayout, "Source layout alignment greater than its size"); + if (!srcImpl.isAlignedForElement(srcOffset, srcLayout)) { + throw new IllegalArgumentException("Source segment incompatible with alignment constraints"); + } + srcImpl.checkAccess(srcOffset, elementCount * dstInfo.scale(), true); + Objects.checkFromIndexSize(dstIndex, elementCount, Array.getLength(dstArray)); + if (dstInfo.scale() == 1 || srcLayout.order() == ByteOrder.nativeOrder()) { + ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), null, + srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, + dstArray, dstInfo.base() + (dstIndex * dstInfo.scale()), elementCount * dstInfo.scale()); + } else { + ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), null, + srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, + dstArray, dstInfo.base() + (dstIndex * dstInfo.scale()), elementCount * dstInfo.scale(), dstInfo.scale()); + } + } + + @ForceInline + public static void copy(Object srcArray, int srcIndex, + MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset, + int elementCount) { + var srcInfo = Utils.BaseAndScale.of(srcArray); + if (srcArray.getClass().componentType() != dstLayout.carrier()) { + throw new IllegalArgumentException("Incompatible value layout: " + dstLayout); + } + Objects.checkFromIndexSize(srcIndex, elementCount, Array.getLength(srcArray)); + AbstractMemorySegmentImpl destImpl = (AbstractMemorySegmentImpl)dstSegment; + Utils.checkElementAlignment(dstLayout, "Destination layout alignment greater than its size"); + if (!destImpl.isAlignedForElement(dstOffset, dstLayout)) { + throw new IllegalArgumentException("Destination segment incompatible with alignment constraints"); + } + destImpl.checkAccess(dstOffset, elementCount * srcInfo.scale(), false); + if (srcInfo.scale() == 1 || dstLayout.order() == ByteOrder.nativeOrder()) { + ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(null, destImpl.sessionImpl(), + srcArray, srcInfo.base() + (srcIndex * srcInfo.scale()), + destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcInfo.scale()); + } else { + ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(null, destImpl.sessionImpl(), + srcArray, srcInfo.base() + (srcIndex * srcInfo.scale()), + destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcInfo.scale(), srcInfo.scale()); + } + } + + public static long mismatch(MemorySegment srcSegment, long srcFromOffset, long srcToOffset, + MemorySegment dstSegment, long dstFromOffset, long dstToOffset) { + AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)Objects.requireNonNull(srcSegment); + AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)Objects.requireNonNull(dstSegment); + long srcBytes = srcToOffset - srcFromOffset; + long dstBytes = dstToOffset - dstFromOffset; + srcImpl.checkAccess(srcFromOffset, srcBytes, true); + dstImpl.checkAccess(dstFromOffset, dstBytes, true); + + long bytes = Math.min(srcBytes, dstBytes); + long i = 0; + if (bytes > 7) { + if (srcImpl.get(JAVA_BYTE, srcFromOffset) != dstImpl.get(JAVA_BYTE, dstFromOffset)) { + return 0; + } + i = AbstractMemorySegmentImpl.vectorizedMismatchLargeForBytes(srcImpl.sessionImpl(), dstImpl.sessionImpl(), + srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcFromOffset, + dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstFromOffset, + bytes); + if (i >= 0) { + return i; + } + long remaining = ~i; + assert remaining < 8 : "remaining greater than 7: " + remaining; + i = bytes - remaining; + } + for (; i < bytes; i++) { + if (srcImpl.get(JAVA_BYTE, srcFromOffset + i) != dstImpl.get(JAVA_BYTE, dstFromOffset + i)) { + return i; + } + } + return srcBytes != dstBytes ? bytes : -1; + } + + private static int getScaleFactor(Buffer buffer) { + return switch (buffer) { + case ByteBuffer _ -> 0; + case CharBuffer _, ShortBuffer _ -> 1; + case IntBuffer _, FloatBuffer _ -> 2; + case LongBuffer _, DoubleBuffer _ -> 3; + }; + } + + // accessors + + @ForceInline + @Override + public byte get(ValueLayout.OfByte layout, long offset) { + return (byte) layout.varHandle().get((MemorySegment)this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfByte layout, long offset, byte value) { + layout.varHandle().set((MemorySegment)this, offset, value); + } + + @ForceInline + @Override + public boolean get(ValueLayout.OfBoolean layout, long offset) { + return (boolean) layout.varHandle().get((MemorySegment)this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfBoolean layout, long offset, boolean value) { + layout.varHandle().set((MemorySegment)this, offset, value); + } + + @ForceInline + @Override + public char get(ValueLayout.OfChar layout, long offset) { + return (char) layout.varHandle().get((MemorySegment)this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfChar layout, long offset, char value) { + layout.varHandle().set((MemorySegment)this, offset, value); + } + + @ForceInline + @Override + public short get(ValueLayout.OfShort layout, long offset) { + return (short) layout.varHandle().get((MemorySegment)this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfShort layout, long offset, short value) { + layout.varHandle().set((MemorySegment)this, offset, value); + } + + @ForceInline + @Override + public int get(ValueLayout.OfInt layout, long offset) { + return (int) layout.varHandle().get((MemorySegment)this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfInt layout, long offset, int value) { + layout.varHandle().set((MemorySegment)this, offset, value); + } + + @ForceInline + @Override + public float get(ValueLayout.OfFloat layout, long offset) { + return (float) layout.varHandle().get((MemorySegment)this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfFloat layout, long offset, float value) { + layout.varHandle().set((MemorySegment)this, offset, value); + } + + @ForceInline + @Override + public long get(ValueLayout.OfLong layout, long offset) { + return (long) layout.varHandle().get((MemorySegment)this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfLong layout, long offset, long value) { + layout.varHandle().set((MemorySegment)this, offset, value); + } + + @ForceInline + @Override + public double get(ValueLayout.OfDouble layout, long offset) { + return (double) layout.varHandle().get((MemorySegment)this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfDouble layout, long offset, double value) { + layout.varHandle().set((MemorySegment)this, offset, value); + } + + @ForceInline + @Override + public MemorySegment get(AddressLayout layout, long offset) { + return (MemorySegment) layout.varHandle().get((MemorySegment)this, offset); + } + + @ForceInline + @Override + public void set(AddressLayout layout, long offset, MemorySegment value) { + Objects.requireNonNull(value); + layout.varHandle().set((MemorySegment)this, offset, value); + } + + @ForceInline + @Override + public byte getAtIndex(ValueLayout.OfByte layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (byte) layout.varHandle().get((MemorySegment)this, index * layout.byteSize()); + } + + @ForceInline + @Override + public boolean getAtIndex(ValueLayout.OfBoolean layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (boolean) layout.varHandle().get((MemorySegment)this, index * layout.byteSize()); + } + + @ForceInline + @Override + public char getAtIndex(ValueLayout.OfChar layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (char) layout.varHandle().get((MemorySegment)this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfChar layout, long index, char value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set((MemorySegment)this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public short getAtIndex(ValueLayout.OfShort layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (short) layout.varHandle().get((MemorySegment)this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfByte layout, long index, byte value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set((MemorySegment)this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set((MemorySegment)this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfShort layout, long index, short value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set((MemorySegment)this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public int getAtIndex(ValueLayout.OfInt layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (int) layout.varHandle().get((MemorySegment)this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfInt layout, long index, int value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set((MemorySegment)this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public float getAtIndex(ValueLayout.OfFloat layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (float) layout.varHandle().get((MemorySegment)this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfFloat layout, long index, float value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set((MemorySegment)this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public long getAtIndex(ValueLayout.OfLong layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (long) layout.varHandle().get((MemorySegment)this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfLong layout, long index, long value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set((MemorySegment)this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public double getAtIndex(ValueLayout.OfDouble layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (double) layout.varHandle().get((MemorySegment)this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfDouble layout, long index, double value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set((MemorySegment)this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public MemorySegment getAtIndex(AddressLayout layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (MemorySegment) layout.varHandle().get((MemorySegment)this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(AddressLayout layout, long index, MemorySegment value) { + Objects.requireNonNull(value); + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set((MemorySegment)this, index * layout.byteSize(), value); + } + + @Override + public String getString(long offset) { + return getString(offset, sun.nio.cs.UTF_8.INSTANCE); + } + + @Override + public String getString(long offset, Charset charset) { + Objects.requireNonNull(charset); + return StringSupport.read(this, offset, charset); + } + + @Override + public void setString(long offset, String str) { + Objects.requireNonNull(str); + setString(offset, str, sun.nio.cs.UTF_8.INSTANCE); + } + + @Override + public void setString(long offset, String str, Charset charset) { + Objects.requireNonNull(charset); + Objects.requireNonNull(str); + StringSupport.write(this, offset, charset, str); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/ArenaImpl.class b/tests/test_data/std/jdk/internal/foreign/ArenaImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..3f308696edc7d1a02f9cb5f759c6594df2abf983 GIT binary patch literal 1574 zcma)6TTc@~6#k~SZOd|Lt0171YJpyaiWg9dXsIEAR7|M!fy9UHc7TQLF4W?y>*=?6Znv{pV%$#$+?>m>7KYxGz0#L=fI06Vt2+0T|!Z32AoGB$;F%C)} znnzr97$U2hp*d>|!Cbx(LliLyaTx=U8K#a}$0f~hxMe7MY2UQCc3_k$7B`g5_KD6Q z+1$1@(_qNediuWSZPPlhdtM@@EMbTt+tXRtHC1yu?n2Cnj0BPlDf`eo)muB<=GGba zP#M@>9CvV6!l;Zfk>6}j+#4bo!m4iCJdSZpNSKsy9}gHNdPeU$nr<^ps)t-XuIRd{ zDh{Pw*FN)#(W>ZF62i-EZRHzrq%kcaBjX_+G0gPDtMh|4H=GScbxcd+1U;;HsJvrh z*e1B!7IZIPyY6bYN8OZNs&bqvIU{2ha|}aWvTbvd8c!;P^u7=S$fF>kDC05a8Pa_y z8AAJ-P7{*Nt@j6)P+}On3F%H6L-E$bm2VJn)ogJpYE3iv_G!Dxt&d7mr=4VtTBkP@ zOB3tPX2?0zs0Gu#tL=|^nObbC<_W>%bA1!a)`cs@M4RUh7n4G>y2UUkmhQxe2_SQ~ z7w$=Nd&Q9H+Y5$x-8{8azM+Y{hJ2L^qJ#|creScasw*}fPYLT{68&@Eb3#19l%p#g zi!?6*Ff7nJDXs##Op@Xt(l_irPsqARe>>z65Z1zXutMJLJf6|cs27RnctI=SCzz;GSi*7#zvQloweStn7jp6-BeV_7yD%a|$ns!l zjv%Z;+)^hvDuOSOx|SraMUXg&5QG#DBkE(&N$Fth5}HUkmCjt@UOFS7=o!Ak)U_NB zZiyV1UASokMTnnS3NP`>m6^f{{RQd2>{EQAxCr?t3hB%xvMb^7aPS9m0sK#}N^N=V o5)|B$CVYZ~Pmt&k&^?Y-@(xp`YXly^8@#1&oTw|*fNCW64~1fJ1^@s6 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/ArenaImpl.java b/tests/test_data/std/jdk/internal/foreign/ArenaImpl.java new file mode 100644 index 00000000..027aed5f --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/ArenaImpl.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.foreign; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySegment.Scope; +import java.util.Objects; + +public final class ArenaImpl implements Arena { + + private final MemorySessionImpl session; + private final boolean shouldReserveMemory; + ArenaImpl(MemorySessionImpl session) { + this.session = session; + shouldReserveMemory = session instanceof ImplicitSession; + } + + @Override + public Scope scope() { + return session; + } + + @Override + public void close() { + session.close(); + } + + public MemorySegment allocateNoInit(long byteSize, long byteAlignment) { + Utils.checkAllocationSizeAndAlign(byteSize, byteAlignment); + return SegmentFactories.allocateSegment(byteSize, byteAlignment, session, shouldReserveMemory); + } + + @Override + public MemorySegment allocate(long byteSize, long byteAlignment) { + MemorySegment segment = allocateNoInit(byteSize, byteAlignment); + return segment.fill((byte)0); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/CABI.class b/tests/test_data/std/jdk/internal/foreign/CABI.class new file mode 100644 index 0000000000000000000000000000000000000000..9ebca45c6c79411e69cd2d8a94bba6fc63df3676 GIT binary patch literal 3118 zcmaJ@=~o-q75@zq%t#C%E4CACyx__)ON?xX5XTS~S%8f#mN0-VI|&`60S^dC8I1_I zZIZT$o9<2PHo;wzZb{dK$mhgrd(xAB>4%)2e&~PG)8+K{-VDdWiH(r%-2L6<-8&!u z?@xaLki`2c>J+ptWtZc2-nE>(nTszJ9LrwJ$CHUOqai2=>ZnJ9f_fuu%*`s;o4TiX zzmV5-goJ#<#nJJ(zFt9U)S(Mfb82*a=F(guF_k>$vzm3Z2v*BjA~`oVR5#7I`#{mf3~SnBRT8a zJE)^wy7APEN1r$*G(MvvCdk@IB9%ImNL~=chjkng#KxI%V`g%4VrqJLNYFcVbfH^; z8kek0k4mGw)&{Y@1q{kM`4`CXH^X9NZ^cu!=-XQUa~S}$9C7_ zX2!J(`S@AOopcIC%W>BelA>T&(Xm(UoV93WYq(7IryQd8`2M-V%>R(c&ai^`r>oqn z@frMCoKrEX<2)`Xh;8fn)s^^&cS}-se%W%2aF{OxXn)4wR3U9HC;Qi6*^O0C?%ZC)w_%C#}tBrX%#a%W^s|-d#C7I_jXoPJ!P&J z$~=&o7#f-yHrRIUH5K0yO=Po}zaL zhI(GZ96Q!r$@cYzVPalIMn@LpM(&vM!eErvb7eDEVvTDH<9BxFWetmzSv%Rst60xb zCH}N9mXTAjq9ZSA(*DU@POyEL&HSRVUUDtofskFgXy>zq=Sv!jOowSQwc>osaCDS} z8PzV0nVAVgLz%}f7Be3Ec^zv$n?)|K36*O)J}+qXb}3=6Y4{?wr9#fq@FEe%E@f8x zdNq8BLM6@%s(nTD(aQ>sZ9DE(3CwvrzF_8Z^JZo_KH@)kT_wiHbsb+7V?|BQOic}s zPiv?bU42qRNQ17SMMG4>E)5T9*sEc`hIS1x4M&934|TkbH>ezwlYq(I-_d#h>7(GL zjvwL294DE=O0n!($+F{EdA8C%F@x@TUs$azC&6SP%c8e13TwQ)GH*H4=6sHnXsVDg zbF-#n3*09L^X7`=-Q6So?3*#my;{glnhs^So)|&Uy=oJL46Z2CEjv_Y?{O^!MP+#d zO|PfDwp7lO%@iwW;x)@GkC{c^t;*r!#ib2oa{h2TT60Il2pqUiz^8e>uu&*G8Eb?i ziboQIu17>Mc$~>U!H#VnY!$l`AmmPzkc&`4ZaoRP;UwfjlaL!sLM|)`xtt_y_aRr0 z#JO$gVUK7JAhJhn8R9Da`~+{%|4)e>A{2k&3OYW(BOl@DCNTwX^0z_qVwC56M4goH zB@`OrsM1x%@sFSg`MPcLZ;_&VQurBuPV5)_)>G{zAJ<03PfX3{U?x443Lsd*dE;zP{gub9Wj zwDJ!u;4PlwAkWl_U*jE?TA}wh`TQFevH^dmt|>VIj!7C!<+HPEmgvG=nO>}Qg78;n2=pRB!2Usg3O*Pd>*Rw1} zx}m~ron|s4Mp|PnjC6#g-2|ky5|G$N5MsIscnb~@G&0x5-JWC6@CUr@d;YiY`Mp2W zZ}io`ZG7z(0uuRpP$H^CzELlcutdJuAdx1Cd`p!`L?YkTB=Uenz7z4}c1!HL5l^sH zVy{I!$u^07FA|b^2PF3WNLXTrBz7axD6zv;{NNTks@S-NSHuHad_IgOJj@Ys xgr5%dqLY2og>epwr|}4u_^P>v9$e?E<_#QUEn}?h3D(xTckkjo+Ni_k{{cJH%`N}{ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/CABI.java b/tests/test_data/std/jdk/internal/foreign/CABI.java new file mode 100644 index 00000000..500e312b --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/CABI.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.internal.foreign; + +import jdk.internal.foreign.abi.fallback.FallbackLinker; +import jdk.internal.vm.ForeignLinkerSupport; +import jdk.internal.util.OperatingSystem; +import jdk.internal.util.StaticProperty; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static sun.security.action.GetPropertyAction.privilegedGetProperty; + +public enum CABI { + SYS_V, + WIN_64, + LINUX_AARCH_64, + MAC_OS_AARCH_64, + WIN_AARCH_64, + AIX_PPC_64, + LINUX_PPC_64, + LINUX_PPC_64_LE, + LINUX_RISCV_64, + LINUX_S390, + FALLBACK, + UNSUPPORTED; + + private static final CABI CURRENT = computeCurrent(); + + private static CABI computeCurrent() { + String abi = privilegedGetProperty("jdk.internal.foreign.CABI"); + if (abi != null) { + return CABI.valueOf(abi); + } + + if (ForeignLinkerSupport.isSupported()) { + // figure out the ABI based on the platform + String arch = StaticProperty.osArch(); + long addressSize = ADDRESS.byteSize(); + // might be running in a 32-bit VM on a 64-bit platform. + // addressSize will be correctly 32 + if ((arch.equals("amd64") || arch.equals("x86_64")) && addressSize == 8) { + if (OperatingSystem.isWindows()) { + return WIN_64; + } else { + return SYS_V; + } + } else if (arch.equals("aarch64")) { + if (OperatingSystem.isMacOS()) { + return MAC_OS_AARCH_64; + } else if (OperatingSystem.isWindows()) { + return WIN_AARCH_64; + } else { + // The Linux ABI follows the standard AAPCS ABI + return LINUX_AARCH_64; + } + } else if (arch.equals("ppc64")) { + if (OperatingSystem.isLinux()) { + return LINUX_PPC_64; + } else if (OperatingSystem.isAix()) { + return AIX_PPC_64; + } + } else if (arch.equals("ppc64le")) { + if (OperatingSystem.isLinux()) { + return LINUX_PPC_64_LE; + } + } else if (arch.equals("riscv64")) { + if (OperatingSystem.isLinux()) { + return LINUX_RISCV_64; + } + } else if (arch.equals("s390x")) { + if (OperatingSystem.isLinux()) { + return LINUX_S390; + } + } + } else if (FallbackLinker.isSupported()) { + return FALLBACK; // fallback linker + } + + return UNSUPPORTED; + } + + public static CABI current() { + return CURRENT; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/ConfinedSession$ConfinedResourceList.class b/tests/test_data/std/jdk/internal/foreign/ConfinedSession$ConfinedResourceList.class new file mode 100644 index 0000000000000000000000000000000000000000..403996a6b9397685ac6d17b6dd9d91f8a1baa6a0 GIT binary patch literal 1244 zcmb`H&rcIU6vw}_tt>5zRltf>s6xg5P?p4#sqwPb&}6~Hl3vNsox;L&w(c$j{vhL7 zBawK}yML7NO}lLZHpBym?##UIe7@f|@6G=H^W!G~2OC)!NSR1mxP>W(mxtbw?Wrf_Lk@c;aN*WksqjLuP;j%rN!ZSAP74AyuxlGnhukMApI# zEQVJTiB6!pz7k%-EREKexv8$EH{6Mc>rIUvI#O_T+^=VF8#xnqEZo($oEu;=%sB4* zR^#oi+idMShzx5*T=;$y)B}6Gl*gnHHOl}^S`o_!D=ccLPzo_5|n~xhURfMTKaMN^7e@YnnohhG-K^i@m^@Ifj8@hR#g9^ri3p z2ldIP`dnLqRoANT{Y_o9`%GdoAgha&wPxmAzHjgIUG~Y}|Ni+GfE;WM9RinE%+<8z z1k!U1JN>}*q*Zg$IoEk$Inpdk-?v<6{O!0TeYfsaWx?`;1O#F_y3j4qJ#9Hwa800d zVzQDz58@gUYOPn`)UF6~a?SOgH2vq-)@^~C6NMGyp^>%?rhzN?qFhiZ}#=r{Z)PPHU$Y4|ed)}25=jRuHz(5k)Qj> zk)FUn1U#~BLdPUh0td3?g<@{8G*g(#mS+}ox9=9`1&&0FEa#!SD$^CiyJ0w{ElKt) zKG1MZM;hk^M%!d}ZWV~vWRP{ttZ53QnD9MRUnZ|=>MSnmn8Jqwy>wA=Z6mO3DKNQ5 zCzD|!FX{LgpD-(it?KJ-R!C-iBEOfkTtP;|w2rG_wI6%uq;oP@cFjgynCfoZbyw@_ zie=P!Gc4OSj~BwNnI81Tk;P{kaymZ849l{Ol4qmVR1#zJ3wP8~BrQ4H@O|du3*69< z*KrfK1WvYX{|A)S#CA7Z85Jl+d$Hj;0#yz?%c-$BTkYD|vdbA;J{h(-R#)4EwdX!E z?%Pts?QKL`U66P3R27Te_M`M>JkRwKDB??{D69y%niIkI`sxwm_2YTwR?r)|;*ll_)0G znygs9MS!g1xD*REI{ojc--l~yqqUr#b*Z*_$0p$n5xj;r5h1=(_k*16`edI7b*m{@ zJ=0b04#l`bK4vT;S!zd#M&(e+XTv5M+@Xc%RGQdnMd=4rY6gl#^}Is?2{Wx^tYs6` zUJaJO)UI9qj^b|!1=UzPoq2k!E@51o8of|9y^3PFXV;f58y!q*(pUa2L03M`gZ3Q9sUKn`aEntMQ^Gjq>^k* zY~iEVZ8D>D2b4&u%$Uz(j8rBV=Zm-(iTzZQl#bJkbUy>2;u1&fAB>0|Eza~WwRo-3 znM%d6EnFT*4t)9o*EcZxJ5E1G^42R97gC$JLken79}b|fEh%ZvUF7U}UgsBZl=q1$ z0hN?N0vfo_kpkymqq2rVoW@lSJ77Zct)K-S@M|D49 ADF6Tf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/ConfinedSession.java b/tests/test_data/std/jdk/internal/foreign/ConfinedSession.java new file mode 100644 index 00000000..4ff0df78 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/ConfinedSession.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.foreign; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; + +import jdk.internal.vm.annotation.ForceInline; + +/** + * A confined session, which features an owner thread. The liveness check features an additional + * confinement check - that is, calling any operation on this session from a thread other than the + * owner thread will result in an exception. Because of this restriction, checking the liveness bit + * can be performed in plain mode. + */ +final class ConfinedSession extends MemorySessionImpl { + + private int asyncReleaseCount = 0; + + static final VarHandle ASYNC_RELEASE_COUNT; + + static { + try { + ASYNC_RELEASE_COUNT = MethodHandles.lookup().findVarHandle(ConfinedSession.class, "asyncReleaseCount", int.class); + } catch (Throwable ex) { + throw new ExceptionInInitializerError(ex); + } + } + + public ConfinedSession(Thread owner) { + super(owner, new ConfinedResourceList()); + } + + @Override + @ForceInline + public void acquire0() { + checkValidState(); + if (state == MAX_FORKS) { + throw tooManyAcquires(); + } + state++; + } + + @Override + @ForceInline + public void release0() { + if (Thread.currentThread() == owner) { + state--; + } else { + // It is possible to end up here in two cases: this session was kept alive by some other confined session + // which is implicitly released (in which case the release call comes from the cleaner thread). Or, + // this session might be kept alive by a shared session, which means the release call can come from any + // thread. + ASYNC_RELEASE_COUNT.getAndAdd(this, 1); + } + } + + void justClose() { + checkValidState(); + int asyncCount = (int)ASYNC_RELEASE_COUNT.getVolatile(this); + if ((state == 0 && asyncCount == 0) + || ((state - asyncCount) == 0)) { + state = CLOSED; + } else { + throw alreadyAcquired(state - asyncCount); + } + } + + /** + * A confined resource list; no races are possible here. + */ + static final class ConfinedResourceList extends ResourceList { + @Override + void add(ResourceCleanup cleanup) { + if (fst != ResourceCleanup.CLOSED_LIST) { + cleanup.next = fst; + fst = cleanup; + } else { + throw alreadyClosed(); + } + } + + @Override + void cleanup() { + if (fst != ResourceCleanup.CLOSED_LIST) { + ResourceCleanup prev = fst; + fst = ResourceCleanup.CLOSED_LIST; + cleanup(prev); + } else { + throw alreadyClosed(); + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/FunctionDescriptorImpl.class b/tests/test_data/std/jdk/internal/foreign/FunctionDescriptorImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..7adb1c37d739189daf9a378b4d7a35ee0a1a7ac6 GIT binary patch literal 7867 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 aI7LiTPc>q?m?;+UTbQh@6?LKkQ~w94PINZ_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/FunctionDescriptorImpl.java b/tests/test_data/std/jdk/internal/foreign/FunctionDescriptorImpl.java new file mode 100644 index 00000000..da172728 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/FunctionDescriptorImpl.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import static java.util.Objects.requireNonNull; + +/** + * @implSpec This class and its subclasses are immutable, thread-safe and value-based. + */ +public final class FunctionDescriptorImpl implements FunctionDescriptor { + + private final MemoryLayout resLayout; // Nullable + private final List argLayouts; + + private FunctionDescriptorImpl(MemoryLayout resLayout, List argLayouts) { + if (resLayout instanceof PaddingLayout) { + throw new IllegalArgumentException("Unsupported padding layout return in function descriptor: " + resLayout); + } + Optional paddingLayout = argLayouts.stream().filter(l -> l instanceof PaddingLayout).findAny(); + if (paddingLayout.isPresent()) { + throw new IllegalArgumentException("Unsupported padding layout argument in function descriptor: " + paddingLayout.get()); + } + this.resLayout = resLayout; + this.argLayouts = List.copyOf(argLayouts); + } + + /** + * {@return the return layout (if any) associated with this function descriptor} + */ + public Optional returnLayout() { + return Optional.ofNullable(resLayout); + } + + /** + * {@return the argument layouts associated with this function descriptor (as an immutable list)}. + */ + public List argumentLayouts() { + return argLayouts; + } + + /** + * Returns a function descriptor with the given argument layouts appended to the argument layout array + * of this function descriptor. + * + * @param addedLayouts the argument layouts to append. + * @return the new function descriptor. + */ + public FunctionDescriptorImpl appendArgumentLayouts(MemoryLayout... addedLayouts) { + return insertArgumentLayouts(argLayouts.size(), addedLayouts); + } + + /** + * Returns a function descriptor with the given argument layouts inserted at the given index, into the argument + * layout array of this function descriptor. + * + * @param index the index at which to insert the arguments + * @param addedLayouts the argument layouts to insert at given index. + * @return the new function descriptor. + * @throws IllegalArgumentException if {@code index < 0 || index > argumentLayouts().size()}. + */ + public FunctionDescriptorImpl insertArgumentLayouts(int index, MemoryLayout... addedLayouts) { + if (index < 0 || index > argLayouts.size()) + throw new IllegalArgumentException("Index out of bounds: " + index); + List added = List.of(addedLayouts); // null check on array and its elements + List newLayouts = new ArrayList<>(argLayouts.size() + addedLayouts.length); + newLayouts.addAll(argLayouts.subList(0, index)); + newLayouts.addAll(added); + newLayouts.addAll(argLayouts.subList(index, argLayouts.size())); + return new FunctionDescriptorImpl(resLayout, newLayouts); + } + + /** + * Returns a function descriptor with the given memory layout as the new return layout. + * + * @param newReturn the new return layout. + * @return the new function descriptor. + */ + public FunctionDescriptorImpl changeReturnLayout(MemoryLayout newReturn) { + requireNonNull(newReturn); + return new FunctionDescriptorImpl(newReturn, argLayouts); + } + + /** + * Returns a function descriptor with the return layout dropped. This is useful to model functions + * which return no values. + * + * @return the new function descriptor. + */ + public FunctionDescriptorImpl dropReturnLayout() { + return new FunctionDescriptorImpl(null, argLayouts); + } + + private static Class carrierTypeFor(MemoryLayout layout) { + if (layout instanceof ValueLayout valueLayout) { + return valueLayout.carrier(); + } else if (layout instanceof GroupLayout || layout instanceof SequenceLayout) { + return MemorySegment.class; + } else { + // Note: we should not worry about padding layouts, as they cannot be present in a function descriptor + throw new AssertionError("Cannot get here"); + } + } + + @Override + public MethodType toMethodType() { + Class returnValue = resLayout != null ? carrierTypeFor(resLayout) : void.class; + Class[] argCarriers = new Class[argLayouts.size()]; + for (int i = 0; i < argCarriers.length; i++) { + argCarriers[i] = carrierTypeFor(argLayouts.get(i)); + } + return MethodType.methodType(returnValue, argCarriers); + } + + /** + * {@return the string representation of this function descriptor} + */ + @Override + public String toString() { + return String.format("(%s)%s", + argLayouts.stream().map(Object::toString) + .collect(Collectors.joining()), + returnLayout() + .map(Object::toString) + .orElse("v")); + } + + /** + * Compares the specified object with this function descriptor for equality. Returns {@code true} if and only if the specified + * object is also a function descriptor, and all the following conditions are met: + *
    + *
  • the two function descriptors have equals return layouts (see {@link MemoryLayout#equals(Object)}), or both have no return layout;
  • + *
  • the two function descriptors have argument layouts that are pair-wise {@linkplain MemoryLayout#equals(Object) equal}; and
  • + *
+ * + * @param other the object to be compared for equality with this function descriptor. + * @return {@code true} if the specified object is equal to this function descriptor. + */ + @Override + public boolean equals(Object other) { + return other instanceof FunctionDescriptorImpl f && + Objects.equals(resLayout, f.resLayout) && + Objects.equals(argLayouts, f.argLayouts); + } + + /** + * {@return the hash code value for this function descriptor} + */ + @Override + public int hashCode() { + return Objects.hash(argLayouts, resLayout); + } + + public static FunctionDescriptor of(MemoryLayout resLayout, List argLayouts) { + return new FunctionDescriptorImpl(resLayout, argLayouts); + } + + public static FunctionDescriptor ofVoid(List argLayouts) { + return new FunctionDescriptorImpl(null, argLayouts); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/GlobalSession$HeapSession.class b/tests/test_data/std/jdk/internal/foreign/GlobalSession$HeapSession.class new file mode 100644 index 0000000000000000000000000000000000000000..2f79f1fb0d1f3dbc23631f3dc5899cacdfc38012 GIT binary patch literal 935 zcmb7C%Wl&^6g?9=aq2or8)yrZKq;l8V*EgyxrV}}505n|yxbMKsc?&J8|_fMYzw9v4TfnmXPkVTGRb2>U`N-q+D z$5nIe2SV<9&4 z;lUn1nw8E^<};F@G?Cr+<6tNr$fVmp#NW}YV#xPI7`6Q{VsJX1CxVvZA(dfR{7nID zkboKb&uE`oLb@4r&*CE4OXPLvRlgVNAHnL46IdTmct?Q@*2xwL4h&%82^>7dW%5?j z1XOT^JW5T784+Hkaw+YYFgml+_=@5ytTn!%xL1FV!Y%qpCYmr|HuvQhGO`cT&uZ W)WCLvx`}FXW>BNkCX8NN9r+(M!^*M% literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/GlobalSession.class b/tests/test_data/std/jdk/internal/foreign/GlobalSession.class new file mode 100644 index 0000000000000000000000000000000000000000..3fe5dc42f90e93c3ebbd6fedce844410fbbed9a4 GIT binary patch literal 1402 zcmbVLTTc@~6#k}NDZMC)ih_5n*aEU9g!q6VF&i#51rxwN_%>}v7~IaTJG(^xlP^AL ze9(7)l<~}TDO;@3@X+ZwXXkw1cP{hu*SGHgJS>!uL%sl~f(sa9m^M65SL>}3#!)PwR6!XPhS`xQn|{#deyW9`q5|dlffl^&3xz=mKULmWFzEqGBkux+Qpcx+@K(MCAEgYe5i? z7?wvu{ITwXhL}aAoy+bm3CoZaP-pPYfjXc_drtd!!jeXCpPomKUM(;NM$h#kotMa4 zL7pt2FwfW*u+L=XFhQqz+rT1Se}cehMcEJVkgOS+NR{~JoFYZW M@tA%!ip)F3-y>8`wg3PC literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/GlobalSession.java b/tests/test_data/std/jdk/internal/foreign/GlobalSession.java new file mode 100644 index 00000000..c075778b --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/GlobalSession.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.foreign; + +import jdk.internal.access.JavaNioAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.vm.annotation.ForceInline; +import sun.nio.ch.DirectBuffer; + +import java.nio.Buffer; +import java.util.Objects; + +/** + * The global, non-closeable, shared session. Similar to a shared session, but its {@link #close()} method throws unconditionally. + * Adding new resources to the global session, does nothing: as the session can never become not-alive, there is nothing to track. + * Acquiring and or releasing a memory session similarly does nothing. + */ +non-sealed class GlobalSession extends MemorySessionImpl { + + public GlobalSession() { + super(null, null); + } + + @Override + @ForceInline + public void release0() { + // do nothing + } + + @Override + public boolean isCloseable() { + return false; + } + + @Override + @ForceInline + public void acquire0() { + // do nothing + } + + @Override + void addInternal(ResourceList.ResourceCleanup resource) { + // do nothing + } + + @Override + public void justClose() { + throw nonCloseable(); + } + + /** + * This is a global session that wraps a heap object. Possible objects are: Java arrays, buffers and + * class loaders. Objects of two heap sessions are compared by identity. That is, if the wrapped object is the same, + * then the resulting heap sessions are also considered equals. We do not compare the objects using + * {@link Object#equals(Object)}, as that would be problematic when comparing buffers, whose equality and + * hash codes are content-dependent. + */ + static class HeapSession extends GlobalSession { + + final Object ref; + + public HeapSession(Object ref) { + super(); + this.ref = Objects.requireNonNull(ref); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof HeapSession session && + ref == session.ref; + } + + @Override + public int hashCode() { + return System.identityHashCode(ref); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfByte.class b/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfByte.class new file mode 100644 index 0000000000000000000000000000000000000000..c8102a43686d4b23e6dfd5258a32183393405e37 GIT binary patch literal 2180 zcmcIlYi}Dx6g}hE*~Hm2PDo;09%&)8wjnX0DFs|Y?9e7LepF4VNGlZ9_Bh^jy=!*Y zKoDQ~IY>~Uqyh=?nIBbg#@@JAY*m1$to6)}=bn4+xex#K^tV3%Y~fB6A&hAV>xf`n zAbnJSlre2zy0&3u8jdT?Lp!r0jdn@49QSxn9=4?I@3z{O!1ztmHvJ8O&19i?WPD>} zEW=F$JAuoJPZw zzJMsG;|n@w5EBSj4NnTp4fBig)>srTVP3<6jzz=;X1h^zeA5b|@B}Wn^6QT2%CcjZ zI~K#fk{kw04IgPp2!tNyC#mo&I$l*I=S#US4syla?eal>|K6>G+}*pm{YkuzB@LH! zT*ey$S4Yb5IXQXDc?OfS>w7iBVo+g)Awb`wk~VCSjndPy66P&|v1DpjNpMw15-Gmd zJ8glll7)Yfx6zKDmoZWZ;cXr7U`1f2V|zwJZcD!sPAM#yI2#LXtMHD&;pCe zK;vF^+CHntu!yJOnvQi`7nttj^-RLa)WbYw+H&dym?@gJEO%N}>E1J{O24_HLm}@Q zuBqOG!?52pne}V`AvPAFCGA7MN#d?F>J{5MW<5R-&^*~KcLCPUsALT{1$les_hcFI zYEGN0-ZH++S!~CW;XNXxQLnp171)1KIm-&fO44sS^*e@Zv?Qkj-OZmRVzAi-zWg6p zG?a3$6287+O~AJEW=|0n4aF) z&`>7C$UJnLhIWIEhBek$h~pB7^5L9>!28^_Fu@NnonBg53@?l)v{Q&*co4!3eyc(T zn$Th51MW6x$jkT;A8}PX4lY8e9cLBBy1OjT!rk3Xd>mM8;1g1SYSh5B2{q(^`0vp6 z)4yVJ$>8_&<%LLM{1mf4^QRsO#Z@s?1lGx&CVc|&K7lwk=~fYlL%HqU%h9c}XLAK^ z)vEBOl(Q$8`x7spcjb0n_2QZeTnXf{5Jnw4$}N~z&6~s-Rj%kpfX*( zRK$<*+6mtLQJx3+VE`l$JGM#bKBX&_wd)j4NjH^V>dJM3E9Ya70}y91+@i@W6BFb5 z?1|;nC<{W%1ffOJr%0ctHHaDM#YSUJxxR5vT4lWYJVMWm*KvEu_yq6$6JsUF_KOgN eMYKbOLfA#2yN2)?*Eyc3CMqJq|DX~oNc;_|!OuDX literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfChar.class b/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfChar.class new file mode 100644 index 0000000000000000000000000000000000000000..dba4dc09880300e07ae1bfc4285393852fb43d2a GIT binary patch literal 2181 zcmcIlU2hvj6g}hE*~Hm2PG}NRK0@2jI)=oArW8mCaScsk{81&PBCSvu+mm?H^={Z* zBgzvJAo0QrFZ>FmQlSKagm~shA4{d?L>y~2$s{(83 zLh(R;CbPD5_Oq4hfvN>7g}cSRU?)JnZ@G>JTA9CNU`Sx8@AbaE=PG;ohV+JEAZcO* zCds&ad%g+;L_r^)F)@aeK)fn_B{0#;FUea2Nj!tI1}05RVOn53jG`4-b`*s#aK=-g zwk%JTU8mf#8TO@gFW7wVk%1Y3*uDHP6@Jdd^P1#jDfiKCuDH2g-re4)Y~9|?ZEfXt zhVde14ZLLHJT3@a?yJLxB<0WDU^F?WzFm_xql)J@a$5p)-Y;vt7Ar}5n$ya>EHIFs z-_#mhHj&0W-|MYIfltzff04NUj-Qk=Qi$Od6R%=HV65f%a!;+Rpb{mIqzd{**2HUA z5*TW*^mNbyQ|UQ(e!zmfD`5C4takwxPrqdK zb_IF+))!=%@N4cNSFfVWRl!=TV74wv~=dq^{uf*-M-Ymto&fZ^*Id8O~+AQ z-j+TS!1T1|hJi96`sN{Q8rpR?8kSgNG0saM$%lgy0&j5F#1KEgXl8a{Dn2L z#Df^F@mm)%@D)sajW@Ylr6DilExgTD?>M;#rFR@w7zlSOJd20B>v$)!SjD@f0NtpO zYYTeH0n@+1*vb5i;aSP=(esmunZaX>Kjcqs5}GUUZAf65+-cGwFx??AjWxQ}1g4?g zw(sTWR@<|=BDZ?gcq7``FPQiP&z^SmUFfPE*GS|_;06{Vh(!|95b;Mi_aoPCn%{TX z#yht8j_oxn6Y8ZSeuNi}aPb>;8svvAkVx#*8l`)Wu5{L}QaCN$NM<&a>j;-l$M9tr z#7PYA(`1~9NpXGrq;h(cMWJP*&=Q$rWKPrS#!R$hqcNvk$G9!6HeP%Zp~uF{xY=WT pgxCLxu@+?gX$Zn1+Mq%)Y@!gZF?_&vf+xC(ikRVlPze>x{0$^Q&{O~b literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfDouble.class b/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfDouble.class new file mode 100644 index 0000000000000000000000000000000000000000..658ade3f4b95f0fe1f603d2c40db964dad7e72cc GIT binary patch literal 2190 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfLong.class b/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl$OfLong.class new file mode 100644 index 0000000000000000000000000000000000000000..dce756300fd575802d1e2b7c9a89ce78c10cc357 GIT binary patch literal 2180 zcmcIlU2hvj6g}hE*~Hm2PDo;0K0+b1wjnX0DFs|Y+(45Ue^d=rq!kKld+cnw-Zi^x zM0w}uAVGx^1QOzzHzauAg%@7<6^JwIjcdhL1&GR8&+K^ax#yny;h+Bc?gs!{xEV(T zV;Z75Vi*_59yRXeOxu^PZCJUc<4Ut-=XRvgDa*Fw-rtk0wzU1-cE=JJzh>H|zag-h zE|!jrPmP>q*sWZ(b|mY5zIdlJ66_Sn^GwH9K>5sV4HE)uBd?G2ya+ho(cuL39isXE`@ZmwBw7Xq7C{-)l2ZdX=3j33I z7E2nQ({TaM3tSp0!w2N#EnjCa1-r3VH!KDfRTu*FJt}F#7Wp_mEh}MO6c|fqc9jH| zbfl5td!ySC_&8ns7kL})_)!@ng$Q2K@iJBfX1ca#H08GRt6}a)s;F+{bi9H!fr&#_ zo(fuEF&%2$%TC8<^%xfMG+frPjw=GweY~DYG@ZFyq)b~*g8(xn)0UNPyC&WDjhfPL zuH;b2+lFhZ_wX?4ADYbi<^K>Hi_nsG%ReM>R~n6~ZQW-*-Vx9|8I-#KYiCrlhMR)C zJ@a$2jCpmZ!&Pq^pA{^&W7+WT5z=ThT%ro>KdzkR1rlZHA3BYjhHJDXrvly0pC)3k z*#$oOA6OJ>p6?oU|5T0stRa*5p3`;f@`kB0cYb7zt*Y*&_7&;*JC4U$pzqqYbhj+S zV*;3--q_GkA;ic$1WiM`!A8RxYb?TX3B>tuPD0={?%J5(2bj(-tt>_t##7n}#MeBC z;3~gWAp^fa$FF#uyA2xhGTy+OT-A<)i%@FES%tA+m*-hD*j>Y0p~VK?CIzTQ4PBd1 zLk>uO4{bmD4JMZieotRmh^59)F#8pM>XA@ff!_iG>*P+8K7nMPKoXmDs|X~a-1hDj z=vLXYxk9&URd`d%*|(Vc5l^0V^?Tr|7uQtiO5i$HLWoroQxMSyIR7QrL7IOI*hc%d zTYcNBR3^|%Mf?EI9OH#ACki5P|q z#7!hHERa2@Kgd~5pgc#~xrXa0Yv0LjDtWlATCVr7qV`+L3AS2?w!rWW%dvu0fwfGb zcp$%&Ia@mWxpMVD)q<76z2ZQyQy|~BTt@?~EZj9PB5-x!^?|xgDvzQ8AuDn?pH=B@e3wi)Fh|3^PlbIi(4C|y~<{J=gwY!XD7cq zikC5G;1v@W@v6Y(fkJ#rQvUo+Mw55ym725}RU!ltp!Y#}>o-|R($&0{=5>Lg%)*uy z;j)Pg7WiIo9}37!;a{X~u;ZsDjT~Zl!^E3d6qsl`zHF!s6_lg&kySz8$eDNxR|H0y ztUevKz)U8Rxs#y7fE6Td;u(0`#4@f4jCb)mCh^R|{R*pK-K`T~qG&m))NWOkcSlyW zf>TA8Qr?xGrQf5&c+j+%_~ri+91GD_&VJA&b5F^7*|8t8ChrLtz6xtzfb}ydUHzRw z;=c7YX(s%dd&t#n$*=M@dvaU)4+tsib&se5yU!|XD*~x)6*S%YZRyFD;%K0|^QW2U z?RbID{|6TNsvmf=7M!Zl9XMo?thjBjrfyj}br%L!*^=&HYF|=*u<81o2j-UJC~w`C zJ`+IAqS;}fM2vxn2>XVHz0HOztg;w~CXnRAX$gUMxNBjAA7DH?w>T4@9!?u45I^%E zhU@&+r3`!r6W`-q?pA5Y%Xkm(bJaUeFGA@Z2Ns6H-3rg*;qC@Lh%8p|At^xjYUJ92 zo^-(MZ!mVVk1;wY`8|GdI*}ee!Q@Z;sY60@1%3z#ER#D;x&&ss1ZJ^Dx0=8#wA;?T zJl$%0wpZjbR}TnXI7Vg#{7Vj3cTgbRu|?sIwqPJs^?TsWnRX5nbu5U88VXy0PqBDAzGAosHq!9*ENz zKBmbe6O-clv8BHE-vF>Ij_t}%SVb&4mtiHb<`Z)h83r2huiQ`B4l literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl.class b/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..caa3ba946a92aff8f2c4f29503e9fe44e5ff9327 GIT binary patch literal 4060 zcmb_f`&S#s75)Z;R){4Q*f_;$0)8bj0V}rSBrVjjL<|;{kb^Kab{xEtMzBWORaYz9 zq)pOy-S;bfIDN!T-Plc?w!t=r^qf9^?cdbX({C2Z5?C(boN^AjyEAj=e)qeNnf=#) zKKdJgVSLnzCT!8rtfK`!fxZjb`LJoZ(y@$uIA=T3oVCIyq)|-Bg6%A%ii90Ud471v)Pn7maY)HS^(Q(KT&uC(t4bMVG60g!acDoF7zJ z9?`KCL4oG9QIgzdbzR=DX2Z$!1(|UNm7z`@+pt}r$<7IcLJux#xPJgU@Ti7Q=;+2y zfddVFjigJiV`SV0{`!VY%XE(l41~tc#2ac?wMr$rtXLY{Kc(FIq>jh&gn-Y^(tH3y^Y00Qb8_l6Hwb=j;Xb9_g1_#&ZBn)?s1`DRe$b`nYR>NU(dN!)z zh`>{|-A`Gia5{tOtaQhib>pTT@fHZ|Q;Ale(G|@#%b0gj3~P8v$8n4($Llq!HE@clT-qCD zRz|FBDr4lCoz2nd$>Rd+Y&=|pxf{g^mEkcj(lM0-pVbjpk@hQkQs!&24dX~^IH}`h zOgzN(H4X@LSn`r8(kQoxmUB7j2n>bJMq{zM(x~F9=BQW6gOy6LOgmiDCeS8K>Ntfd z0?n3-0@KWpkDv5wS+81d*hfhJX-sQ4qvI@I5qP|ocU8S9BVU$rW5F&nt6Rq+Q<0ff z=AUffUftro$(-_Ounn(bM#Fg>hGKf}|Flq15@=Te@oG=CJXOUR9a&Yy+Y^z~Gm&^~ zblk%+6PcKZOe;5XI%dJ53V0Y(Cz2DB%%=@Orsh~%M0r7>oM+l@1kh7ZhzdF^g{Z5B z$g^65RMhc#Fdh6Jq}VtC?b{Gg%u;Y%1*a^qXCpXVuE1QzxQBW!*Lx3t{8_ba=#eGBRf6$uj-eTDD3?PL4`9SveAeJnB@r-Y+?xRs~~T z*4mQ5qgATb^()mr8B4X4`NhfV39x6aV-5Siz`6fJb9?B;fzAdK(w(!jCk@9aNM5c; zm47HhCcNte&wNHDkh04pXv9>Rx3giZJfI3uplzIoJVV1oEou0zz~P1`R>LjW-CnZG zjGKnv2^`v#;z-^$Tn)b$IJhZ2RgoHQ2t2bXHFgyZf7mQYuQh7;<7Pn)^D?2~gUza~ zX56-u(kYlOFFC1lI+Hg_EG%BfVwNSH;ni0SA2O^B3Gl8KT)y^l;afetSf$CF=M-;g z$s9>x0Vi{-7e0SAn%*ieKHjWyrn#3*a0hSsKI~M-7N2&i!@`s7)1G99qztOdsV8~& zru0MLtI(Pflg!B-y^#Hz-=$1#PrOMUfJG`^1?5ZMno z>f`z!Q40JRyZNg~2os*#rG&hY`OBl@((byHSf6%{wK}$&dG~Ytf{dx)^Jw1wZ}p{kD0qyZ zuU5i-gxqVKZtLsW)z#ANTS7|Nu4nmR9R+O_D{pg62fYtc*8ThOOZ=)r!^_-6{S7SQ zb1OI}a2x4G$Q79CF~10V1uWLvxVVUg6}+wgEYcJ5_Uvs_* zzrj0{K?1*qcX1u>;U?b4E&Qo6dW&y2IeMM5*YIbKrdbYAvbxBOf0dPW+tT sbSdvrzCpP}d5sqCaoxL=%aqqCmnh$(yi0kL@($(ulq;0CC~u?tzs$=wRsaA1 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl.java b/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl.java new file mode 100644 index 00000000..2512b9e5 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/HeapMemorySegmentImpl.java @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package jdk.internal.foreign; + +import java.lang.foreign.ValueLayout; +import java.nio.ByteBuffer; +import java.util.Objects; +import java.util.Optional; + +import jdk.internal.access.JavaNioAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.vm.annotation.ForceInline; + +/** + * Implementation for heap memory segments. A heap memory segment is composed by an offset and + * a base object (typically an array). To enhance performances, the access to the base object needs to feature + * sharp type information, as well as sharp null-check information. For this reason, many concrete subclasses + * of {@link HeapMemorySegmentImpl} are defined (e.g. {@link OfFloat}), so that each subclass can override the + * {@link HeapMemorySegmentImpl#unsafeGetBase()} method so that it returns an array of the correct (sharp) type. Note that + * the field type storing the 'base' coordinate is just Object; similarly, all the constructor in the subclasses + * accept an Object 'base' parameter instead of a sharper type (e.g. {@code byte[]}). This is deliberate, as + * using sharper types would require use of type-conversions, which in turn would inhibit some C2 optimizations, + * such as the elimination of store barriers in methods like {@link HeapMemorySegmentImpl#dup(long, long, boolean, MemorySessionImpl)}. + */ +abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl { + + // Constants defining the maximum alignment supported by various kinds of heap arrays. + + private static final long MAX_ALIGN_BYTE_ARRAY = ValueLayout.JAVA_BYTE.byteAlignment(); + private static final long MAX_ALIGN_SHORT_ARRAY = ValueLayout.JAVA_SHORT.byteAlignment(); + private static final long MAX_ALIGN_INT_ARRAY = ValueLayout.JAVA_INT.byteAlignment(); + private static final long MAX_ALIGN_LONG_ARRAY = ValueLayout.JAVA_LONG.byteAlignment(); + + final long offset; + final Object base; + + @Override + public Optional heapBase() { + return readOnly ? + Optional.empty() : + Optional.of(base); + } + + @ForceInline + HeapMemorySegmentImpl(long offset, Object base, long length, boolean readOnly, MemorySessionImpl session) { + super(length, readOnly, session); + this.offset = offset; + this.base = base; + } + + @Override + public long unsafeGetOffset() { + return offset; + } + + @Override + public final long maxByteAlignment() { + return address() == 0 + ? maxAlignMask() + : Math.min(maxAlignMask(), Long.lowestOneBit(address())); + } + + @Override + abstract HeapMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySessionImpl scope); + + @Override + ByteBuffer makeByteBuffer() { + if (!(base instanceof byte[] baseByte)) { + throw new UnsupportedOperationException("Not an address to an heap-allocated byte array"); + } + JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess(); + return nioAccess.newHeapByteBuffer(baseByte, (int)offset - Utils.BaseAndScale.BYTE.base(), (int) byteSize(), null); + } + + // factories + + public static final class OfByte extends HeapMemorySegmentImpl { + + OfByte(long offset, Object base, long length, boolean readOnly, MemorySessionImpl session) { + super(offset, base, length, readOnly, session); + } + + @Override + OfByte dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { + return new OfByte(this.offset + offset, base, size, readOnly, scope); + } + + @Override + public byte[] unsafeGetBase() { + return (byte[])Objects.requireNonNull(base); + } + + @Override + public long maxAlignMask() { + return MAX_ALIGN_BYTE_ARRAY; + } + + @Override + public long address() { + return offset - Utils.BaseAndScale.BYTE.base(); + } + } + + public static final class OfChar extends HeapMemorySegmentImpl { + + OfChar(long offset, Object base, long length, boolean readOnly, MemorySessionImpl session) { + super(offset, base, length, readOnly, session); + } + + @Override + OfChar dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { + return new OfChar(this.offset + offset, base, size, readOnly, scope); + } + + @Override + public char[] unsafeGetBase() { + return (char[])Objects.requireNonNull(base); + } + + @Override + public long maxAlignMask() { + return MAX_ALIGN_SHORT_ARRAY; + } + + @Override + public long address() { + return offset - Utils.BaseAndScale.CHAR.base(); + } + } + + public static final class OfShort extends HeapMemorySegmentImpl { + + OfShort(long offset, Object base, long length, boolean readOnly, MemorySessionImpl session) { + super(offset, base, length, readOnly, session); + } + + @Override + OfShort dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { + return new OfShort(this.offset + offset, base, size, readOnly, scope); + } + + @Override + public short[] unsafeGetBase() { + return (short[])Objects.requireNonNull(base); + } + + @Override + public long maxAlignMask() { + return MAX_ALIGN_SHORT_ARRAY; + } + + @Override + public long address() { + return offset - Utils.BaseAndScale.SHORT.base(); + } + } + + public static final class OfInt extends HeapMemorySegmentImpl { + + OfInt(long offset, Object base, long length, boolean readOnly, MemorySessionImpl session) { + super(offset, base, length, readOnly, session); + } + + @Override + OfInt dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { + return new OfInt(this.offset + offset, base, size, readOnly, scope); + } + + @Override + public int[] unsafeGetBase() { + return (int[])Objects.requireNonNull(base); + } + + @Override + public long maxAlignMask() { + return MAX_ALIGN_INT_ARRAY; + } + + @Override + public long address() { + return offset - Utils.BaseAndScale.INT.base(); + } + } + + public static final class OfLong extends HeapMemorySegmentImpl { + + OfLong(long offset, Object base, long length, boolean readOnly, MemorySessionImpl session) { + super(offset, base, length, readOnly, session); + } + + @Override + OfLong dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { + return new OfLong(this.offset + offset, base, size, readOnly, scope); + } + + @Override + public long[] unsafeGetBase() { + return (long[])Objects.requireNonNull(base); + } + + @Override + public long maxAlignMask() { + return MAX_ALIGN_LONG_ARRAY; + } + + @Override + public long address() { + return offset - Utils.BaseAndScale.LONG.base(); + } + } + + public static final class OfFloat extends HeapMemorySegmentImpl { + + OfFloat(long offset, Object base, long length, boolean readOnly, MemorySessionImpl session) { + super(offset, base, length, readOnly, session); + } + + @Override + OfFloat dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { + return new OfFloat(this.offset + offset, base, size, readOnly, scope); + } + + @Override + public float[] unsafeGetBase() { + return (float[])Objects.requireNonNull(base); + } + + @Override + public long maxAlignMask() { + return MAX_ALIGN_INT_ARRAY; + } + + @Override + public long address() { + return offset - Utils.BaseAndScale.FLOAT.base(); + } + } + + public static final class OfDouble extends HeapMemorySegmentImpl { + + OfDouble(long offset, Object base, long length, boolean readOnly, MemorySessionImpl session) { + super(offset, base, length, readOnly, session); + } + + @Override + OfDouble dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { + return new OfDouble(this.offset + offset, base, size, readOnly, scope); + } + + @Override + public double[] unsafeGetBase() { + return (double[])Objects.requireNonNull(base); + } + + @Override + public long maxAlignMask() { + return MAX_ALIGN_LONG_ARRAY; + } + + @Override + public long address() { + return offset - Utils.BaseAndScale.DOUBLE.base(); + } + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/ImplicitSession.class b/tests/test_data/std/jdk/internal/foreign/ImplicitSession.class new file mode 100644 index 0000000000000000000000000000000000000000..fc103498f988822bbef686880fa1643d79a4588d GIT binary patch literal 1280 zcmbVMOK;Oa5dJnXag&;cmOh|73MG_0+PDxZA*Dh>5tS+em0AcAw~e!HH@NGtb`bqf zT#yh{9N^B6Ld-fLF;xzTgV!^&^L_KQfByRR9Y6zHIi!%bVL7;f48v--^VXFr5?XQJ zJq)yvN6I}o=2~S6IF=V!-lF?&^bg|URVhULsIS12l7zz^!c29b~^kg)maI^@6 zzV<{@h7rS7b0X}yI0^LW5M($C`w3V*hZ*E;TyijrIfjKUf6rZ?t0Py7L$~1zu7qZo z(&C7s7;(4Q96Rl`yTXg=3Cn(8Dc<%)y_7H}xC$|6?2*Gf7Hlj!Si%*Cr7^AX-xr5M z3*`xhSuMDC%-hnJ(do{>wlE=$QY%NDTy}5`*BKlYsD>Ye!USWe6q6afQenT>3v?tp zdp)6fL{oYC!4o|r)ESnO^ojKAr51zL2s*@=Z%QRz^iSGCzZ}GvYX%mcYUdiI4#3O!L(U#7_!}d7{ykG+(EoA zJJR%H{#@j$X+L#sSJA{9J`Y0?+Nd(r{$sCfP&#Y>2BetDm9$Y~SowPwhI=^P9ja@z zN7$sHr|44zeSeIe8+6_z?HSUsJzxF`Rwm;##azxbhh;kLk>R0C+%jwV28wH%>-08$sq{y4##IcE+X-Z9ge;9hR)*=4`j7u!{05+bb^$4* zbC}bSL6*TdNsSK6C?lpUWPD-W8sByk(2Na3sTWxzb9&)HJ-#aCU?vtkV$@x?IV_z?mFM zI^MuphMNhIRyNh%Ct@&Y&GzozM!T`aa62iL83Aeq%Hh0@H}Mujh7ShzkYTf&6seY6 zc8LU8(D61d66fOkfZIMpGcoe499t6=@9iIoj;vK4s=P_)C5Gzc?XhAzqVIacP`4E& zTts;eml-aN`~zu`!hzF~mg|_`I@}xH8wig}*JGG#xLv_eY*~(I2mO8F?eTq^ETxv) z;r0XWS!x{_=VZ^K+6s28PcA1iNYeGV-wSu5UTl&LG@;6CO#G6ZRZ&KaM!&k%76Yu2ZiVuFe9?ax`{??77|h+~a*ghlj|}>K!{eXZc+^ zL|g_QCH+GT9v;YA%#v6{==%!k>WQ?k6BC79H}E>*uB9X`PLB7QB7t&m3tw)#KArFE z@vULpab4+4j}O9HeGPR66th?_;B$PD!-kGKXsA16OtKd^(&`H{Bs&5!jJOE6Hynsf;deZ1Ky4g{G;HqsaYGd2(di)Z z-PJK4R}-}i-GNQV5#A`IAgN2IucaKmWLTU)X9>$Nf8u0*#c*YUcm)+Xv`z${4cQQ%K#OwpKGeTLjmG>L;>j=<+bhX_orxQh1(#!yBj3Uht52GYjTk5fVZj%AP@ zXHdoJG_>^E^#1?MfaY-xYB!bqMH7J1gG234k3U44NI zz;u!!O<|?lxKfR{eILx&Ai{1CUhR1+ij=Re{toRK&P^vBXFMN;x=FwcL7@IQBR9t;2g literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/LayoutPath$GroupElementByIndex.class b/tests/test_data/std/jdk/internal/foreign/LayoutPath$GroupElementByIndex.class new file mode 100644 index 0000000000000000000000000000000000000000..1478dfdeabb6e1982cdad69699a4b8ba7c15282b GIT binary patch literal 2517 zcmbVOZBrXn6n-uw*(6;EO@Rtxp_SGo*rtfB)lihz5)3aEiqiUaNp8c!vYT#pJI%Mw z_%eR*i!*-oC+LiwQJA4K>SuqHdhYHfS<^^n9ERMzchB>jbDneVN&fun}gb`ur+vksYR_8`Jdsh@qtHcnQ)(p*_Vdze!w-rPgE;Wtvx-QCGpS8-)p)l;l zCq+@QHPeV9&JfERCGlizdhB`}3RLN$hhZR9XyP|*OEb#3^mYsh^eH&2B8hVhQ~RZZ ztY+B4GPs_7Xj(!m8`%P{nU1}|?Y;3kmg!U$bs@dZ)m%pmVNE(@U@LJ9U{Jw%6)$0k zVYCAsgIW#{GK{BI(uEG7oPw7b&bKBr=V*FKSaA%aJBkYoJwfV}JRehW5tm3>Ua1I! zG``wSlNV(2nRAk2TvA+S7;yt_6wTAKZWzUDBt}}=r&VMy!4S1g&xWBtMJcu*i93O- zDy|_*a#DDDjbVYJJG~sa&SE90-zHVOfhh`Nk5~8R&5~fa)seehsdMSPH)~IJ4 zqbP4e_MXA5+ImG;+%_$S5EX2j7BBroK{LdfbGR$4ExxOhAjyJRD}m5hqhW#2X5NDc(BSVK3(6cu=mW;2DkX3pgTs?alLW37%q15L#fg<$hTbPhIZ6+ zrp%dN{A?VB@AyJ}m!;^|(EBAH<5O+>IA$A|bx!H$ai zcpwK=<3d`FVQYsX>&fFIX{hej$rzpmWz>wv=7Gq1hRfV2>7qJbFwFy}64c3`xB=yS z;8v|77DTmZX%%YJAY@+W)oSp-=XmfUNzl6-3XNXa05hb{Q@=5vOROfaYz0yqzi4&JzxkG!DDy?-t$xb+r6)qPe5ca~RWfew%iW z5JESt!DSK7QBa9TIG}U#xO_EJz#&MA6*I(A==K69?S9!=jYiTpl+q{vgW$}nP?i9axKgx6bT2pC{vbpRjG8l}LzCc8^JspUPYL;{=G!pC$%KPqT9fKM<)P5CK4kHo-H Hguu{0!-9Fc literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/LayoutPath$GroupElementByName.class b/tests/test_data/std/jdk/internal/foreign/LayoutPath$GroupElementByName.class new file mode 100644 index 0000000000000000000000000000000000000000..b7ba74dfdb91b92016d676fea11748abb57cd6af GIT binary patch literal 2428 zcmbVOZEw?76n<`-#7S_QmjzfEE6^3l%fM?XV_Ql$+ESV=O*>l3fW62~E{$8q4%aqQ zq9lZYcBAt~bwWQL3;!Ucx&{pfwgMMu*cTqH4p(Ky~G%EGqtQ|`ef8JBT|*jL+aZcrL- z40fQGt|QRpI6hz)nJTzYS7ltob%wZY`a%r3d^iC?I7v!CK}HcJhA5fUI}FQYbx4fE zS;$hU-H>q;3OUhKt>%*1pk&<{iaj95?w zsrOon;mR=BvNr}Q$D-+R$G}Y2@jiRO5kq2=`d76bL6Q9u67a`NIkYp3@Icm^I)llc z9~#C21(Mt}9Z}~inoD-7KUr?N-czO4xMi=JmQ7XGorUQ|)3hyHsBND}D~?QxVJsEH zdJ-G>TEasao7i$EOs_SCW7t}Y2O~1jBt~|+U<|Lq#i1E5&3&%;f~%_0(782THO+me z9p))$+Yobs;#Q~4m$_9JTAL~_tg@u5mKELzFrJ+R30ogDu4zJ641)^~l2ajNPYz@W z-!M$}i5QewhBHT+=^4Y-zQ!q3Ncipu_#jbAozEL)Xt<5gZw?=We0A>_8Y2?DNAU^m ze@b8Lo&=C8z6LA(3F&dM^asXX(a{J#qh}TofW1J32_$G8XBNt|e~!*c4fD85tNZ4{ zGc3@1ly1qNNz0w9^mOgq4eTUJ#osY@fOmeQP2WO{M8JLwp(c8$34D$(=$vj;To0gD zNRKpd@h?m~d5!n77Y{J$qfTb0==}iG$I*ZC&}CmQK+n*0z87H5(CT7J#Y21u{Cdo} zR!Cjysn23DP@fN?ix*3W_~^g%eahm!;NtXWWZ5&E=>?|*jzrynjzrVqOIqXPnqNX+(U;3*4Wm?I dRjlC=?OgD_a@eN(cMgy7B$mKae2ecf@h?R`W?=vT literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/LayoutPath$SequenceElement.class b/tests/test_data/std/jdk/internal/foreign/LayoutPath$SequenceElement.class new file mode 100644 index 0000000000000000000000000000000000000000..2c8dfd148cb65af264522102223606ba07abe933 GIT binary patch literal 2216 zcmb7F-*4Mg6#j0~#7=5RTDHN;ezzM*3N>ZpXG%wxwlt8Yg_KFa(`|BT+&Xr!uP5c1 ze}@MK(k68h;spsIUiQGhgE%*K6E`ihP!!)EKHs_LeBZgpfBtj)D}Wll$RmZchA9IX zWEqNw{1G>8?i`q3ini-@7_uvtW64#9bgBF>4;?uTc>~ih7_J|7j!esu!gIK7e&>3^ zI&jPeAGm?s<+96A@WuCmaN1(S7CqrehWS#tkpQdec$r~l0$M8PP{fReSp%=&0)v_0 zW}!8Cwq9?x_STxU4Tj~UASTh(Je_{Yz^izTA;bH9d%&<>N^(<8&UTihm^1J?t}y6b z?ssc$M=;z=^nE78a$WhlX5cz*kaCnhw|$1q|L>_WE`*)^L(!Ji@;8bAs+D<$%J}Vx z=-Z;_dV^5<1*Lr?xQ5#dH-`3sw5Uh|r!6hlF~4%SH`wV5k4x8MmKHn$&g&r<7Xb4qqCN-S^3O6_K%6hyCdThgTN9StKP&Sh^u~hKt1Z$nS_e2Ii_{&b(r{a~|M4!{WA(UAME#J>C;^>4*V+rEN#| zGuNWa$7SGA=s(2Z;YF^-b`nzwZC{|*N+Q>*#7Dm623}iiT1v;lxGgLx5-9ej@a2~4 zQ&Y&EberM>*Ok8Xct6b5*KwZ#g)G+ccz~LQbpspNRJ~_JvKKhg>IpL>I|4G~_D_5< zJdSg0Igi{UVTOiV-09fDUud}QQP7Xm6xBqGxCpp6=!_&*wHt@jZ0`HcT`j)9@L?wK48IRT-vF-NkK&+hfEFc+jwO%K3Sw zBwI)tmZ>wO=ywYXV3{8c9iHDo?>4(|)Xyj=EQ>||H)g1NzfF6}a+yYTh*mkqW#C7e#-oj=sznFQP{UR* z1z#a+m8xD@JjT`k!iU-Fqil7&gS%kGH6raE;gzSmk*8c`@i*vCaB(u{cqqBZ)w=}D zQ20fq-+LqV=7%u>)6Y=+`YCSyf`Za8&cYvL{66ia@B!(i#*a`Pjyff!*1*T~&lBns eS{1R1PiZ}eG|hEv5nH!V$LHA`8fan{m;VLl>@Mp7 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/LayoutPath$SequenceElementByIndex.class b/tests/test_data/std/jdk/internal/foreign/LayoutPath$SequenceElementByIndex.class new file mode 100644 index 0000000000000000000000000000000000000000..02e238fa51be865425d29fb5ef066563f9694ed4 GIT binary patch literal 2538 zcmbVO-BTM?6#rdFvPrs-Gy)aGLMyFFuuZXw)zB)R5)2a%~8dhYHf*``2d9EP0xanA3Y^E>CBhJq-=#g$*gUl{iM zqq3;lnrTE4XNVPyig+|SHF_-$1*&w>!_c2Dw(Lu`r5W4#%tj0eBo&-hk-|$1le?9@ zoMzaSB@j+1-^Xnyo4B&5SJK+-B_E|^N4LIM)5jPl9Bou6FYq2Dj>~Rbg@4v=~BEwha;<35lX+h!tmlOIYiCOD9@VMYGKH4Q^?2?;nQj z9gQ-)(Wx3IF~-nSvUz!LnOA+pTfFM=UW+1?VCYRmuo1^6_*B8B zio3Wc=T`G&T8?3B`y%Jj<6F|0-D-d_JPp#Q84t}pk@FN6xlz$YZLDaTdrmdTlRtw4 z%=w1v^{SW?wX&sEsaJz0vpTQUf(Jgvy%#}(-sN;?X47l{wO|;+av=rv-N5mqUBQzxeft z(Dy5Cx?IN*QUUuh;3(E~6vG_m>7J$@#(k&-f+7nHKf}=GA%;`09$>^neJypF)(1$p zqyOZhtDc>YewL>Hf{!^tQerCEBU}T1ZVT?afVt8%pTvj0x#U}B7tM|z;jNSG2Rxl- za#1Xz;5trW$w$hOjtnF$6Z++pFv1>8a+*l~h>Rr3*GbASV%hP((0_n8+Gz;p(ID9` z7?MB)Mc3mpR$RG?HCOiIW0Fw{%xkjSw3A%kp-LoB!a6>q6Z(xoyMBC*L2Ak`@Kq!R Jjxq!W{{u;Cg7yFa literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/LayoutPath$SequenceElementByRange.class b/tests/test_data/std/jdk/internal/foreign/LayoutPath$SequenceElementByRange.class new file mode 100644 index 0000000000000000000000000000000000000000..e3e14b338a39161b6bcde76ccf06e6c0ef0a3210 GIT binary patch literal 2800 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/LayoutPath.java b/tests/test_data/std/jdk/internal/foreign/LayoutPath.java new file mode 100644 index 00000000..ebd83d1c --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/LayoutPath.java @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.internal.foreign; + +import jdk.internal.vm.annotation.ForceInline; + +import java.lang.foreign.AddressLayout; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.UnaryOperator; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.joining; + +/** + * This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout)}), + * a path can be constructed by selecting layout elements using the selector methods provided by this class + * (see {@link #sequenceElement()}, {@link #sequenceElement(long)}, {@link #sequenceElement(long, long)}, {@link #groupElement(String)}). + * Once a path has been fully constructed, clients can ask for the offset associated with the layout element selected + * by the path (see {@link #offset}), or obtain var handle to access the selected layout element + * given an address pointing to a segment associated with the root layout (see {@link #dereferenceHandle()}). + */ +public class LayoutPath { + + private static final long[] EMPTY_STRIDES = new long[0]; + private static final long[] EMPTY_BOUNDS = new long[0]; + private static final MethodHandle[] EMPTY_DEREF_HANDLES = new MethodHandle[0]; + + private static final MethodHandle MH_ADD_SCALED_OFFSET; + private static final MethodHandle MH_SLICE; + private static final MethodHandle MH_SLICE_LAYOUT; + private static final MethodHandle MH_CHECK_ENCL_LAYOUT; + private static final MethodHandle MH_SEGMENT_RESIZE; + private static final MethodHandle MH_ADD; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MH_ADD_SCALED_OFFSET = lookup.findStatic(LayoutPath.class, "addScaledOffset", + MethodType.methodType(long.class, long.class, long.class, long.class, long.class)); + MH_SLICE = lookup.findVirtual(MemorySegment.class, "asSlice", + MethodType.methodType(MemorySegment.class, long.class, long.class)); + MH_SLICE_LAYOUT = lookup.findVirtual(MemorySegment.class, "asSlice", + MethodType.methodType(MemorySegment.class, long.class, MemoryLayout.class)); + MH_CHECK_ENCL_LAYOUT = lookup.findStatic(LayoutPath.class, "checkEnclosingLayout", + MethodType.methodType(void.class, MemorySegment.class, long.class, MemoryLayout.class)); + MH_SEGMENT_RESIZE = lookup.findStatic(LayoutPath.class, "resizeSegment", + MethodType.methodType(MemorySegment.class, MemorySegment.class, MemoryLayout.class)); + MH_ADD = lookup.findStatic(Long.class, "sum", + MethodType.methodType(long.class, long.class, long.class)); + } catch (Throwable ex) { + throw new ExceptionInInitializerError(ex); + } + } + + private final MemoryLayout layout; + private final long offset; + private final LayoutPath enclosing; + private final long[] strides; + private final long[] bounds; + private final MethodHandle[] derefAdapters; + + private LayoutPath(MemoryLayout layout, long offset, long[] strides, long[] bounds, MethodHandle[] derefAdapters, LayoutPath enclosing) { + this.layout = layout; + this.offset = offset; + this.strides = strides; + this.bounds = bounds; + this.derefAdapters = derefAdapters; + this.enclosing = enclosing; + } + + // Layout path selector methods + + public LayoutPath sequenceElement() { + SequenceLayout seq = requireSequenceLayout(); + MemoryLayout elem = seq.elementLayout(); + return LayoutPath.nestedPath(elem, offset, addStride(elem.byteSize()), addBound(seq.elementCount()), derefAdapters, this); + } + + public LayoutPath sequenceElement(long start, long step) { + SequenceLayout seq = requireSequenceLayout(); + checkSequenceBounds(seq, start); + MemoryLayout elem = seq.elementLayout(); + long elemSize = elem.byteSize(); + long nelems = step > 0 ? + seq.elementCount() - start : + start + 1; + long maxIndex = Math.ceilDiv(nelems, Math.abs(step)); + return LayoutPath.nestedPath(elem, offset + (start * elemSize), + addStride(elemSize * step), addBound(maxIndex), derefAdapters, this); + } + + public LayoutPath sequenceElement(long index) { + SequenceLayout seq = requireSequenceLayout(); + checkSequenceBounds(seq, index); + long elemSize = seq.elementLayout().byteSize(); + long elemOffset = elemSize * index; + return LayoutPath.nestedPath(seq.elementLayout(), offset + elemOffset, strides, bounds, derefAdapters, this); + } + + public LayoutPath groupElement(String name) { + GroupLayout g = requireGroupLayout(); + long offset = 0; + MemoryLayout elem = null; + for (int i = 0; i < g.memberLayouts().size(); i++) { + MemoryLayout l = g.memberLayouts().get(i); + if (l.name().isPresent() && + l.name().get().equals(name)) { + elem = l; + break; + } else if (g instanceof StructLayout) { + offset += l.byteSize(); + } + } + if (elem == null) { + throw badLayoutPath( + String.format("cannot resolve '%s' in layout %s", name, breadcrumbs())); + } + return LayoutPath.nestedPath(elem, this.offset + offset, strides, bounds, derefAdapters, this); + } + + public LayoutPath groupElement(long index) { + GroupLayout g = requireGroupLayout(); + long elemSize = g.memberLayouts().size(); + long offset = 0; + MemoryLayout elem = null; + for (int i = 0; i <= index; i++) { + if (i == elemSize) { + throw badLayoutPath( + String.format("cannot resolve element %d in layout: %s", index, breadcrumbs())); + } + elem = g.memberLayouts().get(i); + if (g instanceof StructLayout && i < index) { + offset += elem.byteSize(); + } + } + return LayoutPath.nestedPath(elem, this.offset + offset, strides, bounds, derefAdapters, this); + } + + public LayoutPath derefElement() { + if (!(layout instanceof AddressLayout addressLayout) || + addressLayout.targetLayout().isEmpty()) { + throw badLayoutPath( + String.format("Cannot dereference layout: %s", breadcrumbs())); + } + MemoryLayout derefLayout = addressLayout.targetLayout().get(); + MethodHandle handle = dereferenceHandle(false).toMethodHandle(VarHandle.AccessMode.GET); + handle = MethodHandles.filterReturnValue(handle, + MethodHandles.insertArguments(MH_SEGMENT_RESIZE, 1, derefLayout)); + return derefPath(derefLayout, handle, this); + } + + private static MemorySegment resizeSegment(MemorySegment segment, MemoryLayout layout) { + return Utils.longToAddress(segment.address(), layout.byteSize(), layout.byteAlignment()); + } + + // Layout path projections + + public long offset() { + return offset; + } + + public VarHandle dereferenceHandle() { + return dereferenceHandle(true); + } + + public VarHandle dereferenceHandle(boolean adapt) { + if (!(layout instanceof ValueLayout valueLayout)) { + throw new IllegalArgumentException( + String.format("Path does not select a value layout: %s", breadcrumbs())); + } + + VarHandle handle = Utils.makeRawSegmentViewVarHandle(valueLayout); + handle = MethodHandles.collectCoordinates(handle, 1, offsetHandle()); + + // we only have to check the alignment of the root layout for the first dereference we do, + // as each dereference checks the alignment of the target address when constructing its segment + // (see Utils::longToAddress) + if (derefAdapters.length == 0) { + // insert align check for the root layout on the initial MS + offset + List> coordinateTypes = handle.coordinateTypes(); + MethodHandle alignCheck = MethodHandles.insertArguments(MH_CHECK_ENCL_LAYOUT, 2, rootLayout()); + handle = MethodHandles.collectCoordinates(handle, 0, alignCheck); + int[] reorder = IntStream.concat(IntStream.of(0, 1), IntStream.range(0, coordinateTypes.size())).toArray(); + handle = MethodHandles.permuteCoordinates(handle, coordinateTypes, reorder); + } + + if (adapt) { + if (derefAdapters.length > 0) { + // plug up the base offset if we have at least 1 enclosing dereference + handle = MethodHandles.insertCoordinates(handle, 1, 0); + } + for (int i = derefAdapters.length; i > 0; i--) { + MethodHandle adapter = derefAdapters[i - 1]; + // the first/outermost adapter will have a base offset coordinate, the rest are constant 0 + if (i > 1) { + // plug in a constant 0 base offset for all but the outermost access in a deref chain + adapter = MethodHandles.insertArguments(adapter, 1, 0); + } + handle = MethodHandles.collectCoordinates(handle, 0, adapter); + } + } + return handle; + } + + @ForceInline + private static long addScaledOffset(long base, long index, long stride, long bound) { + Objects.checkIndex(index, bound); + return base + (stride * index); + } + + public MethodHandle offsetHandle() { + MethodHandle mh = MethodHandles.insertArguments(MH_ADD, 0, offset); + for (int i = strides.length - 1; i >= 0; i--) { + MethodHandle collector = MethodHandles.insertArguments(MH_ADD_SCALED_OFFSET, 2, strides[i], bounds[i]); + // (J, ...) -> J to (J, J, ...) -> J + // i.e. new coord is prefixed. Last coord will correspond to innermost layout + mh = MethodHandles.collectArguments(mh, 0, collector); + } + + return mh; + } + + private MemoryLayout rootLayout() { + return enclosing != null ? enclosing.rootLayout() : this.layout; + } + + public MethodHandle sliceHandle() { + MethodHandle sliceHandle; + if (enclosing != null) { + // drop the alignment check for the accessed element, we check the root layout instead + sliceHandle = MH_SLICE; // (MS, long, long) -> MS + sliceHandle = MethodHandles.insertArguments(sliceHandle, 2, layout.byteSize()); // (MS, long) -> MS + } else { + sliceHandle = MH_SLICE_LAYOUT; // (MS, long, MemoryLayout) -> MS + sliceHandle = MethodHandles.insertArguments(sliceHandle, 2, layout); // (MS, long) -> MS + } + sliceHandle = MethodHandles.collectArguments(sliceHandle, 1, offsetHandle()); // (MS, long, ...) -> MS + + if (enclosing != null) { + // insert align check for the root layout on the initial MS + offset + MethodType oldType = sliceHandle.type(); + MethodHandle alignCheck = MethodHandles.insertArguments(MH_CHECK_ENCL_LAYOUT, 2, rootLayout()); + sliceHandle = MethodHandles.collectArguments(sliceHandle, 0, alignCheck); // (MS, long, MS, long) -> MS + int[] reorder = IntStream.concat(IntStream.of(0, 1), IntStream.range(0, oldType.parameterCount())).toArray(); + sliceHandle = MethodHandles.permuteArguments(sliceHandle, oldType, reorder); // (MS, long, ...) -> MS + } + + return sliceHandle; + } + + private static void checkEnclosingLayout(MemorySegment segment, long offset, MemoryLayout enclosing) { + ((AbstractMemorySegmentImpl)segment).checkAccess(offset, enclosing.byteSize(), true); + if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(offset, enclosing)) { + throw new IllegalArgumentException(String.format( + "Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s" + , offset, enclosing.byteAlignment(), enclosing, segment)); + } + } + + public MemoryLayout layout() { + return layout; + } + + // Layout path construction + + public static LayoutPath rootPath(MemoryLayout layout) { + return new LayoutPath(layout, 0L, EMPTY_STRIDES, EMPTY_BOUNDS, EMPTY_DEREF_HANDLES, null); + } + + private static LayoutPath nestedPath(MemoryLayout layout, long offset, long[] strides, long[] bounds, MethodHandle[] derefAdapters, LayoutPath encl) { + return new LayoutPath(layout, offset, strides, bounds, derefAdapters, encl); + } + + private static LayoutPath derefPath(MemoryLayout layout, MethodHandle handle, LayoutPath encl) { + MethodHandle[] handles = Arrays.copyOf(encl.derefAdapters, encl.derefAdapters.length + 1); + handles[encl.derefAdapters.length] = handle; + return new LayoutPath(layout, 0L, EMPTY_STRIDES, EMPTY_BOUNDS, handles, null); + } + + // Helper methods + + private SequenceLayout requireSequenceLayout() { + return requireLayoutType(SequenceLayout.class, "sequence"); + } + + private GroupLayout requireGroupLayout() { + return requireLayoutType(GroupLayout.class, "group"); + } + + private T requireLayoutType(Class layoutClass, String name) { + if (!layoutClass.isAssignableFrom(layout.getClass())) { + throw badLayoutPath( + String.format("attempting to select a %s element from a non-%s layout: %s", + name, name, breadcrumbs())); + } + return layoutClass.cast(layout); + } + + private void checkSequenceBounds(SequenceLayout seq, long index) { + if (index >= seq.elementCount()) { + throw badLayoutPath(String.format("sequence index out of bounds; index: %d, elementCount is %d for layout %s", + index, seq.elementCount(), breadcrumbs())); + } + } + + private static IllegalArgumentException badLayoutPath(String cause) { + return new IllegalArgumentException("Bad layout path: " + cause); + } + + private long[] addStride(long stride) { + long[] newStrides = Arrays.copyOf(strides, strides.length + 1); + newStrides[strides.length] = stride; + return newStrides; + } + + private long[] addBound(long maxIndex) { + long[] newBounds = Arrays.copyOf(bounds, bounds.length + 1); + newBounds[bounds.length] = maxIndex; + return newBounds; + } + + private String breadcrumbs() { + return Stream.iterate(this, Objects::nonNull, lp -> lp.enclosing) + .map(LayoutPath::layout) + .map(Object::toString) + .collect(joining(", selected from: ")); + } + + public record GroupElementByName(String name) + implements MemoryLayout.PathElement, UnaryOperator { + + // Assert invariants + public GroupElementByName { + Objects.requireNonNull(name); + } + + @Override + public LayoutPath apply(LayoutPath layoutPath) { + return layoutPath.groupElement(name); + } + + @Override + public String toString() { + return "groupElement(\"" + name + "\")"; + } + } + + public record GroupElementByIndex(long index) + implements MemoryLayout.PathElement, UnaryOperator { + + // Assert invariants + public GroupElementByIndex { + if (index < 0) { + throw new IllegalArgumentException("Index < 0"); + } + } + + @Override + public LayoutPath apply(LayoutPath layoutPath) { + return layoutPath.groupElement(index); + } + + @Override + public String toString() { + return "groupElement(" + index + ")"; + } + + } + + public record SequenceElementByIndex(long index) + implements MemoryLayout.PathElement, UnaryOperator { + + // Assert invariants + public SequenceElementByIndex { + if (index < 0) { + throw new IllegalArgumentException("Index < 0"); + } + } + + @Override + public LayoutPath apply(LayoutPath layoutPath) { + return layoutPath.sequenceElement(index); + } + + @Override + public String toString() { + return "sequenceElement(" + index + ")"; + } + + } + + public record SequenceElementByRange(long start, long step) + implements MemoryLayout.PathElement, UnaryOperator { + + // Assert invariants + public SequenceElementByRange { + if (start < 0) { + throw new IllegalArgumentException("Start index must be positive: " + start); + } + if (step == 0) { + throw new IllegalArgumentException("Step must be != 0: " + step); + } + } + + @Override + public LayoutPath apply(LayoutPath layoutPath) { + return layoutPath.sequenceElement(start, step); + } + + @Override + public String toString() { + return "sequenceElement(" + start + ", " + step + ")"; + } + + } + + public record SequenceElement() + implements MemoryLayout.PathElement, UnaryOperator { + + private static final SequenceElement INSTANCE = new SequenceElement(); + + @Override + public LayoutPath apply(LayoutPath layoutPath) { + return layoutPath.sequenceElement(); + } + + @Override + public String toString() { + return "sequenceElement()"; + } + + public static MemoryLayout.PathElement instance() { + return INSTANCE; + } + + } + + public record DereferenceElement() + implements MemoryLayout.PathElement, UnaryOperator { + + private static final DereferenceElement INSTANCE = new DereferenceElement(); + + @Override + public LayoutPath apply(LayoutPath layoutPath) { + return layoutPath.derefElement(); + } + + // Overriding here will ensure DereferenceElement will have a hash code + // that is different from the hash code of SequenceElement. + @Override + public int hashCode() { + return 31; + } + + @Override + public String toString() { + return "dereferenceElement()"; + } + + public static MemoryLayout.PathElement instance() { + return INSTANCE; + } + + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/MappedMemorySegmentImpl.class b/tests/test_data/std/jdk/internal/foreign/MappedMemorySegmentImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..e5c9dbd5ae2070463047c541fd41f417bf6d2ffe GIT binary patch literal 3437 zcmcImTXz#x6#h;UGHE(MTPOuYN-4!Oy@X3qG+5{jXlU9(pxPkdbaK*8o6K}&CSd&q z{sn)5FFq)0E4r4;Cm;M#F87|9Tj-0L*i%jfQV&9-@ z6=`LbnP1qXXj3K4Tu&{nZA#rqH?7o+T2h%F_I8+tm1+Q|fSK{iDjbUCz1`jCFh3dAz(?iX!fXwbctK4?V zvd|X=t_90GVAQ#ZSXS{6j|6(xrSnhK3MAUa8K90d$z#SUP%4iv7^YmTme*wEv9?yC zm7WDl*Gel|#o%{;G2(0(Hi_wQj7cvQsTG#Y(hkkYJQdL9R--rr{P?FzLzASHvbH4~ zLrI{orj@p7MS8W0MO!+=%{IOy6osZ~&V3@;dTDhVYDM5^&e8NOTJ!n6jk*V%jFjuH ztaLW4!m?J;%974g%H*@RAhh5?C@|y+tbP)-x4nCWQfRSTddWYx<2kEJ?Zy2ka4tZG z~I`!P_Jae=NmdaFXAoj`Z8|5T(mdPdoUNRIsk<$GET z;jwEFrt28F8AlgVctUTJh|;wiEBJ)&{6uFhx#TB?V~cJ+YY}muKEpzN2qmBvE(YbvFXlv#CcwBf|G*puu!Q_0t&cBs1MJ5LVb8aPfVx}OvBs9G&mfZ6+Y~J`oiDh z$^L;o4E&B*JJM|z>4NJkUPp@8k>dE=MH0|(&G$M=cTP?y@-1K8f_Q0|ZAwGP_a^B4 zS@SKQ`)M6y@_*p`YYZiKG0X|!l{Xlpqmt6Ri|btLa8s=_WcmOXk!^w)^dWS2ueeAk z>HmQBVLR3`VLc?Q+`(9r^^9mfuMv;eKrpXcUqgv}gGiWD=kfDWx6*_)(!?u@@KE>; zC;V=m+6LnEPWt!Y5)C*?A?>B*Mm{^dgwD2;%u~!yF-nr>=JBLE)&v}e811@4$6SF* z%x!st47f`=NldKUUEFV1)8!^#oxU$gCf(F=U372!x~BNQoA3FmFH?m)?_%K~uS%2G u4jLw&M>o#m{}$)^+lrIM+D5&K{ca5b~H(f$Y0~A_Xx=0mjL1KmAR>Wl$AX3@`sVZ@FcBhGp5hH5hIu-=-lk#Jxj3;ZP&WYZ^-3_tI16b3qf&piLwKPY*}RrFI6LYQ|1S(xp;clI3YSATnv8D@P^sj?oIF zZwlPq>HUT8d#lWFFZ5j&=v={jwx0_`c~z3Ya!(mLn2rZz59L5}rroOwsgI;pA)X~8 z&kqrJ+q;tPdjfHBKH8*T&;5-G%~${Xm}g-S%(G*{oOlrXN8$U1P}RS~^EA#zTP@m%BO_MNkOiToerRI}c})L5d|7Vpzel6d`bncNu#TGEdGR zzSQLvwxJBMhBoh8e-7X_?r_9vm|uR0MqNw3A^y-_Jj0D2{~&B!KuBf?5mxI{_i&$m dR1;dOGwax3zs{(eY`3CCu5BV^zr=Z7zX2@3-{=4U literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList$ResourceCleanup$2.class b/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList$ResourceCleanup$2.class new file mode 100644 index 0000000000000000000000000000000000000000..704b0e9a676c10654dda877e4548e4b97c88c5bb GIT binary patch literal 983 zcmb_bTTj$L6#mX`-R^d)EQp|Z11YyPu?hNMf-x}-DoNo1%)a-#PR3*Y6)c0Yq49p@zB($Hxsc2-_$9(@?5HipAzFh**%Gd#wY%*2+5CR#2$A8q)AXafBSjaO31;x(bZzR_#r7N%Tud`#O8Ggm=y zTwXH3`So!KH+lpo(tSagilq{J=PG8FzYUH7E#VI9zSZGj4)ZJtcPo#r@RF_StosG@ z9XAR8DtNXw1!&RAm?{qLaefU8xX;pIoDcB0@+{&B%LUZ2%oD6QEk0YuDocx%pFd&? B1W5n@ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList$ResourceCleanup.class b/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList$ResourceCleanup.class new file mode 100644 index 0000000000000000000000000000000000000000..3fc2f908696d30b0c0fcdbf18eea25b8e3f1bf53 GIT binary patch literal 1111 zcmb_bO>fgc5Pg%lb>g`6gV0jG(}a-rfCW9aLPDm9NT!vVs#3)PIqtUI;H)dJgWz9* zI8>q%KY$;Fn03++i5_~0CC~Hhdfv>=zWM#<=Pv+0HXIaCv|+iJ!7O2+7k&=CI8>+J zUbiQrj4-<`mCRldimmlS8zsU{@A#7^RVGpu#@X$B#v*2Iq~J4s19kZH2JX3jQVDA1D=eW3gq@%}puY3kNQWWh`LP#*&NM zs1p1s9E4EugT2nqn~y=ebHLRGQy|?USW0~1?puCxEC};~RAP6~?~3%m^oFn$BvBY2 zhN(3EXwk~fq$b$Wu*n1`Ik{>l;luS^o>IYcqol8+j0HfbUU#L0(smS&1m$#cdAyb8 zJj?&-=edyt2kZ)+y-Rdvqd{oith)rat&~XpIMiBb8_x)vHwzsr)yS54CRNNAapjJ5 zY}Hs&1)e4I-a(b^T_Y|=3uK0h?J|2FBQefwT!6mwM*%Br%{HjYL12OAKVa2_TZDVO z3zTpl4|vCrY@(R|Q@(_K#6;z9yf{fzn;oeQwvWZ n+hHxMoZ|_51=O&XV;xT!*Z4q9)X}oc6g9EVX!E*x+#&o0zStnb literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList.class b/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl$ResourceList.class new file mode 100644 index 0000000000000000000000000000000000000000..f2e8ed872923612728e4b0b7312a0eedafe27e93 GIT binary patch literal 1276 zcmb_cT~8B16g_v@c9&&KOI5x^6hVY;OZkW|Vti>ZV78c0!u!$=u+Yvn+pXdcGCY$Q zOnlHcO#A^p`7?Ynpx$Y*Rd`WjHhX7h?wxbboVj;DetY{4Kmm&uH1rtIZNv~Kr1rh% zUcTzd-TbrdeNm1G@khS&qsN4vnb|E1CVCB6Hu_Zf(thP2@5@Mp(yQiof>8LoGG7$6 zAbeR8jfNk{wOYM8wILcoGb{_&Z!n@!t_n{!>lP9Ute;T$2b>OQp^auBMHub!-)PFn zuZfkzvZzN)#6l8j8`p51knk#%QnOwUnWLx>hG*RF#?8Gjc;RhV#q#V{FH;<}F@#}) zF2y0UUvd8f*<}NxgmgD4vz00*%ewopyt=SKabLU(GKT z^=Qv;5FY#swPjApau8NogulPe%h$l7F<{t~1WgE%`g;_orzN9l@E$u{o=S*sZ~u+e5Kdmm2#U?vJ%X7(TG-qMr2@)F#Ts|BiL(F zim*`ixHMQ(`}f*S{+wP^oj$=Gp@A^MFK`pXY-9Y*?ZkGBXL%l#FP3=&I_3`zx7aE- z@CD;+?REfe;|`z$6S&(Nxyjf&fXNQnQU~k=Mi)%AF>uCv&#wY9!#)OVv-!l4oB@mE zW{TNUOlMDEA7Nukb$B4`c(=Gip z%;P?cfFMj|4 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl.class b/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..e6b03bdd369cfac4face5d7bfe2d00eab52ca45e GIT binary patch literal 7916 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 Q7Gi=J$9en{6Wr^60mVcp`~Uy| literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl.java b/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl.java new file mode 100644 index 00000000..aef62be8 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/MemorySessionImpl.java @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package jdk.internal.foreign; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment.Scope; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.lang.ref.Cleaner; +import java.util.Objects; + +import jdk.internal.foreign.GlobalSession.HeapSession; +import jdk.internal.misc.ScopedMemoryAccess; +import jdk.internal.vm.annotation.ForceInline; + +/** + * This class manages the temporal bounds associated with a memory segment as well + * as thread confinement. A session has a liveness bit, which is updated when the session is closed + * (this operation is triggered by {@link MemorySessionImpl#close()}). This bit is consulted prior + * to memory access (see {@link #checkValidStateRaw()}). + * There are two kinds of memory session: confined memory session and shared memory session. + * A confined memory session has an associated owner thread that confines some operations to + * associated owner thread such as {@link #close()} or {@link #checkValidStateRaw()}. + * Shared sessions do not feature an owner thread - meaning their operations can be called, in a racy + * manner, by multiple threads. To guarantee temporal safety in the presence of concurrent thread, + * shared sessions use a more sophisticated synchronization mechanism, which guarantees that no concurrent + * access is possible when a session is being closed (see {@link jdk.internal.misc.ScopedMemoryAccess}). + */ +public abstract sealed class MemorySessionImpl + implements Scope + permits ConfinedSession, GlobalSession, SharedSession { + static final int OPEN = 0; + static final int CLOSED = -1; + + static final VarHandle STATE; + static final int MAX_FORKS = Integer.MAX_VALUE; + + static final ScopedMemoryAccess.ScopedAccessError ALREADY_CLOSED = new ScopedMemoryAccess.ScopedAccessError(MemorySessionImpl::alreadyClosed); + static final ScopedMemoryAccess.ScopedAccessError WRONG_THREAD = new ScopedMemoryAccess.ScopedAccessError(MemorySessionImpl::wrongThread); + // This is the session of all zero-length memory segments + public static final MemorySessionImpl GLOBAL_SESSION = new GlobalSession(); + + final ResourceList resourceList; + final Thread owner; + int state = OPEN; + + static { + try { + STATE = MethodHandles.lookup().findVarHandle(MemorySessionImpl.class, "state", int.class); + } catch (Exception ex) { + throw new ExceptionInInitializerError(ex); + } + } + + public Arena asArena() { + return new ArenaImpl(this); + } + + @ForceInline + public static MemorySessionImpl toMemorySession(Arena arena) { + return (MemorySessionImpl) arena.scope(); + } + + public final boolean isCloseableBy(Thread thread) { + Objects.requireNonNull(thread); + return isCloseable() && + (owner == null || owner == thread); + } + + public void addCloseAction(Runnable runnable) { + Objects.requireNonNull(runnable); + addInternal(ResourceList.ResourceCleanup.ofRunnable(runnable)); + } + + /** + * Add a cleanup action. If a failure occurred (because of an add vs. close race), call the cleanup action. + * This semantics is useful when allocating new memory segments, since we first do a malloc/mmap and _then_ + * we register the cleanup (free/munmap) against the session; so, if registration fails, we still have to + * clean up memory. From the perspective of the client, such a failure would manifest as a factory + * returning a segment that is already "closed" - which is always possible anyway (e.g. if the session + * is closed _after_ the cleanup for the segment is registered but _before_ the factory returns the + * new segment to the client). For this reason, it's not worth adding extra complexity to the segment + * initialization logic here - and using an optimistic logic works well in practice. + */ + public void addOrCleanupIfFail(ResourceList.ResourceCleanup resource) { + try { + addInternal(resource); + } catch (Throwable ex) { + resource.cleanup(); + throw ex; + } + } + + void addInternal(ResourceList.ResourceCleanup resource) { + checkValidState(); + // Note: from here on we no longer check the session state. Two cases are possible: either the resource cleanup + // is added to the list when the session is still open, in which case everything works ok; or the resource + // cleanup is added while the session is being closed. In this latter case, what matters is whether we have already + // called `ResourceList::cleanup` to run all the cleanup actions. If not, we can still add this resource + // to the list (and, in case of an add vs. close race, it might happen that the cleanup action will be + // called immediately after). + resourceList.add(resource); + } + + protected MemorySessionImpl(Thread owner, ResourceList resourceList) { + this.owner = owner; + this.resourceList = resourceList; + } + + public static MemorySessionImpl createConfined(Thread thread) { + return new ConfinedSession(thread); + } + + public static MemorySessionImpl createShared() { + return new SharedSession(); + } + + public static MemorySessionImpl createImplicit(Cleaner cleaner) { + return new ImplicitSession(cleaner); + } + + public static MemorySessionImpl createHeap(Object ref) { + return new HeapSession(ref); + } + + public abstract void release0(); + + public abstract void acquire0(); + + public void whileAlive(Runnable action) { + Objects.requireNonNull(action); + acquire0(); + try { + action.run(); + } finally { + release0(); + } + } + + public final Thread ownerThread() { + return owner; + } + + public final boolean isAccessibleBy(Thread thread) { + Objects.requireNonNull(thread); + return owner == null || owner == thread; + } + + /** + * Returns true, if this session is still open. This method may be called in any thread. + * @return {@code true} if this session is not closed yet. + */ + public boolean isAlive() { + return state >= OPEN; + } + + /** + * This is a faster version of {@link #checkValidState()}, which is called upon memory access, and which + * relies on invariants associated with the memory session implementations (volatile access + * to the closed state bit is replaced with plain access). This method should be monomorphic, + * to avoid virtual calls in the memory access hot path. This method is not intended as general purpose method + * and should only be used in the memory access handle hot path; for liveness checks triggered by other API methods, + * please use {@link #checkValidState()}. + */ + @ForceInline + public void checkValidStateRaw() { + if (owner != null && owner != Thread.currentThread()) { + throw WRONG_THREAD; + } + if (state < OPEN) { + throw ALREADY_CLOSED; + } + } + + /** + * Checks that this session is still alive (see {@link #isAlive()}). + * @throws IllegalStateException if this session is already closed or if this is + * a confined session and this method is called outside the owner thread. + */ + public void checkValidState() { + try { + checkValidStateRaw(); + } catch (ScopedMemoryAccess.ScopedAccessError error) { + throw error.newRuntimeException(); + } + } + + public static void checkValidState(MemorySegment segment) { + ((AbstractMemorySegmentImpl)segment).sessionImpl().checkValidState(); + } + + @Override + protected Object clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + public boolean isCloseable() { + return true; + } + + /** + * Closes this session, executing any cleanup action (where provided). + * @throws IllegalStateException if this session is already closed or if this is + * a confined session and this method is called outside the owner thread. + */ + public void close() { + justClose(); + resourceList.cleanup(); + } + + abstract void justClose(); + + /** + * A list of all cleanup actions associated with a memory session. Cleanup actions are modelled as instances + * of the {@link ResourceCleanup} class, and, together, form a linked list. Depending on whether a session + * is shared or confined, different implementations of this class will be used, see {@link ConfinedSession.ConfinedResourceList} + * and {@link SharedSession.SharedResourceList}. + */ + public abstract static class ResourceList implements Runnable { + ResourceCleanup fst; + + abstract void add(ResourceCleanup cleanup); + + abstract void cleanup(); + + public final void run() { + cleanup(); // cleaner interop + } + + static void cleanup(ResourceCleanup first) { + RuntimeException pendingException = null; + ResourceCleanup current = first; + while (current != null) { + try { + current.cleanup(); + } catch (RuntimeException ex) { + if (pendingException == null) { + pendingException = ex; + } else if (ex != pendingException) { + // note: self-suppression is not supported + pendingException.addSuppressed(ex); + } + } + current = current.next; + } + if (pendingException != null) { + throw pendingException; + } + } + + public abstract static class ResourceCleanup { + ResourceCleanup next; + + public abstract void cleanup(); + + static final ResourceCleanup CLOSED_LIST = new ResourceCleanup() { + @Override + public void cleanup() { + throw new IllegalStateException("This resource list has already been closed!"); + } + }; + + static ResourceCleanup ofRunnable(Runnable cleanupAction) { + return new ResourceCleanup() { + @Override + public void cleanup() { + cleanupAction.run(); + } + }; + } + } + } + + // helper functions to centralize error handling + + static IllegalStateException tooManyAcquires() { + return new IllegalStateException("Session acquire limit exceeded"); + } + + static IllegalStateException alreadyAcquired(int acquires) { + return new IllegalStateException(String.format("Session is acquired by %d clients", acquires)); + } + + static IllegalStateException alreadyClosed() { + return new IllegalStateException("Already closed"); + } + + static WrongThreadException wrongThread() { + return new WrongThreadException("Attempted access outside owning thread"); + } + + static UnsupportedOperationException nonCloseable() { + return new UnsupportedOperationException("Attempted to close a non-closeable session"); + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/NativeMemorySegmentImpl.class b/tests/test_data/std/jdk/internal/foreign/NativeMemorySegmentImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..648c3a3c05f496f588800586957cc830964a9f86 GIT binary patch literal 2654 zcmb_d-%}e^6#i~VvLso`kEBo(OKHb8M9S9wuxbzqw6sJZNLt#`)_O@Uu#nx&>~5&| z;;VmvPd@q9mpY>zMbsJp0RJfQ+|4Fz0yx8rJF~lY@4e@o?|k36XaD}^kG}xSU@eXi zIuwLeL=a^d-zslwy6Fnr15Qb&%7R81kOn1(xRv4lax~aR9 z3|G_n)%jzs8&-~^Tc)(ij;_SfiI{@8iUd@Kb1jC3?v%8Lro-0-Lu^C1jqy-=v^7Lv zXI8pAqoNx<3<+K?+rn{*`q$*5BRx77p>%OTR}3kfRnV_u0OuISS|T?RUgWO6BO1U1 z>2?^p$-we)yoI+F45@er=NbC8_zu@oMImEq~BXlmu65&49Q$&xBFR+);hdtNui zV$E0+_5;3Fp_#sUtHdiS+}7o{KN)s6b%&HYZIn)1@N&VdP`$BLsy(M5SJCCA?FC--kSNGATy9aUk?Ij+hQZ~U>FS19(H)&~$(g3*(h;&uN~I0Lj-m19 zvNmhkB{64Kh#R7+b5ro@G^Fm`-N@M=|*8->yAm$*PpAw-Rg@W^&cqXga5n`rh^8oi;h zLhq5x$l1tX^f$1~K9oIlDL)`FoI>w6uMi&o70I7zQwOH#*-s`Q2QiG3^J^HwbqaF> zIhwuct&L!s{%rCZ@q#jMM2(3&$hkYX>+hSzJw$PzW=9b^AXgCusc@Jnm;*gh2ecBH z3dvP`Mw3y>XrA8G)NqlWG8c_*BHGej!^iud+W1@nbw`56jvCKMPnMhFxuj9V3t) z;8=To@uQYKQ>5Bcl3dbui!_s}B{IXFT6@U02fq?(ZBa>dzzlYv|J19;F&uKA) MFYtoivI4*S7ZSZoF#rGn literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/NativeMemorySegmentImpl.java b/tests/test_data/std/jdk/internal/foreign/NativeMemorySegmentImpl.java new file mode 100644 index 00000000..c2043cf4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/NativeMemorySegmentImpl.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package jdk.internal.foreign; + +import java.nio.ByteBuffer; +import java.util.Optional; + +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.ForceInline; + +/** + * Implementation for native memory segments. A native memory segment is essentially a wrapper around + * a native long address. + */ +sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl permits MappedMemorySegmentImpl { + + final long min; + + @ForceInline + NativeMemorySegmentImpl(long min, long length, boolean readOnly, MemorySessionImpl scope) { + super(length, readOnly, scope); + this.min = (Unsafe.getUnsafe().addressSize() == 4) + // On 32-bit systems, normalize the upper unused 32-bits to zero + ? min & 0x0000_0000_FFFF_FFFFL + // On 64-bit systems, all the bits are used + : min; + } + + @Override + public long address() { + return min; + } + + @Override + public Optional heapBase() { + return Optional.empty(); + } + + public final long maxByteAlignment() { + return address() == 0 + ? 1L << 62 + : Long.lowestOneBit(address()); + } + + @ForceInline + @Override + NativeMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { + return new NativeMemorySegmentImpl(min + offset, size, readOnly, scope); + } + + @Override + ByteBuffer makeByteBuffer() { + return NIO_ACCESS.newDirectByteBuffer(min, (int) this.length, null, this); + } + + @Override + public boolean isNative() { + return true; + } + + @Override + public long unsafeGetOffset() { + return min; + } + + @Override + public Object unsafeGetBase() { + return null; + } + + @Override + public long maxAlignMask() { + return 0; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/SegmentFactories$1.class b/tests/test_data/std/jdk/internal/foreign/SegmentFactories$1.class new file mode 100644 index 0000000000000000000000000000000000000000..3a7de21951ee70bb44653b8b9fb1c4561b19addb GIT binary patch literal 1353 zcma)6TTc@~6#fPlmX<|sQV~RM1xi&a;=KsgS|Sb9#0n3*nCW&33)@|?vn9cQ;;V@o zA0?vE2Y-M+%6Mk!Hk8!FO?J*)&iT%F=A1LX|NQ&~Ad6fCZD`k_8R$SK!`y!PAZ0ne z@EmTZDy}E2T_;r(yH(-%Yuxl*&k{1e$es%FwU&<(^x!%ddnK z-jN`U9i?Fy=utj;l?Jy7Sd@#_TcOT+4fLrqBS1a&g*u300E0R%8yG^2A={GMrl`8! zaZyNVxz2j^(2kQ^x8|8*!;*euk+lVPYKIJ+%a&vLD-7+4`RxdXaaG5Nfl*vzm}%+Z zV)TTuRVZfGattFIO%_#4nyD>E@`^}DaUJ72CJansiedO)iVV?;C&XD83|bzkUtXGwf6px&NMo6{xos0aD#Ek6XDCo;t!ag~-zdNI4h2ByDVsaH zjSdRcf+P{~u7Z&M3s?G7^6QQxysXWo6jH}ihNY(K4=*5uXn1PWwkmWT&lqO^&yakc z?-2?(T-Lh;6V#Fe^gw8Red=8RNK$tPl6p9h)UTw`M*k2}V7N`Q9NN)Eax^)93YHu@ zg`SLQr|3?`I!|#a`5paV0;5G5JIM%mk2^FP!F&`;xJxUBdx+H`IT28LQzy8R{0jCB zVy9^*-{GmI6IBLu7BRNpEx$Z8RCv5Mzffgc5Pg%lapD*n3gx2|C^T)8RB9yPfE2_fqM|6R5P=-HZJj0E;;bXDQ?)+} z354K)gaj9U6k=?}0n<>y!RwjP%zN`@XTSgW^cg@K^%8Q(+pt{Bp+ML;?7wL$9m!A& zzxg@{r5fmFR}O|!N87@Sf>23Qy-RS9gkK%&p%{&1NZ9OTDuw4sW2OKvCwb4p;P|BF zpoo$U$3+<~p`EErId|nS2v53j;d;zG<&&oG?T8(}WdMA)kRhoX9qV6}t3B+Pe|mV4vjz6@W8eV-!>oxl@* zPlPJ=CqXMZP=-6plBD8K54=UNy;Q5yO$M>8V)(^BleZ4Vk>ExiYtIji(t}+Y9Rz(F zHwbH)N&Jn@#VxE59KPHMIN`YVG~4T0V{E<3=B7laF15u2;BK3~(1Yo=q*=+*vGC%a zG|`j5M7(u7TFbEQ3uC0QQ6=1)sVIe*y*)P83G4q>$eh0~9?vy(C##1QenLflO;oAG zkBF@te`PFyaFMP1?8gzOvH2d<_yGHDl5>gA0_OlMG4<#pjf!ZbvZ2II{z&!<0ft=k!9TB{}S>^J)2m?8aAvFYgt9j GD*Xgo?;|q+ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/SegmentFactories.class b/tests/test_data/std/jdk/internal/foreign/SegmentFactories.class new file mode 100644 index 0000000000000000000000000000000000000000..bfc8fc789f72f4eb691bb606addd7e83f4275beb GIT binary patch literal 6872 zcmb7J33waD75>MTyw+x&18jo>m;f=@A;dsZ0&$We+i@ZzOQ{tbY=?%mw6+z?lCzT1 z1ZWF{l)DX(0)ZANJ<^s?AVA{a5@>0G())nk_kGd(rlkMuu4GA;UEALm&CKr1``>%> z=6`P|FTe5hQ2;Gsu8INQBHIf1gjCe9_8a@h& z>apmRMnpvg<|>${VZIb}W>G;M#z?~488VW|Xd><#8I1|d3lACL;cg0vgi?CSkaCXG za6Bpn=IW71ODvHzyx|lV2%J#wpRlJh9gpk%F{7!WTS2wJ(xQ+7Jr&(3bJO(T$q2huV6>daj8?d@!8$nl8t$b&kZso*RP z^=J?{tEfg@gi0=M*6G}MBox+ThJdTNXVW?XiY#WsRl9;l zf%A$=*)H*~KSFsJIf~1BN(j=e>vhC1QLo{ea z-@yPUUpBORm^t32VFz|H%XD}z+tT6n`-3f8ynf$$5}|09id?1PYP?;b!ZebGnc-na zgq3{Wso@%2D^R7!Vu>)1w(WyUO?`CKFd4J;#8R;f*DKhq;ayU%g?Tn*oM`crfWlNV z81EWYaN|_mSD4QhpQqvm+$_o977D0u@1=p%t^&7dcsJf7a2zvH&}@krdOSVq8)(y` zq~i@UCHuvlMlz8$!-hYaOl1d-G-ec)F>B zq=PXBAI3)%?AP#7nS2`Z^md{=&sT8(k4lvulU2zqG?G=xK|G=0Nexfokie-E9?!TT&xbr%fiAzF z{E(CQiq2$6?ZcRcBY0Xs^R~8jl8Uy3e7y`T;d8Uk)yhpyC6G)ceayC|c7 z;rXWcg(Lc~Vb_Ar+pf4(c}kw{=SeFrDdV$=vVnzSHkKzU(42=EB{EAbE~f^iBT-hc z<^8O4B-IMcN#@qU<*aKW!FY@TDtdW#nGLLxw=zd`7LSC=VmUm_!{IojhVN3*5u-br zjM7cscs#*sniA-xfb+W&a-AYP?GkyCCl65CvfUi$GtaLjV#V_%T!57@=MY>bShIp)-5|` z#riYs(|Nlw@U(nb;S+O@JE(Pn;I~ZvQ#BUlU+1lJZ`Ww(v##f4s$;#6_Od2ic1Ohf?$0DoqiZ zKub~0rhdp5QdrXeG>%!rtC$`sc{{GwjXMZtETJ_ z7L22+r*=`5yT)}GCp^Z9rIzq&;saienkk@#8m+?#SZ{%?u-?_-WlLv@#^>3Smek=3 zI0Y`N_eFfknfGOUh01=FPhBXPUxu%-Czby?TdC?d998>>BvGrRs!~f^x6-U?w%v27 z6yWD?2Nwh^l@?jgs8 zydVpH z<3hO&HuOR|3b>5Rd#GnGufzIyPqdjAI(<2+G~iqKHs>9WYD*OsTzD1VnHIjufnQ5_ z_H*DbE`+~=@H*l92@ocHgz(`4`0q}F|K7ClUI)IF@a*Tnw-v$<5k5-zt%M&Ye2nnJ z1@PaW1pk9+;nzFx?SyAP2i{)@KT7y*gf|JFBz%hS$pZKvPJ;i@wD27c{6@mFp99}n z2)~2yI|+X!;jbe6)r7yQ0RG35;D0hLe8_?CCOrE&@Rt?BUqkq734a~ocM<-2!tW}8 z|LG+7pG^zjsH|42%Z-&4HClB= z?IG;pR83lG(`-AAWB+!J?x2--VlMXbLisKd>D@R7_wZ`+E-c5rxDfY|gzx9w+XLvt zgFK24A&rL_4F|X#kKi^uYI$WdPyQ}i{VT>yg|yt_19sT^wL{W-vLw9+zp+SqIWEU< z`L>Mm+weOp-a2{z_pS;m^j6IjjrJ#b3kBY2;(8+~YXV zv-B`Nv8v3@fVbATACvPu!edXF*qze}4UAL4Pg3kN^uSS^gy*PYB_`&VEj8ED zb0?wF@{*fxRs0Qqx0rhkY=x;3{(*m5My!EMjnXS?oSl$2Tj(<^@or1g;G7F4@IIKJfPbJ3pqpT9o zJb~?Fc=ieGEkszs6L*2-Xg5kKnq5@z-vlVZfABh6spSD)mi?FgembU(VfO}V7%ImE zFGCqT$3zL+R<@;V+u6F MAX_MALLOC_ALIGN ? + byteSize + (byteAlignment - 1) : + byteSize); + + if (shouldReserve) { + AbstractMemorySegmentImpl.NIO_ACCESS.reserveMemory(alignedSize, byteSize); + } + + long buf = allocateMemoryWrapper(alignedSize); + long alignedBuf = Utils.alignUp(buf, byteAlignment); + AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(buf, alignedSize, + false, sessionImpl); + sessionImpl.addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() { + @Override + public void cleanup() { + UNSAFE.freeMemory(buf); + if (shouldReserve) { + AbstractMemorySegmentImpl.NIO_ACCESS.unreserveMemory(alignedSize, byteSize); + } + } + }); + if (alignedSize != byteSize) { + long delta = alignedBuf - buf; + segment = segment.asSlice(delta, byteSize); + } + return segment; + } + + private static long allocateMemoryWrapper(long size) { + try { + return UNSAFE.allocateMemory(size); + } catch (IllegalArgumentException ex) { + throw new OutOfMemoryError(); + } + } + + public static MemorySegment mapSegment(long size, UnmapperProxy unmapper, boolean readOnly, MemorySessionImpl sessionImpl) { + ensureInitialized(); + if (unmapper != null) { + AbstractMemorySegmentImpl segment = + new MappedMemorySegmentImpl(unmapper.address(), unmapper, size, + readOnly, sessionImpl); + MemorySessionImpl.ResourceList.ResourceCleanup resource = + new MemorySessionImpl.ResourceList.ResourceCleanup() { + @Override + public void cleanup() { + unmapper.unmap(); + } + }; + sessionImpl.addOrCleanupIfFail(resource); + return segment; + } else { + return new MappedMemorySegmentImpl(0, null, 0, readOnly, sessionImpl); + } + } + + // The method below needs to be called before any concrete subclass of MemorySegment + // is instantiated. This is to make sure that we cannot have an initialization deadlock + // where one thread attempts to initialize e.g. MemorySegment (and then NativeMemorySegmentImpl, via + // the MemorySegment.NULL field) while another thread is attempting to initialize + // NativeMemorySegmentImpl (and then MemorySegment, the super-interface). + @ForceInline + private static void ensureInitialized() { + MemorySegment segment = MemorySegment.NULL; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/SharedSession$SharedResourceList.class b/tests/test_data/std/jdk/internal/foreign/SharedSession$SharedResourceList.class new file mode 100644 index 0000000000000000000000000000000000000000..de3f33daa3696f11d32113074717d844c86d5ea7 GIT binary patch literal 2363 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 L6?lxNGhP1zq?}r_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/StringSupport.class b/tests/test_data/std/jdk/internal/foreign/StringSupport.class new file mode 100644 index 0000000000000000000000000000000000000000..09aba84fb3d0ff2542e999c84e05d080987806e4 GIT binary patch literal 7201 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/StringSupport.java b/tests/test_data/std/jdk/internal/foreign/StringSupport.java new file mode 100644 index 00000000..b74d09be --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/StringSupport.java @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.foreign; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.util.ArraysSupport; +import sun.security.action.GetPropertyAction; + +import java.lang.foreign.MemorySegment; +import java.nio.charset.Charset; + +import static java.lang.foreign.ValueLayout.*; + +/** + * Miscellaneous functions to read and write strings, in various charsets. + */ +public final class StringSupport { + + static final JavaLangAccess JAVA_LANG_ACCESS = SharedSecrets.getJavaLangAccess(); + + private StringSupport() {} + + public static String read(MemorySegment segment, long offset, Charset charset) { + return switch (CharsetKind.of(charset)) { + case SINGLE_BYTE -> readByte(segment, offset, charset); + case DOUBLE_BYTE -> readShort(segment, offset, charset); + case QUAD_BYTE -> readInt(segment, offset, charset); + }; + } + + public static void write(MemorySegment segment, long offset, Charset charset, String string) { + switch (CharsetKind.of(charset)) { + case SINGLE_BYTE -> writeByte(segment, offset, charset, string); + case DOUBLE_BYTE -> writeShort(segment, offset, charset, string); + case QUAD_BYTE -> writeInt(segment, offset, charset, string); + } + } + + private static String readByte(MemorySegment segment, long offset, Charset charset) { + long len = chunkedStrlenByte(segment, offset); + byte[] bytes = new byte[(int)len]; + MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, (int)len); + return new String(bytes, charset); + } + + private static void writeByte(MemorySegment segment, long offset, Charset charset, String string) { + int bytes = copyBytes(string, segment, charset, offset); + segment.set(JAVA_BYTE, offset + bytes, (byte)0); + } + + private static String readShort(MemorySegment segment, long offset, Charset charset) { + long len = chunkedStrlenShort(segment, offset); + byte[] bytes = new byte[(int)len]; + MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, (int)len); + return new String(bytes, charset); + } + + private static void writeShort(MemorySegment segment, long offset, Charset charset, String string) { + int bytes = copyBytes(string, segment, charset, offset); + segment.set(JAVA_SHORT_UNALIGNED, offset + bytes, (short)0); + } + + private static String readInt(MemorySegment segment, long offset, Charset charset) { + long len = strlenInt(segment, offset); + byte[] bytes = new byte[(int)len]; + MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, (int)len); + return new String(bytes, charset); + } + + private static void writeInt(MemorySegment segment, long offset, Charset charset, String string) { + int bytes = copyBytes(string, segment, charset, offset); + segment.set(JAVA_INT_UNALIGNED, offset + bytes, 0); + } + + /** + * {@return the shortest distance beginning at the provided {@code start} + * to the encountering of a zero byte in the provided {@code segment}} + *

+ * The method divides the region of interest into three distinct regions: + *

    + *
  • head (access made on a byte-by-byte basis) (if any)
  • + *
  • body (access made with eight bytes at a time at physically 64-bit-aligned memory) (if any)
  • + *
  • tail (access made on a byte-by-byte basis) (if any)
  • + *
+ *

+ * The body is using a heuristic method to determine if a long word + * contains a zero byte. The method might have false positives but + * never false negatives. + *

+ * This method is inspired by the `glibc/string/strlen.c` implementation + * + * @param segment to examine + * @param start from where examination shall begin + * @throws IllegalArgumentException if the examined region contains no zero bytes + * within a length that can be accepted by a String + */ + public static int chunkedStrlenByte(MemorySegment segment, long start) { + + // Handle the first unaligned "head" bytes separately + int headCount = (int)SharedUtils.remainsToAlignment(segment.address() + start, Long.BYTES); + + int offset = 0; + for (; offset < headCount; offset++) { + byte curr = segment.get(JAVA_BYTE, start + offset); + if (curr == 0) { + return offset; + } + } + + // We are now on a long-aligned boundary so this is the "body" + int bodyCount = bodyCount(segment.byteSize() - start - headCount); + + for (; offset < bodyCount; offset += Long.BYTES) { + // We know we are `long` aligned so, we can save on alignment checking here + long curr = segment.get(JAVA_LONG_UNALIGNED, start + offset); + // Is this a candidate? + if (mightContainZeroByte(curr)) { + for (int j = 0; j < 8; j++) { + if (segment.get(JAVA_BYTE, start + offset + j) == 0) { + return offset + j; + } + } + } + } + + // Handle the "tail" + return requireWithinArraySize((long) offset + strlenByte(segment, start + offset)); + } + + /* Bits 63 and N * 8 (N = 1..7) of this number are zero. Call these bits + the "holes". Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111110 11111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE FFFFFFFF GGGGGGGG HHHHHHHH + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. + */ + private static final long HIMAGIC_FOR_BYTES = 0x8080_8080_8080_8080L; + private static final long LOMAGIC_FOR_BYTES = 0x0101_0101_0101_0101L; + + static boolean mightContainZeroByte(long l) { + return ((l - LOMAGIC_FOR_BYTES) & (~l) & HIMAGIC_FOR_BYTES) != 0; + } + + private static final long HIMAGIC_FOR_SHORTS = 0x8000_8000_8000_8000L; + private static final long LOMAGIC_FOR_SHORTS = 0x0001_0001_0001_0001L; + + static boolean mightContainZeroShort(long l) { + return ((l - LOMAGIC_FOR_SHORTS) & (~l) & HIMAGIC_FOR_SHORTS) != 0; + } + + static int requireWithinArraySize(long size) { + if (size > ArraysSupport.SOFT_MAX_ARRAY_LENGTH) { + throw newIaeStringTooLarge(); + } + return (int) size; + } + + static int bodyCount(long remaining) { + return (int) Math.min( + // Make sure we do not wrap around + Integer.MAX_VALUE - Long.BYTES, + // Remaining bytes to consider + remaining) + & -Long.BYTES; // Mask 0xFFFFFFF8 + } + + private static int strlenByte(MemorySegment segment, long start) { + for (int offset = 0; offset < ArraysSupport.SOFT_MAX_ARRAY_LENGTH; offset += 1) { + byte curr = segment.get(JAVA_BYTE, start + offset); + if (curr == 0) { + return offset; + } + } + throw newIaeStringTooLarge(); + } + + /** + * {@return the shortest distance beginning at the provided {@code start} + * to the encountering of a zero short in the provided {@code segment}} + *

+ * Note: The inspected region must be short aligned. + * + * @see #chunkedStrlenByte(MemorySegment, long) for more information + * + * @param segment to examine + * @param start from where examination shall begin + * @throws IllegalArgumentException if the examined region contains no zero shorts + * within a length that can be accepted by a String + */ + public static int chunkedStrlenShort(MemorySegment segment, long start) { + + // Handle the first unaligned "head" bytes separately + int headCount = (int)SharedUtils.remainsToAlignment(segment.address() + start, Long.BYTES); + + int offset = 0; + for (; offset < headCount; offset += Short.BYTES) { + short curr = segment.get(JAVA_SHORT_UNALIGNED, start + offset); + if (curr == 0) { + return offset; + } + } + + // We are now on a long-aligned boundary so this is the "body" + int bodyCount = bodyCount(segment.byteSize() - start - headCount); + + for (; offset < bodyCount; offset += Long.BYTES) { + // We know we are `long` aligned so, we can save on alignment checking here + long curr = segment.get(JAVA_LONG_UNALIGNED, start + offset); + // Is this a candidate? + if (mightContainZeroShort(curr)) { + for (int j = 0; j < Long.BYTES; j += Short.BYTES) { + if (segment.get(JAVA_SHORT_UNALIGNED, start + offset + j) == 0) { + return offset + j; + } + } + } + } + + // Handle the "tail" + return requireWithinArraySize((long) offset + strlenShort(segment, start + offset)); + } + + private static int strlenShort(MemorySegment segment, long start) { + for (int offset = 0; offset < ArraysSupport.SOFT_MAX_ARRAY_LENGTH; offset += Short.BYTES) { + short curr = segment.get(JAVA_SHORT_UNALIGNED, start + offset); + if (curr == (short)0) { + return offset; + } + } + throw newIaeStringTooLarge(); + } + + // The gain of using `long` wide operations for `int` is lower than for the two other `byte` and `short` variants + // so, there is only one method for ints. + public static int strlenInt(MemorySegment segment, long start) { + for (int offset = 0; offset < ArraysSupport.SOFT_MAX_ARRAY_LENGTH; offset += Integer.BYTES) { + // We are guaranteed to be aligned here so, we can use unaligned access. + int curr = segment.get(JAVA_INT_UNALIGNED, start + offset); + if (curr == 0) { + return offset; + } + } + throw newIaeStringTooLarge(); + } + + public enum CharsetKind { + SINGLE_BYTE(1), + DOUBLE_BYTE(2), + QUAD_BYTE(4); + + final int terminatorCharSize; + + CharsetKind(int terminatorCharSize) { + this.terminatorCharSize = terminatorCharSize; + } + + public int terminatorCharSize() { + return terminatorCharSize; + } + + public static CharsetKind of(Charset charset) { + // Comparing the charset to specific internal implementations avoids loading the class `StandardCharsets` + if (charset == sun.nio.cs.UTF_8.INSTANCE || + charset == sun.nio.cs.ISO_8859_1.INSTANCE || + charset == sun.nio.cs.US_ASCII.INSTANCE) { + return SINGLE_BYTE; + } else if (charset instanceof sun.nio.cs.UTF_16LE || + charset instanceof sun.nio.cs.UTF_16BE || + charset instanceof sun.nio.cs.UTF_16) { + return DOUBLE_BYTE; + } else if (charset instanceof sun.nio.cs.UTF_32LE || + charset instanceof sun.nio.cs.UTF_32BE || + charset instanceof sun.nio.cs.UTF_32) { + return QUAD_BYTE; + } else { + throw new IllegalArgumentException("Unsupported charset: " + charset); + } + } + } + + public static boolean bytesCompatible(String string, Charset charset) { + return JAVA_LANG_ACCESS.bytesCompatible(string, charset); + } + + public static int copyBytes(String string, MemorySegment segment, Charset charset, long offset) { + if (bytesCompatible(string, charset)) { + copyToSegmentRaw(string, segment, offset); + return string.length(); + } else { + byte[] bytes = string.getBytes(charset); + MemorySegment.copy(bytes, 0, segment, JAVA_BYTE, offset, bytes.length); + return bytes.length; + } + } + + public static void copyToSegmentRaw(String string, MemorySegment segment, long offset) { + JAVA_LANG_ACCESS.copyToSegmentRaw(string, segment, offset); + } + + private static IllegalArgumentException newIaeStringTooLarge() { + return new IllegalArgumentException("String too large"); + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/SystemLookup$1.class b/tests/test_data/std/jdk/internal/foreign/SystemLookup$1.class new file mode 100644 index 0000000000000000000000000000000000000000..e97b6884768ecf5f1661cbf50390cf7960f71649 GIT binary patch literal 900 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/SystemLookup.class b/tests/test_data/std/jdk/internal/foreign/SystemLookup.class new file mode 100644 index 0000000000000000000000000000000000000000..4a88a283a1f824808e8506741c6706f50a924bac GIT binary patch literal 8339 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 Y3_j)0D(gZ1)#CEClf*WpL>KD+54S4}IsgCw literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/SystemLookup.java b/tests/test_data/std/jdk/internal/foreign/SystemLookup.java new file mode 100644 index 00000000..98e02140 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/SystemLookup.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.foreign; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandles; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import jdk.internal.loader.NativeLibrary; +import jdk.internal.loader.RawNativeLibraries; +import sun.security.action.GetPropertyAction; + +import static java.lang.foreign.ValueLayout.ADDRESS; + +public final class SystemLookup implements SymbolLookup { + + private SystemLookup() { } + + private static final SystemLookup INSTANCE = new SystemLookup(); + + /* A fallback lookup, used when creation of system lookup fails. */ + private static final SymbolLookup FALLBACK_LOOKUP = name -> { + Objects.requireNonNull(name); + return Optional.empty(); + }; + + /* + * On POSIX systems, dlsym will allow us to lookup symbol in library dependencies; the same trick doesn't work + * on Windows. For this reason, on Windows we do not generate any side-library, and load msvcrt.dll directly instead. + */ + private static final SymbolLookup SYSTEM_LOOKUP = makeSystemLookup(); + + private static SymbolLookup makeSystemLookup() { + try { + if (Utils.IS_WINDOWS) { + return makeWindowsLookup(); + } else { + return libLookup(libs -> libs.load(jdkLibraryPath("syslookup"))); + } + } catch (Throwable ex) { + // This can happen in the event of a library loading failure - e.g. if one of the libraries the + // system lookup depends on cannot be loaded for some reason. In such extreme cases, rather than + // fail, return a dummy lookup. + return FALLBACK_LOOKUP; + } + } + + private static SymbolLookup makeWindowsLookup() { + @SuppressWarnings("removal") + String systemRoot = AccessController.doPrivileged(new PrivilegedAction<>() { + @Override + public String run() { + return System.getenv("SystemRoot"); + } + }); + Path system32 = Path.of(systemRoot, "System32"); + Path ucrtbase = system32.resolve("ucrtbase.dll"); + Path msvcrt = system32.resolve("msvcrt.dll"); + + @SuppressWarnings("removal") + boolean useUCRT = AccessController.doPrivileged(new PrivilegedAction<>() { + @Override + public Boolean run() { + return Files.exists(ucrtbase); + } + }); + Path stdLib = useUCRT ? ucrtbase : msvcrt; + SymbolLookup lookup = libLookup(libs -> libs.load(stdLib)); + + if (useUCRT) { + // use a fallback lookup to look up inline functions from fallback lib + + SymbolLookup fallbackLibLookup = + libLookup(libs -> libs.load(jdkLibraryPath("syslookup"))); + + @SuppressWarnings("restricted") + MemorySegment funcs = fallbackLibLookup.findOrThrow("funcs") + .reinterpret(WindowsFallbackSymbols.LAYOUT.byteSize()); + + Function> fallbackLookup = name -> Optional.ofNullable(WindowsFallbackSymbols.valueOfOrNull(name)) + .map(symbol -> funcs.getAtIndex(ADDRESS, symbol.ordinal())); + + final SymbolLookup finalLookup = lookup; + lookup = name -> { + Objects.requireNonNull(name); + if (Utils.containsNullChars(name)) return Optional.empty(); + return finalLookup.find(name).or(() -> fallbackLookup.apply(name)); + }; + } + + return lookup; + } + + private static SymbolLookup libLookup(Function loader) { + NativeLibrary lib = loader.apply(RawNativeLibraries.newInstance(MethodHandles.lookup())); + return name -> { + Objects.requireNonNull(name); + if (Utils.containsNullChars(name)) return Optional.empty(); + try { + long addr = lib.lookup(name); + return addr == 0 ? + Optional.empty() : + Optional.of(MemorySegment.ofAddress(addr)); + } catch (NoSuchMethodException e) { + return Optional.empty(); + } + }; + } + + /* + * Returns the path of the given library name from JDK + */ + private static Path jdkLibraryPath(String name) { + Path javahome = Path.of(GetPropertyAction.privilegedGetProperty("java.home")); + String lib = Utils.IS_WINDOWS ? "bin" : "lib"; + String libname = System.mapLibraryName(name); + return javahome.resolve(lib).resolve(libname); + } + + + public static SystemLookup getInstance() { + return INSTANCE; + } + + @Override + public Optional find(String name) { + return SYSTEM_LOOKUP.find(name); + } + + // fallback symbols missing from ucrtbase.dll + // this list has to be kept in sync with the table in the companion native library + private enum WindowsFallbackSymbols { + // stdio + fprintf, + fprintf_s, + fscanf, + fscanf_s, + fwprintf, + fwprintf_s, + fwscanf, + fwscanf_s, + printf, + printf_s, + scanf, + scanf_s, + snprintf, + sprintf, + sprintf_s, + sscanf, + sscanf_s, + swprintf, + swprintf_s, + swscanf, + swscanf_s, + vfprintf, + vfprintf_s, + vfscanf, + vfscanf_s, + vfwprintf, + vfwprintf_s, + vfwscanf, + vfwscanf_s, + vprintf, + vprintf_s, + vscanf, + vscanf_s, + vsnprintf, + vsnprintf_s, + vsprintf, + vsprintf_s, + vsscanf, + vsscanf_s, + vswprintf, + vswprintf_s, + vswscanf, + vswscanf_s, + vwprintf, + vwprintf_s, + vwscanf, + vwscanf_s, + wprintf, + wprintf_s, + wscanf, + wscanf_s, + + // time + gmtime; + + static WindowsFallbackSymbols valueOfOrNull(String name) { + try { + return valueOf(name); + } catch (IllegalArgumentException e) { + return null; + } + } + + static final SequenceLayout LAYOUT = MemoryLayout.sequenceLayout( + values().length, ADDRESS); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/Utils$1VarHandleCache.class b/tests/test_data/std/jdk/internal/foreign/Utils$1VarHandleCache.class new file mode 100644 index 0000000000000000000000000000000000000000..0dd837019ef40a5c9541b5096b2b091ab94e81ad GIT binary patch literal 797 zcma)4+iuf95Iviub>f&Nlsn;8icni249^LbDpM3BCm>QH@lccWXM%2LjKXDw!IXV`pC?MUud^?iMkS)F|js6sYO3sj6{6EM~aa3 z&_rBOvdsK5uwth&VR#h&e{-Z!?L_KqvhKj7aU@>IOv25l@i^<2D%jVNGKtiap0HCh zc5sW~=D&43+`(Oj)`HK)8-6?xlLhT&D8+HnAj7k*rT+gmp6#XhAM>Hg`y#PjlhEhz zUTQ7kK=C9IG=jB4C0`+)(DqC8(WvHZ|74rwm2fdf>BkYWPKZyIkzLt20sEAvT%t1z z19M!a(>qPT6q=gN# LF6GzB-beE%3YEx_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/Utils$BaseAndScale.class b/tests/test_data/std/jdk/internal/foreign/Utils$BaseAndScale.class new file mode 100644 index 0000000000000000000000000000000000000000..0d21a6f92b2ab7acea88275918d55363c3d413a9 GIT binary patch literal 3610 zcmb_e`F9&d68_qbJ+f%Wu^|_MM1+LcauSh*g%H^W$p@BExh?_-z4+z>%*a5$FZr~Q-mJ=m?D9@`^1WoC+o!EjY`df8ej7H?U}Y9dEB zacst=3}N?FLCfByySXWb4d>BMwRi?z#&J2elGVwP!EOdZU7eqC;a!B|3QxJSH!&a> zS90tSjGAn3|G=Q&T*a|VaH>-o@4ba1>PhsZ`x72#H^&|iB;B96NvOm)t`>~iuKuB9 zx?911hV9G#rwl`zRE>l^S)9>KxBFyHE4aF4D!7JWHw^QuLaB*|+96crhbfQZ^H%AX{VrW=)$ycf;{j5GyFtm(1 zL#cL28HjJ7@Fd02Cm=$uCAnejLs}HTVTSeR^J=&W4E;jw2tzwbtTG#dUibzGqydgB z2FZXa)tTzF@?`Ap{{u87Forpf;#N8iDhk!0n02fkVP%c9jMiZk#}wSgal0t&O=T|5 z=uR#+WIE~unYtk{FpwA-6O}QROk}&q`g?k^-ITPW7~{A@Xa_}7nXc|z$FiM?ba$B2 zcwEFeN43zL>J!(=C^U|VfRZShO57<9y;3BAD^R963?Z^nTIW?-C5*{ot&pj}xs$^d zGV3J{)n_G&%TcV5sKB_3<78kTucj+e?&i2>g-iv`eH`}-89$ujCa8q@6UUz`MJiDK z!tqxjvPpU*ua8QchdCZuDHK4WyHI9oLs~brOmSvhvj^32akV$4ExN{sRa+PDK68yb zrBha}JFK}=R{n@;Q%zEvAXb$%A&Y3K(=6ZJtE?+ZAMbt=doSMuJ`6*B)>U)Uht+~_ z3pK7(MP)B;IZ7?b@>*LT)ni-E@Oxc2YZdLB)}spt!(Kz%D|RBGjOMt#mg6dTmEqE| zIw@;_RGW(}bY0T2T*tN5f((bF;7tm|v7~~32->OOZ9%gN-W4>ZU{=r`1s@37r{E(& zyF&Pc%n_|L?zPSa28C9ALoLpPQNkArz7(zQY*}xxi>9m3XffINmTaN3csO|5>E;P* zT8l{&dsQ=UXwHtbWla|g@j#gUi!8t?QyioY8$TBKcQMofmaovM8b(%kwK$nSAI4Ys zTEPOxIef#gZTVam&6hxa1R3ha7lX=h=J)hNc+jOeIa@EdmK}6mcA|hIek_9SmIXsb zv8*jFWhqaYre=GP8XW}>&PxjZ#jtZZ1m^)=JQ@W*GHkuDD5au2M{0B-8u)-Znzv|z zqo*b@iV@u`CLWK{@ZwRLSv*RUibrWe@hHtD9;I=FXo#8--ROjRn%)kh8f%C)MCZYx zTh2m>M$V%C46&;4H~Ot5aj>2EJ3U88m_+fY2PB?^N%TKG38Sj;7(Lfj5nHf?)sN!| z5)eE6hxQTbr=ufZq48+Cy1n(X1#AR9Bqn`^C7}(0-L&@8I!LR7Ru`>4T1QIQGK=04 zw#_10!uDCTm9TRb*Ot&ci>pg$okg^Sy|dVH4*N#V;lRi|{?K&o91ce3&^Cu8JrNS9CJNjybw zPt)3p@GoM_ZfE;zEJh6R6GEdHVEj1jBPv3sL>G_&gc&O%Ew@noNH@~>@yvPD zZvj4DmHJUU>#MiXW+I1`12xevp^pi-@;;3sVUAAvbql>h($ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/Utils.class b/tests/test_data/std/jdk/internal/foreign/Utils.class new file mode 100644 index 0000000000000000000000000000000000000000..b471d734b734c2d0e5d8eaf41243612439aae52a GIT binary patch literal 11419 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 l*mtk;>-;8v594RT1!iE44}b$(aDeq8`s(M^Zh literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/Utils.java b/tests/test_data/std/jdk/internal/foreign/Utils.java new file mode 100644 index 00000000..2ed65e3d --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/Utils.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package jdk.internal.foreign; + +import java.lang.foreign.AddressLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemoryLayout.PathElement; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.StructLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +import jdk.internal.access.SharedSecrets; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.ForceInline; +import sun.invoke.util.Wrapper; + +import static sun.security.action.GetPropertyAction.privilegedGetProperty; + +/** + * This class contains misc helper functions to support creation of memory segments. + */ +public final class Utils { + + public static final boolean IS_WINDOWS = privilegedGetProperty("os.name").startsWith("Windows"); + + // Suppresses default constructor, ensuring non-instantiability. + private Utils() {} + + private static final MethodHandle BYTE_TO_BOOL; + private static final MethodHandle BOOL_TO_BYTE; + private static final MethodHandle ADDRESS_TO_LONG; + private static final MethodHandle LONG_TO_ADDRESS; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + BYTE_TO_BOOL = lookup.findStatic(Utils.class, "byteToBoolean", + MethodType.methodType(boolean.class, byte.class)); + BOOL_TO_BYTE = lookup.findStatic(Utils.class, "booleanToByte", + MethodType.methodType(byte.class, boolean.class)); + ADDRESS_TO_LONG = lookup.findStatic(SharedUtils.class, "unboxSegment", + MethodType.methodType(long.class, MemorySegment.class)); + LONG_TO_ADDRESS = lookup.findStatic(Utils.class, "longToAddress", + MethodType.methodType(MemorySegment.class, long.class, long.class, long.class)); + } catch (Throwable ex) { + throw new ExceptionInInitializerError(ex); + } + } + + public static long alignUp(long n, long alignment) { + return (n + alignment - 1) & -alignment; + } + + public static MemorySegment alignUp(MemorySegment ms, long alignment) { + long offset = ms.address(); + return ms.asSlice(alignUp(offset, alignment) - offset); + } + + /** + * This method returns a raw var handle, that is, a var handle that does not perform any size + * or alignment checks. Such checks are added (using adaptation) by {@link LayoutPath#dereferenceHandle()}. + *

+ * We provide two level of caching of the generated var handles. First, the var handle associated + * with a {@link ValueLayout#varHandle()} call is cached inside a stable field of the value layout implementation. + * This optimizes common code idioms like {@code JAVA_INT.varHandle().getInt(...)}. A second layer of caching + * is then provided by this method: after all, var handles constructed by {@link MemoryLayout#varHandle(PathElement...)} + * will be obtained by adapting some raw var handle generated by this method. + * + * @param layout the value layout for which a raw memory segment var handle is to be created. + * @return a raw memory segment var handle. + */ + public static VarHandle makeRawSegmentViewVarHandle(ValueLayout layout) { + final class VarHandleCache { + private static final Map HANDLE_MAP = new ConcurrentHashMap<>(); + } + return VarHandleCache.HANDLE_MAP + .computeIfAbsent(layout.withoutName(), Utils::makeRawSegmentViewVarHandleInternal); + } + + private static VarHandle makeRawSegmentViewVarHandleInternal(ValueLayout layout) { + Class baseCarrier = layout.carrier(); + if (layout.carrier() == MemorySegment.class) { + baseCarrier = switch ((int) ValueLayout.ADDRESS.byteSize()) { + case Long.BYTES -> long.class; + case Integer.BYTES -> int.class; + default -> throw new UnsupportedOperationException("Unsupported address layout"); + }; + } else if (layout.carrier() == boolean.class) { + baseCarrier = byte.class; + } + + VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memorySegmentViewHandle(baseCarrier, + layout.byteAlignment() - 1, layout.order()); + + if (layout.carrier() == boolean.class) { + handle = MethodHandles.filterValue(handle, BOOL_TO_BYTE, BYTE_TO_BOOL); + } else if (layout instanceof AddressLayout addressLayout) { + handle = MethodHandles.filterValue(handle, + MethodHandles.explicitCastArguments(ADDRESS_TO_LONG, MethodType.methodType(baseCarrier, MemorySegment.class)), + MethodHandles.explicitCastArguments(MethodHandles.insertArguments(LONG_TO_ADDRESS, 1, + pointeeByteSize(addressLayout), pointeeByteAlign(addressLayout)), + MethodType.methodType(MemorySegment.class, baseCarrier))); + } + return handle; + } + + public static boolean byteToBoolean(byte b) { + return b != 0; + } + + private static byte booleanToByte(boolean b) { + return b ? (byte)1 : (byte)0; + } + + @ForceInline + public static MemorySegment longToAddress(long addr, long size, long align) { + if (!isAligned(addr, align)) { + throw new IllegalArgumentException("Invalid alignment constraint for address: " + toHexString(addr)); + } + return SegmentFactories.makeNativeSegmentUnchecked(addr, size); + } + + @ForceInline + public static MemorySegment longToAddress(long addr, long size, long align, MemorySessionImpl scope) { + if (!isAligned(addr, align)) { + throw new IllegalArgumentException("Invalid alignment constraint for address: " + toHexString(addr)); + } + return SegmentFactories.makeNativeSegmentUnchecked(addr, size, scope); + } + + @ForceInline + public static boolean isAligned(long offset, long align) { + return (offset & (align - 1)) == 0; + } + + @ForceInline + public static boolean isElementAligned(ValueLayout layout) { + // Fast-path: if both size and alignment are powers of two, we can just + // check if one is greater than the other. + assert isPowerOfTwo(layout.byteSize()); + return layout.byteAlignment() <= layout.byteSize(); + } + + @ForceInline + public static void checkElementAlignment(ValueLayout layout, String msg) { + if (!isElementAligned(layout)) { + throw new IllegalArgumentException(msg); + } + } + + @ForceInline + public static void checkElementAlignment(MemoryLayout layout, String msg) { + if (layout.byteSize() % layout.byteAlignment() != 0) { + throw new IllegalArgumentException(msg); + } + } + + public static long pointeeByteSize(AddressLayout addressLayout) { + return addressLayout.targetLayout() + .map(MemoryLayout::byteSize) + .orElse(0L); + } + + public static long pointeeByteAlign(AddressLayout addressLayout) { + return addressLayout.targetLayout() + .map(MemoryLayout::byteAlignment) + .orElse(1L); + } + + public static void checkAllocationSizeAndAlign(long byteSize, long byteAlignment) { + // byteSize should be >= 0 + Utils.checkNonNegativeArgument(byteSize, "allocation size"); + checkAlign(byteAlignment); + } + + public static void checkAlign(long byteAlignment) { + // alignment should be > 0, and power of two + if (byteAlignment <= 0 || + ((byteAlignment & (byteAlignment - 1)) != 0L)) { + throw new IllegalArgumentException("Invalid alignment constraint : " + byteAlignment); + } + } + + @ForceInline + public static void checkNonNegativeArgument(long value, String name) { + if (value < 0) { + throw new IllegalArgumentException("The provided " + name + " is negative: " + value); + } + } + + @ForceInline + public static void checkNonNegativeIndex(long value, String name) { + if (value < 0) { + throw new IndexOutOfBoundsException("The provided " + name + " is negative: " + value); + } + } + + private static long computePadding(long offset, long align) { + boolean isAligned = offset == 0 || offset % align == 0; + if (isAligned) { + return 0; + } else { + long gap = offset % align; + return align - gap; + } + } + + /** + * {@return return a struct layout constructed from the given elements, with padding + * computed automatically so that they are naturally aligned}. + * + * @param elements the structs' fields + */ + public static StructLayout computePaddedStructLayout(MemoryLayout... elements) { + long offset = 0L; + List layouts = new ArrayList<>(); + long align = 0; + for (MemoryLayout l : elements) { + long padding = computePadding(offset, l.byteAlignment()); + if (padding != 0) { + layouts.add(MemoryLayout.paddingLayout(padding)); + offset += padding; + } + layouts.add(l); + align = Math.max(align, l.byteAlignment()); + offset += l.byteSize(); + } + long padding = computePadding(offset, align); + if (padding != 0) { + layouts.add(MemoryLayout.paddingLayout(padding)); + } + return MemoryLayout.structLayout(layouts.toArray(MemoryLayout[]::new)); + } + + public static int byteWidthOfPrimitive(Class primitive) { + return Wrapper.forPrimitiveType(primitive).bitWidth() / 8; + } + + public static boolean isPowerOfTwo(long value) { + return (value & (value - 1)) == 0L; + } + + public static L wrapOverflow(Supplier layoutSupplier) { + try { + return layoutSupplier.get(); + } catch (ArithmeticException ex) { + throw new IllegalArgumentException("Layout size exceeds Long.MAX_VALUE"); + } + } + + public static boolean containsNullChars(String s) { + return s.indexOf('\u0000') >= 0; + } + + public static String toHexString(long value) { + return "0x" + Long.toHexString(value); + } + + public record BaseAndScale(int base, long scale) { + + public static final BaseAndScale BYTE = + new BaseAndScale(Unsafe.ARRAY_BYTE_BASE_OFFSET, Unsafe.ARRAY_BYTE_INDEX_SCALE); + public static final BaseAndScale CHAR = + new BaseAndScale(Unsafe.ARRAY_CHAR_BASE_OFFSET, Unsafe.ARRAY_CHAR_INDEX_SCALE); + public static final BaseAndScale SHORT = + new BaseAndScale(Unsafe.ARRAY_SHORT_BASE_OFFSET, Unsafe.ARRAY_SHORT_INDEX_SCALE); + public static final BaseAndScale INT = + new BaseAndScale(Unsafe.ARRAY_INT_BASE_OFFSET, Unsafe.ARRAY_INT_INDEX_SCALE); + public static final BaseAndScale FLOAT = + new BaseAndScale(Unsafe.ARRAY_FLOAT_BASE_OFFSET, Unsafe.ARRAY_FLOAT_INDEX_SCALE); + public static final BaseAndScale LONG = + new BaseAndScale(Unsafe.ARRAY_LONG_BASE_OFFSET, Unsafe.ARRAY_LONG_INDEX_SCALE); + public static final BaseAndScale DOUBLE = + new BaseAndScale(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, Unsafe.ARRAY_DOUBLE_INDEX_SCALE); + + public static BaseAndScale of(Object array) { + return switch (array) { + case byte[] _ -> BaseAndScale.BYTE; + case char[] _ -> BaseAndScale.CHAR; + case short[] _ -> BaseAndScale.SHORT; + case int[] _ -> BaseAndScale.INT; + case float[] _ -> BaseAndScale.FLOAT; + case long[] _ -> BaseAndScale.LONG; + case double[] _ -> BaseAndScale.DOUBLE; + default -> throw new IllegalArgumentException("Not a supported array class: " + array.getClass().getSimpleName()); + }; + } + + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ABIDescriptor.class b/tests/test_data/std/jdk/internal/foreign/abi/ABIDescriptor.class new file mode 100644 index 0000000000000000000000000000000000000000..ed0bd631540535545523c803c45ae0ee29f5765e GIT binary patch literal 1596 zcmd5+TTc@~6#fQ!?*IisU2lkTX}7=%DySgZf+kHs6Kndy({#JE3uU+2PBHOUY2wDj z2Y-M+%6Mj4LnW=@!3SUFoSAc-Z_YPAet!E7U>BPyj9@g52uBn#hRm@z6IN4rb?a^Q z*s&!;Y}@r*xx+A;%~g^}AQ?xBBMr{5cw9TNTu(ZICz{rgA2@E^vqaUk3dPc%)3yV* zCH;UQA_BX?u(UrsfE-*&6+3~mrOJ$ROd!L+U9Z)VWlAIJ4wXDS9G;|d(DTz7rZ}#s z3}b#ro~KZ`XE?4Z%fy-A6w+-vy)b3F&SBsN!+2W?`=rpM8=X2H0l`Yje2e3@GN;=O zQS(2PTf%nK`7Fm>%rPYB(n8veHHP`iHhQ09zCU(dC0yiKQiqdL1a(IiYPF!R%N&QP zt$`zpoudoZWsVhPowh|w0a`0dA%9A>V9mxn7{U@umS^(ozO;y=5zk-?h5OH%k#F)7fV$w7sA*RilXozd(Of1Ar(};(- zV;YGN_e>)hV!|N_2llGB7xQG5BC$@MGQI#xE6jV+jBN literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ABIDescriptor.java b/tests/test_data/std/jdk/internal/foreign/abi/ABIDescriptor.java new file mode 100644 index 00000000..b25280ed --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/ABIDescriptor.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +/** + * Carrier class used to communicate with the VM + * + * It is particularly low-level since the VM will be accessing these fields directly + */ +public class ABIDescriptor { + final Architecture arch; + + public final VMStorage[][] inputStorage; + public final VMStorage[][] outputStorage; + + final VMStorage[][] volatileStorage; + + final int stackAlignment; + final int shadowSpace; + + final VMStorage scratch1; + final VMStorage scratch2; + + final VMStorage targetAddrStorage; + final VMStorage retBufAddrStorage; + final VMStorage capturedStateStorage; + + public ABIDescriptor(Architecture arch, VMStorage[][] inputStorage, VMStorage[][] outputStorage, + VMStorage[][] volatileStorage, int stackAlignment, int shadowSpace, + VMStorage scratch1, VMStorage scratch2, + VMStorage targetAddrStorage, VMStorage retBufAddrStorage, + VMStorage capturedStateStorage) { + this.arch = arch; + this.inputStorage = inputStorage; + this.outputStorage = outputStorage; + this.volatileStorage = volatileStorage; + this.stackAlignment = stackAlignment; + this.shadowSpace = shadowSpace; + this.scratch1 = scratch1; + this.scratch2 = scratch2; + this.targetAddrStorage = targetAddrStorage; + this.retBufAddrStorage = retBufAddrStorage; + this.capturedStateStorage = capturedStateStorage; + } + + public VMStorage targetAddrStorage() { + return targetAddrStorage; + } + + public VMStorage retBufAddrStorage() { + return retBufAddrStorage; + } + + public VMStorage capturedStateStorage() { + return capturedStateStorage; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker$LinkRequest.class b/tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker$LinkRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..a1d0bc0423da0e943d8ccb6a14d66023ae84acd5 GIT binary patch literal 1941 zcmbVNTT|0e5dKb~O@Tn6Toh11<<^2kL=-KeT!x`qK!M>wpVIb7LrYFgQfB;5KFExW zGd%bM{85g3l9Z-n+hKTUPR?fc+ud(3{qy(gH-JrSbs~f|1??)rh%oe?>gT#v(#;d? zfaipjXNasCrs1qHw9O`tI}k;Of=(4(P#Km^^F_@t9d4O=N&6x!Zk(8!o;9@ftnFBO z&dC^Nkz14UIN)C^+;$i`^W4r^M%fV-!*r(RvI?+WF>{U~%&lv^lyuyqB8FZDMU>@N zn_)K7Gyu=>zNeXrQ?_vx{TN_~I^xi=4D*B`-2$L_2B}0KW)I4BFr?xR?vjIoZWlI1 zo-?f6(m`4VJfdP0_oxCyoL-`I-`x%^5bb{Ul;@mO;uFJ10=q7D3+8W1apIVv-OD;g z#O{q;F6$T+Bl z_GnUegzYHM7-pJ6*Beu-RHwFgLkLHXVA*5Ij$(<@tW93ZAEFq|6aBhl5xnTc3SKIB zr6Pq@hVdFFR>gFTGp>2u_>c@8*{T-?GH~t z;u{`)EAzng2NX6-x@|YW_#Dt_;Jt2UuPdykO_N(LB&YW23alvwZyBa)3^c&3W~5+) zVXU<(mBvdSPiT{cXu3m)%OxrolU!?bMo1RMeR_`3ZI{kAI%COSV9B{lD9QOtbYGAt zgmG7$(ephf=sDr3;sGAgjf`Aq`90=>hwzBrJ3=IuBA}0U;Up+*dS9edsw&AVlH&)x z{_jEcRD2J8wCScAm=6NqZ)84-Y2SR6oJl^S$+;^GH?tq|bgmPOVg|E>Kt)5sN7CFo z5KjJt(khFv55tIxWCP>wn;3^N=Vm&O$L_g6l?8ezPOqw7O&47m!*jG#-JjwamhqZo Sang%o0c#k+8?4h`@$f(B$>0G1 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker$UpcallStubFactory.class b/tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker$UpcallStubFactory.class new file mode 100644 index 0000000000000000000000000000000000000000..6a619f69f2c7d9abe7c5975c4ffec6bae260b8dd GIT binary patch literal 380 zcma)2!AiqG6r9&;(#9%^zaXd=_bfS;LaET|A$an%NuF_&&93Zj3;vo1KfsR?w}PnX z!ONS+n}L}(uW!#U0A@HyF(6#FbtjYw?2Odn-a1x|5wcWbTKeE*6_(0$>`rbUE2(u6 z*5y1Nt$RwbLpW^ZMhY!WBW}u;t3Vj_vg56eaCf%+;+5Ihj>U?@gRK|R)SB~e^r!XI zv61=tAIysTXj^d8vk5sNE9}};JXe|t$3Np}Fbe o&z^Af>-mI07{(p}iZ$#aiQ5oqoCAz7{=f{Ah*?y|u-H$=@4l>WSO5S3 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker.class b/tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker.class new file mode 100644 index 0000000000000000000000000000000000000000..1f017ab1c0c1a978b25814bdbee087fb05ff3538 GIT binary patch literal 16908 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker.java b/tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker.java new file mode 100644 index 00000000..4f3baaa0 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/AbstractLinker.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +import jdk.internal.foreign.SystemLookup; +import jdk.internal.foreign.Utils; +import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker; +import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker; +import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker; +import jdk.internal.foreign.abi.fallback.FallbackLinker; +import jdk.internal.foreign.abi.ppc64.aix.AixPPC64Linker; +import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64Linker; +import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker; +import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker; +import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker; +import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker; +import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker; +import jdk.internal.foreign.layout.AbstractLayout; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; + +import java.lang.foreign.AddressLayout; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.StructLayout; +import java.lang.foreign.UnionLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.HashSet; +import java.util.List; +import java.nio.ByteOrder; +import java.util.Objects; +import java.util.Set; + +public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker, + SysVx64Linker, WindowsAArch64Linker, + Windowsx64Linker, AixPPC64Linker, + LinuxPPC64Linker, LinuxPPC64leLinker, + LinuxRISCV64Linker, LinuxS390Linker, + FallbackLinker { + + public interface UpcallStubFactory { + MemorySegment makeStub(MethodHandle target, Arena arena); + } + + private record LinkRequest(FunctionDescriptor descriptor, LinkerOptions options) {} + private final SoftReferenceCache DOWNCALL_CACHE = new SoftReferenceCache<>(); + private final SoftReferenceCache UPCALL_CACHE = new SoftReferenceCache<>(); + private final Set CANONICAL_LAYOUTS_CACHE = new HashSet<>(canonicalLayouts().values()); + + @Override + @CallerSensitive + public final MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) { + Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle"); + SharedUtils.checkSymbol(symbol); + return downcallHandle0(function, options).bindTo(symbol); + } + + @Override + @CallerSensitive + public final MethodHandle downcallHandle(FunctionDescriptor function, Option... options) { + Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle"); + return downcallHandle0(function, options); + } + + private MethodHandle downcallHandle0(FunctionDescriptor function, Option... options) { + Objects.requireNonNull(function); + Objects.requireNonNull(options); + checkLayouts(function); + function = stripNames(function); + LinkerOptions optionSet = LinkerOptions.forDowncall(function, options); + validateVariadicLayouts(function, optionSet); + + return DOWNCALL_CACHE.get(new LinkRequest(function, optionSet), linkRequest -> { + FunctionDescriptor fd = linkRequest.descriptor(); + MethodType type = fd.toMethodType(); + MethodHandle handle = arrangeDowncall(type, fd, linkRequest.options()); + handle = SharedUtils.maybeCheckCaptureSegment(handle, linkRequest.options()); + handle = SharedUtils.maybeInsertAllocator(fd, handle); + return handle; + }); + } + + protected abstract MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options); + + @Override + @CallerSensitive + public final MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options) { + Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "upcallStub"); + Objects.requireNonNull(arena); + Objects.requireNonNull(target); + Objects.requireNonNull(function); + checkLayouts(function); + SharedUtils.checkExceptions(target); + function = stripNames(function); + LinkerOptions optionSet = LinkerOptions.forUpcall(function, options); + + MethodType type = function.toMethodType(); + if (!type.equals(target.type())) { + throw new IllegalArgumentException("Wrong method handle type: " + target.type()); + } + + UpcallStubFactory factory = UPCALL_CACHE.get(new LinkRequest(function, optionSet), linkRequest -> + arrangeUpcall(type, linkRequest.descriptor(), linkRequest.options())); + return factory.makeStub(target, arena); + } + + protected abstract UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options); + + @Override + public SystemLookup defaultLookup() { + return SystemLookup.getInstance(); + } + + // C spec mandates that variadic arguments smaller than int are promoted to int, + // and float is promoted to double + // See: https://en.cppreference.com/w/c/language/conversion#Default_argument_promotions + // We reject the corresponding layouts here, to avoid issues where unsigned values + // are sign extended when promoted. (as we don't have a way to unambiguously represent signed-ness atm). + private void validateVariadicLayouts(FunctionDescriptor function, LinkerOptions optionSet) { + if (optionSet.isVariadicFunction()) { + List argumentLayouts = function.argumentLayouts(); + List variadicLayouts = argumentLayouts.subList(optionSet.firstVariadicArgIndex(), argumentLayouts.size()); + + for (MemoryLayout variadicLayout : variadicLayouts) { + if (variadicLayout.equals(ValueLayout.JAVA_BOOLEAN) + || variadicLayout.equals(ValueLayout.JAVA_BYTE) + || variadicLayout.equals(ValueLayout.JAVA_CHAR) + || variadicLayout.equals(ValueLayout.JAVA_SHORT) + || variadicLayout.equals(ValueLayout.JAVA_FLOAT)) { + throw new IllegalArgumentException("Invalid variadic argument layout: " + variadicLayout); + } + } + } + } + + private void checkLayouts(FunctionDescriptor descriptor) { + descriptor.returnLayout().ifPresent(this::checkLayout); + descriptor.argumentLayouts().forEach(this::checkLayout); + } + + private void checkLayout(MemoryLayout layout) { + // Note: we should not worry about padding layouts, as they cannot be present in a function descriptor + if (layout instanceof SequenceLayout) { + throw new IllegalArgumentException("Unsupported layout: " + layout); + } else { + checkLayoutRecursive(layout); + } + } + + // some ABIs have special handling for struct members + protected void checkStructMember(MemoryLayout member, long offset) { + checkLayoutRecursive(member); + } + + private void checkLayoutRecursive(MemoryLayout layout) { + if (layout instanceof ValueLayout vl) { + checkSupported(vl); + } else if (layout instanceof StructLayout sl) { + checkHasNaturalAlignment(layout); + long offset = 0; + long lastUnpaddedOffset = 0; + for (MemoryLayout member : sl.memberLayouts()) { + // check element offset before recursing so that an error points at the + // outermost layout first + checkMemberOffset(sl, member, lastUnpaddedOffset, offset); + checkStructMember(member, offset); + + offset += member.byteSize(); + if (!(member instanceof PaddingLayout)) { + lastUnpaddedOffset = offset; + } + } + checkGroupSize(sl, lastUnpaddedOffset); + } else if (layout instanceof UnionLayout ul) { + checkHasNaturalAlignment(layout); + long maxUnpaddedLayout = 0; + for (MemoryLayout member : ul.memberLayouts()) { + checkLayoutRecursive(member); + if (!(member instanceof PaddingLayout)) { + maxUnpaddedLayout = Long.max(maxUnpaddedLayout, member.byteSize()); + } + } + checkGroupSize(ul, maxUnpaddedLayout); + } else if (layout instanceof SequenceLayout sl) { + checkHasNaturalAlignment(layout); + checkLayoutRecursive(sl.elementLayout()); + } + } + + // check for trailing padding + private void checkGroupSize(GroupLayout gl, long maxUnpaddedOffset) { + long expectedSize = Utils.alignUp(maxUnpaddedOffset, gl.byteAlignment()); + if (gl.byteSize() != expectedSize) { + throw new IllegalArgumentException("Layout '" + gl + "' has unexpected size: " + + gl.byteSize() + " != " + expectedSize); + } + } + + // checks both that there is no excess padding between 'memberLayout' and + // the previous layout + private void checkMemberOffset(StructLayout parent, MemoryLayout memberLayout, + long lastUnpaddedOffset, long offset) { + long expectedOffset = Utils.alignUp(lastUnpaddedOffset, memberLayout.byteAlignment()); + if (expectedOffset != offset) { + throw new IllegalArgumentException("Member layout '" + memberLayout + "', of '" + parent + "'" + + " found at unexpected offset: " + offset + " != " + expectedOffset); + } + } + + private void checkSupported(ValueLayout valueLayout) { + valueLayout = valueLayout.withoutName(); + if (valueLayout instanceof AddressLayout addressLayout) { + valueLayout = addressLayout.withoutTargetLayout(); + } + if (!CANONICAL_LAYOUTS_CACHE.contains(valueLayout.withoutName())) { + throw new IllegalArgumentException("Unsupported layout: " + valueLayout); + } + } + + private void checkHasNaturalAlignment(MemoryLayout layout) { + if (!((AbstractLayout) layout).hasNaturalAlignment()) { + throw new IllegalArgumentException("Layout alignment must be natural alignment: " + layout); + } + } + + @SuppressWarnings("restricted") + private static MemoryLayout stripNames(MemoryLayout ml) { + // we don't care about transferring alignment and byte order here + // since the linker already restricts those such that they will always be the same + return switch (ml) { + case StructLayout sl -> MemoryLayout.structLayout(stripNames(sl.memberLayouts())); + case UnionLayout ul -> MemoryLayout.unionLayout(stripNames(ul.memberLayouts())); + case SequenceLayout sl -> MemoryLayout.sequenceLayout(sl.elementCount(), stripNames(sl.elementLayout())); + case AddressLayout al -> al.targetLayout() + .map(tl -> al.withoutName().withTargetLayout(stripNames(tl))) // restricted + .orElseGet(al::withoutName); + default -> ml.withoutName(); // ValueLayout and PaddingLayout + }; + } + + private static MemoryLayout[] stripNames(List layouts) { + return layouts.stream() + .map(AbstractLinker::stripNames) + .toArray(MemoryLayout[]::new); + } + + private static FunctionDescriptor stripNames(FunctionDescriptor function) { + return function.returnLayout() + .map(rl -> FunctionDescriptor.of(stripNames(rl), stripNames(function.argumentLayouts()))) + .orElseGet(() -> FunctionDescriptor.ofVoid(stripNames(function.argumentLayouts()))); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Architecture.class b/tests/test_data/std/jdk/internal/foreign/abi/Architecture.class new file mode 100644 index 0000000000000000000000000000000000000000..b273cfcbaf08a5c9fe4fc4de2462e6eddca6ecbb GIT binary patch literal 185 zcmYk0F%E)26h!AE0z#vQFww?6gE29ovcSr2Sy%i(7PBrUdNd0U;Gv95VqrONk~j1I zJYN7d$YKP9d3|gI8>g+2tvGd7b7h1qS*)!(v(w7;R>uel(^}r7Xr-yduB?4Q$oN_~ zsha)$q6y(5UmggF^Qqv+kK}~3=z6R4mRrwe|Kio)j0l90KLrGSXN(BLUW~*O!ern` Ezo}g;?EnA( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Architecture.java b/tests/test_data/std/jdk/internal/foreign/abi/Architecture.java new file mode 100644 index 00000000..c94c4485 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/Architecture.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +public interface Architecture { + boolean isStackType(int cls); + int typeSize(int cls); +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$Allocate.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$Allocate.class new file mode 100644 index 0000000000000000000000000000000000000000..c2b277e5721ecb7f59dc48aa6affd96f2b0b9012 GIT binary patch literal 3256 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 V{2qU#@lQ1Vg~q?)@AwB={twca_S^sf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$BufferStore.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$BufferStore.class new file mode 100644 index 0000000000000000000000000000000000000000..182e2ebf0022184f43750e37433902c4503f0f19 GIT binary patch literal 5548 zcmb7I33nUS75?6M8B3bjj$;{265=FIVk?UXi_=6Q!OBA9IyOa#X+mijOCxJyStCZH zEVL9_NSp4Z=>}b)P+D4Amh7~J($a((D>Cv2?pNQUQq%1ov(7f5qo6Z)2hQ9u>09p`G z5!4WZCa~sUdNOL}9mCG+xoF0+4RazN)yK_f+{~xV{6ufOl*t%&(%}+CS(!}Ha0JAV z6x6Dr4ebJr&d~x_=MPsl-R zxtt}(%tf~wx0NWYp(U1LLac&k46#+4dusEMPI($u(N2Qh$+8a7D?ft;0}7}Ikl zBZ$qoR>c+#TX7vDprUtzK{a960`s!wMAj%eqj@84GIXRuuEKGR@w=U#ESRauZP`+O za@3Em=Dwk!ME{VAodT^Dk#Po46Qdp%_!qzs-l}3)!)}ZSEUu81b$0;{>qo5;ckLJ& z92-247};}R@5tbA;`)&t+<8Tn`ZI9#j%KJuEQFP~LBrc{BaQDye`F?8S8eArQim}Y zuS6{Ij%m0FZ)a4yV3NB=Z>)i{YF0SOtYv$E_DeuFGl6G^;xP>+r@_Dlb3ntb(CJJU zOnl#-9Re$7MIe3PS|lX_u)3_C9e~R-6qk{esmYB*E@w>Wxul~z#*QN?qu`iUUIh!p zB^7rj9h-G1UNUoO8HE#QXu+gF|K7ZDq`-1uq+h1%-YpO(#T;t&49di$xc6wd6L%3@Rxf6^S!ouI^>dY+kb>T) z;cnbRi?UqnvQ%!HqnIiimP^lm74LsDJ!!jP8*EBOK1KL}BwLp5lw^PEtP<*0=*^KW zF@dhW`pU=LWG(V6&^B!54X@1Y(Z_QX)G=(O^xT+koATZN*yvnPZb4Qo)#Xi$2+SHW&f}xyJ7dbr;nYb zd@434wqZ+8`&`q9qH>w{8}VQ+M@Q2%t^tE?#c*2@&nQVgaVp|gmn4geK*%L1x2aGu zYi69mDXWyHk^$S8(s|O#Pms>#Dbsnjmq-LQ%t?ca;>_5bua3aLoPHi``1rByU#ku~QY29e)$XO1CXune|&>}yhM7NPO&U>;aF?D>=Zs?S zuw_k_3e`sSdwZ3ceMVVqw;RQjZ5Cv?sUoPmO87EvuA-S?_nHpxdx%y~75}I~KZ6O&4pi|kfy*nHXCft9&)Znf%a{UzV`xB! zyhigh)FCgz{PqFP6&&X~@4TD`_^k;aB;|+rW^t4kf^g&vL}bY+sFAg&FfS5rJcapB zaG?Po=Kp3gL0N#0a2`RUWWY!9F^+O3H{?2Ja?1vHCO2!u$2qU89p~C7_+?%LSwLbC z6MTgCQp6{5f>UeSo?-9f z>izh<2U|Ht8SQ}R@<48CDuZ3QshRNm&SLd_2zSeQRI1b6bQV`Wg8z0mJ&S?Uc*_P= zQVj$e27=+hS;PiHk}@1TCO;nwht6V9-=Kwq?Je1X)^O-i0>xc?r1hn_4)EE+=Po{% zcjEeR>(MUt&T#7;#|PTFo1a9YOAEK1!)Oy8f!>K^W&MOlu-7BlCkd|W#5*bk_j&~H z^a#c!!IGz8?0Xs$`_91ZICvVlaOgA&r%^nE!_R~R;ZS-Y5Dtbzw@Pj9zi@^0RHGYD z8Co4m4_cI^SfDJ!Vx<>RWfe9m{n)BR5Leb9p{&I%$~vT#DDF|#Xd}P?W7Apj;=~l|d0!wz-~vkRCaKR(ydG*@lzu?2DYe z@k<68{EPSR||EBuW?qi46`Wjx4l0mShlzRFop`nnub zoOv-NzdeM98545$HCl=}!P(dG4eH+_TJb2p$yi+=8o0}2%&zG?abv zLsZ4%DptORjz%F~!=PvsOL}@1USLA2Dq2)@sd!SwNfoC(N-}z(c^32KwU5GNMy=;4 z!$ggo$L+x5oGNv>?d7WKYc!u1v&anWcYv_p4Ex0(62bg8GDKNO6Ta)>{2t^lqzazF4>&GjRCuMjworRz`Z-d_^8HiBNeh06=ka4k z>96@U&i59|_ziRDxBLm`#pVEh&+%oBf8h8hj>owEXO2(eFZe6RlN|rX@$dL2UPbr+ E0rm*FhX4Qo literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$Builder.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$Builder.class new file mode 100644 index 0000000000000000000000000000000000000000..b295f4b64ea828e16e57be5ddf65532cc6eb4c4b GIT binary patch literal 6528 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 L6n5D^Pp19>yF@3~ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$Cast.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$Cast.class new file mode 100644 index 0000000000000000000000000000000000000000..66dce070e81b7f09fcda1c8791988c5f42299ad5 GIT binary patch literal 5373 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 R4C5xPU()&&zQ$d|{s;DN${GLw literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$Dereference.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$Dereference.class new file mode 100644 index 0000000000000000000000000000000000000000..90691de4a61be6e6e60948c6e1a5b7c55de8d28b GIT binary patch literal 517 zcma)3%}&BV5dIcv%b$v(D4slU05$djG#EtwsS%{P3F$^9+|^p#dtQJE)E+3aw`s=fI!|O?l(iHE`7|sRQ08Ix zKio%o%+v$RvUu1NI9 w4TbP^G&tKVvS^`-%`)1;cIh3o*}GiZK?nOBA1zS2Zk=-u4$$L@gG2Ow0E2{ujQ{`u literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$Dup.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$Dup.class new file mode 100644 index 0000000000000000000000000000000000000000..e54e0dfc4e5421784c475583c7b600d70c3da388 GIT binary patch literal 2761 zcmcguTXz~&6#fnb2FOH`*u++CsV!{-Xvb>WYQbnOjX^2Z649pK1~?5QleZ6h}+V_6WqE#o{ckW{3Bs@n|33E?C5xF_KvLw1t=q>w>0Nsr4ivbaJUC|7H{ z>($M>3|A*pM8Y+Oi>EoGtoX8|E1JQp?m>fFyJ|xxp%yDS3?`?qmvKt!*aO8K?oT9F}HqZ&{h z*P<}BURxsbOGL#sj$-8$QF8SLHNl93rDf zL&+G-V$X1@$p5bdo$Q7|_wkx)c}%z4V_>E@VM9%n5>;yIL0eAMOxJ4iZA~0UIcRs+ z1%}M3+;(JF3yrxt*<;W{0})z`1x);LxJwIaQ26_B|RwDS2W~;bKGvUvr zF-GHD;BTZey5U4+&)KSP+;cV;I3ohw!fh{V@(NU38YP zM(-jN5u(sd${*u(;CGsiQ%(v3SfK05rz7BR0KZKHKabA>c!`_|;S>47G2R-7_r*^1 z_MgByHi#iXH^?ymmpvX}_D^IUKF2$M;F8E5U8U&hSAi&(Eib^k*!IS&_}m+T9U4<) m{Uy<4P{sp#zeFNtsN`z2-(A%4T|9}0G(Mv7d;Ex>aqcDZ)y)F{ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$Move.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$Move.class new file mode 100644 index 0000000000000000000000000000000000000000..c25b350bb4bdb84720315dad0b6ce6b7c1772fb6 GIT binary patch literal 523 zcma)(&rZTX5XQen+EPSCQ4~)e{DU6s186)*Vl)9YX~KP>YqMCkW_L^Ct9kGNd?@2A zR4<0;VKbYVUuM4f=Hv729Y7DA02PL#N%9;?WrbEei=J{VWU3-QlF_wPiB##~AfJf< zRfgt-&v=w^l|~Pvi5S}eKEuIZ4HyDrbInu1aNIrZFXe}Wc)?vTRPE~v@h!*yOzmad z7%GM_Y2>!hM6`bsmuFW5)#JR-V{s!hq8jBg=dKw;?Oqsrn;T0L9)+GtYefIa~IyUCfLzALUwN13JL;wAU*qa5F}AIYX6t?7jq$vM0GzR!8y@ALORr+)&-!Hy$>J_-FY1~AAl za;O|B8C@|BGIzLYT4jd8WzEo>6^6dK`Q0Hz5t9&?F$9@m*cER$nx0wb4;q|=>Smo` zd~UwbLb_c#R(Fo;L~C{~#K%22+wo$4SHfhQ z3q0b&<~L-#iMJT~>kYfYa6Sy@n)bt%XnLO^IXHQ zm3@ATJ8O!~6BM8;GG;K#5OvI=V`;_#!x|mk&HOdZD3j2P?>2#w4F|%*$O`1EGUhN( z$Q8w||7#4c5GmbR+V)XaEj1RCx zhUK@5JFDBdn-r4XJSO2f!}QAzr(E#dHeApQzTK#mxV58{baG^(V5*9~t5}+N_Fwip z6^*dlClgF?FUol`-fkB z9&I_~b+;UrlPlR3f*3#R1JzQIic)bJ7MYjqVBQ5y*b{T>v~F>S;g=3YD#DlKa$c0V zQ0LZ6(V^zB(J<8B)C#6j_O+VLEod5krL5{Yg^b|c7{u)0Ach;S$dD3H_s?ax-V;cZ zFL_T1h*8%IMW!o#>U1v(wO?Q&&?grD?shz#qVnFfXa92&3g>Y6qVVU zG`@)xsAX06M_jyUHY}BIXrhc|zn!Lq4vB4Z+u1a2O60*{Hjb>BrXxCgeTzF4vusE4 zEdz!J@qHXW;719Hj1ttg5oa|FN2~FSN5EI4SeF7UhKGJ|-0IehBeTkBB8n3>6{D3#>2De;DPK|CT zG=wD3;JWror7l5ZNcEs9dR0)q5_E>89+b(gUaz2V2U`i0IJ2$1Im01AI3zq^xcFjG z${sIvSfptc0Xc?#lVWJmG?i#i7cu(3K~EW4DV;Eod<^!GHW7SC|Kc+ukMI%gWlsPf zyXp*CER&Q_{#o4YXq`%(Kw@}?b6X3E;U^ePC0;+lR0IOB&jn1Np8%gA9y!5C+jKE-Erz$#%((CU3#YkteoyLEaS!A*L%fm^f_q<*4xfYz~8 z!0N&uxbz$yaVJIO84{7dTpCNBN|VNzPlI5viM)`e-RJnir8|ZKw#Xns&GU|s-zFL! zq1zaxOVyY3EC?;qDqJijPjMOejkevKEcpaR>E`s+8S3uEt~MXUt-Xfkz* zWH)`!!O^DuQ53O52vOW^rpgr;2N-&a^u5P;?-3S7d|4=AekV8Xx&*(*H|}~3_uLiO oqcu*_-w{k2_fe+j%jCo~WhbY&@1ugl!5FHv)@U_QhlQzs0T>5PH~;_u literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$SegmentOffset.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$SegmentOffset.class new file mode 100644 index 0000000000000000000000000000000000000000..44a393c57f83d98ef150f190490663f26fa35c37 GIT binary patch literal 3642 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 L^$Tp_YaIFq#ZE_F literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$VMLoad.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$VMLoad.class new file mode 100644 index 0000000000000000000000000000000000000000..ec7875d023311b398e273cd208804c701ae7ddd2 GIT binary patch literal 3410 zcmcguTUQ%Z6#hCA++`ryy; z%?G=d)m0w+0sbT(s^6KJBoiP3`rtz{XU^>X?QidW_TK03SBHNAScH>83>^wORdgXP z(6_4{Xc<$pb}|q3qV1Ff;`4@Ocnbm@6O&s>B#=~)Qqc`n;OcH^FJoAq?pT_c*|r_s z*s(HN!N}Y*tde2vjBl;xZH*|3>)DRBqYI4ZTPkg>t_M(4j1 zEt;C^W>XXzkV1n3gAXPB8K{b`kuot3Iv78st0sNOH^ z>P0U*xh2uxmVUk?a7CiGa<##_8y9g&!I+Bo@V>xYOO-G>IT^W%qw{}UhH1HK70Jr< zBbFnp(@jR02SJI3A@pT{sUBBx8CL`np1tll%#6UDHU^s0myLo3>RAaop<)tgf|fP6 zyl9sg(&=-6<|M|niWywvF=I+J(-l}aJ3_?yTG}2d_)y?-%gEInTeT0!Ho4C8s(Dq1 z>!ApmAIkakLRR2*8#;~5AJyggVIqT&^yUpqU#spHbZ0{=m^3wzw~Ly&r8$Ot4>vo# zvO)LT9JCtupr*)eq#1{05@PkO>R#C{J83XA`{6Ke%?PrVoU)dy%YRn&vmb4;cojwNMLR3;p`h7=MkH9a-6tk_1=Y-;uZAX{Y zcRsaR%~Gr0Hfv3AUEkT)E$^;rGS`In!<3X=&^IJ->opm&++>3Ydd1Cifztw9W+NAEgXWO3ZIa(zse>VZL zQ{|cC3US(ns$nbwa-rP8M2ju07d$U}}aGer@SHO?ZfjRCx zk=H^#d((eHq^Dj$Nl(8(&vR~d;0FKW6o>c+H@O}QL~#qZ`9>w*1iy17jl}RV*Q(U; zcdm2i6Rwjn3d${nEV2}t#~pr_95(rk@!36<{sa9lF%(0?zPz_Wyh2L+>vI?hMC%;7 zv4Bqr*RU*iKI2Z{@LjI%@d6x}`Wc;c9vGgQp{=(9d+&DOB%`rTGU@V-&IL+!qr;(5 z0$~ZC`;>;Uj4%8E4Pym48fs9I@?X{|eT9DB(eiwk-p}$W1E!=8@d5A~m$74!4`Ql> z1p0X!TRlPjD)8%>)Mv03s?XDyjC~?Kb%?1}`a#eWb^jB%j|V<)-kL+CjQsM literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding$VMStore.class b/tests/test_data/std/jdk/internal/foreign/abi/Binding$VMStore.class new file mode 100644 index 0000000000000000000000000000000000000000..29246e25ef89a02566a01e347e0a3f1390c03c97 GIT binary patch literal 3606 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/Binding.java b/tests/test_data/std/jdk/internal/foreign/abi/Binding.java new file mode 100644 index 00000000..1f7f3327 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/Binding.java @@ -0,0 +1,902 @@ +/* + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +import jdk.internal.foreign.AbstractMemorySegmentImpl; +import jdk.internal.foreign.Utils; +import jdk.internal.foreign.abi.BindingInterpreter.LoadFunc; +import jdk.internal.foreign.abi.BindingInterpreter.StoreFunc; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_INT_UNALIGNED; +import static java.lang.foreign.ValueLayout.JAVA_SHORT_UNALIGNED; + +/** + * The binding operators defined in the Binding class can be combined into argument and return value processing 'recipes'. + * + * The binding operators are interpreted using a stack-base interpreter. Operators can either consume operands from the + * stack, or push them onto the stack. + * + * In the description of each binding we talk about 'boxing' and 'unboxing'. + * - Unboxing is the process of taking a Java value and decomposing it, and storing components into machine + * storage locations. As such, the binding interpreter stack starts with the Java value on it, and should end empty. + * - Boxing is the process of re-composing a Java value by pulling components from machine storage locations. + * If a MemorySegment is needed to store the result, one should be allocated using the ALLOCATE_BUFFER operator. + * The binding interpreter stack starts off empty, and ends with the value to be returned as the only value on it. + * A binding operator can be interpreted differently based on whether we are boxing or unboxing a value. For example, + * the CONVERT_ADDRESS operator 'unboxes' a MemoryAddress to a long, but 'boxes' a long to a MemoryAddress. + * + * Here are some examples of binding recipes derived from C declarations, and according to the Windows ABI (recipes are + * ABI-specific). Note that each argument has its own recipe, which is indicated by '[number]:' (though, the only + * example that has multiple arguments is the one using varargs). + * + * -------------------- + * + * void f(int i); + * + * Argument bindings: + * 0: VM_STORE(rcx, int.class) // move an 'int' into the RCX register + * + * Return bindings: + * none + * + * -------------------- + * + * void f(int* i); + * + * Argument bindings: + * 0: UNBOX_ADDRESS // the 'MemoryAddress' is converted into a 'long' + * VM_STORE(rcx, long.class) // the 'long' is moved into the RCX register + * + * Return bindings: + * none + * + * -------------------- + * + * int* f(); + * + * Argument bindings: + * none + * + * Return bindings: + * 0: VM_LOAD(rax, long) // load a 'long' from the RAX register + * BOX_ADDRESS // convert the 'long' into a 'MemoryAddress' + * + * -------------------- + * + * typedef struct { // fits into single register + * int x; + * int y; + * } MyStruct; + * + * void f(MyStruct ms); + * + * Argument bindings: + * 0: BUFFER_LOAD(0, long.class) // From the struct's memory region, load a 'long' from offset '0' + * VM_STORE(rcx, long.class) // and copy that into the RCX register + * + * Return bindings: + * none + * + * -------------------- + * + * typedef struct { // does not fit into single register + * long long x; + * long long y; + * } MyStruct; + * + * void f(MyStruct ms); + * + * For the Windows ABI: + * + * Argument bindings: + * 0: COPY(16, 8) // copy the memory region containing the struct + * BASE_ADDRESS // take the base address of the copy + * UNBOX_ADDRESS // converts the base address to a 'long' + * VM_STORE(rcx, long.class) // moves the 'long' into the RCX register + * + * Return bindings: + * none + * + * For the SysV ABI: + * + * Argument bindings: + * 0: DUP // duplicates the MemoryRegion operand + * BUFFER_LOAD(0, long.class) // loads a 'long' from offset '0' + * VM_STORE(rdx, long.class) // moves the long into the RDX register + * BUFFER_LOAD(8, long.class) // loads a 'long' from offset '8' + * VM_STORE(rcx, long.class) // moves the long into the RCX register + * + * Return bindings: + * none + * + * -------------------- + * + * typedef struct { // fits into single register + * int x; + * int y; + * } MyStruct; + * + * MyStruct f(); + * + * Argument bindings: + * none + * + * Return bindings: + * 0: ALLOCATE(GroupLayout(C_INT, C_INT)) // allocate a buffer with the memory layout of the struct + * DUP // duplicate the allocated buffer + * VM_LOAD(rax, long.class) // loads a 'long' from rax + * BUFFER_STORE(0, long.class) // stores a 'long' at offset 0 + * + * -------------------- + * + * typedef struct { // does not fit into single register + * long long x; + * long long y; + * } MyStruct; + * + * MyStruct f(); + * + * !! uses synthetic argument, which is a pointer to a pre-allocated buffer + * + * Argument bindings: + * 0: UNBOX_ADDRESS // unbox the MemoryAddress synthetic argument + * VM_STORE(rcx, long.class) // moves the 'long' into the RCX register + * + * Return bindings: + * none + * + * -------------------- + * + * void f(int dummy, ...); // varargs + * + * f(0, 10f); // passing a float + * + * Argument bindings: + * 0: VM_STORE(rcx, int.class) // moves the 'int dummy' into the RCX register + * + * 1: DUP // duplicates the '10f' argument + * VM_STORE(rdx, float.class) // move one copy into the RDX register + * VM_STORE(xmm1, float.class) // moves the other copy into the xmm2 register + * + * Return bindings: + * none + * + * -------------------- + */ +public sealed interface Binding { + + void verify(Deque> stack); + + void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator); + + private static void checkType(Class type) { + if (type != Object.class && (!type.isPrimitive() || type == void.class)) + throw new IllegalArgumentException("Illegal type: " + type); + } + + private static void checkOffset(long offset) { + if (offset < 0) + throw new IllegalArgumentException("Negative offset: " + offset); + } + + private static void checkByteWidth(int byteWidth, Class type) { + if (byteWidth < 0 || byteWidth > Utils.byteWidthOfPrimitive(type)) + throw new IllegalArgumentException("Illegal byteWidth: " + byteWidth); + } + + static VMStore vmStore(VMStorage storage, Class type) { + checkType(type); + return new VMStore(storage, type); + } + + static VMLoad vmLoad(VMStorage storage, Class type) { + checkType(type); + return new VMLoad(storage, type); + } + + static BufferStore bufferStore(long offset, Class type) { + return bufferStore(offset, type, Utils.byteWidthOfPrimitive(type)); + } + + static BufferStore bufferStore(long offset, Class type, int byteWidth) { + checkType(type); + checkOffset(offset); + checkByteWidth(byteWidth, type); + return new BufferStore(offset, type, byteWidth); + } + + static BufferLoad bufferLoad(long offset, Class type) { + return Binding.bufferLoad(offset, type, Utils.byteWidthOfPrimitive(type)); + } + + static BufferLoad bufferLoad(long offset, Class type, int byteWidth) { + checkType(type); + checkOffset(offset); + checkByteWidth(byteWidth, type); + return new BufferLoad(offset, type, byteWidth); + } + + static Copy copy(MemoryLayout layout) { + return new Copy(layout.byteSize(), layout.byteAlignment()); + } + + static Allocate allocate(MemoryLayout layout) { + return new Allocate(layout.byteSize(), layout.byteAlignment()); + } + + static BoxAddress boxAddressRaw(long size, long align) { + return new BoxAddress(size, align, false); + } + + static BoxAddress boxAddress(MemoryLayout layout) { + return new BoxAddress(layout.byteSize(), layout.byteAlignment(), true); + } + + static BoxAddress boxAddress(long byteSize) { + return new BoxAddress(byteSize, 1, true); + } + + // alias + static SegmentOffset unboxAddress() { + return segmentOffsetNoAllowHeap(); + } + + static SegmentBase segmentBase() { + return SegmentBase.INSTANCE; + } + + static SegmentOffset segmentOffsetAllowHeap() { + return SegmentOffset.INSTANCE_ALLOW_HEAP; + } + + static SegmentOffset segmentOffsetNoAllowHeap() { + return SegmentOffset.INSTANCE_NO_ALLOW_HEAP; + } + + static Dup dup() { + return Dup.INSTANCE; + } + + static ShiftLeft shiftLeft(int shiftAmount) { + if (shiftAmount <= 0) + throw new IllegalArgumentException("shiftAmount must be positive"); + return new ShiftLeft(shiftAmount); + } + + static ShiftRight shiftRight(int shiftAmount) { + if (shiftAmount <= 0) + throw new IllegalArgumentException("shiftAmount must be positive"); + return new ShiftRight(shiftAmount); + } + + static Binding cast(Class fromType, Class toType) { + if (fromType == int.class) { + if (toType == boolean.class) { + return Cast.INT_TO_BOOLEAN; + } else if (toType == byte.class) { + return Cast.INT_TO_BYTE; + } else if (toType == short.class) { + return Cast.INT_TO_SHORT; + } else if (toType == char.class) { + return Cast.INT_TO_CHAR; + } else if (toType == long.class) { + return Cast.INT_TO_LONG; + } + } else if (toType == int.class) { + if (fromType == boolean.class) { + return Cast.BOOLEAN_TO_INT; + } else if (fromType == byte.class) { + return Cast.BYTE_TO_INT; + } else if (fromType == short.class) { + return Cast.SHORT_TO_INT; + } else if (fromType == char.class) { + return Cast.CHAR_TO_INT; + } else if (fromType == long.class) { + return Cast.LONG_TO_INT; + } + } else if (fromType == long.class) { + if (toType == byte.class) { + return Cast.LONG_TO_BYTE; + } else if (toType == short.class) { + return Cast.LONG_TO_SHORT; + } else if (toType == char.class) { + return Cast.LONG_TO_CHAR; + } + } else if (toType == long.class) { + if (fromType == byte.class) { + return Cast.BYTE_TO_LONG; + } else if (fromType == short.class) { + return Cast.SHORT_TO_LONG; + } else if (fromType == char.class) { + return Cast.CHAR_TO_LONG; + } + } + throw new IllegalArgumentException("Unknown conversion: " + fromType + " -> " + toType); + } + + + static Binding.Builder builder() { + return new Binding.Builder(); + } + + /** + * A builder helper class for generating lists of Bindings + */ + class Builder { + private final List bindings = new ArrayList<>(); + + private static boolean isSubIntType(Class type) { + return type == boolean.class || type == byte.class || type == short.class || type == char.class; + } + + public Binding.Builder vmStore(VMStorage storage, Class type) { + if (isSubIntType(type)) { + bindings.add(Binding.cast(type, int.class)); + type = int.class; + } + bindings.add(Binding.vmStore(storage, type)); + return this; + } + + public Binding.Builder vmLoad(VMStorage storage, Class type) { + Class loadType = type; + if (isSubIntType(type)) { + loadType = int.class; + } + bindings.add(Binding.vmLoad(storage, loadType)); + if (isSubIntType(type)) { + bindings.add(Binding.cast(int.class, type)); + } + return this; + } + + public Binding.Builder bufferStore(long offset, Class type) { + bindings.add(Binding.bufferStore(offset, type)); + return this; + } + + public Binding.Builder bufferStore(long offset, Class type, int byteWidth) { + bindings.add(Binding.bufferStore(offset, type, byteWidth)); + return this; + } + + public Binding.Builder bufferLoad(long offset, Class type) { + bindings.add(Binding.bufferLoad(offset, type)); + return this; + } + + public Binding.Builder bufferLoad(long offset, Class type, int byteWidth) { + bindings.add(Binding.bufferLoad(offset, type, byteWidth)); + return this; + } + + public Binding.Builder copy(MemoryLayout layout) { + bindings.add(Binding.copy(layout)); + return this; + } + + public Binding.Builder allocate(MemoryLayout layout) { + bindings.add(Binding.allocate(layout)); + return this; + } + + public Binding.Builder boxAddressRaw(long size, long align) { + bindings.add(Binding.boxAddressRaw(size, align)); + return this; + } + + public Binding.Builder boxAddress(MemoryLayout layout) { + bindings.add(Binding.boxAddress(layout)); + return this; + } + + public Binding.Builder unboxAddress() { + bindings.add(Binding.unboxAddress()); + return this; + } + + public Binding.Builder segmentBase() { + bindings.add(Binding.segmentBase()); + return this; + } + + public Binding.Builder segmentOffsetAllowHeap() { + bindings.add(Binding.segmentOffsetAllowHeap()); + return this; + } + + public Binding.Builder segmentOffsetNoAllowHeap() { + bindings.add(Binding.segmentOffsetNoAllowHeap()); + return this; + } + + public Binding.Builder dup() { + bindings.add(Binding.dup()); + return this; + } + + // Converts to long if needed then shifts left by the given number of Bytes. + public Binding.Builder shiftLeft(int shiftAmount, Class type) { + if (type != long.class) { + bindings.add(Binding.cast(type, long.class)); + } + bindings.add(Binding.shiftLeft(shiftAmount)); + return this; + } + + // Shifts right by the given number of Bytes then converts from long if needed. + public Binding.Builder shiftRight(int shiftAmount, Class type) { + bindings.add(Binding.shiftRight(shiftAmount)); + if (type != long.class) { + bindings.add(Binding.cast(long.class, type)); + } + return this; + } + + public List build() { + return List.copyOf(bindings); + } + } + + sealed interface Move extends Binding { + VMStorage storage(); + Class type(); + } + + /** + * VM_STORE([storage location], [type]) + * Pops a [type] from the operand stack, and moves it to [storage location] + * The [type] must be one of byte, short, char, int, long, float, or double. + * [storage location] may be 'null', indicating that this value should be passed + * to the VM stub, but does not have an explicit target register (e.g. oop offsets) + */ + record VMStore(VMStorage storage, Class type) implements Move { + + @Override + public void verify(Deque> stack) { + Class actualType = stack.pop(); + Class expectedType = type(); + SharedUtils.checkType(actualType, expectedType); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + storeFunc.store(storage(), stack.pop()); + } + } + + /** + * VM_LOAD([storage location], [type]) + * Loads a [type] from [storage location], and pushes it onto the operand stack. + * The [type] must be one of byte, short, char, int, long, float, or double + */ + record VMLoad(VMStorage storage, Class type) implements Move { + + @Override + public void verify(Deque> stack) { + stack.push(type()); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + stack.push(loadFunc.load(storage(), type())); + } + } + + sealed interface Dereference extends Binding { + long offset(); + Class type(); + } + + /** + * BUFFER_STORE([offset into memory region], [type], [width]) + * Pops a [type] from the operand stack, then pops a MemorySegment from the operand stack. + * Stores [width] bytes of the value contained in the [type] to [offset into memory region]. + * The [type] must be one of byte, short, char, int, long, float, or double + */ + record BufferStore(long offset, Class type, int byteWidth) implements Dereference { + + @Override + public void verify(Deque> stack) { + Class storeType = stack.pop(); + SharedUtils.checkType(storeType, type()); + Class segmentType = stack.pop(); + SharedUtils.checkType(segmentType, MemorySegment.class); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + Object value = stack.pop(); + MemorySegment writeAddress = (MemorySegment) stack.pop(); + if (SharedUtils.isPowerOfTwo(byteWidth())) { + // exact size match + SharedUtils.write(writeAddress, offset(), type(), value); + } else { + // non-exact match, need to do chunked load + long longValue = ((Number) value).longValue(); + // byteWidth is smaller than the width of 'type', so it will always be < 8 here + int remaining = byteWidth(); + int chunkOffset = 0; + do { + int chunkSize = Integer.highestOneBit(remaining); // next power of 2, in bytes + long writeOffset = offset() + SharedUtils.pickChunkOffset(chunkOffset, byteWidth(), chunkSize); + int shiftAmount = chunkOffset * Byte.SIZE; + switch (chunkSize) { + case 4 -> { + int writeChunk = (int) (((0xFFFF_FFFFL << shiftAmount) & longValue) >>> shiftAmount); + writeAddress.set(JAVA_INT_UNALIGNED, writeOffset, writeChunk); + } + case 2 -> { + short writeChunk = (short) (((0xFFFFL << shiftAmount) & longValue) >>> shiftAmount); + writeAddress.set(JAVA_SHORT_UNALIGNED, writeOffset, writeChunk); + } + case 1 -> { + byte writeChunk = (byte) (((0xFFL << shiftAmount) & longValue) >>> shiftAmount); + writeAddress.set(JAVA_BYTE, writeOffset, writeChunk); + } + default -> + throw new IllegalStateException("Unexpected chunk size for chunked write: " + chunkSize); + } + remaining -= chunkSize; + chunkOffset += chunkSize; + } while (remaining != 0); + } + } + } + + /** + * BUFFER_LOAD([offset into memory region], [type], [width]) + * Pops a MemorySegment from the operand stack, + * and then loads [width] bytes from it at [offset into memory region], into a [type]. + * The [type] must be one of byte, short, char, int, long, float, or double + */ + record BufferLoad(long offset, Class type, int byteWidth) implements Dereference { + + @Override + public void verify(Deque> stack) { + Class actualType = stack.pop(); + SharedUtils.checkType(actualType, MemorySegment.class); + Class newType = type(); + stack.push(newType); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + MemorySegment readAddress = (MemorySegment) stack.pop(); + if (SharedUtils.isPowerOfTwo(byteWidth())) { + // exact size match + stack.push(SharedUtils.read(readAddress, offset(), type())); + } else { + // non-exact match, need to do chunked load + long result = 0; + // byteWidth is smaller than the width of 'type', so it will always be < 8 here + int remaining = byteWidth(); + int chunkOffset = 0; + do { + int chunkSize = Integer.highestOneBit(remaining); // next power of 2 + long readOffset = offset() + SharedUtils.pickChunkOffset(chunkOffset, byteWidth(), chunkSize); + long readChunk = switch (chunkSize) { + case 4 -> Integer.toUnsignedLong(readAddress.get(JAVA_INT_UNALIGNED, readOffset)); + case 2 -> Short.toUnsignedLong(readAddress.get(JAVA_SHORT_UNALIGNED, readOffset)); + case 1 -> Byte.toUnsignedLong(readAddress.get(JAVA_BYTE, readOffset)); + default -> + throw new IllegalStateException("Unexpected chunk size for chunked write: " + chunkSize); + }; + result |= readChunk << (chunkOffset * Byte.SIZE); + remaining -= chunkSize; + chunkOffset += chunkSize; + } while (remaining != 0); + + if (type() == int.class) { // 3 byte write + stack.push((int) result); + } else if (type() == long.class) { // 5, 6, 7 byte write + stack.push(result); + } else { + throw new IllegalStateException("Unexpected type for chunked load: " + type()); + } + } + } + } + + /** + * COPY([size], [alignment]) + * Creates a new MemorySegment with the given [size] and [alignment], + * and copies contents from a MemorySegment popped from the top of the operand stack into this new buffer, + * and pushes the new buffer onto the operand stack + */ + record Copy(long size, long alignment) implements Binding { + private static MemorySegment copyBuffer(MemorySegment operand, long size, long alignment, SegmentAllocator allocator) { + return allocator.allocate(size, alignment) + .copyFrom(operand.asSlice(0, size)); + } + + @Override + public void verify(Deque> stack) { + Class actualType = stack.pop(); + SharedUtils.checkType(actualType, MemorySegment.class); + stack.push(MemorySegment.class); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + MemorySegment operand = (MemorySegment) stack.pop(); + MemorySegment copy = copyBuffer(operand, size, alignment, allocator); + stack.push(copy); + } + } + + /** + * ALLOCATE([size], [alignment]) + * Creates a new MemorySegment with the give [size] and [alignment], and pushes it onto the operand stack. + */ + record Allocate(long size, long alignment) implements Binding { + private static MemorySegment allocateBuffer(long size, long alignment, SegmentAllocator allocator) { + return allocator.allocate(size, alignment); + } + + @Override + public void verify(Deque> stack) { + stack.push(MemorySegment.class); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + stack.push(allocateBuffer(size, alignment, allocator)); + } + } + + /** + * SEGMENT_BASE() + * Pops a MemorySegment from the stack, retrieves the heap base object from it, or null if there is none + * (See: AbstractMemorySegmentImpl::unsafeGetBase), and pushes the result onto the operand stack. + */ + record SegmentBase() implements Binding { + static final SegmentBase INSTANCE = new SegmentBase(); + + @Override + public void verify(Deque> stack) { + Class actualType = stack.pop(); + SharedUtils.checkType(actualType, MemorySegment.class); + stack.push(Object.class); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + stack.push(((AbstractMemorySegmentImpl)stack.pop()).unsafeGetBase()); + } + } + + /** + * SEGMENT_OFFSET([allowHeap]) + * Pops a MemorySegment from the stack, retrieves the offset from it, + * (See: AbstractMemorySegmentImpl::unsafeGetOffset), and pushes the result onto the operand stack. + * Note that for heap segments, the offset is a virtual address into the heap base object. + * If [allowHeap] is 'false' an exception will be thrown for heap segments (See SharedUtils::checkNative). + */ + record SegmentOffset(boolean allowHeap) implements Binding { + static final SegmentOffset INSTANCE_NO_ALLOW_HEAP = new SegmentOffset(false); + static final SegmentOffset INSTANCE_ALLOW_HEAP = new SegmentOffset(true); + + @Override + public void verify(Deque> stack) { + Class actualType = stack.pop(); + SharedUtils.checkType(actualType, MemorySegment.class); + stack.push(long.class); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + MemorySegment operand = (MemorySegment) stack.pop(); + if (!allowHeap) { + SharedUtils.checkNative(operand); + } + stack.push(((AbstractMemorySegmentImpl)operand).unsafeGetOffset()); + } + } + + /** + * BOX_ADDRESS() + * Pops a 'long' from the operand stack, converts it to a 'MemorySegment', with the given size and memory scope + * (either the context scope, or the global scope), and pushes that onto the operand stack. + */ + record BoxAddress(long size, long align, boolean needsScope) implements Binding { + + @Override + public void verify(Deque> stack) { + Class actualType = stack.pop(); + SharedUtils.checkType(actualType, long.class); + stack.push(MemorySegment.class); + } + + @Override + @SuppressWarnings("restricted") + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + MemorySegment segment = Utils.longToAddress((long) stack.pop(), size, align); + if (needsScope) { + segment = segment.reinterpret((Arena) allocator, null); // restricted + } + stack.push(segment); + } + } + + /** + * DUP() + * Duplicates the value on the top of the operand stack (without popping it!), + * and pushes the duplicate onto the operand stack + */ + record Dup() implements Binding { + static final Dup INSTANCE = new Dup(); + + @Override + public void verify(Deque> stack) { + stack.push(stack.peekLast()); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + stack.push(stack.peekLast()); + } + } + + /** + * ShiftLeft([shiftAmount]) + * Shifts the Bytes on the top of the operand stack (64 bit unsigned). + * Shifts left by the given number of Bytes. + */ + record ShiftLeft(int shiftAmount) implements Binding { + + @Override + public void verify(Deque> stack) { + Class last = stack.pop(); + SharedUtils.checkType(last, long.class); + stack.push(long.class); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + long l = (long) stack.pop(); + l <<= (shiftAmount * Byte.SIZE); + stack.push(l); + } + } + + /** + * ShiftRight([shiftAmount]) + * Shifts the Bytes on the top of the operand stack (64 bit unsigned). + * Shifts right by the given number of Bytes. + */ + record ShiftRight(int shiftAmount) implements Binding { + + @Override + public void verify(Deque> stack) { + Class last = stack.pop(); + SharedUtils.checkType(last, long.class); + stack.push(long.class); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + long l = (long) stack.pop(); + l >>>= (shiftAmount * Byte.SIZE); + stack.push(l); + } + } + + /** + * CAST([fromType], [toType]) + * Pop a [fromType] from the stack, convert it to [toType], and push the resulting + * value onto the stack. + * + */ + enum Cast implements Binding { + INT_TO_BOOLEAN(int.class, boolean.class) { + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + // implement least significant byte non-zero test + int arg = (int) stack.pop(); + boolean result = Utils.byteToBoolean((byte) arg); + stack.push(result); + } + }, + INT_TO_BYTE(int.class, byte.class), + INT_TO_CHAR(int.class, char.class), + INT_TO_SHORT(int.class, short.class), + INT_TO_LONG(int.class, long.class), + + BOOLEAN_TO_INT(boolean.class, int.class), + BYTE_TO_INT(byte.class, int.class), + CHAR_TO_INT(char.class, int.class), + SHORT_TO_INT(short.class, int.class), + LONG_TO_INT(long.class, int.class), + + LONG_TO_BYTE(long.class, byte.class), + LONG_TO_SHORT(long.class, short.class), + LONG_TO_CHAR(long.class, char.class), + + BYTE_TO_LONG(byte.class, long.class), + SHORT_TO_LONG(short.class, long.class), + CHAR_TO_LONG(char.class, long.class); + + private final Class fromType; + private final Class toType; + + Cast(Class fromType, Class toType) { + this.fromType = fromType; + this.toType = toType; + } + + public Class fromType() { + return fromType; + } + + public Class toType() { + return toType; + } + + @Override + public void verify(Deque> stack) { + Class actualType = stack.pop(); + SharedUtils.checkType(actualType, fromType); + stack.push(toType); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + Object arg = stack.pop(); + MethodHandle converter = MethodHandles.explicitCastArguments(MethodHandles.identity(toType), + MethodType.methodType(toType, fromType)); + try { + Object result = converter.invoke(arg); + stack.push(result); + } catch (Throwable e) { + throw new InternalError(e); + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter$LoadFunc.class b/tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter$LoadFunc.class new file mode 100644 index 0000000000000000000000000000000000000000..134008b35356ad4d7c2d60cb808ff1894668086f GIT binary patch literal 525 zcmbVJO-lnY5Pef?x2?5SFXG9I2S32Qc&i9nC>B-)3%#e?bV-d9$!7g=9{d6RC~LDLjp3Q$Y*f}>yq5DQ zacVX!IE_#z^cLz>#a3|^KTH=o4TQRt2ZYgavX*snHxACLO!t%D{()6_-alDFz8U+3 z)>!nYP6KFdi6JTd+Z9I>Y=g1y}$b1^HLz;;IZIfp7q4!W@_~{vkNL1$2s9} zNpfjS2`gJ!Hdm<@{mpxwhg+A22s?zcwZ5#5Cv-;4+E?ai8P@!~yYb^Z_yK;DINO7W zrI&fjo7p#S-q-iXCx9u&F?xjSYW1Qld(*P6)w*eoEm`T@syoXo%jG=u-dZE|Z0V&x z>$r%~CyXoou2rqMR8M(j3QrigFhRIEU+mP)9)gT6&1CUkU~-WW(q+@Ng_+q}gpRje zT!mkRljn}TeKnbNHm}VsbK|wQ4Lic=ALU>-(7N7Svet!}5QdM&`TNHC7zc#Qoo2V! z6Gn4p(@tycoRMY8Zz>UiuqWXHB>4;w$*Yf8Y7avsf{{$5g8Lh8ghRnpI8nt>l>7jK CCw40U literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter.class b/tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter.class new file mode 100644 index 0000000000000000000000000000000000000000..17be4ff951ba91cfe0fafedb3d0d21ad468ce35d GIT binary patch literal 2599 zcmb_eTW=dh7(L_L#`ZQh(gYV;(l%}FB#sNDDb0q2Bqb1VT#Ab&cw5_xvx&PlyKB_G zApQog2*fKqRiP5%8Hv9@{|6G6Gvl?h4T)S!VZ}B1rlqvWBcm@(QK}wVMJg`1$BJ8St#1hp;a&1o}Yq- zXc}qg8qVn$#hAd@ao}C+i;g7_Yj?bTf%Dno$wo%5lEwrkHN2!_3g-nzkF#Y1ff3uc zT+?s40@K-Cw}L{k8_XMN%;04W866k!iooP?gk;db&}TB^qK->=jo=(L zJ=LonlEKh$Szz{{eps*_c5}>T;q#Vj*$t;)R_(%;?bL0jk;W{p>X^edfuss-yB0fr zAMjOZl@vyCP_13rN2XiuT$!Y;osLr*F0I%y>p@n3TYIR>R^y@N_?yjUt0pz2{u*vP zx4E0HYd%(JQ@GyU+<6@fQmSaX)z**~SQvr^72a;u>4GuZ#wv9lRxS5|S#5G=vPcxo zis{<&J(!I7`?e>LA4V!eAl`ARtw#c1pJK9*X{4uylQX;vFQTV_s0v&e2%ngvrrVGz z{O45A_0_JosKoe5_;i`qvxdO!ft^nG6swp$8wkvWK%8k7s_gk@?NDGMgsJOnp3diY z^KrYkqsyUSssGwQ#Kt<+xfV)OJ($h`b1OZR>!SbJGQ)qW`b)xw1rF3Xaeby<@tM-ysFid9knPa=_6pK2T&0MKPjwMN*80D9ZRPM#~-B v;J@OpNzN_elSJ}gE|1WJ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter.java b/tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter.java new file mode 100644 index 00000000..9434e70a --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/BindingInterpreter.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +import java.lang.foreign.SegmentAllocator; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; + +public class BindingInterpreter { + + static void unbox(Object arg, List bindings, StoreFunc storeFunc, SegmentAllocator allocator) { + Deque stack = new LinkedList<>(); // Use LinkedList as a null-friendly Deque for null segment bases + + stack.push(arg); + for (Binding b : bindings) { + b.interpret(stack, storeFunc, null, allocator); + } + } + + static Object box(List bindings, LoadFunc loadFunc, SegmentAllocator allocator) { + Deque stack = new ArrayDeque<>(); + for (Binding b : bindings) { + b.interpret(stack, null, loadFunc, allocator); + } + return stack.pop(); + } + + @FunctionalInterface + public interface StoreFunc { + void store(VMStorage storage, Object o); + } + + @FunctionalInterface + public interface LoadFunc { + Object load(VMStorage storage, Class type); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer$1.class b/tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer$1.class new file mode 100644 index 0000000000000000000000000000000000000000..37dc360242e0a20569c000c48bf9cf6343ff924b GIT binary patch literal 2254 zcma)7O>7%g5dL1AW^LysF(DgJkBNKBU^#R_1O4?#BMew3T4j^ zLhBxhr&MUBZ1|yZuf)@A)TZ2epf0gr1!g^WB@FD7=vO(%9nYwT9+Wu5*5s&HU2^II z4oe(ibK9)7Z26XJDo+weaZJM?&-qz_{o9R0&lr_J;GmlGHltIqYTzd%PV%&mHcqd! zriX*qYlGKm@Oo|V>U4tSotAhG&kM9q<%)~N{NhMHpB)>{(Yug+D78b}V<%^NLEbs`)Rf##3DsU1vB>uJ+HcBbYA!=!NgWAWtl3Kvma>N(*6b@1Wwy(DgXGY#Dv*k9OMYq9GU@e+ zpD`WVwS%+jQq2i8XS@fOR6;R{J zf>-rTYn+ynK==O_#}QUQ*~eVd@hY@bW~`v>l{8cZ4sG`iH7pP39dDUuK?C{7YK&33Q34YiiqdzTzVBdgUZbd)`#f@NyXP@? rpEz~)p16mlXvSMgj!!=xhz0cAP?i9jgqT7TaZ9IhXhck_rdR literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer.class b/tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer.class new file mode 100644 index 0000000000000000000000000000000000000000..3dec97e9ab3986a1ac3a10ecd9f0238f8eb00d9d GIT binary patch literal 37068 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 akzRuI3Z$1Iy%OmaNUuVA71D2{rT;(hlk+$L literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer.java b/tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer.java new file mode 100644 index 00000000..7f5ef54b --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/BindingSpecializer.java @@ -0,0 +1,996 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.Label; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; +import jdk.internal.foreign.AbstractMemorySegmentImpl; +import jdk.internal.foreign.MemorySessionImpl; +import jdk.internal.foreign.Utils; +import jdk.internal.foreign.abi.Binding.Allocate; +import jdk.internal.foreign.abi.Binding.BoxAddress; +import jdk.internal.foreign.abi.Binding.BufferLoad; +import jdk.internal.foreign.abi.Binding.BufferStore; +import jdk.internal.foreign.abi.Binding.Cast; +import jdk.internal.foreign.abi.Binding.Copy; +import jdk.internal.foreign.abi.Binding.Dup; +import jdk.internal.foreign.abi.Binding.SegmentBase; +import jdk.internal.foreign.abi.Binding.SegmentOffset; +import jdk.internal.foreign.abi.Binding.ShiftLeft; +import jdk.internal.foreign.abi.Binding.ShiftRight; +import jdk.internal.foreign.abi.Binding.VMLoad; +import jdk.internal.foreign.abi.Binding.VMStore; +import sun.security.action.GetBooleanAction; +import sun.security.action.GetPropertyAction; + +import java.io.IOException; +import java.lang.constant.ClassDesc; +import java.lang.constant.Constable; +import java.lang.constant.ConstantDesc; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.ClassFileFormatVersion; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.List; + +import static java.lang.constant.ConstantDescs.*; +import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.TypeKind.*; + +public class BindingSpecializer { + private static final String DUMP_CLASSES_DIR + = GetPropertyAction.privilegedGetProperty("jdk.internal.foreign.abi.Specializer.DUMP_CLASSES_DIR"); + private static final boolean PERFORM_VERIFICATION + = GetBooleanAction.privilegedGetProperty("jdk.internal.foreign.abi.Specializer.PERFORM_VERIFICATION"); + + // Bunch of helper constants + private static final int CLASSFILE_VERSION = ClassFileFormatVersion.latest().major(); + + private static final ClassDesc CD_Arena = desc(Arena.class); + private static final ClassDesc CD_MemorySegment = desc(MemorySegment.class); + private static final ClassDesc CD_MemorySegment_Scope = desc(MemorySegment.Scope.class); + private static final ClassDesc CD_SharedUtils = desc(SharedUtils.class); + private static final ClassDesc CD_AbstractMemorySegmentImpl = desc(AbstractMemorySegmentImpl.class); + private static final ClassDesc CD_MemorySessionImpl = desc(MemorySessionImpl.class); + private static final ClassDesc CD_Utils = desc(Utils.class); + private static final ClassDesc CD_SegmentAllocator = desc(SegmentAllocator.class); + private static final ClassDesc CD_ValueLayout = desc(ValueLayout.class); + private static final ClassDesc CD_ValueLayout_OfBoolean = desc(ValueLayout.OfBoolean.class); + private static final ClassDesc CD_ValueLayout_OfByte = desc(ValueLayout.OfByte.class); + private static final ClassDesc CD_ValueLayout_OfShort = desc(ValueLayout.OfShort.class); + private static final ClassDesc CD_ValueLayout_OfChar = desc(ValueLayout.OfChar.class); + private static final ClassDesc CD_ValueLayout_OfInt = desc(ValueLayout.OfInt.class); + private static final ClassDesc CD_ValueLayout_OfLong = desc(ValueLayout.OfLong.class); + private static final ClassDesc CD_ValueLayout_OfFloat = desc(ValueLayout.OfFloat.class); + private static final ClassDesc CD_ValueLayout_OfDouble = desc(ValueLayout.OfDouble.class); + private static final ClassDesc CD_AddressLayout = desc(AddressLayout.class); + + private static final MethodTypeDesc MTD_NEW_BOUNDED_ARENA = MethodTypeDesc.of(CD_Arena, CD_long); + private static final MethodTypeDesc MTD_NEW_EMPTY_ARENA = MethodTypeDesc.of(CD_Arena); + private static final MethodTypeDesc MTD_SCOPE = MethodTypeDesc.of(CD_MemorySegment_Scope); + private static final MethodTypeDesc MTD_SESSION_IMPL = MethodTypeDesc.of(CD_MemorySessionImpl); + private static final MethodTypeDesc MTD_CLOSE = MTD_void; + private static final MethodTypeDesc MTD_CHECK_NATIVE = MethodTypeDesc.of(CD_void, CD_MemorySegment); + private static final MethodTypeDesc MTD_UNSAFE_GET_BASE = MethodTypeDesc.of(CD_Object); + private static final MethodTypeDesc MTD_UNSAFE_GET_OFFSET = MethodTypeDesc.of(CD_long); + private static final MethodTypeDesc MTD_COPY = MethodTypeDesc.of(CD_void, CD_MemorySegment, CD_long, CD_MemorySegment, CD_long, CD_long); + private static final MethodTypeDesc MTD_LONG_TO_ADDRESS_NO_SCOPE = MethodTypeDesc.of(CD_MemorySegment, CD_long, CD_long, CD_long); + private static final MethodTypeDesc MTD_LONG_TO_ADDRESS_SCOPE = MethodTypeDesc.of(CD_MemorySegment, CD_long, CD_long, CD_long, CD_MemorySessionImpl); + private static final MethodTypeDesc MTD_ALLOCATE = MethodTypeDesc.of(CD_MemorySegment, CD_long, CD_long); + private static final MethodTypeDesc MTD_HANDLE_UNCAUGHT_EXCEPTION = MethodTypeDesc.of(CD_void, CD_Throwable); + private static final MethodTypeDesc MTD_RELEASE0 = MTD_void; + private static final MethodTypeDesc MTD_ACQUIRE0 = MTD_void; + private static final MethodTypeDesc MTD_INTEGER_TO_UNSIGNED_LONG = MethodTypeDesc.of(CD_long, CD_int); + private static final MethodTypeDesc MTD_SHORT_TO_UNSIGNED_LONG = MethodTypeDesc.of(CD_long, CD_short); + private static final MethodTypeDesc MTD_BYTE_TO_UNSIGNED_LONG = MethodTypeDesc.of(CD_long, CD_byte); + private static final MethodTypeDesc MTD_BYTE_TO_BOOLEAN = MethodTypeDesc.of(CD_boolean, CD_byte); + + private static final ConstantDesc CLASS_DATA_DESC = DynamicConstantDesc.of(BSM_CLASS_DATA); + + private static final String CLASS_NAME_DOWNCALL = "jdk/internal/foreign/abi/DowncallStub"; + private static final String CLASS_NAME_UPCALL = "jdk/internal/foreign/abi/UpcallStub"; + private static final String METHOD_NAME = "invoke"; + + // Instance fields start here + private final CodeBuilder cb; + private final MethodType callerMethodType; + private final CallingSequence callingSequence; + private final ABIDescriptor abi; + private final MethodType leafType; + + private int[] leafArgSlots; + private int[] scopeSlots; + private int curScopeLocalIdx = -1; + private int returnAllocatorIdx = -1; + private int contextIdx = -1; + private int returnBufferIdx = -1; + private int retValIdx = -1; + private Deque> typeStack; + private List> leafArgTypes; + private int paramIndex; + private long retBufOffset; // for needsReturnBuffer + + private BindingSpecializer(CodeBuilder cb, MethodType callerMethodType, + CallingSequence callingSequence, ABIDescriptor abi, MethodType leafType) { + this.cb = cb; + this.callerMethodType = callerMethodType; + this.callingSequence = callingSequence; + this.abi = abi; + this.leafType = leafType; + } + + static MethodHandle specializeDowncall(MethodHandle leafHandle, CallingSequence callingSequence, ABIDescriptor abi) { + MethodType callerMethodType = callingSequence.callerMethodType(); + if (callingSequence.needsReturnBuffer()) { + callerMethodType = callerMethodType.dropParameterTypes(0, 1); // Return buffer does not appear in the parameter list + } + callerMethodType = callerMethodType.insertParameterTypes(0, SegmentAllocator.class); + + byte[] bytes = specializeHelper(leafHandle.type(), callerMethodType, callingSequence, abi); + + try { + MethodHandles.Lookup definedClassLookup = MethodHandles.lookup() + .defineHiddenClassWithClassData(bytes, leafHandle, false); + return definedClassLookup.findStatic(definedClassLookup.lookupClass(), METHOD_NAME, callerMethodType); + } catch (IllegalAccessException | NoSuchMethodException e) { + throw new InternalError("Should not happen", e); + } + } + + static MethodHandle specializeUpcall(MethodType targetType, CallingSequence callingSequence, ABIDescriptor abi) { + MethodType callerMethodType = callingSequence.callerMethodType(); + callerMethodType = callerMethodType.insertParameterTypes(0, MethodHandle.class); // target + + byte[] bytes = specializeHelper(targetType, callerMethodType, callingSequence, abi); + + try { + // For upcalls, we must initialize the class since the upcall stubs don't have a clinit barrier, + // and the slow path in the c2i adapter we end up calling can not handle the particular code shape + // where the caller is an upcall stub. + MethodHandles.Lookup defineClassLookup = MethodHandles.lookup().defineHiddenClass(bytes, true); + return defineClassLookup.findStatic(defineClassLookup.lookupClass(), METHOD_NAME, callerMethodType); + } catch (IllegalAccessException | NoSuchMethodException e) { + throw new InternalError("Should not happen", e); + } + } + + private static byte[] specializeHelper(MethodType leafType, MethodType callerMethodType, + CallingSequence callingSequence, ABIDescriptor abi) { + String className = callingSequence.forDowncall() ? CLASS_NAME_DOWNCALL : CLASS_NAME_UPCALL; + byte[] bytes = ClassFile.of().build(ClassDesc.ofInternalName(className), clb -> { + clb.withFlags(ACC_PUBLIC + ACC_FINAL + ACC_SUPER); + clb.withSuperclass(CD_Object); + clb.withVersion(CLASSFILE_VERSION, 0); + + clb.withMethodBody(METHOD_NAME, desc(callerMethodType), ACC_PUBLIC | ACC_STATIC, + cb -> new BindingSpecializer(cb, callerMethodType, callingSequence, abi, leafType).specialize()); + }); + + if (DUMP_CLASSES_DIR != null) { + String fileName = className + escapeForFileName(callingSequence.functionDesc().toString()) + ".class"; + Path dumpPath = Path.of(DUMP_CLASSES_DIR).resolve(fileName); + try { + Files.createDirectories(dumpPath.getParent()); + Files.write(dumpPath, bytes); + } catch (IOException e) { + throw new InternalError(e); + } + } + + if (PERFORM_VERIFICATION) { + List errors = ClassFile.of().verify(bytes); + if (!errors.isEmpty()) { + errors.forEach(System.err::println); + throw new IllegalStateException("Verification error(s)"); + } + } + + return bytes; + } + + private static String escapeForFileName(String str) { + StringBuilder sb = new StringBuilder(str.length()); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + sb.append(switch (c) { + case ' ' -> '_'; + case '[', '<' -> '{'; + case ']', '>' -> '}'; + case '/', '\\', ':', '*', '?', '"', '|' -> '!'; // illegal in Windows file names. + default -> c; + }); + } + return sb.toString(); + } + + // binding operand stack manipulation + + private void pushType(Class type) { + typeStack.push(type); + } + + private Class popType(Class expected) { + Class found = typeStack.pop(); + if (!expected.equals(found)) { + throw new IllegalStateException( + String.format("Invalid type on binding operand stack; found %s - expected %s", + found.descriptorString(), expected.descriptorString())); + } + return found; + } + + // specialization + + private void specialize() { + // slots that store the output arguments (passed to the leaf handle) + leafArgSlots = new int[leafType.parameterCount()]; + for (int i = 0; i < leafType.parameterCount(); i++) { + leafArgSlots[i] = cb.allocateLocal(TypeKind.from(leafType.parameterType(i))); + } + + // allocator passed to us for allocating the return MS (downcalls only) + if (callingSequence.forDowncall()) { + returnAllocatorIdx = 0; // first param + + // for downcalls we also acquire/release scoped parameters before/after the call + // create a bunch of locals here to keep track of their scopes (to release later) + int[] initialScopeSlots = new int[callerMethodType.parameterCount()]; + int numScopes = 0; + for (int i = 0; i < callerMethodType.parameterCount(); i++) { + if (shouldAcquire(i)) { + int scopeLocal = cb.allocateLocal(ReferenceType); + initialScopeSlots[numScopes++] = scopeLocal; + cb.loadConstant(null); + cb.storeLocal(ReferenceType, scopeLocal); // need to initialize all scope locals here in case an exception occurs + } + } + scopeSlots = Arrays.copyOf(initialScopeSlots, numScopes); // fit to size + curScopeLocalIdx = 0; // used from emitGetInput + } + + // create a Binding.Context for this call + if (callingSequence.allocationSize() != 0) { + cb.loadConstant(callingSequence.allocationSize()); + cb.invokestatic(CD_SharedUtils, "newBoundedArena", MTD_NEW_BOUNDED_ARENA); + } else if (callingSequence.forUpcall() && needsSession()) { + cb.invokestatic(CD_SharedUtils, "newEmptyArena", MTD_NEW_EMPTY_ARENA); + } else { + cb.getstatic(CD_SharedUtils, "DUMMY_ARENA", CD_Arena); + } + contextIdx = cb.allocateLocal(ReferenceType); + cb.storeLocal(ReferenceType, contextIdx); + + // in case the call needs a return buffer, allocate it here. + // for upcalls the VM wrapper stub allocates the buffer. + if (callingSequence.needsReturnBuffer() && callingSequence.forDowncall()) { + emitLoadInternalAllocator(); + emitAllocateCall(callingSequence.returnBufferSize(), 1); + returnBufferIdx = cb.allocateLocal(ReferenceType); + cb.storeLocal(ReferenceType, returnBufferIdx); + } + + Label tryStart = cb.newLabel(); + Label tryEnd = cb.newLabel(); + Label catchStart = cb.newLabel(); + + cb.labelBinding(tryStart); + + // stack to keep track of types on the bytecode stack between bindings. + // this is needed to e.g. emit the right DUP instruction, + // but also used for type checking. + typeStack = new ArrayDeque<>(); + // leaf arg types are the types of the args passed to the leaf handle. + // these are collected from VM_STORE instructions for downcalls, and + // recipe outputs for upcalls (see uses emitSetOutput for both) + leafArgTypes = new ArrayList<>(); + paramIndex = 1; // +1 to skip SegmentAllocator or MethodHandle + for (int i = 0; i < callingSequence.argumentBindingsCount(); i++) { + if (callingSequence.forDowncall()) { + // for downcalls, recipes have an input value, which we set up here + if (callingSequence.needsReturnBuffer() && i == 0) { + assert returnBufferIdx != -1; + cb.loadLocal(ReferenceType, returnBufferIdx); + pushType(MemorySegment.class); + } else { + emitGetInput(); + } + } + + // emit code according to binding recipe + doBindings(callingSequence.argumentBindings(i)); + + if (callingSequence.forUpcall()) { + // for upcalls, recipes have a result, which we handle here + if (callingSequence.needsReturnBuffer() && i == 0) { + // return buffer ptr is wrapped in a MemorySegment above, but not passed to the leaf handle + popType(MemorySegment.class); + returnBufferIdx = cb.allocateLocal(ReferenceType); + cb.storeLocal(ReferenceType, returnBufferIdx); + } else { + // for upcalls the recipe result is an argument to the leaf handle + emitSetOutput(typeStack.pop()); + } + } + assert typeStack.isEmpty(); + } + + assert leafArgTypes.equals(leafType.parameterList()); + + // load the leaf MethodHandle + if (callingSequence.forDowncall()) { + cb.loadConstant(CLASS_DATA_DESC); + } else { + cb.loadLocal(ReferenceType, 0); // load target arg + } + cb.checkcast(CD_MethodHandle); + // load all the leaf args + for (int i = 0; i < leafArgSlots.length; i++) { + cb.loadLocal(TypeKind.from(leafArgTypes.get(i)), leafArgSlots[i]); + } + // call leaf MH + cb.invokevirtual(CD_MethodHandle, "invokeExact", desc(leafType)); + + // for downcalls, store the result of the leaf handle call away, until + // it is requested by a VM_LOAD in the return recipe. + if (callingSequence.forDowncall() && leafType.returnType() != void.class) { + emitSaveReturnValue(leafType.returnType()); + } + // for upcalls we leave the return value on the stack to be picked up + // as an input of the return recipe. + + // return value processing + if (callingSequence.hasReturnBindings()) { + if (callingSequence.forUpcall()) { + pushType(leafType.returnType()); + } + + retBufOffset = 0; // offset for reading from return buffer + doBindings(callingSequence.returnBindings()); + + if (callingSequence.forUpcall() && !callingSequence.needsReturnBuffer()) { + // was VM_STOREd somewhere in the bindings + emitRestoreReturnValue(callerMethodType.returnType()); + } + cb.labelBinding(tryEnd); + // finally + emitCleanup(); + + if (callerMethodType.returnType() == void.class) { + // The case for upcalls that return by return buffer + assert typeStack.isEmpty(); + cb.return_(); + } else { + popType(callerMethodType.returnType()); + assert typeStack.isEmpty(); + cb.return_(TypeKind.from(callerMethodType.returnType())); + } + } else { + assert callerMethodType.returnType() == void.class; + assert typeStack.isEmpty(); + cb.labelBinding(tryEnd); + // finally + emitCleanup(); + cb.return_(); + } + + cb.labelBinding(catchStart); + // finally + emitCleanup(); + if (callingSequence.forDowncall()) { + cb.athrow(); + } else { + cb.invokestatic(CD_SharedUtils, "handleUncaughtException", MTD_HANDLE_UNCAUGHT_EXCEPTION); + if (callerMethodType.returnType() != void.class) { + TypeKind returnTypeKind = TypeKind.from(callerMethodType.returnType()); + emitConstZero(returnTypeKind); + cb.return_(returnTypeKind); + } else { + cb.return_(); + } + } + + cb.exceptionCatchAll(tryStart, tryEnd, catchStart); + } + + private boolean needsSession() { + return callingSequence.argumentBindings() + .filter(BoxAddress.class::isInstance) + .map(BoxAddress.class::cast) + .anyMatch(BoxAddress::needsScope); + } + + private boolean shouldAcquire(int paramIndex) { + if (!callingSequence.forDowncall() || // we only acquire in downcalls + paramIndex == 0) { // the first parameter in a downcall is SegmentAllocator + return false; + } + + // if call needs return buffer, the descriptor has an extra leading layout + int offset = callingSequence.needsReturnBuffer() ? 0 : 1; + MemoryLayout paramLayout = callingSequence.functionDesc() + .argumentLayouts() + .get(paramIndex - offset); + + // is this an address layout? + return paramLayout instanceof AddressLayout; + } + + private void emitCleanup() { + emitCloseContext(); + if (callingSequence.forDowncall()) { + emitReleaseScopes(); + } + } + + private void doBindings(List bindings) { + for (Binding binding : bindings) { + switch (binding) { + case VMStore vmStore -> emitVMStore(vmStore); + case VMLoad vmLoad -> emitVMLoad(vmLoad); + case BufferStore bufferStore -> emitBufferStore(bufferStore); + case BufferLoad bufferLoad -> emitBufferLoad(bufferLoad); + case Copy copy -> emitCopyBuffer(copy); + case Allocate allocate -> emitAllocBuffer(allocate); + case BoxAddress boxAddress -> emitBoxAddress(boxAddress); + case SegmentBase unused -> emitSegmentBase(); + case SegmentOffset segmentOffset -> emitSegmentOffset(segmentOffset); + case Dup unused -> emitDupBinding(); + case ShiftLeft shiftLeft -> emitShiftLeft(shiftLeft); + case ShiftRight shiftRight -> emitShiftRight(shiftRight); + case Cast cast -> emitCast(cast); + } + } + } + + private void emitSetOutput(Class storeType) { + cb.storeLocal(TypeKind.from(storeType), leafArgSlots[leafArgTypes.size()]); + leafArgTypes.add(storeType); + } + + private void emitGetInput() { + Class highLevelType = callerMethodType.parameterType(paramIndex); + cb.loadLocal(TypeKind.from(highLevelType), cb.parameterSlot(paramIndex)); + + if (shouldAcquire(paramIndex)) { + cb.dup(); + emitAcquireScope(); + } + + pushType(highLevelType); + paramIndex++; + } + + private void emitAcquireScope() { + cb.checkcast(CD_AbstractMemorySegmentImpl); + cb.invokevirtual(CD_AbstractMemorySegmentImpl, "sessionImpl", MTD_SESSION_IMPL); + Label skipAcquire = cb.newLabel(); + Label end = cb.newLabel(); + + // start with 1 scope to maybe acquire on the stack + assert curScopeLocalIdx != -1; + boolean hasOtherScopes = curScopeLocalIdx != 0; + for (int i = 0; i < curScopeLocalIdx; i++) { + cb.dup(); // dup for comparison + cb.loadLocal(ReferenceType, scopeSlots[i]); + cb.if_acmpeq(skipAcquire); + } + + // 1 scope to acquire on the stack + cb.dup(); + int nextScopeLocal = scopeSlots[curScopeLocalIdx++]; + // call acquire first here. So that if it fails, we don't call release + cb.invokevirtual(CD_MemorySessionImpl, "acquire0", MTD_ACQUIRE0); // call acquire on the other + cb.storeLocal(ReferenceType, nextScopeLocal); // store off one to release later + + if (hasOtherScopes) { // avoid ASM generating a bunch of nops for the dead code + cb.goto_(end); + + cb.labelBinding(skipAcquire); + cb.pop(); // drop scope + } + + cb.labelBinding(end); + } + + private void emitReleaseScopes() { + for (int scopeLocal : scopeSlots) { + cb.loadLocal(ReferenceType, scopeLocal); + cb.ifThen(Opcode.IFNONNULL, ifCb -> { + ifCb.loadLocal(ReferenceType, scopeLocal); + ifCb.invokevirtual(CD_MemorySessionImpl, "release0", MTD_RELEASE0); + }); + } + } + + private void emitSaveReturnValue(Class storeType) { + TypeKind typeKind = TypeKind.from(storeType); + retValIdx = cb.allocateLocal(typeKind); + cb.storeLocal(typeKind, retValIdx); + } + + private void emitRestoreReturnValue(Class loadType) { + assert retValIdx != -1; + cb.loadLocal(TypeKind.from(loadType), retValIdx); + pushType(loadType); + } + + private void emitLoadInternalSession() { + assert contextIdx != -1; + cb.loadLocal(ReferenceType, contextIdx); + cb.checkcast(CD_Arena); + cb.invokeinterface(CD_Arena, "scope", MTD_SCOPE); + cb.checkcast(CD_MemorySessionImpl); + } + + private void emitLoadInternalAllocator() { + assert contextIdx != -1; + cb.loadLocal(ReferenceType, contextIdx); + } + + private void emitCloseContext() { + assert contextIdx != -1; + cb.loadLocal(ReferenceType, contextIdx); + cb.checkcast(CD_Arena); + cb.invokeinterface(CD_Arena, "close", MTD_CLOSE); + } + + private void emitBoxAddress(BoxAddress boxAddress) { + popType(long.class); + cb.loadConstant(boxAddress.size()); + cb.loadConstant(boxAddress.align()); + if (needsSession()) { + emitLoadInternalSession(); + cb.invokestatic(CD_Utils, "longToAddress", MTD_LONG_TO_ADDRESS_SCOPE); + } else { + cb.invokestatic(CD_Utils, "longToAddress", MTD_LONG_TO_ADDRESS_NO_SCOPE); + } + pushType(MemorySegment.class); + } + + private void emitAllocBuffer(Allocate binding) { + if (callingSequence.forDowncall()) { + assert returnAllocatorIdx != -1; + cb.loadLocal(ReferenceType, returnAllocatorIdx); + } else { + emitLoadInternalAllocator(); + } + emitAllocateCall(binding.size(), binding.alignment()); + pushType(MemorySegment.class); + } + + private void emitBufferStore(BufferStore bufferStore) { + Class storeType = bufferStore.type(); + TypeKind storeTypeKind = TypeKind.from(storeType); + long offset = bufferStore.offset(); + int byteWidth = bufferStore.byteWidth(); + + popType(storeType); + popType(MemorySegment.class); + + if (SharedUtils.isPowerOfTwo(byteWidth)) { + int valueIdx = cb.allocateLocal(storeTypeKind); + cb.storeLocal(storeTypeKind, valueIdx); + + ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType); + cb.loadConstant(offset); + cb.loadLocal(storeTypeKind, valueIdx); + MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, desc(storeType)); + cb.invokeinterface(CD_MemorySegment, "set", descriptor); + } else { + // long longValue = ((Number) value).longValue(); + if (storeType == int.class) { + cb.i2l(); + } else { + assert storeType == long.class; // chunking only for int and long + } + int longValueIdx = cb.allocateLocal(LongType); + cb.storeLocal(LongType, longValueIdx); + int writeAddrIdx = cb.allocateLocal(ReferenceType); + cb.storeLocal(ReferenceType, writeAddrIdx); + + int remaining = byteWidth; + int chunkOffset = 0; + do { + int chunkSize = Integer.highestOneBit(remaining); // next power of 2, in bytes + Class chunkStoreType; + long mask; + switch (chunkSize) { + case Integer.BYTES -> { + chunkStoreType = int.class; + mask = 0xFFFF_FFFFL; + } + case Short.BYTES -> { + chunkStoreType = short.class; + mask = 0xFFFFL; + } + case Byte.BYTES -> { + chunkStoreType = byte.class; + mask = 0xFFL; + } + default -> + throw new IllegalStateException("Unexpected chunk size for chunked write: " + chunkSize); + } + //int writeChunk = (int) (((0xFFFF_FFFFL << shiftAmount) & longValue) >>> shiftAmount); + int shiftAmount = chunkOffset * Byte.SIZE; + mask = mask << shiftAmount; + cb.loadLocal(LongType, longValueIdx); + cb.loadConstant(mask); + cb.land(); + if (shiftAmount != 0) { + cb.loadConstant(shiftAmount); + cb.lushr(); + } + cb.l2i(); + TypeKind chunkStoreTypeKind = TypeKind.from(chunkStoreType); + int chunkIdx = cb.allocateLocal(chunkStoreTypeKind); + cb.storeLocal(chunkStoreTypeKind, chunkIdx); + // chunk done, now write it + + //writeAddress.set(JAVA_SHORT_UNALIGNED, offset, writeChunk); + cb.loadLocal(ReferenceType, writeAddrIdx); + ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkStoreType); + long writeOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize); + cb.loadConstant(writeOffset); + cb.loadLocal(chunkStoreTypeKind, chunkIdx); + MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, desc(chunkStoreType)); + cb.invokeinterface(CD_MemorySegment, "set", descriptor); + + remaining -= chunkSize; + chunkOffset += chunkSize; + } while (remaining != 0); + } + } + + // VM_STORE and VM_LOAD are emulated, which is different for down/upcalls + private void emitVMStore(VMStore vmStore) { + Class storeType = vmStore.type(); + TypeKind storeTypeKind = TypeKind.from(storeType); + popType(storeType); + + if (callingSequence.forDowncall()) { + // processing arg + emitSetOutput(storeType); + } else { + // processing return + if (!callingSequence.needsReturnBuffer()) { + emitSaveReturnValue(storeType); + } else { + int valueIdx = cb.allocateLocal(storeTypeKind); + cb.storeLocal(storeTypeKind, valueIdx); // store away the stored value, need it later + + assert returnBufferIdx != -1; + cb.loadLocal(ReferenceType, returnBufferIdx); + ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType); + cb.loadConstant(retBufOffset); + cb.loadLocal(storeTypeKind, valueIdx); + MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, desc(storeType)); + cb.invokeinterface(CD_MemorySegment, "set", descriptor); + retBufOffset += abi.arch.typeSize(vmStore.storage().type()); + } + } + } + + private void emitVMLoad(VMLoad vmLoad) { + Class loadType = vmLoad.type(); + + if (callingSequence.forDowncall()) { + // processing return + if (!callingSequence.needsReturnBuffer()) { + emitRestoreReturnValue(loadType); + } else { + assert returnBufferIdx != -1; + cb.loadLocal(ReferenceType, returnBufferIdx); + ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType); + cb.loadConstant(retBufOffset); + MethodTypeDesc descriptor = MethodTypeDesc.of(desc(loadType), valueLayoutType, CD_long); + cb.invokeinterface(CD_MemorySegment, "get", descriptor); + retBufOffset += abi.arch.typeSize(vmLoad.storage().type()); + pushType(loadType); + } + } else { + // processing arg + emitGetInput(); + } + } + + private void emitDupBinding() { + Class dupType = typeStack.peek(); + emitDup(dupType); + pushType(dupType); + } + + private void emitShiftLeft(ShiftLeft shiftLeft) { + popType(long.class); + cb.loadConstant(shiftLeft.shiftAmount() * Byte.SIZE); + cb.lshl(); + pushType(long.class); + } + + private void emitShiftRight(ShiftRight shiftRight) { + popType(long.class); + cb.loadConstant(shiftRight.shiftAmount() * Byte.SIZE); + cb.lushr(); + pushType(long.class); + } + + private void emitCast(Cast cast) { + Class fromType = cast.fromType(); + Class toType = cast.toType(); + + popType(fromType); + switch (cast) { + case INT_TO_BOOLEAN -> { + // implement least significant byte non-zero test + + // select first byte + cb.loadConstant(0xFF); + cb.iand(); + + // convert to boolean + cb.invokestatic(CD_Utils, "byteToBoolean", MTD_BYTE_TO_BOOLEAN); + } + case INT_TO_BYTE -> cb.i2b(); + case INT_TO_CHAR -> cb.i2c(); + case INT_TO_SHORT -> cb.i2s(); + case BYTE_TO_LONG, CHAR_TO_LONG, SHORT_TO_LONG, INT_TO_LONG -> cb.i2l(); + case LONG_TO_BYTE -> { cb.l2i(); cb.i2b(); } + case LONG_TO_SHORT -> { cb.l2i(); cb.i2s(); } + case LONG_TO_CHAR -> { cb.l2i(); cb.i2c(); } + case LONG_TO_INT -> cb.l2i(); + case BOOLEAN_TO_INT, BYTE_TO_INT, CHAR_TO_INT, SHORT_TO_INT -> { + // no-op in bytecode + } + default -> throw new IllegalStateException("Unknown cast: " + cast); + } + pushType(toType); + } + + private void emitSegmentBase() { + popType(MemorySegment.class); + cb.checkcast(CD_AbstractMemorySegmentImpl); + cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetBase", MTD_UNSAFE_GET_BASE); + pushType(Object.class); + } + + private void emitSegmentOffset(SegmentOffset segmentOffset) { + popType(MemorySegment.class); + + if (!segmentOffset.allowHeap()) { + cb.dup(); + cb.invokestatic(CD_SharedUtils, "checkNative", MTD_CHECK_NATIVE); + } + cb.checkcast(CD_AbstractMemorySegmentImpl); + cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetOffset", MTD_UNSAFE_GET_OFFSET); + + pushType(long.class); + } + + private void emitBufferLoad(BufferLoad bufferLoad) { + Class loadType = bufferLoad.type(); + long offset = bufferLoad.offset(); + int byteWidth = bufferLoad.byteWidth(); + + popType(MemorySegment.class); + + if (SharedUtils.isPowerOfTwo(byteWidth)) { + ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType); + cb.loadConstant(offset); + MethodTypeDesc descriptor = MethodTypeDesc.of(desc(loadType), valueLayoutType, CD_long); + cb.invokeinterface(CD_MemorySegment, "get", descriptor); + } else { + // chunked + int readAddrIdx = cb.allocateLocal(ReferenceType); + cb.storeLocal(ReferenceType, readAddrIdx); + + cb.loadConstant(0L); // result + int resultIdx = cb.allocateLocal(LongType); + cb.storeLocal(LongType, resultIdx); + + int remaining = byteWidth; + int chunkOffset = 0; + do { + int chunkSize = Integer.highestOneBit(remaining); // next power of 2 + Class chunkType; + ClassDesc toULongHolder; + MethodTypeDesc toULongDescriptor; + switch (chunkSize) { + case Integer.BYTES -> { + chunkType = int.class; + toULongHolder = CD_Integer; + toULongDescriptor = MTD_INTEGER_TO_UNSIGNED_LONG; + } + case Short.BYTES -> { + chunkType = short.class; + toULongHolder = CD_Short; + toULongDescriptor = MTD_SHORT_TO_UNSIGNED_LONG; + } + case Byte.BYTES -> { + chunkType = byte.class; + toULongHolder = CD_Byte; + toULongDescriptor = MTD_BYTE_TO_UNSIGNED_LONG; + } + default -> + throw new IllegalStateException("Unexpected chunk size for chunked write: " + chunkSize); + } + // read from segment + cb.loadLocal(ReferenceType, readAddrIdx); + ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkType); + MethodTypeDesc descriptor = MethodTypeDesc.of(desc(chunkType), valueLayoutType, CD_long); + long readOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize); + cb.loadConstant(readOffset); + cb.invokeinterface(CD_MemorySegment, "get", descriptor); + cb.invokestatic(toULongHolder, "toUnsignedLong", toULongDescriptor); + + // shift to right offset + int shiftAmount = chunkOffset * Byte.SIZE; + if (shiftAmount != 0) { + cb.loadConstant(shiftAmount); + cb.lshl(); + } + // add to result + cb.loadLocal(LongType, resultIdx); + cb.lor(); + cb.storeLocal(LongType, resultIdx); + + remaining -= chunkSize; + chunkOffset += chunkSize; + } while (remaining != 0); + + cb.loadLocal(LongType, resultIdx); + if (loadType == int.class) { + cb.l2i(); + } else { + assert loadType == long.class; // should not have chunking for other types + } + } + + pushType(loadType); + } + + private void emitCopyBuffer(Copy copy) { + long size = copy.size(); + long alignment = copy.alignment(); + + popType(MemorySegment.class); + + // operand/srcSegment is on the stack + // generating a call to: + // MemorySegment::copy(MemorySegment srcSegment, long srcOffset, MemorySegment dstSegment, long dstOffset, long bytes) + cb.loadConstant(0L); + // create the dstSegment by allocating it. Similar to: + // context.allocator().allocate(size, alignment) + emitLoadInternalAllocator(); + emitAllocateCall(size, alignment); + cb.dup(); + int storeIdx = cb.allocateLocal(ReferenceType); + cb.storeLocal(ReferenceType, storeIdx); + cb.loadConstant(0L); + cb.loadConstant(size); + cb.invokestatic(CD_MemorySegment, "copy", MTD_COPY, true); + + cb.loadLocal(ReferenceType, storeIdx); + pushType(MemorySegment.class); + } + + private void emitAllocateCall(long size, long alignment) { + cb.loadConstant(size); + cb.loadConstant(alignment); + cb.invokeinterface(CD_SegmentAllocator, "allocate", MTD_ALLOCATE); + } + + private ClassDesc emitLoadLayoutConstant(Class type) { + ClassDesc valueLayoutType = valueLayoutTypeFor(type); + String valueLayoutConstantName = valueLayoutConstantFor(type); + cb.getstatic(CD_ValueLayout, valueLayoutConstantName, valueLayoutType); + return valueLayoutType; + } + + private static String valueLayoutConstantFor(Class type) { + if (type == boolean.class) { + return "JAVA_BOOLEAN"; + } else if (type == byte.class) { + return "JAVA_BYTE"; + } else if (type == short.class) { + return "JAVA_SHORT_UNALIGNED"; + } else if (type == char.class) { + return "JAVA_CHAR_UNALIGNED"; + } else if (type == int.class) { + return "JAVA_INT_UNALIGNED"; + } else if (type == long.class) { + return "JAVA_LONG_UNALIGNED"; + } else if (type == float.class) { + return "JAVA_FLOAT_UNALIGNED"; + } else if (type == double.class) { + return "JAVA_DOUBLE_UNALIGNED"; + } else if (type == MemorySegment.class) { + return "ADDRESS_UNALIGNED"; + } else { + throw new IllegalStateException("Unknown type: " + type); + } + } + + private static ClassDesc valueLayoutTypeFor(Class type) { + if (type == boolean.class) { + return CD_ValueLayout_OfBoolean; + } else if (type == byte.class) { + return CD_ValueLayout_OfByte; + } else if (type == short.class) { + return CD_ValueLayout_OfShort; + } else if (type == char.class) { + return CD_ValueLayout_OfChar; + } else if (type == int.class) { + return CD_ValueLayout_OfInt; + } else if (type == long.class) { + return CD_ValueLayout_OfLong; + } else if (type == float.class) { + return CD_ValueLayout_OfFloat; + } else if (type == double.class) { + return CD_ValueLayout_OfDouble; + } else if (type == MemorySegment.class) { + return CD_AddressLayout; + } else { + throw new IllegalStateException("Unknown type: " + type); + } + } + + private void emitDup(Class type) { + if (type == double.class || type == long.class) { + cb.dup2(); + } else { + cb.dup(); + } + } + + /* + * Low-level emit helpers. + */ + + private void emitConstZero(TypeKind kind) { + switch (kind) { + case BooleanType, ByteType, ShortType, CharType, IntType -> cb.iconst_0(); + case LongType -> cb.lconst_0(); + case FloatType -> cb.fconst_0(); + case DoubleType -> cb.dconst_0(); + case ReferenceType -> cb.aconst_null(); + } + } + + @SuppressWarnings("unchecked") + private static T desc(Constable c) { + return (T) c.describeConstable().orElseThrow(); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/CallingSequence.class b/tests/test_data/std/jdk/internal/foreign/abi/CallingSequence.class new file mode 100644 index 0000000000000000000000000000000000000000..50b6702333a0635f67201e04c5d8bd027b03bf6d GIT binary patch literal 5693 zcmc&&`*&1V75+|MGnw2x7(&{RPzFdbnG^;o0!=7|1So?6DxuUyt-ZpU% zTKllp`l_vOZGE)j1FhCt?F69~s0eb8`qRh%Q7o59KE( zEk|&>4Xna7)Y$P2j3)1)#_E7fh!|KS6Iy6ddcu?iWLSpQ8R)^a9P(t7c7pt53Fc~- z&m~i_kz_Wf^?09wUYXryI#c->%gzmX^93qupdZ&MG?U?J%Q>8pb%@kEvYsniF&<(baVC3#m zxN1)CGHivwWXjAPG&2g@Ns5HD)?hy3!upBf`wZNS{e(+q_s(Q;)R2^ng>V2L3}D2- zL9urI(nx1aO_&+Rla-LYF`6@TRu~G04cvkcDTFi!yR&hd9QRZw;%J(qWo(QZIEq^p zf-`1Dk1Fh{YH_(}6|;$4@=OhG6RkeXkgBc-Co>>T=hWeh<(RU0nlOfs1n^M0*xyMosZE$R*+E^7gKhS!WLiLNYdP~ zaO(369o$KXee=ai$zjPb0`y$(m`QC)Y~n$uHy-b!pOwikfkLC{yfb0#OUg!Uuh>!>C4i~VP&%E< z<{UHQ9&)p7c!8%5e;uk)GrX?WM$9(hEVc*mTdpv-C5F>HbL$gu8_p~A`wtD;_f?Jv zv183i+DMJ-y8UYRFuW82yz^fq@y`vikhKI+VDrWA}*BL z+!9|B8|;g>;n~&(ye4(*&jx;>-(C;l4ZIn^TL#|7I|^&H>HcsV(S9PQ=A=2nBMeV> zO*8(tH~l7-rTG1(ok&^Po{@BVI-l{1B~4Z0~9LC5zgJWTQr}-|lL* zP2oJ*#W~zmgG%&cJ{{XVbQklx#OT5IJj@v1#M*jduB`+a^MTZtfqb7rP1w(0q0A2w zsATJoDj*6^m4t^p4VtMz;7J7P&Y-SVK-@rcDIfQNG<%vnEo!5tX_r{giXT)_rn%B0 z$A?q2h_{=n!pka!AF3*R8b7SEa(kulBUOc0mT2&Ecy%R*PgNCOg&&nxb|XW)*!3)V z@rUa(RfX476<%E_T&ODigu*A{X23>MlIzLkgF>ux*!s{G_x6N9lV3 zT}9BoS;Wudkc9aW{uOr~$E10Ct#4O`b%uC}d;J2l#YJ@ECEr@BytNe0l(gPUcv+y$ zUEt#j>HLZhr>$J)mR$nz(~{0dyv-RFA5iJ>Cp;eRtc>N?e4u_JnEVc__o$T$NRd#2 z|1&(wUrFHW$cd!H(=Woh{Vb+N`oqU(apJcAu+0b8Y@S7iZ&~+knfsP^-`d@`yG5Y( z#_s4WPMt=7fB2K^=$^&>;ZM2q)_3b{#o6Ic%iM=+)S34#6TIl!E>|Y}8F&8L(#-zw zXGNfY7N3{MclYjAU2@)_HE(f)zRf=e-(gYsD@()Q_)pa({x@-%SLI7^@DJRNcbTgH z$;9+8%}<0FL)fI#p(NAO9{oWE*faP!S$Ueh&8Ynkh61qEzY$y47LwDAOBidAn}zFE zc0E|RpDyYp+}vA-UlLM2b$Cwa-dZo4K966sR}}dRzrR6&fhVmO8DFpH)~omvUZp`& M&lQcjOhY>V2S})k=l}o! literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/CallingSequence.java b/tests/test_data/std/jdk/internal/foreign/abi/CallingSequence.java new file mode 100644 index 00000000..e301f692 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/CallingSequence.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +import java.lang.foreign.FunctionDescriptor; + +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.stream.Stream; + +public class CallingSequence { + private final boolean forUpcall; + private final MethodType callerMethodType; + private final MethodType calleeMethodType; + private final FunctionDescriptor desc; + private final boolean needsReturnBuffer; + private final long returnBufferSize; + private final long allocationSize; + + private final List returnBindings; + private final List> argumentBindings; + + private final LinkerOptions linkerOptions; + + public CallingSequence(boolean forUpcall, MethodType callerMethodType, MethodType calleeMethodType, FunctionDescriptor desc, + boolean needsReturnBuffer, long returnBufferSize, long allocationSize, + List> argumentBindings, List returnBindings, + LinkerOptions linkerOptions) { + this.forUpcall = forUpcall; + this.callerMethodType = callerMethodType; + this.calleeMethodType = calleeMethodType; + this.desc = desc; + this.needsReturnBuffer = needsReturnBuffer; + this.returnBufferSize = returnBufferSize; + this.allocationSize = allocationSize; + this.returnBindings = returnBindings; + this.argumentBindings = argumentBindings; + this.linkerOptions = linkerOptions; + } + + /** + * An important distinction is that downcalls have 1 recipe per caller parameter and + * each callee parameter corresponds to a VM_STORE. Upcalls have 1 recipe per callee parameter and + * each caller parameter corresponds to a VM_LOAD. + * + * The VM_STOREs are then implemented by the leaf handle for downcalls, and vice versa, the wrapper + * stub that wraps an upcall handle implements the VM_LOADS. In both cases the register values are + * communicated through Java primitives. + * + * The 'argumentBindingsCount' below corresponds to the number of recipes, so it is the + * caller parameter count for downcalls, and the callee parameter count for upcalls. + * + * @return the number of binding recipes in this calling sequence + */ + public int argumentBindingsCount() { + return argumentBindings.size(); + } + + public List argumentBindings(int i) { + return argumentBindings.get(i); + } + + public Stream argumentBindings() { + return argumentBindings.stream().flatMap(List::stream); + } + + public List returnBindings() { + return returnBindings; + } + + public boolean forUpcall() { + return forUpcall; + } + + public boolean forDowncall() { + return !forUpcall; + } + + /** + * Returns the caller method type, which is the high-level method type + * for downcalls (the type of the downcall method handle) + * and the low-level method type (all primitives, VM facing) for upcalls. + * + * Note that for downcalls a single parameter in this method type corresponds + * to a single argument binding recipe in this calling sequence, but it may + * correspond to multiple parameters in the callee method type (for instance + * if a struct is split into multiple register values). + * + * @return the caller method type. + */ + public MethodType callerMethodType() { + return callerMethodType; + } + + /** + * Returns the callee method type, which is the low-level method type + * (all primitives, VM facing) for downcalls and the high-level method type + * for upcalls (also the method type of the user-supplied target MH). + * + * Note that for upcalls a single parameter in this method type corresponds + * to a single argument binding recipe in this calling sequence, but it may + * correspond to multiple parameters in the caller method type (for instance + * if a struct is reconstructed from multiple register values). + * + * @return the callee method type. + */ + public MethodType calleeMethodType() { + return calleeMethodType; + } + + public FunctionDescriptor functionDesc() { + return desc; + } + + /** + * Whether this calling sequence needs a return buffer. + * + * A return buffer is used to support functions that return values + * in multiple registers, which is not possible to do just with Java primitives + * (we can only return 1 value in Java, meaning only 1 register value). + * + * To emulate these multi-register returns, we instead use a pre-allocated buffer + * (the return buffer) from/into which the return values are loaded/stored. + * + * For downcalls, we allocate the buffer in Java code, and pass the address down + * to the VM stub, which stores the returned register values into this buffer. + * VM_LOADs in the binding recipe for the return value then load the value from this buffer. + * + * For upcalls, the VM stub allocates a buffer (on the stack), and passes the address + * to the Java method handle it calls. VM_STOREs in the return binding recipe then + * store values into this buffer, after which the VM stub moves the values from the buffer + * into the right register. + * + * @return whether this calling sequence needs a return buffer. + */ + public boolean needsReturnBuffer() { + return needsReturnBuffer; + } + + /** + * The size of the return buffer, if one is needed. + * + * @see #needsReturnBuffer + * + * @return the return buffer size + */ + public long returnBufferSize() { + return returnBufferSize; + } + + /** + * The amount of bytes this calling sequence needs to allocate during an invocation. + * + * Includes the return buffer size as well as space for any buffer copies in the recipes. + * + * @return the allocation size + */ + public long allocationSize() { + return allocationSize; + } + + public boolean hasReturnBindings() { + return !returnBindings.isEmpty(); + } + + public int capturedStateMask() { + return linkerOptions.capturedCallState() + .mapToInt(CapturableState::mask) + .reduce(0, (a, b) -> a | b); + } + + public boolean needsTransition() { + return !linkerOptions.isCritical(); + } + + public int numLeadingParams() { + return 2 + (linkerOptions.hasCapturedCallState() ? 1 : 0); // 2 for addr, allocator + } + + public String asString() { + StringBuilder sb = new StringBuilder(); + + sb.append("CallingSequence: {\n"); + sb.append(" callerMethodType: ").append(callerMethodType); + sb.append(" calleeMethodType: ").append(calleeMethodType); + sb.append(" FunctionDescriptor: ").append(desc); + sb.append(" Argument Bindings:\n"); + for (int i = 0; i < argumentBindingsCount(); i++) { + sb.append(" ").append(i).append(": ").append(argumentBindings.get(i)).append("\n"); + } + if (!returnBindings.isEmpty()) { + sb.append(" ").append("Return: ").append(returnBindings).append("\n"); + } + sb.append("}\n"); + + return sb.toString(); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/CallingSequenceBuilder.class b/tests/test_data/std/jdk/internal/foreign/abi/CallingSequenceBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..e02b6b5752c6e70bae73c8951ef8ab6ca4d4966d GIT binary patch literal 14989 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 Iv#9d_0T_#CzyJUM literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/CallingSequenceBuilder.java b/tests/test_data/std/jdk/internal/foreign/abi/CallingSequenceBuilder.java new file mode 100644 index 00000000..a439df3e --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/CallingSequenceBuilder.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +import jdk.internal.foreign.Utils; +import jdk.internal.foreign.abi.Binding.*; +import jdk.internal.foreign.abi.Binding.BoxAddress; +import jdk.internal.foreign.abi.Binding.BufferLoad; +import jdk.internal.foreign.abi.Binding.BufferStore; +import jdk.internal.foreign.abi.Binding.Cast; +import jdk.internal.foreign.abi.Binding.Copy; +import jdk.internal.foreign.abi.Binding.Dup; +import jdk.internal.foreign.abi.Binding.SegmentBase; +import jdk.internal.foreign.abi.Binding.SegmentOffset; +import jdk.internal.foreign.abi.Binding.ShiftLeft; +import jdk.internal.foreign.abi.Binding.ShiftRight; +import jdk.internal.foreign.abi.Binding.VMLoad; +import jdk.internal.foreign.abi.Binding.VMStore; +import sun.security.action.GetPropertyAction; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodType; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +import static java.lang.invoke.MethodType.methodType; + +public class CallingSequenceBuilder { + private static final boolean VERIFY_BINDINGS = Boolean.parseBoolean( + GetPropertyAction.privilegedGetProperty("java.lang.foreign.VERIFY_BINDINGS", "true")); + + private final ABIDescriptor abi; + private final LinkerOptions linkerOptions; + + private final boolean forUpcall; + private final List> inputBindings = new ArrayList<>(); + private List outputBindings = List.of(); + + private MethodType mt = MethodType.methodType(void.class); + private FunctionDescriptor desc = FunctionDescriptor.ofVoid(); + + public CallingSequenceBuilder(ABIDescriptor abi, boolean forUpcall, LinkerOptions linkerOptions) { + this.abi = abi; + this.forUpcall = forUpcall; + this.linkerOptions = linkerOptions; + } + + public final CallingSequenceBuilder addArgumentBindings(Class carrier, MemoryLayout layout, + List bindings) { + addArgumentBinding(inputBindings.size(), carrier, layout, bindings); + return this; + } + + private void addArgumentBinding(int index, Class carrier, MemoryLayout layout, List bindings) { + verifyBindings(true, carrier, bindings); + inputBindings.add(index, bindings); + mt = mt.insertParameterTypes(index, carrier); + desc = desc.insertArgumentLayouts(index, layout); + } + + public CallingSequenceBuilder setReturnBindings(Class carrier, MemoryLayout layout, + List bindings) { + verifyBindings(false, carrier, bindings); + this.outputBindings = bindings; + mt = mt.changeReturnType(carrier); + desc = desc.changeReturnLayout(layout); + return this; + } + + private boolean needsReturnBuffer() { + return outputBindings.stream() + .filter(Binding.Move.class::isInstance) + .count() > 1; + } + + public CallingSequence build() { + boolean needsReturnBuffer = needsReturnBuffer(); + long returnBufferSize = needsReturnBuffer ? computeReturnBufferSize() : 0; + long allocationSize = computeAllocationSize() + returnBufferSize; + MethodType callerMethodType; + MethodType calleeMethodType; + if (!forUpcall) { + if (linkerOptions.hasCapturedCallState()) { + addArgumentBinding(0, MemorySegment.class, ValueLayout.ADDRESS, List.of( + Binding.unboxAddress(), + Binding.vmStore(abi.capturedStateStorage(), long.class))); + } + addArgumentBinding(0, MemorySegment.class, ValueLayout.ADDRESS, List.of( + Binding.unboxAddress(), + Binding.vmStore(abi.targetAddrStorage(), long.class))); + if (needsReturnBuffer) { + addArgumentBinding(0, MemorySegment.class, ValueLayout.ADDRESS, List.of( + Binding.unboxAddress(), + Binding.vmStore(abi.retBufAddrStorage(), long.class))); + } + + callerMethodType = mt; + calleeMethodType = computeCalleeTypeForDowncall(); + } else { // forUpcall == true + if (needsReturnBuffer) { + addArgumentBinding(0, MemorySegment.class, ValueLayout.ADDRESS, List.of( + Binding.vmLoad(abi.retBufAddrStorage(), long.class), + Binding.boxAddress(returnBufferSize))); + } + + callerMethodType = computeCallerTypeForUpcall(); + calleeMethodType = mt; + } + return new CallingSequence(forUpcall, callerMethodType, calleeMethodType, desc, needsReturnBuffer, + returnBufferSize, allocationSize, inputBindings, outputBindings, linkerOptions); + } + + private MethodType computeCallerTypeForUpcall() { + return computeTypeHelper(VMLoad.class, VMStore.class); + } + + private MethodType computeCalleeTypeForDowncall() { + return computeTypeHelper(VMStore.class, VMLoad.class); + } + + private MethodType computeTypeHelper(Class inputVMClass, + Class outputVMClass) { + Class[] paramTypes = inputBindings.stream() + .flatMap(List::stream) + .filter(inputVMClass::isInstance) + .map(inputVMClass::cast) + .map(Binding.Move::type) + .toArray(Class[]::new); + + Binding.Move[] retMoves = outputBindings.stream() + .filter(outputVMClass::isInstance) + .map(outputVMClass::cast) + .toArray(Binding.Move[]::new); + Class returnType = retMoves.length == 1 ? retMoves[0].type() : void.class; + + return methodType(returnType, paramTypes); + } + + private long computeAllocationSize() { + // FIXME: > 16 bytes alignment might need extra space since the + // starting address of the allocator might be un-aligned. + long size = 0; + for (List bindings : inputBindings) { + for (Binding b : bindings) { + if (b instanceof Copy copy) { + size = Utils.alignUp(size, copy.alignment()); + size += copy.size(); + } else if (b instanceof Allocate allocate) { + size = Utils.alignUp(size, allocate.alignment()); + size += allocate.size(); + } + } + } + return size; + } + + private long computeReturnBufferSize() { + return outputBindings.stream() + .filter(Binding.Move.class::isInstance) + .map(Binding.Move.class::cast) + .map(Binding.Move::storage) + .map(VMStorage::type) + .mapToLong(abi.arch::typeSize) + .sum(); + } + + private void verifyBindings(boolean forArguments, Class carrier, List bindings) { + if (VERIFY_BINDINGS) { + if (forUpcall == forArguments) { + verifyBoxBindings(carrier, bindings); + } else { + verifyUnboxBindings(carrier, bindings); + } + } + } + + private static void verifyUnboxBindings(Class inType, List bindings) { + Deque> stack = new ArrayDeque<>(); + stack.push(inType); + + for (Binding b : bindings) { + if (!isUnbox(b)) + throw new IllegalArgumentException("Unexpected operator: " + b); + b.verify(stack); + } + + if (!stack.isEmpty()) { + throw new IllegalArgumentException("Stack must be empty after recipe"); + } + } + + static boolean isUnbox(Binding binding) { + return switch (binding) { + case VMStore unused -> true; + case BufferLoad unused -> true; + case Copy unused -> true; + case Dup unused -> true; + case SegmentBase unused -> true; + case SegmentOffset unused -> true; + case ShiftLeft unused -> true; + case ShiftRight unused -> true; + case Cast unused -> true; + case VMLoad unused -> false; + case BufferStore unused -> false; + case Allocate unused -> false; + case BoxAddress unused -> false; + }; + } + + private static void verifyBoxBindings(Class expectedOutType, List bindings) { + Deque> stack = new ArrayDeque<>(); + + for (Binding b : bindings) { + if (!isBox(b)) + throw new IllegalArgumentException("Unexpected operator: " + b); + b.verify(stack); + } + + if (stack.size() != 1) { + throw new IllegalArgumentException("Stack must contain exactly 1 value"); + } + + Class actualOutType = stack.pop(); + SharedUtils.checkType(actualOutType, expectedOutType); + } + + static boolean isBox(Binding binding) { + return switch (binding) { + case VMLoad unused -> true; + case BufferStore unused -> true; + case Copy unused -> true; + case Allocate unused -> true; + case BoxAddress unused -> true; + case Dup unused -> true; + case ShiftLeft unused -> true; + case ShiftRight unused -> true; + case Cast unused -> true; + + case VMStore unused -> false; + case BufferLoad unused -> false; + case SegmentBase unused -> false; + case SegmentOffset unused -> false; + }; + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/CapturableState.class b/tests/test_data/std/jdk/internal/foreign/abi/CapturableState.class new file mode 100644 index 0000000000000000000000000000000000000000..b3cb8f8fb754061170a9b86fd7d37f826ff4eb5f GIT binary patch literal 5565 zcmbVQ2Y3_b8Gg^Ue73lNqB3d|f+2?3GDfVB1cN~sLqv>Ckuf#2b2A}s>E3(qy+@k&zdKncS;HBCLsK6H z&>@9nR7hw#I&>_qn~r9isu3TyY)v0AgBW*zqLVzoOnSv{^Ttf9$ z-PE0S35$cGe9mNZpYVKzf|a;RLTy$ApiovbBPIa-#uHsn*vB_Gb2X-Bur z_U6>Xa%v8UEWgM2UvJl6lVQ3?&k+4T{8O?M$Po_23B^gi3 zXN21Tyt><&(~Tj`4&w-(BFc1t&Nemo)j(x4IA|U-trKR0$uiv1AZXGGhQN}nR>#IP zlWE&JJ0>%=wAEmQD6DD7%cP< zJQL5Nu(T&x!n&XnGkD5o&a)*%3Yn8~d${^b6S15QTUPasYCi)Ts$?jeWs{(BlD0RwCDP=BmN+pDeVp?Qv-*R-Me}YrG$rX6d1gTy{QZa$$)YnmcULKbJ~)J zMFG~<;H|6%9vOlj)Fz%<(kYCQdO{S~dDqTNeU-sa2x2vIzHS&ZsrCU$yy_Gm;rr z<&5fFYEwL)syvvIs;FDcJ(VQvDartXT{sGCox2O|bV4R<-Z^STUZ&gT^JoUDiqxDW zN%ub|RK!p-gF|YgFQ9Qlq3Z?)MZWL3TeD3vN-mYgGuHMp0h+sW%`~wx>lh5ZZ>Ttc z>gmRH5*nM5MTwqwwkV&;eo_$EY)u>fF_+j*7l$|uKT52_DJy5EwcWZ%zl9~&leI!L zaoA~D4g;!=c^QKyAsm+HMRO5R>!1on=4i7}Ih#Nl= z8$VX?S==ANPbI7_3jeH;is0vhHULDv$YE3ee%Y;8b}UlNq_8)5Bl#fkk> z5&T}ljkMsgNX$n%nAQ>eQOvDmum$-}5vM;3&3{qw1w0tRgWULg82`XOW&BIQzww`< zlbUWGw~lG?F1IikKXq6YCj@rhdF%p(Zx00V^O?MG-=La9hL&yYvaDmdv9_651a^uT zdrysNLGro3^i)1FZx9+^a))XdDV;Y0cKf7hYPNfW)Uq-jl5ka_PRbzejc1NLcTCHY z#DQL5D6+g54_T@#I!2Tu71O~5Z^wEDZV9hAwL9v>tsmgZTf4jRdd@d>Vw`Y|iYuzS z@V!eLnelo1@%|{I-&-_=LxC*#s`Xgy`M;CgDT;U+unIMf!T& z$9spM-^5jLgriby5{oZE67&^C^x~Hd#iPPUT$?U&Cq%Z>f|O?x9*>2v+qlYH8)Ge3 zoW~Wh)^lix)m61#Kw|}Ga4fbcbPj7{i>l9I!#$+))YQ9fZ{Yupm`8(_(7k2YOhwm1 zsNO`NC=(xb>BN%&rqbOL&{Vlk0vwM{z*CJ&+^r*?0wVEO^7$CQSK#9ai|YWNg!#=} z#pm)#Y@WoHDeM4av8w_Ck|2az;IV&#P=1n7de93o0?Jm8JvN0KeEx!@3%HTL>r9~s zm_VusZ4ZWaBE21psd_0ASj|i58s4%C5oq-zz!Jw9UvZqPP#lWgi-ywh?F}%8d<-Sg zvdS>WN}0RMGOxp@%P_CKizWmU=RjFz4vR9(8%mk`W->>@VlMd1Cm3wu^R|oV@4tv6 z{pa!I=uHzCjPWlz%zu*@oq{1EFjj%6Gl}CD@bn7i#c95rz;n*y`2}|uyScNI#kUJ9 z(8=F>c4I5SF95&I1D-~3TKPt7qrW0$YFj37D;2-6)Qjz|fW;n>A32ia^Gr~QqS(Jn z!Kl9vcNFaMO133nM+jdOZGg-?k54m;8UU75GZ*_S$5EN;uNsG(>JN=0oD$-K>AMOw z_!0(u<~#XKd`2#kH~P}b=*!0Oa&o`=Jl=2?mG17FtD supportedStates() { + return Stream.of(values()).filter(CapturableState::isSupported); + } + + public static CapturableState forName(String name) { + return Stream.of(values()) + .filter(stl -> stl.stateName().equals(name)) + .filter(CapturableState::isSupported) + .findAny() + .orElseThrow(() -> new IllegalArgumentException( + "Unknown name: " + name +", must be one of: " + + supportedStates() + .map(CapturableState::stateName) + .collect(Collectors.joining(", ")))); + } + + public String stateName() { + return stateName; + } + + public ValueLayout layout() { + return layout; + } + + public int mask() { + return mask; + } + + public boolean isSupported() { + return isSupported; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/DowncallLinker$1.class b/tests/test_data/std/jdk/internal/foreign/abi/DowncallLinker$1.class new file mode 100644 index 0000000000000000000000000000000000000000..7ace477d68d9ac20c05a751356a04286f244ad7f GIT binary patch literal 1351 zcma)6T~8B16g@)=%a)~-7E$pFb%nMd3mQ#KjRyIMjRj0fny4>M+vzf}%$nUTzMA-Z zFu_1feDDYOql|aj0x3{JA7_*R@YF;fVg}+C`Z2(e+ph08Qbi(A z+;bX!Af&4tUX{+W|5eqv=ar<|5rMtHVC`|w_5^P%25!iZ`Bd8Gd))E3a-EIpwx~sg z1O{OmNLUzx#gICCfnngKR5E(S5XFvOSqx?mU~@?yQYTNS}3uX?nTF8L%% zg$GivJDc%nOOhZnS4FiK3M7OMvggTytAiR=1 z0>g_-1gNZOrMN2!=k3$f4V{CI8SLJLohBi(d@ajar>WRP*>46lu`0E2nQr0d^nDU| zMb$h%BrDs*3`{djU(q}ZIpi6}q}ua$M7tL{jX}D6Ck;;8^SH6g!rc`rTJ$`!k$7I@ ze{a^^6zn45QWoi}WghVY`FMiYc@7MN>mrQa`XM#7Ra8m@OCAqH5gM4IhUrQ4e1B`B zwYj>(4bW?R-ZS{pG8vNHbz_nq;UE}B=?nc9fmBNWJJ3q+3?YLU#%T7A)-io2KYIk0 z{{*6&Ulda=@nD{~SeT>uIcqi?3+@O^PxQPjZyG3)8@_%dN-KJ$9EIPP@ zyEJONO{zlUrSpdb_u&x3ALE}1aJGC3nP{aypz43N;3nG_)rm zpz?%-c;&Z%lyH0K4?sl%eh}h}?KrmRhJr17c4ogh=X|%BU;p~$DS$;hP9uS&fs~1t zFd~rOZtN5tFH(Ug-D1-Zl+*Hxa?>d;`CoW->ADri+fhO8mcZG4>E@aa4cArF4!m-^ z*;IkR#mctamqk~4tv*6k?fSu!nriJTFDhx$Q4?v535-NrPMEtv>dFgpm&Rb?Wdq|T zCXf-x9Mi3CZmW7k&^gC*qIrSjOnyVNoi=d>S=t6FqRw?C8>`J`sAwzfF-+kV1FxER z4buX-SRJ)38K}nN$Z7X+@x ziWp7=U1W9ys3IoQcc0B5>u!w$WV~)VHYX1RfeV5#!$u z6mv9#yaCI^ED8dbVre$2HOi7LMT+Rj9tY;Ed=PX8XJgQ(*qRkE!lUHn;*}nQ3QP{fs*6jIK!t5Lx~W6)kG>F? z8jcS$+>23mz`BDqXU#JTmH*|R-us-k6d0@d?Vzrf9i6K)!%@GkVb>isje(lL-PpY+suUO>mW>NMw@nD# zMv`|Gk8dE8(brUG&(S;<38e&4ZvhyUXp zn`az%<1FrszYYBW#E!V!IeG7^{od7gNB8 z_=ue3;Ay%*-f^5qnb&s`OI+1K>b|?jcU_Ik#JJDZ1RlWVnBw*F5Y^7gIjnG;=58H6 R{ke@*d@_>8I;|dI`ft>iLi7Lt literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/DowncallLinker$InvocationData.class b/tests/test_data/std/jdk/internal/foreign/abi/DowncallLinker$InvocationData.class new file mode 100644 index 0000000000000000000000000000000000000000..a80b41d1337053edad4de53db904304580a0d558 GIT binary patch literal 1948 zcmbVNTTc^F5dKbSyKP-4l#2q&MM2tvtawF>sI)OODQJZ7piigmfi7Kk>+TlgKk-NS zAc@3;2Y-M+$~b!gw$L_&hwj-ko%v?wo6G+Fck%~79)$!#=#dbX5kZupf1e+6MdSLO z@=;U_v&s-%QFYZ`W#~y~cH)R3E+HY~24se3`_;Ol>b5X-t|_~QDbzh(;bm1R7+>`Y z*R+zV*M&J#)DMjcw^c(gaGNuPHNkfoCQIl3R8px6Wkc9Cqq@%ZswQ%dyFM97^fM$K zI91=<5?`7^uLy>0siXURt8Oku*`{O+Vu>8(X$XNDQTPXNayDV-K zMLufWs^yI;MVY(4kD?Ryn2d4UraDmGT(cN9t_>K7`F(j`RP0>llSjf?)!S8}Ge;L` z&g@WWy|j~5d9m3%C<}9&mo*|HRiYNqcDSiJcV8H`Ybxcm+}TI>I#A1c9rJ;k{6J7A z653F@O?lh~E;0-geP`(gXkdmD;-$YBrd!b35yY_I=yaNei!3oDwv47(5${xom%-Ky z7o8BOgEoa_uN#&vL1CEd2;OQ;ZE`xd{cDC{Teis?9zj+NkBJ&*@N!g#;3y>-B>MFx zqj;XcGG0h{DI{6PJ&(GSDryG>bfvpNI|{RS8Q2T65cS( zo|DieDG6%~6Wvv*J{|*jNUJSG;~hfE*`>~Ya`qgZQIbV)hn^F3+n}?D&SdsCSa$vx zQg-1Oy+RecybAoH=~Nvhybx?PNdV>6|4P!yM9t zz$l}PkEFPFAd>wBsaqBiABMgy$hI-=y^3)J^KPaKc;KFkR9T>p;`FNO)pW^~(FYS@ bs{126!Be~yHt@8cudv9jmOlCsbKR!j?n|t3q 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 argMoveBindingsStream(CallingSequence callingSequence) { + return callingSequence.argumentBindings() + .filter(Binding.VMStore.class::isInstance) + .map(Binding.VMStore.class::cast); + } + + private Binding.VMLoad[] retMoveBindings(CallingSequence callingSequence) { + return retMoveBindingsStream(callingSequence).toArray(Binding.VMLoad[]::new); + } + + private Stream retMoveBindingsStream(CallingSequence callingSequence) { + return callingSequence.returnBindings().stream() + .filter(Binding.VMLoad.class::isInstance) + .map(Binding.VMLoad.class::cast); + } + + private VMStorage[] toStorageArray(Binding.Move[] moves) { + return Arrays.stream(moves).map(Binding.Move::storage).toArray(VMStorage[]::new); + } + + private record InvocationData(MethodHandle leaf, CallingSequence callingSequence) {} + + Object invokeInterpBindings(SegmentAllocator allocator, Object[] args, InvocationData invData) throws Throwable { + Arena unboxArena = callingSequence.allocationSize() != 0 + ? SharedUtils.newBoundedArena(callingSequence.allocationSize()) + : SharedUtils.DUMMY_ARENA; + List acquiredScopes = new ArrayList<>(); + try (unboxArena) { + MemorySegment returnBuffer = null; + + // do argument processing, get Object[] as result + if (callingSequence.needsReturnBuffer()) { + // we supply the return buffer (argument array does not contain it) + Object[] prefixedArgs = new Object[args.length + 1]; + returnBuffer = unboxArena.allocate(callingSequence.returnBufferSize()); + prefixedArgs[0] = returnBuffer; + System.arraycopy(args, 0, prefixedArgs, 1, args.length); + args = prefixedArgs; + } + + Object[] leafArgs = new Object[invData.leaf.type().parameterCount()]; + BindingInterpreter.StoreFunc storeFunc = new BindingInterpreter.StoreFunc() { + int argOffset = 0; + @Override + public void store(VMStorage storage, Object o) { + leafArgs[argOffset++] = o; + } + }; + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + if (callingSequence.functionDesc().argumentLayouts().get(i) instanceof AddressLayout) { + MemorySessionImpl sessionImpl = ((AbstractMemorySegmentImpl) arg).sessionImpl(); + if (!(callingSequence.needsReturnBuffer() && i == 0)) { // don't acquire unboxArena's scope + sessionImpl.acquire0(); + // add this scope _after_ we acquire, so we only release scopes we actually acquired + // in case an exception occurs + acquiredScopes.add(sessionImpl); + } + } + BindingInterpreter.unbox(arg, callingSequence.argumentBindings(i), storeFunc, unboxArena); + } + + // call leaf + Object o = invData.leaf.invokeWithArguments(leafArgs); + + // return value processing + if (o == null) { + if (!callingSequence.needsReturnBuffer()) { + return null; + } + MemorySegment finalReturnBuffer = returnBuffer; + return BindingInterpreter.box(callingSequence.returnBindings(), + new BindingInterpreter.LoadFunc() { + int retBufReadOffset = 0; + @Override + public Object load(VMStorage storage, Class type) { + Object result1 = SharedUtils.read(finalReturnBuffer, retBufReadOffset, type); + retBufReadOffset += abi.arch.typeSize(storage.type()); + return result1; + } + }, allocator); + } else { + return BindingInterpreter.box(callingSequence.returnBindings(), (storage, type) -> o, + allocator); + } + } finally { + for (MemorySessionImpl sessionImpl : acquiredScopes) { + sessionImpl.release0(); + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$CaptureCallState.class b/tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$CaptureCallState.class new file mode 100644 index 0000000000000000000000000000000000000000..907f78474f57e4e3e0bbc9167509d9672c32fe2f GIT binary patch literal 2176 zcmbtVT~pIQ6g^vLQ%bc36-DtIlomCjC}Jyq6p_vpbgaXJK5g3-0wG(IEslS~2Y-bR zGNa=R5B>mul;hnbEddLI`jBjPv-g~P&%Jl|=dbM_07@vQ5JQiF-ZbJ!Fl5*GCO2*F zte7uFUAhg1MA33AHOtU5o?Gri5`6|zY4jt_Fum4TH!VjA*WtGLR=UDkaZFyb%!=i# z3-@_bS<>-FOT4LCt|)Qat}3nsL)_z=g3vP+pRuJZ+pG#z7$mojrjbFGA*p0lxt6oS zusB}%N2)?DVDMuK;Czz7G>+jok*soWwImzlQ}I7Y%G&XvG*03aNhaR4xa~14{X1gB z>*uvKQCEfBYXhebuX!{B<&CDz&{w7GaGeN-!fxG*`^y{Tj@NAAr>-ztU>KyhbfI+8 zmRn}%4OGk!u~=$t)P(y=ThZ={taE#ryOy4Zi@j>qB86u5Cyoa2X9<{*2TOPtt%9_7RkQBBk<_%bP)By(IcG z3`Qn_LJCDZFfg0OLp)+QzZ10Ea+I|p%pmyClDeSQ24mQY>SsBda$T6g#s%&)Y~hVo zq+D+`!)}S5ArW;$!&g**k(5U^lx*&KT`=B6_H<$2b#!%7m@YexaD7NYg`NHLY|TbH zN4LI#rwn5|%5>psM{3|1!?}aEQf2~KFiF=z3=G5c4C*U^#xryf#xQ~eeaCSYJvc`z zFK8`BV=Dh0EI;uL#um+baGu_JC-4y$=sgtd!bM!78SM{IFVnY14^~F#Ym~m@jD91e z9HYf6xJqwLc!wTM$TUwZ!t*J@!#X?+&1mGeaRm6X2PkkjaLNdQ z2Ix|m=wdzqd_I)`8WDSeZ^)3^a1(<1Qk*$@c?}&)H}NydmFhZ!IEcuXYM_7=iGD0|9see4`2?D3dmr{K-R)A zatx(SzQb*od+YWS;V8e&keimC3}+aI%9YhTOyms|EF6KwU~jg!Z0Uu<_qc2Stb8HY zJ)5_r-IU&z@RvKGR9-MK=gUw!++`?o*HteXf_G*eM+5-_TN|ZRKDSUriNOrj)6kdR zI>SP_c}VzLrP2jCyuOA*M zmF044Q#fI*vQ{8wPwFb1V#t=)Vye$rIE!-(h1q6v`PuWv!t7&)$wSkktM;XZ3mU38 zzr3{aypLyKg5mZ7iB4B_al1qH%*J#UX-6z|w_Czr;VqX49&IWr_$v3Mwv)wdxFLzM z(jyUWsP<#-^KC)mp{1ic+?8z}in{XW)eDbe3B5wx_5`^nuX@*Ww5;Yu;P|o=D!*1) zC63xXo8j`o;uwyV2WTeJ`Xa;e^zpq)kz|#=Uq7>CD+*g9nN2%x(ldpps_Q$VE@Mj4 zO>slVlk<`Y!iEY$19vFzgB610x7VJf`$~mD=<`lYYGC3>k-;eD@O=UIFl*qxMV&s+ zaIT-R-}OSdE$le+B$6TD+5=;FoxZ&EcGQ-zW5)*f+O7yDno4bTJGB%MNzbKLlE9T; zJ0exDl*63MgJ1y0Pbr@Pr~jwbd;D9Ao+tbWQjn<3{<~A!FI@vv;7ff*2Ar{XLjw;P z&VJmLDiYIyNouwX7%pN6qxzYoMIGU*kX*Ot|I-UG3ku^hehUP-`9a#0$Uoc*i zmBD2ibL0v9hAT9lh`msbFvvebr!JwrVMYeXxr(baYS?e+t6|xGv_Dd4tcS*M4c94j zgdXA>3B)AL`h26hi_d^p5#s)|tk@+18lk7w9uPhP{CS}8F?^MTPgDB(0%rB6|F^hJYZ*-8F3l!+#)_zsrHPv%a1+z`4hyt$GP0&n S$2jR{3P0rXXy5^w82=YmjnBUT literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$FirstVariadicArg.class b/tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$FirstVariadicArg.class new file mode 100644 index 0000000000000000000000000000000000000000..80d2cbce2d004b6ec36938e404a4c4417af836ae GIT binary patch literal 2411 zcmbtVTT>iG7(ERvvn&%Jn~;PMlQj}9i^+<&m@J}Pf~+nO0Z|ffy*r(yVVGHGdNJ`2 zSXOD}2l(ov52h-C3aQd}f0X6dGqdavE>ifg+tWSYclvy1PJjLPKRbT{m_#LoCNvvp zF_AzkL)RMLiFTL_H`lE7oOG1%9B$_x zxSo&|C&x=NSCr1W@aC&Zx{lvBEj?c?b5C+hmdCvcLqa;1c*wvC?dU+Kfi4rLk!I*? zFsS2A*POD(nG$~4lU3z<44vGo)HZ~piu{pVQ$9m_aHtsM)|9kqe_!R>aTeVM&Y3um z3k)55Uo*7$@&^$VRxogp;c8>=f^CZmw~1@8%bka15!7Pf62tjM+@kWNQ<;x!VISF6GyMXwKrL<5;afPBO~wiIFJHN-Uy(a&&cuyA-_ z5`zqxfsEs-jC3+3x8_)WhD6L*yTaYhXt=C~8-9t%d}&RT)qfDVZsG=V3`ymN#2L=k zb&qi;(mfc_o_dp^`=D}{)8xOmHQGB2vlMYMBOO3DuaR$>cn`OT=PLJCCtZua^63BA zq@XeLCPwi-eMj+Kjoak7xsxNt3{cnoo`DaJf1={&tFTeE$;{-9Wg5b2J1IcS)iz4P zTjC{~>Q5KlGPi?6Nb_j1MXgGzuy;wWxS`eU?|F>h?HqS7&NEu9l;5h@)4u?V?-r z%3@lEg2j8-4INH~niIa7aeZZAk(eFNw&a<5H|?5mUF9o}S3}wSB-%TvUv#!&C53yq zZ{SN4U*T(pD-D8P%~5hgk7eX*Nb<6OF0tHdwaz8H^`1 zYr;en3H(GiDsV20!W8b%jN$_{hG}|EFq(j1Kf($f_rd|`?*hLc zD}5BjD1DSR(@H0^!#lWrSbnH;a<`%+W-&(yTH-npU5~CKp*1^-Mk0bqU_Kyw7oP^> t0+uw9090GzGy3VezaWW|SjOl0hE^^Hvju!hl8<2lytNG_Sa^V*e*yerY6<`V literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$LinkerOptionImpl.class b/tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions$LinkerOptionImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..fd99242c1697afa5f5ae5ae0a9545abccd0c9ab9 GIT binary patch literal 1434 zcmbVM-%k@k5dIcQuV9tm$S3)j8N-X8kugZ~mF zlIXjClyTal(zIF|Uv@Hc_kA4WYyetU0$`^7pfZ8 zxYVyc+1%H{lLlf8*DwDoYb9j$Whh*St0D9wo`it}Lwrj}p|=_OGueX#h8X7eJe>+c z-}jW}PU^jCK(dii!?DzWIB^k7SdnWIL$Emr}{|jEW>Q4*wBxp8klETKXQ&uAvIUh za!u+57gcFm6=9ZyJmzY@(d{7J>h0Ei*T7ANk;|?`+6<%^7A~Vrz6hO;$QZ^?ELS*| z=0#8KT(q7c+p408EQZpq&wGalwi3SfR6cva5G!~NXBZ}8z8BUiT)nj_E=9&l9;rL9 zl&Jd`!I=Ia0)~y!e~QgB3^~6GU|4FIeV0NRMq7lwYqXu1%3i2!UKCNetzFL5J4d76 zAD(t!eI7Rd%B>67Bn}8kYKW}8Mrw64 zbDUugH|S0+&^y#e_7)cDyiMLdViW=9&cP1P(SLY`fw93;TvO{Zuuk4G f2B?@Ep2i1B?*{T@SIOVP4E>YCGqP)Bw=wezn8u2~ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions.class b/tests/test_data/std/jdk/internal/foreign/abi/LinkerOptions.class new file mode 100644 index 0000000000000000000000000000000000000000..c4d931ba01cacb53f8117612be242a7ce60ba2c4 GIT binary patch literal 6498 zcmcIpd0Z6d8Gb%km}MCR)+0eYFhPL@rP@>@7^0#^63|o##v>uaGQh~PyV;#ZB~5FZ zv}w}DHtCUS&m?W^VcVQ2+8EQrv}tNwaTnkDwvn~G*DoUhN}cB zvzBi+lEbt@Q7cfEMRfvD8jeM6!-^(vF%JvOcm3swdTYa84J!n$$tuzjiI_u1WK&{@&X3w# z56LhwA{y!iuF9_Kwi8x#XmiSn448=k>QLxMqd;&=Dju=IhHcg;Dzwzd$(1@*p;?AK z9yg;5-b$}BN|y9uFr4#bcr(EZjxTu&S<(qGAZ29E2nSPaSJ->#bG1aZp7^r^ReBC zM7nLp-6sv)W)23B@e2OL%;?SyHJHZw(d zA)+}Nw+{Uw6LffKB4ZQ-T%!@6tgHdW15lDD*D4j8H?J8F4_>Y&(GnoI@8<3x&m*-U8M_hrBtkikMMOF`+xz8%*(Npy?StGK3R;8+^ z$Ei4*HuSW#cqY?9$mL<1H?KYW8z_aRa4X5mWF&@?9jXKR>N^_t@(9QwcSLlsFAk0w zZz6N1_H6=Hy2q8A^H0)#Gx<2R*HY?DIo&X)#m>ShB}i6h=OE@dGw3+NIcTIw%){;A zlmkfGC9GMi^9*jLnNr;fr-vr9O;iSc*kG3yG1(}xfp!}m10ma>YAyZ^Vb%rb)icl? zOC`eQHcK@a@4MwHDTKv+hncjyOxcH6Kq@xJVm94l#Jfy;I5v>1z{c_te7_VecumI- z@H*d{+;U}Z^R|TsFMZMsOMA%kcG%EcfgcIGb^Hdu&3SRNqGPcUv$@k4?H@4c4r9;=vqtkQRyyi^dfjWeyGeO( zyAd6Tn917CSZpK}=doeR+n9GGXJZeO{K_U33M`p@ zDRonB$1=VQ6!1$)0lyXSRfl&$`4NVn79Md%kD`Ked_CjuhdFXPuX24LbP6KW_#(7t z`BaFH@OKWcKm&XTp#+V1lurxPYCPu1<~~>YM>!`^)X32c-pB9|K8{cDS)$!Yi4v{! z49b8|<7rer!^Z*#uGrbW$^%o1$MH$da|4dyIOj|7shNb$zl5+gvkH4yeib4(H4_ig z$`S${KZ^x>PT}euO)b7E-?_C#g=>rF7tb$x68o!s^NZKCXe+CZvV*rel6=xpKF3jO=xJabBfXySZoz7_qKlsgdeDYD z=;Kk2C$Sm#^3&ZTe5-#P+Z;b^hsHHk_%uGlz01&v&*F0&qt*C4p5Rs9Nteqw9(P<` zz?F~TNg@_f-eNq(xceZZt(YKpet}PF)lshcBA?d7cahH3G~A%!X$@b}P{UtAxo=>- zhJ_dTvBc+{l@r%$6r*VRWd%990p5d>gbCjquMHYpE zeG@Rwqpz#!0?MnKCSX1R&36L6!jlCi{~ggz?6L+FL1SV zC3n4ng&O)cvLDJ1C;XMzTR1PnR2~Xi#J(^MPMNvefl`@S?m|hiMJOn9B)*6^B}s|H zyh;t1D2eA`bvC|=lG7MD0ljeocTXZEXnWd^%AS4HaKFcwOI(luQ)>b&DvlMpv|^qH zYrDp80m_%BIX9WHXTOU+FXPM3#_2{W%)5wbcrfQ>FawU~6sF_3VA^wMXrJ=jIwDEW zm1U3^E*U0o88SV7D|5vQ`9aDR;!$_p3H|t`)wQVZflH`+7T=`AOrWXm_(mD%moi9U z*D=+hpa*FV1M;q8(}J%26D45G16ZB$PbH=RR;2;&N3CnxeFT)Ot_w9jjUwO4##i7! zhJ}si;qQ`J)x^Kkc+Yh31!NUqv!aZ#ccf6w>k3|F-;iXVOJbj6{g5Q9b5)XeFXKF+ zr4NevUxvjSrTwpD!o^y`XA<4_5(@SdN)5VC<9$;Dc8@1uX`=h_Es9i8U*XuqrY5WH zX*|Sw`#g5ZX6LOYD+u;&juqfL_%5#jK9BQ*Qy, LinkerOptionImpl> optionsMap; + + private LinkerOptions(Map, LinkerOptionImpl> optionsMap) { + this.optionsMap = optionsMap; + } + + public static LinkerOptions forDowncall(FunctionDescriptor desc, Linker.Option... options) { + return forShared(LinkerOptionImpl::validateForDowncall, desc, options); + } + + public static LinkerOptions forUpcall(FunctionDescriptor desc, Linker.Option[] options) { + return forShared(LinkerOptionImpl::validateForUpcall, desc, options); + } + + private static LinkerOptions forShared(BiConsumer validator, + FunctionDescriptor desc, Linker.Option... options) { + Map, LinkerOptionImpl> optionMap = new HashMap<>(); + + for (Linker.Option option : options) { + if (optionMap.containsKey(option.getClass())) { + throw new IllegalArgumentException("Duplicate option: " + option); + } + LinkerOptionImpl opImpl = (LinkerOptionImpl) option; + validator.accept(opImpl, desc); + optionMap.put(option.getClass(), opImpl); + } + + LinkerOptions linkerOptions = new LinkerOptions(optionMap); + if (linkerOptions.hasCapturedCallState() && linkerOptions.isCritical()) { + throw new IllegalArgumentException("Incompatible linker options: captureCallState, critical"); + } + return linkerOptions; + } + + public static LinkerOptions empty() { + return EMPTY; + } + + private T getOption(Class type) { + return type.cast(optionsMap.get(type)); + } + + public boolean isVarargsIndex(int argIndex) { + FirstVariadicArg fva = getOption(FirstVariadicArg.class); + return fva != null && argIndex >= fva.index(); + } + + public boolean hasCapturedCallState() { + return getOption(CaptureCallState.class) != null; + } + + public Stream capturedCallState() { + CaptureCallState stl = getOption(CaptureCallState.class); + return stl == null ? Stream.empty() : stl.saved().stream(); + } + + public boolean isVariadicFunction() { + FirstVariadicArg fva = getOption(FirstVariadicArg.class); + return fva != null; + } + + public int firstVariadicArgIndex() { + return getOption(FirstVariadicArg.class).index(); + } + + public boolean isCritical() { + Critical c = getOption(Critical.class); + return c != null; + } + + public boolean allowsHeapAccess() { + Critical c = getOption(Critical.class); + return c != null && c.allowHeapAccess(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + return o instanceof LinkerOptions that + && Objects.equals(optionsMap, that.optionsMap); + } + + @Override + public int hashCode() { + return Objects.hash(optionsMap); + } + + public sealed interface LinkerOptionImpl extends Linker.Option + permits CaptureCallState, FirstVariadicArg, Critical { + default void validateForDowncall(FunctionDescriptor descriptor) { + throw new IllegalArgumentException("Not supported for downcall: " + this); + } + + default void validateForUpcall(FunctionDescriptor descriptor) { + throw new IllegalArgumentException("Not supported for upcall: " + this); + } + } + + public record FirstVariadicArg(int index) implements LinkerOptionImpl { + @Override + public void validateForDowncall(FunctionDescriptor descriptor) { + if (index < 0 || index > descriptor.argumentLayouts().size()) { + throw new IllegalArgumentException("Index '" + index + "' not in bounds for descriptor: " + descriptor); + } + } + } + + public record CaptureCallState(Set saved) implements LinkerOptionImpl { + @Override + public void validateForDowncall(FunctionDescriptor descriptor) { + // done during construction + } + } + + public record Critical(boolean allowHeapAccess) implements LinkerOptionImpl { + public static Critical ALLOW_HEAP = new Critical(true); + public static Critical DONT_ALLOW_HEAP = new Critical(false); + + @Override + public void validateForDowncall(FunctionDescriptor descriptor) { + // always allowed + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/NativeEntryPoint$CacheKey.class b/tests/test_data/std/jdk/internal/foreign/abi/NativeEntryPoint$CacheKey.class new file mode 100644 index 0000000000000000000000000000000000000000..9d5a8ab20fe003357b47cd30aa7b4b9540a0d525 GIT binary patch literal 3118 zcmcImTT|Oc6#f>lWr!%)i3z0Knvxa^h)9|yX+_fpa>0!u6jR!g-q!X40wYmLW`_UN zhi0apba==Q=#T33tR&m=jd3&6hxP7y&-u>%9R2;z#ajStC=8(w{R#$D#1Ll~J>q9v zFLUca-xfvNDKW%XOw05hG4#)8b_bEbpn@S4SD-T7Jt`gRrsWC8;$?l`c7%Cg>AYa- zo7^+c#8b<2&bMr$m|Nq;L-9hKGYp*w@6ayooSzDYsa!*%X`R`}Lf@!A8&ceRDn>9$ z;t7^vKG#*`6;hrM$;IvBBMAqR2{$ z4^-Tg7$ZK$j>9e2^i11Ik@M$N+`>nsoM-1f$FvR@)-SQHt3!=U#DxKpA@S!`WS|lL zA$Jeg>=HTq!MovSCETKlCETWT5WiJ;nLL?&C$NaFFAGPa=oy(khQU1L4VOM-xZe_? zmF^MW-N;j@`GGJV84SmyP(6FwbE!K_bK}XIcTioGPRKg(m3 z(;#8o1ab^Jlrv!?HmJE8wJvGY+Mv1eL`J54Xz zuMl+%chHZ!bo+~L3ECI6H(=UA6^gc4#jv(iMN*p>s3NVUV^xf6>39{BT3V@M_BGM> z;}iOglRS{@d-S^<;NVl-ryC*q`pWl3Ut?*-q8#DGD^F6}0skcRjQJ<2Y1}_aT@^f_ z^O$eH;CS4sBujv(p(26BTwb%R(& zH5tDw6b&Ct*CQEap6reJW=F}hy)eh{#7~u{c;@fVk)?fway+Q&pr)HEy1AZ%Y7S~S ssN}B+VVqpC1NnLS0vp)GOKjmAs>M8B(QArAmcVoTNM-R8egVhCzk(OT9smFU literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/NativeEntryPoint.class b/tests/test_data/std/jdk/internal/foreign/abi/NativeEntryPoint.class new file mode 100644 index 0000000000000000000000000000000000000000..01f1bf29dec9ae990313d649d7b7a7da1f02377f GIT binary patch literal 5313 zcmcgw`*#z^75>JOwX)dwA+U*!0YMG1g+U}GAwdLVgb4=QP)tPZ(57o?WEQV?)!miB zP2Wx5ZTd>ul0MQ$9(^}JuwC3j`aY+pKlU$Z|AhXU)6+Y%YilJTALpF5KiE4vduQ&w z-~Hy^JNoOtZ{Gos!Czu%KuAGYMI#~%t(UbqEoErtbn491Wu9{xB8PQTcaJcHdi%0X zh@weBOvMJM41JgLGb!D4xov7js$kh%pEgt4l%5*XTz!rYnXWy5)*=ap*erK1S^4wx zMb5Bwq^w9c=d2l?8eRRI7FwEBw4jw?W8S)A<}||?cS}=)`Mk{?hk>0^5NEi*yvv~D zaNE@_bI7(WJBm#VkBycLS1%eoVe@I-AuDO%mTa>>F;#LCCg*wQoSZmTDirAJ70pQ$ zG{fOBw4p;lvYDa1H(;v=O1du_BNIDSbYTlaQ|=Pa&3KOO3`*B}HaXmvRj`%ep>-qI zlhJ7Z(|kUL?MNutp<*ZAwGyh5s~f37+t%g@m5Anyke>{@dY`_B(cY9?A;i)#bYqwB zayP@w+IElBHFxmX@Nw?sY`y4OcDhR= zD!Au3#fY0ZE&)l$iNO6T_F^AHqgE^$^9XR`~k&aKOR)@kcxNX0K=ZTifa*|6FJQ(*qNZyK0(*i>01;y7s^KuheMQaI=rnWNf+H#haFn6ByyJ*vPBVnhPn@Ng zw|SOITfBt|jxlU5i;uguZcZO7=|-O0F$^LU1ufj+=Yj;kTBJP1^9gZyb=z?h(!4_n zA^U`ilNc5!qgdo-o;Vf+%iB5~G`>O`!7_-`VvCWgl`DB5V14b%F%@TUmLcj|-baQ_ zy|v2HQJiBq=%psgOfnT|Wr1*XG(%Jy^RBtv(`DjE5NX}JlpNn$1ICLBt;FWFmvtSvbqR@cNhKu5&{byInUZ^^Fv@2w zd)^0zDplfyrW=I6YbB@%Svk$E0cQ#qMHDUxgmhx&+RmQx65xyq1G5ZDW@Kn^Y={`J zIY1_x7g8C6YbLiT(J@#miueGXc)MhhB*io!e6D1g+LXbGt`1xUB^7hHLZK?V7TAyY zxKa)ohJ&_Nx~TMI^9(1p9;gp}wV!1s zQK_Zvb2Fn_(GP#Kqfs%)idx|5jLP0~IDeHvUCG&^Q>LK1veVvPaX4yYKspRLDrMJZxmhfu@w^c0THw-(=rNw8+h$IpD zs1;T+^akn?%Wr=Rx?Dl4lho`O-02yyteH}g^5^Ou)bB3>GZhO(`xz8p|3^>d+G~R~ z&)+#C?xDKNDW|H#CKYGdvWn~yUAd(xcuQ2TRTl!~s9Y_nB&}9X1%IIAR9;ZwL?tu| z{=~3tZBgoVJsh!v0@y&8q%h**woaqCxKh)zOSB&HNp~>nEspj&(Z(5{QNNee*{f9h-N&B&(nN@7Sb|&0biu27zy=E zj)VaXB>g2k@2mL-y+!F;w*OA}6)54?5e~J7U&ejQXq$*{Ttxfbz3t)l#wFapjP8lO z$vsQh)=z(8vOThhoVHueAuNWF#V8?!rBgU4LC~r2MK@-U80AO z#uL)wbDjnGGQL7GWDCBEuStuu_&SXQj9KZ0@GOfL@S^lRi*MkYa^EbzMRO6_aSN{D zB`EkdNk$Ng9c9gki607lfB#M^1*|+7TEN3MkbV{0gsaOKoLEFAetZEZk_$MsfKlOl z_{f%PXiIK=F2p?X*AVZ%hQ8$1d#-*@Kt@i}Z!fwu$Ky;K-;<;jc!t2*Xw#SReShl| zJ%xRZ$v2^hSU1R6N93dt*rm~9BiTpYC(s%b3Dw`^pQLpItsNi&NvgF+mhirV(T-@- z3)0-FiFkeyg}cj$P9!^`iJ3Kuu8XqRk{uMbQ52HBdKO_jCqNHgf zUZJBG^C`&QMj}iOQzrKvP7zE(MVlo0=JbNi(`{;b9h*+=Fw+8$eKcQ!sq`L7_8g NEP_CACHE = new SoftReferenceCache<>(); + private record CacheKey(MethodType methodType, ABIDescriptor abi, + List argMoves, List retMoves, + boolean needsReturnBuffer, int capturedStateMask, + boolean needsTransition) {} + + private NativeEntryPoint(MethodType methodType, long downcallStubAddress) { + this.methodType = methodType; + this.downcallStubAddress = downcallStubAddress; + } + + public static NativeEntryPoint make(ABIDescriptor abi, + VMStorage[] argMoves, VMStorage[] returnMoves, + MethodType methodType, + boolean needsReturnBuffer, + int capturedStateMask, + boolean needsTransition) { + if (returnMoves.length > 1 != needsReturnBuffer) { + throw new AssertionError("Multiple register return, but needsReturnBuffer was false"); + } + checkType(methodType, needsReturnBuffer, capturedStateMask); + + CacheKey key = new CacheKey(methodType, abi, Arrays.asList(argMoves), Arrays.asList(returnMoves), + needsReturnBuffer, capturedStateMask, needsTransition); + return NEP_CACHE.get(key, k -> { + long downcallStub = makeDowncallStub(methodType, abi, argMoves, returnMoves, needsReturnBuffer, + capturedStateMask, needsTransition); + if (downcallStub == 0) { + throw new OutOfMemoryError("Failed to allocate downcall stub"); + } + NativeEntryPoint nep = new NativeEntryPoint(methodType, downcallStub); + CLEANER.register(nep, () -> freeDowncallStub(downcallStub)); + return nep; + }); + } + + private static void checkType(MethodType methodType, boolean needsReturnBuffer, int savedValueMask) { + if (methodType.parameterType(0) != long.class) { + throw new AssertionError("Address expected as first param: " + methodType); + } + int checkIdx = 1; + if ((needsReturnBuffer && methodType.parameterType(checkIdx++) != long.class) + || (savedValueMask != 0 && methodType.parameterType(checkIdx) != long.class)) { + throw new AssertionError("return buffer and/or preserved value address expected: " + methodType); + } + } + + private static native long makeDowncallStub(MethodType methodType, ABIDescriptor abi, + VMStorage[] encArgMoves, VMStorage[] encRetMoves, + boolean needsReturnBuffer, + int capturedStateMask, + boolean needsTransition); + + private static native boolean freeDowncallStub0(long downcallStub); + private static void freeDowncallStub(long downcallStub) { + if (!freeDowncallStub0(downcallStub)) { + throw new InternalError("Could not free downcall stub"); + } + } + + public MethodType type() { + return methodType; + } + + private static native void registerNatives(); +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/SharedUtils$1.class b/tests/test_data/std/jdk/internal/foreign/abi/SharedUtils$1.class new file mode 100644 index 0000000000000000000000000000000000000000..da6783a6bc4d58f580149b974fffb6d87fc7f305 GIT binary patch literal 956 zcma)4TW=CU6#fPlc8k;^Uh1`_N?XvxjlOD38q!7yZ6DS)8ecl>PGNAFA+v+A{wtrF zXrk}_DB~H#mZULdlRdZjzH`g@_50fo04;2mkVD>wS4IIvhRT3{;$g~FFWm1AL~I#~ zFQt<96+^z!JoFJTY@UM-R5l)sw6P-D9|^;))N1>4EJn^K!FRc@Fl-ExkD*jn7{$}@ zSQ{aGD&$=mMtyEXa$see)t~uTWLQ4W{tviigyIZdODBS1sUwxx8xOm}yye}LBGrzL zd3wl=bpABx*}lve8lCxSzhEe2u^v&nW~14;*u<_FYI72a-cTr8j~tXZ0Z&sZZi%+u zXtysVI!gD%ib#GT3TrbgI(I9jg}B7jMV#u4-b#@kn^^2fH(_OFPfuNMw1#cvkW%$_ zh3)Ia$0|d8o?)qlJ(1bhI-_#sH%bZ9N_m!v%*P{|W3JhKtTU`$0;Opti$V?V(5M<+ zoku?%8+ljB3Q02;d3*}?m5dygNV;d>9V#Tte*w6LDtQdoaf75IKc6H8g75I(pJL%B z#b)^*X86Gw|0Zrt`8$Lz5a)mVqY1x;yu(cS&RWLpNlyXpkd-Imh7iI6V{7$S1;g^B zW9epL#df68unKzBC{$K;N7i3>hUsP|1fmb}5P7P@{YQGM_-8fr;~ewQP1COF9`nd#%bg-D%5~e>tjNZ?w7i)F z25~-u3mVcG5*TS`)bcFu;o1)C;hILxuo?%J9%nnSI~=JKmw&PS#77jDi{#${vh9G% zeN@93F0oQ>&3?_qa~&&th)t%VT$z0javJig%b}WSyHeHTimK&RfzfRF7!?!2 zS@GrCt%gODd#a%nS;cNTH92pn(8&WbA6LC4zekqJl>J+j-l|=XfY_Piu+VT9lzgux z-^|%ft1jy;T@Q9vn!ii%=#q53C$>v++EdGtPRZ0=SGp0*vB>R;>(HqP9tx!YnsSbun-rU$~Fu-XwH4}Af_>k`~J!_9?+)9ioE=% K$jkasIQ9q8cvNx# literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/SharedUtils$3.class b/tests/test_data/std/jdk/internal/foreign/abi/SharedUtils$3.class new file mode 100644 index 0000000000000000000000000000000000000000..b034a36fa417511fcd7f97785c28501dbff0fd7c GIT binary patch literal 1130 zcma)5TTc@~6#j-@wk=zz^@4y3YJs*Y>je`d#)LEwB?TTTBtA~tp-kP*G`mw3e~CW$ zq7S}mqQOg|@BS#`nNoxjh-@-@E_2RzuJilP_n!btxSPTNA`YT1Vu&+jn*2HUe6AYa zTD2)^h9UkyDrp`vMDm4=K_rlLka95ymtkbzd{YNPHk7vz2*nvvdb6a}rc|QNFrF`z zkFlIjVhFRb%P`%nKl7wAB2e7-_CR@6dX+66i2Aybewe$%5F^P38a)=-=6c4( zS)3#5u%_FBp>Sj-E25=??TTo$gfh8`HJ!KK=Ut52uEc7-4uykphME03)>YVPw{>7d zeXT75ZlqR=FKeQ0nH0tlVThJ=ox%>6sS&H4R#gN~c-1FOwybO1-{66?a!(mGTQX$G zmrvG&d4>e{eF8FsIF(;sKB~=q#aWl?whkh6lXiyL-l(n`EoY_-jHZ&MPhA~cV5NU`0=N{OK4 z^Dq>lgIiS8e!KT}p|76ZVL70MnD~z=jj=mfOwz^;fEqz3W4Df8LX-|Y0Mc9}?tb?k zaEm)&#jkL_ApME-1Gq$g`((ggBg)=jf@GJx?0*uMi88xzJ)AkB_AXWYjPy60X81_b zE{cr>_Vxfm>K_6vT@T@2Kf(yZ;XK|U$=)A{as^j=C`%MGMv)UgF!po@7k(Ye;zQSe y5)o_D%ffOwOxY}nn97-OMqV7QoFSD{c_(iXfm(Hrkf z^bau6#9I|(j4{N-c;mn0z41L|rZYievi3Q@_v4(Wr>Fbz>+?PU8F!+nL9K`oLmk2b z+BeHv3B&Sq$5PG2ecREEbt@rDGid?gUDe#tT>)MF18bRo7EVS`kBEpULj#zA-a{+Z zl95n0R7Wr8J;QY4qXOb_<)Pte8w=`ooOaLnFRck$wwUr%hBW37jIq5jI!mIOgfuiElSdoJVz#Ys*B+)PcrB z+UxX92(dPPZuy8JH!w*$Mer20Gy=YVg0TN3x(D$+|22NZ@zCNMgywy0C9DgugD@Q6 z8A36@Zo>KidkAAy)xDgn$_F@C)nDcu3HlS9qX7?dZU}gcGxPZ!JzxYaXvImip$EOB zeHg|V={O|Jk|vRZLb{B5&`8VJhD++<5gwC1!81H3eSw#FMfw_Vu}As=U-6B!7B^|T z!v3cH#59d-=(Wu!=>{;Q)wto}EO CvIGg|wwiOABeb1X?K2Kp;&Mnlx=n(-s0qnIw~T+GHlq zOuD$C2<|H&n+k|RQIRE;G@&dayMQ7tD2SqnqT-4h2=e=$``(+pNhXW>`TYO+bo%bQ z%em*C?Vfw?z3*H9zUy8hs?$FUks@tTz@`E!WGdMi-5ss!jwZHOwY2Yyb!3dNt$fjblnHKEq+*K7%WMZjAw7aS+nTo}?C#s_D@v7Dx(NwH+OD5i( zX0oE)$lub-R8Y~>w5TaWQ)!w-B{of`Ql=w@JB=rHCwIlF*2gkClAUX#iO%jAQy{ai z7mp(=7B!Dib2BPbhiC?sSv1q8!{~6P+2hn@3Z-J1zEnaQGKF&>*L6qJ>FOeyMYAoM zW782dmuc!Sw5`c_Cy?6Qwy~aRx(_9%p+ym<`NP#4ySroCqusTs?R`D5M5cakN31s! zPbMsy&ve*uz1B=Bp4h&+FW%i5OND42=^!m+TJ9hkiS6wLJ7S%YOfu3Qi|hsx5fD5Q zPegiRJ;~I*h*L4WDk6=Kv8jRhx9Zr)N(0pyfPTEFhMQXz57B z1TB}@R7J-!1v5zpEYpk}61)9}=tx>FlDC4XEFXT5w-ackMJL*H5}nLcF{ZrLMZ3E} zzSh{=`(lX>@U$e+*V7z}b|Q0QG!^ZE7(##>MM$b`I)zSUn$jx;F-Wf?1~V!e{S@)o zc^X7-m`$FLuQx<*jcpgE2C0_mn4GL(hDFnn%#L`fGh(`16)C1VT4PbYO$~I0=ulSW zJlG9=i4GBwHL-L@D&Ct(rkHGpz0J{m$v$Z1Opl&@P_e2OBT>8X z0rtY#4x2g&vaPqrAOg86oZBvH& zV6r3?X)`g7XVQf>y;oos#6)L>))(3Ie!3V_PqZ`Io7vLa0n^uzOo5P0wPSYZ zOs3W6Ox))O=z|u0$fgg|N0=6lX>py7o8yUHF_@>~p6ISvL$m|73Ix4nOf<~6o5uuN zySj1M=v9whZ-lv*`DiRpq_#bsNdYkj(*+LNt(m@d7u)JmctRhu>ErYXSTGre6f*6r zIOl%=`oADlOf~c=n?6mK0-=s%@4kjqvWIDnpQzqck)u#K({lbAB0!hh^clJWR=+nD z?}=yPyJOC*0wHRRzXSH=sEVc>Iq^Vkjdu6Bb*qc%D!SUDYi#CStIvvqe zDjrJ}fY|aEC_?+|Y`UJl0L^Zy-CDb?p}D1YGp13W13IPlek2Wfa2(2e#2dVqX--9x--P74jY0Ybx{k!thDE1} z7x_(T_kgs^5vkmEMf4CoY|$e&JxY%O;W3rjx2#xjJbb4Gt$X5`jvecxy|NTp;4MWK zxPr5w4hDruoeRJ3aeBg{CvEyReTS($Zx2pwtD`TKf*%8+7AGs8U6G3LS01PD+Vr$I zrdBcqPczzW(f64SANG^hM}b||ONmrfaJdu?((eN4?6X{IU_{S%YHMWTWVcb8X z7cBa@pz{l+s&Uat?@RBlYTcLK>O*A3L|u<=gie1+FIn^}>Gao3Cy&`_G@9zz0Xkqc z(6_e=WAEErTWhjBI-ELQ_Y*Y-BEO;ETJ$?XxM=2gz=CVs~I}}C%tCT>(cSR#?uc6f=@DXIv-af#%l@$-lTt9^cE0cVmfhxk&i^6 zJLZXI^~B>Jt8sOR6>EzT$@vKvj3=0>c)DYEu7+%CY^~cm%!Y9_WTNIk#NwdEMS@6( zX~me-NUu2gSihdO;@zXfiQ`dX?1t#v<|!6WmCmOz9Xn>{UGSRQqaC}d8r+1}^YP>L zJVvW(i>JeL8Mgad66wC)Ud-sR&X(R-Dk`h_>@*PMFe-2Cj%F}T^+Y<8v2-Mn%tYKK zkp!ymjzz#}xYi*qq2+WC7~!pg_T=6eqC~T0@Dh*kH*p}tPiBtTJdY8#DnMAN8;<@N6<9Fl zn;~TuS&b>!y!)Sw`fgmb`jwmaR90drjB{HVKB%yt1PF6CtwSJ`|lALj-1{MdMWvD}ab zgwl`8D1dHnz8EZ|YXz3p!+gPrf_wrT4HMat09GV}KxR798SmC5vhpcf=xF*GKlmySri7_Mlok6XFXvYH_>G9TM(!P|xiP zZnQzYJ0Wz9+1$n3fm~B_Ej;~PGZXFTh^5n2P2g5D%w4T{g)YWYevW0z z+XPx7$l-z5?^Z0lIcamRgieF;^af*xgACftS{sY@M$%5S*BEQe8p%CQkTl2{oBMb- zmY*FvVja7jcEH&${@zk{#Dd-Qx!2}>{0<+o8Qgv0eVf%ji5s1 zxKwB~n*5MXl@ zQPfOihuO%9^hEa|5{`Avu-wRQ1%HS?Z1G31XTTrz#M2ni+EgmK55zboM=$e4C1GMQ z&%jK6JZ~W4j8w9(*9mb5O+RV#r})z_hnv@KYB{TM!x>H_wsv#NCL?EA3*fQL4f5B5 z;~h~1xZq@5#+O_C8Jn*VQ5k!=>i85+bRGklu_KzUL(HxZS|SlF=x8P;C|zaq)nY>q zhYhJ)TVJeTV}1RG&0=UjYxC#$^U&|EcsCR+8)apRPQ;)_KZEje z&}WG9m52B`zTV<5*n9(j5urz8LkyD~c3^N*Q`mcnr(zqDi4A?--5`q}t2|tDvx=Z} zH`;s??}wOg*wWmLImw5O$AnzH5l#KF&0k>zYzonDRJIv&wvfCI&k6F^u-k#^ zIwF0oiWKo}e7nVW*xb(tM(T;zxp*@U1hIdHZRoeTwykB$W~N9UbRm*`h&h`56vWDE z_)eP#_@L-`y0tsr0S9eOMN^)J&N$tMeqX@DC6^FE9)ixa?(1n!b|dcM4l2k9ZGM8E z^meimm@p*b){?>=Da@_oDZ6jkEwP+h)kOgG9h;xx@4`t~-FU{f`VDIuYd1g}9XxYu zTl~H86xttuS{~x3`3DH+@DBy&rbSyV{?TL`uL$uoq>K1DY%()ejlTV53C1Ci$Un9D zXA;T_n>e6^^0sZ+P}|&i#)kSeA%2d3Zu2i>)+p*m0~4ARIs2u}FY&K1gQR7TXtAGV zo&@>AxQM2j*dKP~w-)gOG+Q|J8=HSC&R!61gsEG^uLzpI&+)2Ez%sjd6aN{+ zO-l&VG%yobYZ1RH&Hn1m_J-kgI2eFvyew>9<-gnf5B?{HfDM?`aLc+PeqCB(G4G>` zFh0bu^P4vRo8LmCc4Q1UT3w{D7_b!n_xXM%5D99kfUOE7);z;d)5My6w9gu|J=m$8MOrX^kK?TacQQqlK%J$?jM*5mK|& zTw5I}lbYS`P4)Fhard_Er=d7BIKDLQJ913 zCU{~3b&;(qC6MlL%mmVN;Vu!lODDw?C%WF$>Oiit)v@Y0PqW~$ZyE*+1@_sm{8)+% zi&0lA1cT!zrDmp0Q=M@#)k^y-$D=6bPY`KAfO zH)k4wlDiBxNMkMclB!`^HnA*w&9EILj;cBx8_=qDQk-4JT&IozjtO9J zcM?|8vq+29gw#~ELm=bCLRrNcKV-L(fW`rXP6ekj=NMCd?aT`8qI1NcB?NX-gd=AI z%By9mw|n!G@n>Z#sXmcO?F%Znl!10w!D3#n`fRmZ?Lj;V8$+_gUF{c8*YWY$ja*kK z7jSh@0YIPwtPZMo0;HKYg9@Ac8Z&NCU5Gq02?f>rP*JA$pnAVM(MO!uOW>C|vqDgP z5cTCeSfyCa58LV^3hOAVcFmei^{uV>z3EzKq3ODrLG^KflfAxe=>C&vyhpH;mrtVr zNS!3<%TR#yaVzEJGtSG35xDebc?ONrfvo3WS6in zF0rlb!f^xxTp9CntBcj`>JCfw+vA{^@w^D!B-y`EPim3)TtyE2|V}5sYd|w*RC$O@Ga-BSUsVhwA8n4 z^&Rz8&iS`o!Z~ULXEp5}KlC!{|GOogcZ$(f&tmno`ktk}Z>t|DEH&~RM$A!XxSQA% z-{HhwJWT5R@{$kxymFBP7l#vq>PNQvv6z>lx@{XgA%lh?g+iEw}Z-84-KBmwj{-J(hs~6QTVF9|6$z6Sj=`Zp&D~v4XQG)b> zW>dA=QdklB&g6Oo7#Z0Ks+VEBB(#S>52X3G>UWlU#a6#pe-N{fjSP*`7sk|ueUGj2 zR0dIr5wV$3L0@-$>>GCuXcGtb&xkptZuBjv{)AOad!K~<>u_2KA!qd$gq+o@Os#&l zkLumY@Gs$=oH2Ve_y}44W~;voO+qqOF%0nzOJO1BJI|bobyaPO0Vg?+8&t1D%Mnn< zOwbGqtJgMsr;DSz3z( zX1Rl2Lhp(l{U1>l`_+Pov|m&|IEjmY>*v?GD=D7 zkgZUygj`C_S{~UZu$CywmZRN_y8T!gCR$@$v8Mbk3DM)2YPH0jyy>S znU43Q#PBtC?gcS%d`M%G!u}h?yki&KLzg>+857(_6?o`joNkkCSLbx$+E_P2ZcMk1 zNlv3k=Zts2@c+X>NKt1Te{?1eEHa_n(eCV-&g!vgIFY*o*$g?fo%huccXOa`ELF%oISL&Uxz4!}V0C%NQ)7OoI=Mo!#ZXUT-G_KAsf6Cmt`YPTsn3b5X32mDEFmfW|;-eZiNmuU z)9RGU8qj+hTp?$B&)I{J19+dyE{O5RHh-j#@6=?>{_;i@#ZFlw*$!3>PQQuY$i;RcyH*<{XjftYsq5y}T@Y;|yy+})+jSqJ2U12!hjbtBQ^ z$pXdNsKeR#%<{Z^6V407dtzJT={S6zT3JY%b5f(>?(V5F>r7Kz1*0jN*bN^Fs#=&f zdtXooBOH#RE%Xz^v86sjI~hhYFeAWAcN*E=6+7oOCsLSIjgeqPP6U!2PjAF|fK*G@ z<~;~D$#DX>1qFNJof(*qX}xi9Y)4;WS4&ry*_bKBMaafQkZE|ozHGCnahB64WJ=tZ zX)q$Ial!)kvdl7m)In@d2AxGd+!Zu1*Sy^7*^^y43xBWn)IF&dlB_3c{57z`B(zeK9P+=(#61f-NCprl$WKE#c7UPK9R$ zX3$J)CkE=@sU2^yg-Msc>;4OvV`CbC0iPUGMkDGs<}Sr2MaNN)jHr*MB;2)*Xd;=2 z!{KtG4N%}jzTx{A>gR|jUH?Jxh^ZcCAS3}oFWBL~OP3G2%#RRrcY7YnYr>t`*Bkzy zA`d?$J4K8R2YBc^s^i&&m-@kEpW4^e z=(c`Aa!Vy{(TX`6Y_%H`355P+wGc~N`kQhReJriZU8=*3jJgkL>4$P+ou26X%(Hg~ z53Znl8_&{@=7iw#H*)s#AnPq%PSVnkPh#qqjY~Ls*u_S|(%+s0dS-vtpl4E+{w{7c z4%^xM=s{MY(Jfu(iSESZu=Ed@B4d)%wSRE<92V)L}Es3`Y`{eookxodNP= z22GURG&s50t$bi=wkZM033AhMxZ0_3wK7Dr$;XLhJj*4} zYTj}B(7YqIZ=MLw%To?Y;<*5D@p%wpZR2ePuDCFs1(gSh??6K7DfnN$Bto>70@SFd zB4s<3^fX<9w<7sqhzpmPKMDyAX(ov-g2Iy#~5dSYdNXOl`WPpyZk*p&IXjN&=i2A3Gs=s)MRx=II+N)`< zAMys&Ts%M?*wUIo+PErE9tczp($;mAI&j1VgLDoO{d9gHa1W_A?SX1<9i%R&R)JF| zFi1PsRo;%FXv3IQ_}U8L#_trmf)>-2bSy5Zo=R8KxpWO}$L-yV=<~SieJ$=AUx%FQ z=^%Z9?xh=WCG(4hc*i?r(T5os0fF@4y43u+9UFFhp(D#y61t^?eUa+cgPI=*71f`Km z!!)0du@l`7(R=`7e-IxXc?92)d5q@Kw`d{mjaJcj4QiWEF9g9}0MrUl64DFx(NGWc zu8+|bcuH!KpereZxX^C7uGEWxr=*sE2LV7Y(@W8|zznO1)QmT1mZb(Lr2eFrxkEbz zgqP;QN{G)V6=;^LcR%paE2yh@Kgv;CABz->k3LQ>hn|WNI1Qak_r-HTnahR_vLv0mXSaj`xgqfz<yXgH=*n#}SoU3W}+!^$_%da7;pRT`=+Un! z&x4vjg+Tp`O6UbToPJJoaQSpTy+lXTuV@+l8hm(}R^c9K4gD71aQPiI(I0(dO=QQK zaL4NCLSad9QE_oG$atbY$r&-@%S-5;==y$oaFD(=Ku<0EioDn0Cma`2uf=Zzew*<- z2fqvO>%y-azZ8CZ@e?b5F@7I8MBi&;K1e^fZ;*bppPB~gr~7HmAicPsU{qe-PbUr1 z@AuR4LHf&nS~5ug*iT0f(i{6JGRR=^tU)f^PcsI&ct1@gNEE-Y%9zhG6~pbz0*60O2)f&=iWb14Qfee1WuDo}U%Z7M1c5v=uQ1LE4ifE9J9^xemSIw6X zqg5(|=No9Fqxi!eA z$>;*cgxAnCj4p(u#`4)Mo5DN=llwGGCex{zOKCHQ@ztCebRN&7oqQPe^5OVq$Sit4 z-apJo7)o?ul-sCMpAJJEq;@(+*CJIUBiE~4%Xq1-L!Qw7QoRN#nf5=f>tTpAMDYW< zf#!l*VY*PCfm8uLGSr~gqO=ggS)&_a;4IyQ)-rRO`g)yLA1TK)&7;D9(`t)mSlobr zZ&JCWb@Q7T9nUIw4Pc8P+a7z41aPsXQHMPaT?0!oK@W1>ssg>Tu&l5=0IIGkD_m)n z70$k%3g<{-4id9hTIGSV!ZNF+ydZE7H?--cWfnNwI>2jJ6 zSqynJOWmm6;8HiLTU_d%r#BkvPNB{EOwca?+O5-@kmpbpc&a!AK!&(TT@IN^8 z2L2DeMiERIt+d6}oF-RuruK6){Fll>Zozyha^#H6cvpO^Pcx?C6Kr!)EL?MR1v%iA zrz@LbuD0MyWRB~13HU1WM`h*1R8cv=oBH{zFu!epxAk*pV2F1p+K=7s?91Z&?tnA} z(8m#39L&_n$5Vh;;^xbVG@Va|EU%&?@H__3MSO}6ze>GTp9O5hgj%HDW^pSlDC4%3 zixPYdBd|wT4lx|$Yv{-vZGAgb6q18~#$gk8)gi@Hkc#*;z&ag_UG3}gXnnR!e5Okn zqJ^M9n?A?w?qrN#^aGv=r_m*j1P;5L#s$W8!~i$=;1xUY0OnkMo(twOU@e4P(a-M$ zlnWI#FMgPgS$yx+G(QLbOMw64LH-~fz9BeP!LfNw6ykNT2+g#dH<)f6zj=jr{GAXj z(r?q}qhpW9PR=&uI1>}ULCY0f9~(a}hY-MWB4~0ADJO z7!;VMw&{MpvUQNJ@%w;IXKiG`hd+$p=Ig9H>$H~ZF1_6yF_?N7`eM4&RhvDo44nj~ zUVBz$KYwY6Z&q-Tb7kq4Tv@6t>gQXB`0D}V`8ZPLu%sQPqXUB7NlUrQCkZF%9e&AL zs^cJoEUR|nS)|^8P&+eVkBiW<@evx#MQB*K9W-_Ujc%aP12hsoG?wXIW1|t&-MYs` z;}TIhpcYwNc_SSmavA2k3e57Ovb8O+7>u}ETz2W$FOqLZ$0>XjC{0IlpN}08oe*Oq z5OoqMMywn5q_8HBO>MmF8FTO%`MY=%vx3Q_M%^BL4Ab)?@r*W+HMZPfbn86#e=pI@~LIV1Qq~#4Y@U8uR|oiSUfC5Wd(Bt&`T)P-mAzwezrxp>fQr&UMe%?t98#eIpt21` zQ=Fm_DVjQdkUM)o9Z_SjJ>qJzLSR^ti*Anos)*Rq+_}J!+D%xW z5#I^}avLnx?f5X~9hl_%G07jGR{lDj!*^1WvG{~z{ZSsoce#e>CccZl#)s&BzMCH9 zd*~^?mtN%i=vTN$r}&$OX_X-LQxw)0V#On~jn?lK#gmkob|JvXd!N1t%<+t~Da*=# z4HeIpzge^1BCPT(su8aVA4`yrw$@ns{qPQ;d%k>=MtH${ZP>n@yPr!H_yZ%F;`X3;-9UrOYn`XQ2#2AY~<{%qIoaD1#J8*-55M zWMN31A}~iYA6}#15pbB_M2If&Lty^HG>0Fdqxexei65iW_*?L+AE$Hq3HZ}b(jNXc zeT=_Dm+@0{Gk=$EF0y~*kUA|ugKG8d$OP+< z3Dym%2FYxcOz=!HE0EbNnJtnDW=ZBUWNwnoEs_Z?Aro90QfEu%xyTe1m6{rv=SyZ( zGQk(gEJ0?cWNw#CFhnv>Lgr4%?D4O{!$u8#oWM97Ml^stgbR_l4@qVGJecuQs>Bt@ zTD!@s6W_+>EVH*^hdE#Azp_{{NxStdM~Wx|6F z6MUpcPL}l8X(*fF{JE6>7_9Zj^(S1)KMc(gO|B?8>>kzIro$?Qfexw+ro*t>3!0g9 zL0G+`pKdkj!mxT5q7o);h1Giy&oJp=SiQH>q)JfbqJA21UQp*^#5tT7RQf=_`jGQd z6jmQw>?A{B^@$};vN)_h<@H-)ht;KC$0bw3>T<8=lBr>JMYfM=VRe;f=_ zwo%bA7lz~O*iJY?S{P^yXxL73p`8l}6YZY1WEO&s>lZIsI;8H@zVMn^X3!Hb<4^i5 z&NLGoL_3;hf`~GdXf{t;HMVRc)oOoP83;AYd{Uy@hj=BYO&Pm=)gs$IDs0o+46&{la+7v6UlE+WtY z{)DVhD-j02Rx8)XGoniCFtlc@iMLQ0ZKVi;U6r&8;lFN#{(2BV?}iVWKuMC?@Z5&r z*Did*Hi2h`Qgk7u5dupg1eU=vqYpvO4EorMF#B$V!uHV3s&o{!-97@pt4^9ekk#Pd6NK85Gg zc)lOc?-k028u3>WRJZHz>mL>tVG=ZdxXo_<^fRdUW7K~Z&z}?)sa{^LpU3lAr(FG( K&eT7p^8W+m+H4d6 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/SharedUtils.java b/tests/test_data/std/jdk/internal/foreign/abi/SharedUtils.java new file mode 100644 index 00000000..83698398 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/SharedUtils.java @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.JavaLangInvokeAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.foreign.CABI; +import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory; +import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker; +import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker; +import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker; +import jdk.internal.foreign.abi.fallback.FallbackLinker; +import jdk.internal.foreign.abi.ppc64.aix.AixPPC64Linker; +import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64Linker; +import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker; +import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker; +import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker; +import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker; +import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker; +import jdk.internal.vm.annotation.ForceInline; + +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.Linker; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemorySegment.Scope; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.ref.Reference; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodType.methodType; + +public final class SharedUtils { + + private SharedUtils() { + } + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess(); + + private static final MethodHandle MH_ALLOC_BUFFER; + private static final MethodHandle MH_BUFFER_COPY; + private static final MethodHandle MH_REACHABILITY_FENCE; + public static final MethodHandle MH_CHECK_SYMBOL; + private static final MethodHandle MH_CHECK_CAPTURE_SEGMENT; + + @SuppressWarnings("restricted") + public static final AddressLayout C_POINTER = ADDRESS + .withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, JAVA_BYTE)); + + public static final Arena DUMMY_ARENA = new Arena() { + @Override + public Scope scope() { + throw new UnsupportedOperationException(); + } + + @Override + public MemorySegment allocate(long byteSize, long byteAlignment) { + throw new UnsupportedOperationException(); + } + + @Override + public void close() { + // do nothing + } + }; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MH_ALLOC_BUFFER = lookup.findVirtual(SegmentAllocator.class, "allocate", + methodType(MemorySegment.class, MemoryLayout.class)); + MH_BUFFER_COPY = lookup.findStatic(SharedUtils.class, "bufferCopy", + methodType(MemorySegment.class, MemorySegment.class, MemorySegment.class)); + MH_REACHABILITY_FENCE = lookup.findStatic(Reference.class, "reachabilityFence", + methodType(void.class, Object.class)); + MH_CHECK_SYMBOL = lookup.findStatic(SharedUtils.class, "checkSymbol", + methodType(void.class, MemorySegment.class)); + MH_CHECK_CAPTURE_SEGMENT = lookup.findStatic(SharedUtils.class, "checkCaptureSegment", + methodType(MemorySegment.class, MemorySegment.class)); + } catch (ReflectiveOperationException e) { + throw new BootstrapMethodError(e); + } + } + + // this allocator should be used when no allocation is expected + public static final SegmentAllocator THROWING_ALLOCATOR = (size, align) -> { + throw new IllegalStateException("Cannot get here"); + }; + + public static long alignUp(long addr, long alignment) { + return ((addr - 1) | (alignment - 1)) + 1; + } + + public static long remainsToAlignment(long addr, long alignment) { + return alignUp(addr, alignment) - addr; + } + + /** + * Takes a MethodHandle that takes an input buffer as a first argument (a MemorySegment), and returns nothing, + * and adapts it to return a MemorySegment, by allocating a MemorySegment for the input + * buffer, calling the target MethodHandle, and then returning the allocated MemorySegment. + * + * This allows viewing a MethodHandle that makes use of in memory return (IMR) as a MethodHandle that just returns + * a MemorySegment without requiring a pre-allocated buffer as an explicit input. + * + * @param handle the target handle to adapt + * @param cDesc the function descriptor of the native function (with actual return layout) + * @return the adapted handle + */ + public static MethodHandle adaptDowncallForIMR(MethodHandle handle, FunctionDescriptor cDesc, CallingSequence sequence) { + if (handle.type().returnType() != void.class) + throw new IllegalArgumentException("return expected to be void for in memory returns: " + handle.type()); + int imrAddrIdx = sequence.numLeadingParams(); + if (handle.type().parameterType(imrAddrIdx) != MemorySegment.class) + throw new IllegalArgumentException("MemorySegment expected as third param: " + handle.type()); + if (cDesc.returnLayout().isEmpty()) + throw new IllegalArgumentException("Return layout needed: " + cDesc); + + MethodHandle ret = identity(MemorySegment.class); // (MemorySegment) MemorySegment + handle = collectArguments(ret, 1, handle); // (MemorySegment, MemorySegment, SegmentAllocator, MemorySegment, ...) MemorySegment + handle = mergeArguments(handle, 0, 1 + imrAddrIdx); // (MemorySegment, MemorySegment, SegmentAllocator, ...) MemorySegment + handle = collectArguments(handle, 0, insertArguments(MH_ALLOC_BUFFER, 1, cDesc.returnLayout().get())); // (SegmentAllocator, MemorySegment, SegmentAllocator, ...) MemorySegment + handle = mergeArguments(handle, 0, 2); // (SegmentAllocator, MemorySegment, ...) MemorySegment + handle = swapArguments(handle, 0, 1); // (MemorySegment, SegmentAllocator, ...) MemorySegment + return handle; + } + + /** + * Takes a MethodHandle that returns a MemorySegment, and adapts it to take an input buffer as a first argument + * (a MemorySegment), and upon invocation, copies the contents of the returned MemorySegment into the input buffer + * passed as the first argument. + * + * @param target the target handle to adapt + * @return the adapted handle + */ + private static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropReturn) { + if (target.type().returnType() != MemorySegment.class) + throw new IllegalArgumentException("Must return MemorySegment for IMR"); + + target = collectArguments(MH_BUFFER_COPY, 1, target); // (MemorySegment, ...) MemorySegment + + if (dropReturn) { // no handling for return value, need to drop it + target = dropReturn(target); + } else { + // adjust return type so that it matches the inferred type of the effective + // function descriptor + target = target.asType(target.type().changeReturnType(MemorySegment.class)); + } + + return target; + } + + public static UpcallStubFactory arrangeUpcallHelper(MethodType targetType, boolean isInMemoryReturn, boolean dropReturn, + ABIDescriptor abi, CallingSequence callingSequence) { + if (isInMemoryReturn) { + // simulate the adaptation to get the type + MethodHandle fakeTarget = MethodHandles.empty(targetType); + targetType = adaptUpcallForIMR(fakeTarget, dropReturn).type(); + } + + UpcallStubFactory factory = UpcallLinker.makeFactory(targetType, abi, callingSequence); + + if (isInMemoryReturn) { + final UpcallStubFactory finalFactory = factory; + factory = (target, scope) -> { + target = adaptUpcallForIMR(target, dropReturn); + return finalFactory.makeStub(target, scope); + }; + } + + return factory; + } + + private static MemorySegment bufferCopy(MemorySegment dest, MemorySegment buffer) { + return dest.copyFrom(buffer); + } + + public static Class primitiveCarrierForSize(long size, boolean useFloat) { + return primitiveLayoutForSize(size, useFloat).carrier(); + } + + public static ValueLayout primitiveLayoutForSize(long size, boolean useFloat) { + if (useFloat) { + if (size == 4) { + return JAVA_FLOAT; + } else if (size == 8) { + return JAVA_DOUBLE; + } + } else { + if (size == 1) { + return JAVA_BYTE; + } else if (size == 2) { + return JAVA_SHORT; + } else if (size <= 4) { + return JAVA_INT; + } else if (size <= 8) { + return JAVA_LONG; + } + } + + throw new IllegalArgumentException("No layout for size: " + size + " isFloat=" + useFloat); + } + + public static Linker getSystemLinker() { + return switch (CABI.current()) { + case WIN_64 -> Windowsx64Linker.getInstance(); + case SYS_V -> SysVx64Linker.getInstance(); + case LINUX_AARCH_64 -> LinuxAArch64Linker.getInstance(); + case MAC_OS_AARCH_64 -> MacOsAArch64Linker.getInstance(); + case WIN_AARCH_64 -> WindowsAArch64Linker.getInstance(); + case AIX_PPC_64 -> AixPPC64Linker.getInstance(); + case LINUX_PPC_64 -> LinuxPPC64Linker.getInstance(); + case LINUX_PPC_64_LE -> LinuxPPC64leLinker.getInstance(); + case LINUX_RISCV_64 -> LinuxRISCV64Linker.getInstance(); + case LINUX_S390 -> LinuxS390Linker.getInstance(); + case FALLBACK -> FallbackLinker.getInstance(); + case UNSUPPORTED -> throw new UnsupportedOperationException("Platform does not support native linker"); + }; + } + + static Map indexMap(Binding.Move[] moves) { + return IntStream.range(0, moves.length) + .boxed() + .collect(Collectors.toMap(i -> moves[i].storage(), i -> i)); + } + + static MethodHandle mergeArguments(MethodHandle mh, int sourceIndex, int destIndex) { + MethodType oldType = mh.type(); + Class sourceType = oldType.parameterType(sourceIndex); + Class destType = oldType.parameterType(destIndex); + if (sourceType != destType) { + // TODO meet? + throw new IllegalArgumentException("Parameter types differ: " + sourceType + " != " + destType); + } + MethodType newType = oldType.dropParameterTypes(destIndex, destIndex + 1); + int[] reorder = new int[oldType.parameterCount()]; + if (destIndex < sourceIndex) { + sourceIndex--; + } + for (int i = 0, index = 0; i < reorder.length; i++) { + if (i != destIndex) { + reorder[i] = index++; + } else { + reorder[i] = sourceIndex; + } + } + return permuteArguments(mh, newType, reorder); + } + + + public static MethodHandle swapArguments(MethodHandle mh, int firstArg, int secondArg) { + MethodType mtype = mh.type(); + int[] perms = new int[mtype.parameterCount()]; + MethodType swappedType = MethodType.methodType(mtype.returnType()); + for (int i = 0 ; i < perms.length ; i++) { + int dst = i; + if (i == firstArg) dst = secondArg; + if (i == secondArg) dst = firstArg; + perms[i] = dst; + swappedType = swappedType.appendParameterTypes(mtype.parameterType(dst)); + } + return permuteArguments(mh, swappedType, perms); + } + + private static MethodHandle reachabilityFenceHandle(Class type) { + return MH_REACHABILITY_FENCE.asType(MethodType.methodType(void.class, type)); + } + + public static void handleUncaughtException(Throwable t) { + if (t != null) { + try { + t.printStackTrace(); + System.err.println("Unrecoverable uncaught exception encountered. The VM will now exit"); + } finally { + JLA.exit(1); + } + } + } + + public static void checkNative(MemorySegment segment) { + if (!segment.isNative()) { + throw new IllegalArgumentException("Heap segment not allowed: " + segment); + } + } + + public static long unboxSegment(MemorySegment segment) { + checkNative(segment); + return segment.address(); + } + + public static void checkExceptions(MethodHandle target) { + Class[] exceptions = JLIA.exceptionTypes(target); + if (exceptions != null && exceptions.length != 0) { + throw new IllegalArgumentException("Target handle may throw exceptions: " + Arrays.toString(exceptions)); + } + } + + public static MethodHandle maybeInsertAllocator(FunctionDescriptor descriptor, MethodHandle handle) { + if (descriptor.returnLayout().isEmpty() || !(descriptor.returnLayout().get() instanceof GroupLayout)) { + // not returning segment, just insert a throwing allocator + handle = insertArguments(handle, 1, THROWING_ALLOCATOR); + } + return handle; + } + + public static MethodHandle maybeCheckCaptureSegment(MethodHandle handle, LinkerOptions options) { + if (options.hasCapturedCallState()) { + // (, SegmentAllocator, , ...) -> ... + handle = MethodHandles.filterArguments(handle, 2, MH_CHECK_CAPTURE_SEGMENT); + } + return handle; + } + + @ForceInline + public static MemorySegment checkCaptureSegment(MemorySegment captureSegment) { + Objects.requireNonNull(captureSegment); + if (captureSegment.equals(MemorySegment.NULL)) { + throw new IllegalArgumentException("Capture segment is NULL: " + captureSegment); + } + return captureSegment.asSlice(0, CapturableState.LAYOUT); + } + + @ForceInline + public static void checkSymbol(MemorySegment symbol) { + Objects.requireNonNull(symbol); + if (symbol.equals(MemorySegment.NULL)) + throw new IllegalArgumentException("Symbol is NULL: " + symbol); + } + + static void checkType(Class actualType, Class expectedType) { + if (expectedType != actualType) { + throw new IllegalArgumentException( + String.format("Invalid operand type: %s. %s expected", actualType, expectedType)); + } + } + + public static boolean isPowerOfTwo(int width) { + return Integer.bitCount(width) == 1; + } + + static long pickChunkOffset(long chunkOffset, long byteWidth, int chunkWidth) { + return ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN + ? byteWidth - chunkWidth - chunkOffset + : chunkOffset; + } + + public static Arena newBoundedArena(long size) { + return new Arena() { + final Arena arena = Arena.ofConfined(); + final SegmentAllocator slicingAllocator = SegmentAllocator.slicingAllocator(arena.allocate(size)); + + @Override + public Scope scope() { + return arena.scope(); + } + + @Override + public void close() { + arena.close(); + } + + @Override + public MemorySegment allocate(long byteSize, long byteAlignment) { + return slicingAllocator.allocate(byteSize, byteAlignment); + } + }; + } + + public static Arena newEmptyArena() { + return new Arena() { + final Arena arena = Arena.ofConfined(); + + @Override + public Scope scope() { + return arena.scope(); + } + + @Override + public void close() { + arena.close(); + } + + @Override + public MemorySegment allocate(long byteSize, long byteAlignment) { + throw new UnsupportedOperationException(); + } + }; + } + + static void writeOverSized(MemorySegment ptr, Class type, Object o) { + // use VH_LONG for integers to zero out the whole register in the process + if (type == long.class) { + ptr.set(JAVA_LONG_UNALIGNED, 0, (long) o); + } else if (type == int.class) { + ptr.set(JAVA_LONG_UNALIGNED, 0, (int) o); + } else if (type == short.class) { + ptr.set(JAVA_LONG_UNALIGNED, 0, (short) o); + } else if (type == char.class) { + ptr.set(JAVA_LONG_UNALIGNED, 0, (char) o); + } else if (type == byte.class) { + ptr.set(JAVA_LONG_UNALIGNED, 0, (byte) o); + } else if (type == float.class) { + ptr.set(JAVA_FLOAT_UNALIGNED, 0, (float) o); + } else if (type == double.class) { + ptr.set(JAVA_DOUBLE_UNALIGNED, 0, (double) o); + } else if (type == boolean.class) { + boolean b = (boolean)o; + ptr.set(JAVA_LONG_UNALIGNED, 0, b ? (long)1 : (long)0); + } else { + throw new IllegalArgumentException("Unsupported carrier: " + type); + } + } + + static void write(MemorySegment ptr, long offset, Class type, Object o) { + if (type == long.class) { + ptr.set(JAVA_LONG_UNALIGNED, offset, (long) o); + } else if (type == int.class) { + ptr.set(JAVA_INT_UNALIGNED, offset, (int) o); + } else if (type == short.class) { + ptr.set(JAVA_SHORT_UNALIGNED, offset, (short) o); + } else if (type == char.class) { + ptr.set(JAVA_CHAR_UNALIGNED, offset, (char) o); + } else if (type == byte.class) { + ptr.set(JAVA_BYTE, offset, (byte) o); + } else if (type == float.class) { + ptr.set(JAVA_FLOAT_UNALIGNED, offset, (float) o); + } else if (type == double.class) { + ptr.set(JAVA_DOUBLE_UNALIGNED, offset, (double) o); + } else if (type == boolean.class) { + ptr.set(JAVA_BOOLEAN, offset, (boolean) o); + } else { + throw new IllegalArgumentException("Unsupported carrier: " + type); + } + } + + static Object read(MemorySegment ptr, long offset, Class type) { + if (type == long.class) { + return ptr.get(JAVA_LONG_UNALIGNED, offset); + } else if (type == int.class) { + return ptr.get(JAVA_INT_UNALIGNED, offset); + } else if (type == short.class) { + return ptr.get(JAVA_SHORT_UNALIGNED, offset); + } else if (type == char.class) { + return ptr.get(JAVA_CHAR_UNALIGNED, offset); + } else if (type == byte.class) { + return ptr.get(JAVA_BYTE, offset); + } else if (type == float.class) { + return ptr.get(JAVA_FLOAT_UNALIGNED, offset); + } else if (type == double.class) { + return ptr.get(JAVA_DOUBLE_UNALIGNED, offset); + } else if (type == boolean.class) { + return ptr.get(JAVA_BOOLEAN, offset); + } else { + throw new IllegalArgumentException("Unsupported carrier: " + type); + } + } + + public static Map canonicalLayouts(ValueLayout longLayout, ValueLayout sizetLayout, ValueLayout wchartLayout) { + return Map.ofEntries( + // specified canonical layouts + Map.entry("bool", ValueLayout.JAVA_BOOLEAN), + Map.entry("char", ValueLayout.JAVA_BYTE), + Map.entry("short", ValueLayout.JAVA_SHORT), + Map.entry("int", ValueLayout.JAVA_INT), + Map.entry("float", ValueLayout.JAVA_FLOAT), + Map.entry("long", longLayout), + Map.entry("long long", ValueLayout.JAVA_LONG), + Map.entry("double", ValueLayout.JAVA_DOUBLE), + Map.entry("void*", ValueLayout.ADDRESS), + Map.entry("size_t", sizetLayout), + Map.entry("wchar_t", wchartLayout), + // unspecified size-dependent layouts + Map.entry("int8_t", ValueLayout.JAVA_BYTE), + Map.entry("int16_t", ValueLayout.JAVA_SHORT), + Map.entry("int32_t", ValueLayout.JAVA_INT), + Map.entry("int64_t", ValueLayout.JAVA_LONG), + // unspecified JNI layouts + Map.entry("jboolean", ValueLayout.JAVA_BOOLEAN), + Map.entry("jchar", ValueLayout.JAVA_CHAR), + Map.entry("jbyte", ValueLayout.JAVA_BYTE), + Map.entry("jshort", ValueLayout.JAVA_SHORT), + Map.entry("jint", ValueLayout.JAVA_INT), + Map.entry("jlong", ValueLayout.JAVA_LONG), + Map.entry("jfloat", ValueLayout.JAVA_FLOAT), + Map.entry("jdouble", ValueLayout.JAVA_DOUBLE) + ); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache$Node.class b/tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache$Node.class new file mode 100644 index 0000000000000000000000000000000000000000..75b7781c8752dc2d6fb1d2cbeb87995a0de13021 GIT binary patch literal 1636 zcmb7^YflqF6o%g^Tb4_OQc%PTD&E>6EH`fyG1^EJXfZ;X@NrrOSSY(>yVVeXkY6?N z5;f686HWY2itls_Euj+muxHMkJ^ReL?fm-l=?j1~Qf&yK$%GL>7|jCF4f$MJMd_?r z3;7LI@CBNuY{&Me1)AcCTq|18YN9QIc0>e5HdZz*+wqm>$fC9CddgmNESa~hMR(PI zrdE}woPtWr!n(SWbypNAo>~<+KVLhDhJ)@5sso)Sq7ifX1R~ zsdn_>q={1z^y2g$r|jDdwd@pp+jXp&sv;1U+uOw*fot)@payIm;~8DGvjQg@eUcMs zU1T|=U-p>yKppi^##2kV)O3pVB6A%VJs0$b#>B+*YUZAE)pm2Cn5C z<<+Ai+DnptCl-BK*v!c7N(W4g33S)yd1>8qUj+Rcij(_a&_pGSwnew>71WHao85c( ze;d}P2()BX$$#vYd=qyB29GgbEYB0iQC_+zOC`m=7`kN`;S~_#bqr3?y)gQh!Vb4B#@?D+erBxx1#{(j^+D(uL~* zS-gZn46u-V3-bp$_3|Dkma{)`FS$Hvd^>FKy)pO^-63R?pV6^A^Z|YEVD=f`U!i?6 z%(XB4b?7zmr7igAqLJ|>XCtx7JB=@Vs+aptDw zo;HqH)y9CUnQARbKb`#oX*YOshEMRVu0xGBv`^DoK+{@4(^U#+!}~OApQimr_aMk>-9G7a&2Q2 JEz~Cw`wKvQe{28% literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache.class b/tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache.class new file mode 100644 index 0000000000000000000000000000000000000000..9396ceba58c253640fe6dd2be54725daa35f549f GIT binary patch literal 2096 zcmbVNZF3q`6n-v{th`hZZCcRQw52g2O*UHVOF^_nX<`URQXdTLLR1qhVk>rscWT(D#)anANlCwj3Pp$$kO` zqH!dVGH@k@w~-cDKkD>M+YOZOO2_PazOoNoQ?_lh>2-r2RaX(qQdMakDuD$n9Mkm) zBY{g<`uQ;^-EYX!FFnziwyl*Cmm8Mv0hb>sxDoTC>= zTi$Vh7^t1@qxOKY3slMensTK}8OHomN|y}0FR(R75QT=R6BZZsV&**^)^m-@w%>1+Dx2EPQl%sit8zy9>b9#I!{fH{ z_hsARPPXn@(rHQG*6Z{VvX1QJbe=v%60>ttV>ZS_svJOasv8U%Yv7X}lb zdF*+?An;{>PX&iwXOIECS-Ci@*PAcBfUgq#_f%5&1otzzpI*eH1RkSm;M)|wLrviJ zq-AaQ#Oo=uK2nf$vU{4--=>2@47DAYZ#H|&p_f7IU1z_;Cl>78>I z_gSI;?=Ymi{O#L#@X;;%@o7hfU+{DJqP_zU^6Sx)F&&|>j(Z~)a@fEoiL?t7EA2vPWu94W(JBo8<4i=C zC{MI|Pl>IAi@!qt83p)o;*Qn_bVa+c6dIkm5XYw@7bdaCd8UaM#xxJ`8CMZ}jxRXI hh?U2eoN4X8A?ZVu@im@sCrhh5gWl$B2fNrq?mu(CEJ6SP literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache.java b/tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache.java new file mode 100644 index 00000000..04565c66 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/SoftReferenceCache.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +import java.lang.ref.SoftReference; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +final class SoftReferenceCache { + private final Map cache = new ConcurrentHashMap<>(); + + public V get(K key, Function valueFactory) { + return cache + .computeIfAbsent(key, k -> new Node()) // short lock (has to be according to ConcurrentHashMap) + .get(key, valueFactory); // long lock, but just for the particular key + } + + private final class Node { + private volatile SoftReference ref; + + V get(K key, Function valueFactory) { + V result; + if (ref == null || (result = ref.get()) == null) { + synchronized (this) { // don't let threads race on the valueFactory::apply call + if (ref == null || (result = ref.get()) == null) { + result = valueFactory.apply(key); // keep alive + ref = new SoftReference<>(result); + } + } + } + return result; + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/StubLocations.class b/tests/test_data/std/jdk/internal/foreign/abi/StubLocations.class new file mode 100644 index 0000000000000000000000000000000000000000..e563b5f55e9b401449f4945eff042196216b6e05 GIT binary patch literal 1467 zcma)5ZBN=z6n-ug3SCjge3^)wV@?4#(QWQUm=h2e6MP9p60#4bVAVQomr_jjZ9i$l zM9s_=Kkr8^JGU^0+gxbU-ky7(^PF>@d(QVCU%mmzVOfNWVe(+-T~aq}%`((_a@Vvp zea}d$RXwTL&1%7{skUw!4L=wJ86J2U`bwGNn|x_Iv%Fl)D+)ub&>KmLv-o8AIZL3J zFKrdqx3gO-EBPWnxgkU5Cxf}nCLQIMx0O<+l>LrL7XUO3R`&!9e>+vYzZOU z5)qU!fI$XNt!^3`!$2%vI8cw&WL-7(k{i_nt!Aer4CA(l5gB2OQo+9gd82tq@sHGc zQ`^{On5Wt=y>oT7(MWY|D7K{=d#UaSoWS89lW_-k8N6xT(CtNrp>C><=W4tx;vPfv zT7k=Jifvlzo+gok_hn4r0p({}J38GbgF6;ql`xJe9xX=EVp)YqeeiJnm=As*Wd1uN zBZ*lqty5crVLH~kxJ3NRO~{!$q-%dcH?;NUVO6tAYPC)~>3`Hm%JkHJDTWa5#d=w_ zbWYdd6b$u{s6&5i&JbMF?0s`*Q?&>~{Y@na_P$PwU!fjX?WRSpBv6^EZnQ;Yn2Kfp zlhmc!l#pP5cuxc@OFf;g)jPMi(3J|m>vXRbE)u1rm`$sut>|2@(3Jt4;cd1wM>jQ0 z(<>~E@L2?CrD<|jnjIh*<`Y5)FYV7^mhg|siqgs-sfEA^ZeAeti7bXE^z}Mt5yFS@ z6fOtPSMDK&SmF#r7hoLkx`Lml9l4FdGdw5j1-%|}`^cfx+;BT&bF{kYNK8yeP7(P` zzt=H|c*(19nEWm(hyLkZa9mOpER9$6+aRl$5%0?&zOQ|vg;oRe=T z?mk807;eXy792x#jE5e_kk0Vv7y&Ltn=|D2k0C(1g-N+7L@4EU-5F#F=R)o$sgF4~ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/StubLocations.java b/tests/test_data/std/jdk/internal/foreign/abi/StubLocations.java new file mode 100644 index 00000000..e3a45250 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/StubLocations.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi; + +// must keep in sync with StubLocations in VM code +public enum StubLocations { + TARGET_ADDRESS, + RETURN_BUFFER, + CAPTURED_STATE_BUFFER; + + public VMStorage storage(byte type) { + return new VMStorage(type, (short) 8, ordinal()); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/UpcallLinker$CallRegs.class b/tests/test_data/std/jdk/internal/foreign/abi/UpcallLinker$CallRegs.class new file mode 100644 index 0000000000000000000000000000000000000000..38e6626c6cb17c37c11bcc966d24b34f4614e8ad GIT binary patch literal 1809 zcmb7E+foxj5Iqx;Y!Vj&5l~RU3y~xs3*tR^1GJzjK?^Vs`ZP(#WJ%bKvm2`XCm*Cr z$|@fG03ZDz%ic?1EfOj`?DR};_vty^J^lOd@h<>tSWO^=0R>?d5kwh=_xJ(Vn%t;q z+oEF1DnoQdH+1_2!$2lmiX(=&f`p1oP#G5XstrvyY#|Na)IOV1=ru#*WnKHws_G zzqv3_;EwOgd!l0JvmY6XnZDB3mr=IF5cYT`sbFHOyj4=jw{0?vQNB((GQgji&ehKRVwlZj`y$Pd z*fHC(BHro_&5>Y-EI7DS|1DwJ8>VF|xW|z0*{wlWDs|`G46mA|ZP}8yJkC}OOAJZ> z0p$H=PEudfH<*m#VFHivSiut&Pw|Xl`jnn*8@9eLG%o`_9z(p`3Bhm}%#>~%m<^$M zh8x_dHib1)FwI80l@DaiZ~B17cijEj66?aMNWDc5G3c_^&T#P8itTAq@YfSb>@Tu8aL^40XuXQykeL--;|2tamON!lMubj5KRvnV6;m)vxQ`o zbP-&q^#+}aBnL<)b3egyb4O5e^G6swBvlAgt~sOi52k6o>6wzeMJIA{p`HIp7d(X9 zw2y~K?WkyYQPewNZlooWj;WG6#xU@mwr3-#o{1k}gvQfM7xz)%TVL*zNc-+96wJv- zEH`(ItG)ckJsUqfS>rBd34sx#jE|(bXCRXM0p&av5g&%0LRaU(ew-u7x=eGJbLBi1 pNDk3Gy{dXO)m$CJ1BB_$i@1+vg z0ABe7Uf8u{buBJ@03XWbJ~I5Y{|R6f-wmP%y&C#- zB+xIA-m?xZqhdK_A;Lz z6{hRqIpJddKHAxnMc>SPEih0Zb1c8^(b4s0LM(O8Y*-GfEX^2dj(jXj&s;VIex;L& z(I@13W!Z_qt)w{vIXe5>%!JIgKwns!6nBc;tRL)1Z_C=LFbSi1Zkfuq<=JW-eeCmh zZKnQKXA9k^B5<)8^rvbAIK3hLUAOeu@~i{N?OYQg-IBWVm!Uc5{{`oNF4ovwo81;1 zj5&evC||)&j4@lds+cd&)##VNNCWMJoaz*aEHu8IKU)F|3hcBg6Ih(foPp##al64c zGhJY?;MTpOyl*RRkHlGeO{Inh)uycZ>u$~0a93cqqu+5=o<@x>m0odOzvg>ZHDq!v ziF@o%u|{LYT8Y`xKGeUU3z$61Qvw>FVLoX-V|*r3{m2hu1DhHi>3EFK1unlVsaJP= z`#>6DX(I=CrtLI*5_leGhs}PtFO5)e-EvA5S)0kb?tZ-*KggovJjR_!af=%_)=^>t zs}-wOYlFeUo;3D0)|2|@Lo<47-nRQ>Tna~s$2lwGf5omx7khA#xB|4o{ik2AAN1S8u$ z#{o(wkVP-%x%!2xevZ@G7ZBO`BWT%$BMfI3kC4tz_8nm?JDE7b#B<8@Vu9~|+5mpW zBHzoQF0R4giYSp!YNotVo=&SP4|UZ{dD0imlrITJ1AYsoh8Tkg{-rqU!41yG69fdI zR2WJWyt5z*`8|yA8uC7sR3JAvDs?S;j5mSbIqiAHUzHzL?hv&< x!rc+>ja9D4=)^;EB#AZL$7fha4iE5zf2PRdB<`TV*%r3(B_{C|p5a?e{sZm%CUgJ* literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/UpcallLinker.class b/tests/test_data/std/jdk/internal/foreign/abi/UpcallLinker.class new file mode 100644 index 0000000000000000000000000000000000000000..09af674274afce347a1ea977242ee8830d47b143 GIT binary patch literal 16386 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 q{IJ2JMX-qK#x)9;jA?N#>Go doBindingsMaker; + if (USE_SPEC) { + MethodHandle doBindings = BindingSpecializer.specializeUpcall(targetType, callingSequence, abi); + doBindingsMaker = target -> { + MethodHandle handle = MethodHandles.insertArguments(doBindings, 0, target); + assert handle.type() == llType; + return handle; + }; + } else { + Map argIndices = SharedUtils.indexMap(argMoves); + Map retIndices = SharedUtils.indexMap(retMoves); + int spreaderCount = callingSequence.calleeMethodType().parameterCount(); + if (callingSequence.needsReturnBuffer()) { + spreaderCount--; // return buffer is dropped from the argument list + } + final int finalSpreaderCount = spreaderCount; + InvocationData invData = new InvocationData(argIndices, retIndices, callingSequence, retMoves, abi); + MethodHandle doBindings = insertArguments(MH_invokeInterpBindings, 2, invData); + doBindingsMaker = target -> { + target = target.asSpreader(Object[].class, finalSpreaderCount); + MethodHandle handle = MethodHandles.insertArguments(doBindings, 0, target); + handle = handle.asCollector(Object[].class, llType.parameterCount()); + return handle.asType(llType); + }; + } + + VMStorage[] args = Arrays.stream(argMoves).map(Binding.Move::storage).toArray(VMStorage[]::new); + VMStorage[] rets = Arrays.stream(retMoves).map(Binding.Move::storage).toArray(VMStorage[]::new); + CallRegs conv = new CallRegs(args, rets); + return (target, scope) -> { + assert target.type() == targetType; + MethodHandle doBindings = doBindingsMaker.apply(target); + checkPrimitive(doBindings.type()); + doBindings = insertArguments(exactInvoker(doBindings.type()), 0, doBindings); + long entryPoint = makeUpcallStub(doBindings, abi, conv, + callingSequence.needsReturnBuffer(), callingSequence.returnBufferSize()); + if (entryPoint == 0) { + throw new OutOfMemoryError("Failed to allocate upcall stub"); + } + return UpcallStubs.makeUpcall(entryPoint, scope); + }; + } + + private static void checkPrimitive(MethodType type) { + if (!type.returnType().isPrimitive() + || type.parameterList().stream().anyMatch(p -> !p.isPrimitive())) + throw new IllegalArgumentException("MethodHandle type must be primitive: " + type); + } + + private static Stream argMoveBindingsStream(CallingSequence callingSequence) { + return callingSequence.argumentBindings() + .filter(Binding.VMLoad.class::isInstance) + .map(Binding.VMLoad.class::cast); + } + + private static Binding.VMLoad[] argMoveBindings(CallingSequence callingSequence) { + return argMoveBindingsStream(callingSequence) + .toArray(Binding.VMLoad[]::new); + } + + private static Binding.VMStore[] retMoveBindings(CallingSequence callingSequence) { + return callingSequence.returnBindings().stream() + .filter(Binding.VMStore.class::isInstance) + .map(Binding.VMStore.class::cast) + .toArray(Binding.VMStore[]::new); + } + + private record InvocationData(Map argIndexMap, + Map retIndexMap, + CallingSequence callingSequence, + Binding.VMStore[] retMoves, + ABIDescriptor abi) {} + + private static Object invokeInterpBindings(MethodHandle leaf, Object[] lowLevelArgs, InvocationData invData) throws Throwable { + Arena allocator = invData.callingSequence.allocationSize() != 0 + ? SharedUtils.newBoundedArena(invData.callingSequence.allocationSize()) + : SharedUtils.newEmptyArena(); + try (allocator) { + /// Invoke interpreter, got array of high-level arguments back + Object[] highLevelArgs = new Object[invData.callingSequence.calleeMethodType().parameterCount()]; + for (int i = 0; i < highLevelArgs.length; i++) { + highLevelArgs[i] = BindingInterpreter.box(invData.callingSequence.argumentBindings(i), + (storage, type) -> lowLevelArgs[invData.argIndexMap.get(storage)], allocator); + } + + MemorySegment returnBuffer = null; + if (invData.callingSequence.needsReturnBuffer()) { + // this one is for us + returnBuffer = (MemorySegment) highLevelArgs[0]; + Object[] newArgs = new Object[highLevelArgs.length - 1]; + System.arraycopy(highLevelArgs, 1, newArgs, 0, newArgs.length); + highLevelArgs = newArgs; + } + + if (DEBUG) { + System.err.println("Java arguments:"); + System.err.println(Arrays.toString(highLevelArgs).indent(2)); + } + + // invoke our target + Object o = leaf.invoke(highLevelArgs); + + if (DEBUG) { + System.err.println("Java return:"); + System.err.println(Objects.toString(o).indent(2)); + } + + Object[] returnValues = new Object[invData.retIndexMap.size()]; + if (leaf.type().returnType() != void.class) { + BindingInterpreter.unbox(o, invData.callingSequence.returnBindings(), + (storage, value) -> returnValues[invData.retIndexMap.get(storage)] = value, null); + } + + if (returnValues.length == 0) { + return null; + } else if (returnValues.length == 1) { + return returnValues[0]; + } else { + assert invData.callingSequence.needsReturnBuffer(); + + assert returnValues.length == invData.retMoves().length; + int retBufWriteOffset = 0; + for (int i = 0; i < invData.retMoves().length; i++) { + Binding.VMStore store = invData.retMoves()[i]; + Object value = returnValues[i]; + SharedUtils.writeOverSized(returnBuffer.asSlice(retBufWriteOffset), store.type(), value); + retBufWriteOffset += invData.abi.arch.typeSize(store.storage().type()); + } + return null; + } + } catch(Throwable t) { + SharedUtils.handleUncaughtException(t); + return null; + } + } + + // used for transporting data into native code + private record CallRegs(VMStorage[] argRegs, VMStorage[] retRegs) {} + + static native long makeUpcallStub(MethodHandle mh, ABIDescriptor abi, CallRegs conv, + boolean needsReturnBuffer, long returnBufferSize); + + private static native void registerNatives(); + static { + registerNatives(); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/UpcallStubs$1.class b/tests/test_data/std/jdk/internal/foreign/abi/UpcallStubs$1.class new file mode 100644 index 0000000000000000000000000000000000000000..cdb817075469c44673ea3f0a7a02a5ca09140a81 GIT binary patch literal 866 zcma)4+iuf95IvKa_)?RGaKDy8O$9+hmUm~yGiT26%+Fune*kFXv5x|ZE}Re-P$Fy{jgFg2r_yK1<%5ZGwLy;z;V$oD!%Lz=Q812(gBc&|ZnMCnt$H?MZ7@qIW0L zIC?K_GBZQjRW?0y+OZURHYJpHlve30La|ow2Pk9RMJ2=~R0+|_4u9|@ln;!QOXdWp z)~WaTY9}K}Snnz=_h*xVG#|tu=18@hu*|+ND)Z+-Cp}b_Q0x9r(`dUzaEA*KK`&SM zR%PgwB^CSRNSp|!@J0{g#40`Blj&hH3UL?r2*E@g&xsRW);irRyBP~TJ{!twBeiJN zSA1Fg=<$RH#B98MY14O!O$p(y*3z_NVXd?-9uS_c6t#d@Ju4T{zgFe1LhgBf%&d6f z&IgVAyn-HYBULKd60%j`cMVk#F0=IvMSg&wvGE1e_zL$^o^yrI66XLfaFx$6w*y?m zb@m81@<@j8oDs7;ukji54HuX7LEftc7dz)Lyg7!0n_N}EE!^hY;T61tjXY9j*5G(C TuV)jRc!)=i&q_A2<@mn=B&F7r literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/UpcallStubs.class b/tests/test_data/std/jdk/internal/foreign/abi/UpcallStubs.class new file mode 100644 index 0000000000000000000000000000000000000000..7d1cf18345236293f562e9e62af20a18a17f1940 GIT binary patch literal 1907 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 N@E@w=$b66TKLI_H6662? literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/AArch64Architecture$StorageType.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/AArch64Architecture$StorageType.class new file mode 100644 index 0000000000000000000000000000000000000000..1bd71903509cc0205f10d3f95db2df7d7e6aee30 GIT binary patch literal 431 zcmbV{%}#?r6ot=~7FybBtv}JdYiHBA77=Y@Q%oV7o7LJ9U>R461FF(a&rHwPJw0Fd%-{e1{wIKO zd>ujuJbrj1@S#&6x~#6MaYHrB@!5rCt!N8$UeZn7zAWI0jTHO{2wYt*t;BWH)+|#s z;)@ka)5~UDUC`sIY898pM&rq()5@=I6Qyox!-`$8)UuX;P}Teh35@<96h9&Y2b)f2 z3_~lcM$#(R?`o!P=BjGwr6Je3 zp>ad4)h-T6jkhD%jb83wtyVR&Bych|{UTsufyFOTY7f!?j$;Q<|x0cv+Zg&B9J0UQz#48;%*OTZ%n`(i02^U{72 zBZUBB)LoUj$E5CY21V*hI-C?Z($-osm6_0LMN6;p?1Km*9>IG!&3$IFNHMu+c0P4$ax$Hh zJ4r>Dr<~~>Pu}EIdSafT%cot95KbU14`ot_+&2EUrefmGj>7mlwK62us{`?->5LRY zBrVHhhSY28e`{z3Lb>$R*y#LBQn|sTA&I)iNiJJ8?Sg95H4n?K5C|4dpE>U;MKjra zdMcfp=gN5{bDK#aGE$GFw!4rX&(Aier z<3J^cDs{V6BiiV>shS&3iT@RWNaR*{gL(PTY0^D(Y`h?m(bOf(TCqBhzF7Eg6Itx+* zKT-iW%)hiFe*^qW--e=r$2b&?KF0oM2+uu3*W5a~d!lRT8Cb)fHT13Hoxhsy?4coG z6ob5g4`2*O_>@SpFL&5*FSY4js>MCNqzAoTmd6n0@ww~ZHTWGTXnJVQ?l;Lgzc3b^LkgmdB^T@;?4rv+_8CshJ;f>CA2>7TIi}2ck1GxN1m%;i+~;Md z&!_Zu_WJt*eZi*~?Oemfr?}i`lCoLHMAM(fDLujkJmKrK>X|B$(4y@uH+fGXN3H^|A4`n|gzw8WhEQqfV{0}0Cgm(Y{ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/AArch64Architecture.java b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/AArch64Architecture.java new file mode 100644 index 00000000..bfd8dd19 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/AArch64Architecture.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Arm Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.aarch64; + +import jdk.internal.foreign.abi.ABIDescriptor; +import jdk.internal.foreign.abi.Architecture; +import jdk.internal.foreign.abi.StubLocations; +import jdk.internal.foreign.abi.VMStorage; + +public final class AArch64Architecture implements Architecture { + public static final Architecture INSTANCE = new AArch64Architecture(); + + private static final short REG64_MASK = 0b0000_0000_0000_0001; + private static final short V128_MASK = 0b0000_0000_0000_0001; + + private static final int INTEGER_REG_SIZE = 8; + private static final int VECTOR_REG_SIZE = 16; + + // Suppresses default constructor, ensuring non-instantiability. + private AArch64Architecture() {} + + @Override + public boolean isStackType(int cls) { + return cls == StorageType.STACK; + } + + @Override + public int typeSize(int cls) { + return switch (cls) { + case StorageType.INTEGER -> INTEGER_REG_SIZE; + case StorageType.VECTOR -> VECTOR_REG_SIZE; + // STACK is deliberately omitted + default -> throw new IllegalArgumentException("Invalid Storage Class: " + cls); + }; + } + + public interface StorageType { + byte INTEGER = 0; + byte VECTOR = 1; + byte STACK = 2; + byte PLACEHOLDER = 3; + } + + public static class Regs { // break circular dependency + public static final VMStorage r0 = integerRegister(0); + public static final VMStorage r1 = integerRegister(1); + public static final VMStorage r2 = integerRegister(2); + public static final VMStorage r3 = integerRegister(3); + public static final VMStorage r4 = integerRegister(4); + public static final VMStorage r5 = integerRegister(5); + public static final VMStorage r6 = integerRegister(6); + public static final VMStorage r7 = integerRegister(7); + public static final VMStorage r8 = integerRegister(8); + public static final VMStorage r9 = integerRegister(9); + public static final VMStorage r10 = integerRegister(10); + public static final VMStorage r11 = integerRegister(11); + public static final VMStorage r12 = integerRegister(12); + public static final VMStorage r13 = integerRegister(13); + public static final VMStorage r14 = integerRegister(14); + public static final VMStorage r15 = integerRegister(15); + public static final VMStorage r16 = integerRegister(16); + public static final VMStorage r17 = integerRegister(17); + public static final VMStorage r18 = integerRegister(18); + public static final VMStorage r19 = integerRegister(19); + public static final VMStorage r20 = integerRegister(20); + public static final VMStorage r21 = integerRegister(21); + public static final VMStorage r22 = integerRegister(22); + public static final VMStorage r23 = integerRegister(23); + public static final VMStorage r24 = integerRegister(24); + public static final VMStorage r25 = integerRegister(25); + public static final VMStorage r26 = integerRegister(26); + public static final VMStorage r27 = integerRegister(27); + public static final VMStorage r28 = integerRegister(28); + public static final VMStorage r29 = integerRegister(29); + public static final VMStorage r30 = integerRegister(30); + public static final VMStorage r31 = integerRegister(31); + public static final VMStorage v0 = vectorRegister(0); + public static final VMStorage v1 = vectorRegister(1); + public static final VMStorage v2 = vectorRegister(2); + public static final VMStorage v3 = vectorRegister(3); + public static final VMStorage v4 = vectorRegister(4); + public static final VMStorage v5 = vectorRegister(5); + public static final VMStorage v6 = vectorRegister(6); + public static final VMStorage v7 = vectorRegister(7); + public static final VMStorage v8 = vectorRegister(8); + public static final VMStorage v9 = vectorRegister(9); + public static final VMStorage v10 = vectorRegister(10); + public static final VMStorage v11 = vectorRegister(11); + public static final VMStorage v12 = vectorRegister(12); + public static final VMStorage v13 = vectorRegister(13); + public static final VMStorage v14 = vectorRegister(14); + public static final VMStorage v15 = vectorRegister(15); + public static final VMStorage v16 = vectorRegister(16); + public static final VMStorage v17 = vectorRegister(17); + public static final VMStorage v18 = vectorRegister(18); + public static final VMStorage v19 = vectorRegister(19); + public static final VMStorage v20 = vectorRegister(20); + public static final VMStorage v21 = vectorRegister(21); + public static final VMStorage v22 = vectorRegister(22); + public static final VMStorage v23 = vectorRegister(23); + public static final VMStorage v24 = vectorRegister(24); + public static final VMStorage v25 = vectorRegister(25); + public static final VMStorage v26 = vectorRegister(26); + public static final VMStorage v27 = vectorRegister(27); + public static final VMStorage v28 = vectorRegister(28); + public static final VMStorage v29 = vectorRegister(29); + public static final VMStorage v30 = vectorRegister(30); + public static final VMStorage v31 = vectorRegister(31); + } + + private static VMStorage integerRegister(int index) { + return new VMStorage(StorageType.INTEGER, REG64_MASK, index, "r" + index); + } + + private static VMStorage vectorRegister(int index) { + return new VMStorage(StorageType.VECTOR, V128_MASK, index, "v" + index); + } + + public static VMStorage stackStorage(short size, int byteOffset) { + return new VMStorage(StorageType.STACK, size, byteOffset); + } + + public static ABIDescriptor abiFor(VMStorage[] inputIntRegs, + VMStorage[] inputVectorRegs, + VMStorage[] outputIntRegs, + VMStorage[] outputVectorRegs, + VMStorage[] volatileIntRegs, + VMStorage[] volatileVectorRegs, + int stackAlignment, + int shadowSpace, + VMStorage scratch1, VMStorage scratch2) { + return new ABIDescriptor( + INSTANCE, + new VMStorage[][] { + inputIntRegs, + inputVectorRegs, + }, + new VMStorage[][] { + outputIntRegs, + outputVectorRegs, + }, + new VMStorage[][] { + volatileIntRegs, + volatileVectorRegs, + }, + stackAlignment, + shadowSpace, + scratch1, scratch2, + StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER), + StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER), + StubLocations.CAPTURED_STATE_BUFFER.storage(StorageType.PLACEHOLDER)); + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$1.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$1.class new file mode 100644 index 0000000000000000000000000000000000000000..1caaa0b5b7eed80e2571997c61c795a6da03c90c GIT binary patch literal 1020 zcmb7?T~8B16o%iSAKTVN3W8MpLRqCnUf=%eqUZTZ})( zYp>PB7-RSW{ssSw@l2_f3lk;TnRDKE=FC3x@%`u5696S_W-x}BhPaLdk_=1T)}iSI zk&prR%~zomUOO;((=$1jZf9%5blx6`lFxfRhU78#`+^cPUpT1#f91n8Qb=pa=(qr# z%Kuqf;=W&$k_T-ejWvc%!+zsMZfBPt8B}ciCN_q|1`!)WV&e?)*g+*t8@{Mx0$GL$ z+i5&2IWHR4cExtA2E+1swxP~$O2;KkGiae~d30tBv3#MT;WEQqmmhP}Cup-4+I_cE z_JrTEqzt8k$mzJEATmRUopMpxS9M%dcJ>cj*=ks|lBEW3=(wo{wY_?!M!?FurQ`O% zQ_l9OXXv=2yhOQLFFG0)X}u9mz1bCR#E^RA`d;8gj|b5E4DnLf5_Bw8FA%l<>!y$n zZ~Ej+RYRBi`&@cT56y8q;_e|`!BA)HurFOv_Eg2>*(+OB|E6`V!1cqP7qoXp)CpS} z))`jLb@>Ec6TN6B>=D0S2?8Mpk5Tlp^Yp0h(xYbCoO)I&BPWjn#U)Zd5TgtbU%*bj zWj;assJ`*fn2guoBmQ(CXGtbTa*kwjB(IayMsl8HY9tp(W>05-KoV(8V-_>WVS&JA zu!wbRQrtojPbga0gH6%FOSlwcxJP(N11#8qO?U_9|$ic7;Hi$DPU4VB5%{}Sf*}wli67lq9*<& z9}I~m{s4cJ@oYgLRui`mow=uX&N+AH-v0Rc^*ewT9u<*8-i1@bB@_ha2J)Ts0vYzb zz3xEyR-mx1Lv1$%^0oTDiwS{egWg+DhgO+T2Hu;T zGD{sB8QE9F{3MVJif~a(1*Zg7Ywb*I&4Yvb{v@U`<6^diIg~T|d9K5r4*TbR1j_NB z9tAeD85=LNDd4oCo)VaC>rm|`!>%%~WH%sEX-B>c_NCEjd)6uIWQW})ZDM$BgE7YS#ztn+ z^?%>Vsrlvxg{v%Po2_Cv2IoapYJc&#HU|EuMzIqm##dW9ZHn^6v3ZhSoxsGditURi zwk~P{k2B2*-*P()l^I>V;)9gOMv>T9`#6gnuN?m#1TLoo#$6sxI<7=3jC>Rr1J%Yc zMB^LW*DLc2$C&(r(r3asRQWx_LlE!bh!3cUkE8+`C&zFFR~eB2*KnOO>Fx$@jzp`t z#a$lrM5jsdX)eu7Ka^a+ZKmI0ki#P5ySR52-{+yF(Jv41aI`L?&b7i^7t0hUA=ecL FzW@v7W={YB literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$Bindings.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$Bindings.class new file mode 100644 index 0000000000000000000000000000000000000000..de920b750b328965d5054aefc21d96263cb0b3fa GIT binary patch literal 1880 zcmbVNT~8B16g^WY+u}l@0*WA@g0=;^qKIe_mbLQN8=kA}sXTJfgV6_twv}tJ95k&_>&ptomMwMH8 z#-=FQvdqx2U|OcT$k3Kb@5B*9TtlahJJ1>C_R9x`X}LmLylQ;4r7-s_gBMMMb6Kj) z%^EAbT3wQo0EHZ1Hm$O0?KupI64`0HCBD^#RT2!Dd{Zoi5%SHcLv-s%pob1@I_p+J z)NFaYDcriW7}#!-v?X=iMIS@VwYOYJ;SBjybB>nh&871fdGXP5ieo^>J=`ab3U?|i zc9~@4ZqKo62q&Mslu%RLudX}+!rM`m)>Q_w!piZ=-u=VL%T05kvA=| zQLhz++~&n9NloT$s^Siprg{&I?QX@SQ_tTv(^S!da4UBCGnc$3sIv&IFLgr!yoOw7 z=qEwvO&b!*Y<0wIpBSbTTC={rngWl7($=|U*JVk3G?nsR<<;owtfHVE*bt7pW;?D1 zgJHTU!A*@u7#`Cs)P(RFtG8^28kR=G* zK0Xwy!YN7f(6wbaWTna-Cu|5XzFY?hvtPQ1L9H3|b;}acgA~*)vBsFu@PT3CLVgQ5 z8kQMGTDww}eC?Q_0TiLj8bMOcK{ajEG@`Wwj0WjL`Z7Xq1vOl0O=Nz7WhPIdWrk1D zbwZ{HMgw<%V~qA=zAGN#F}+cc2hF^l0*~Mc?c)(LtB*i04Y+aQQ%p0oDpxIYMt1z5 z?R5s-cL^AJX?9KA5Z(`b|F7^NJPpDZh)m@pmYF=mV6*rE-{)Ll49}1v1V)O|0g~ap z1JTS+XsuL40~q?1Aag@-S1S#T;3y_NrBj&p)-0aW+D+&5tLoQu# VydztZ{9?#rktDyz68%jF{{dyl!$$xB literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$BoxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$BoxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..c00905e0862727fac9fed4f7a1fc8dd6131b6a65 GIT binary patch literal 5289 zcmb_gX>=P`75=U)X)Jl-c!`t9ZBv(u)OMUWO%s#aX%pFT8o9EaT3(0)31ew&k0Wcu zXq3cZNhzU)043}Y)|R%RWozA{ga(qb7Rpkfv_ByH0S;v?r-uNCrG)!NBTKd=`}hw2aLRDOP1rsWJ=m1c z6dnm)8D)?ObwxSYk_pmCN{dBRmfTd|P+X$D-`}3u-R40#mP@FRQHd(T`l5mgotv;c z*t0X(*V)m3pszDL5b7uRi_0GD4zp>LF_opRK#hczGFD+Vp?pF)q%_CamdznOK1Oi% z@7>c$s0`&6I$}yP+2%zpu8?r0jH|GQP+wHtIp<`59GVR2N|c~1;E$Y!^CU09rmka` zGk-$cSID>)e!{X5{YW4hHPmFXPdQB3P~X+H1fGJ`S{c`&p5U@vO{fx%7M4qyTC6#w zB~7+ZBi2c1lCd5e2#rPUlXYkRR6?~(%U*~G6KkVWA!SNWnS>s;)Qn@YG0?3}>W00g zZGi*K6TnX2i0dV6l5qnz6Pg#*ZB~d~PuSuQAJ)vsc(;=9GqFD#pMG06KgXxvmg~Fq3c^b40H|%@4C-sN(g<45*pN!XtN>LI`CA`>=0}@^*L%|54dufoKcgWe& zIDV2D=MmN}RB3X#ROl0xp<Bw5T~QV5`eW;Pr&Ek<{p@Y6$Hax!dcz@^V*(d2oSjH5aTB*p)jL zHC!NIH3Q z1#z9VP#ZJYK-QYx)nARGsU>(I36b4z+9KoTXVh~xiMq}TRdlQ7xE|f37|Nu|-xfSoJ*JvL{&+ChhjtR;Sx=b3%T^PqtR?HG znJ#ZzaXoAnZ8x*WjK@{OI;+ZNth9}l>*%;$uyZS? zt3uJqMDyAe%Vc>ynS`J5NBE*Sr$8y^5Xvj&sN)9K!M_$z#cJ`bz#}JLEsFG+y~IFJ+{z0^?`fRLh;h8g)MZScXgZ6A9+uVWoJRBdG`4IIhozgujW0J} zYwhbneqQ8h4`0_#z1ZrLYCM}-y*_6e!$Ur&kB|CVaf|TD#dFMh z5x0YB#D|W1==9|$Ph+}}3PM`RG|V)Pwz393SH^&>$(x5x;}|RQmR6Uw$;bK}Wqq7J zcV>^zbrx?Gw|B6qd2^q&jVazW!)zUE#4B6HinGwlnsc~&?>U@gbG)zW{b_uVE&9TNaO?Y9gy?w;)9;|r?{Sd+fCT*sC+N>ONiX0Y z`U|G{{Vcu68Q`yYnl9lY{SD94-|E9x90;3Agur$!ae zU4kE9#T4rdthVOd)BsOrl{&H`K35`(ejcg3mkD_EHJoSsx#%D+AjnbTrBOVAuXAL5 zgRy0y*4qC~-v2G0xfRP^!d3~55^AfxJLoe1*y5GYD&al}-_FdFgeUo*Si)tr!8K=@ z!=-vnlh0R+Oc;EZ!|{9QWC0JcfXx=jfy%1#G(L06#_prIF&Eu#OZR6ieOz$JJGj-s zQ%vi?_wfVkS&kp_vlSB0mE%X8H)>hR(`=57JdcV}UMt6sc{sq&pYU@(kABK#G4KqY Hb$k8?4Kx&@ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$StorageCalculator$StructStorage.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$StorageCalculator$StructStorage.class new file mode 100644 index 0000000000000000000000000000000000000000..b18fcf6ddf6185525443d98f94f67c3455d875c5 GIT binary patch literal 2568 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 Q@pk%haS8f4^KVT5FZh2400000 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$UnboxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger$UnboxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..4183abd0489cd74e5d1a552c10a85182de2d78d3 GIT binary patch literal 5611 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 ZhXv(4qcq^pY)066pM6(T@qa4|{1@bgQUm}1 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/CallArranger.class new file mode 100644 index 0000000000000000000000000000000000000000..eb399a22c58cdb7977f2b1b55c20b75bdde0896d GIT binary patch literal 10034 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 carrier = mt.returnType(); + MemoryLayout layout = cDesc.returnLayout().get(); + csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout)); + } + + for (int i = 0; i < mt.parameterCount(); i++) { + Class carrier = mt.parameterType(i); + MemoryLayout layout = cDesc.argumentLayouts().get(i); + if (varArgsOnStack() && options.isVarargsIndex(i)) { + argCalc.storageCalculator.adjustForVarArgs(); + } + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout)); + } + + return new Bindings(csb.build(), returnInMemory); + } + + public MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, false, options); + + MethodHandle handle = new DowncallLinker(abiDescriptor(), bindings.callingSequence).getBoundMethodHandle(); + + if (bindings.isInMemoryReturn) { + handle = SharedUtils.adaptDowncallForIMR(handle, cDesc, bindings.callingSequence); + } + + return handle; + } + + public UpcallStubFactory arrangeUpcall(MethodType mt, FunctionDescriptor cDesc, + LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, true, options); + final boolean dropReturn = true; /* drop return, since we don't have bindings for it */ + return SharedUtils.arrangeUpcallHelper(mt, bindings.isInMemoryReturn, dropReturn, abiDescriptor(), + bindings.callingSequence); + } + + private static boolean isInMemoryReturn(Optional returnLayout) { + return returnLayout + .filter(GroupLayout.class::isInstance) + .filter(g -> TypeClass.classifyLayout(g) == TypeClass.STRUCT_REFERENCE) + .isPresent(); + } + + class StorageCalculator { + private final boolean forArguments; + private final boolean forVariadicFunction; + private boolean forVarArgs = false; + + private final int[] nRegs = new int[] { 0, 0 }; + private long stackOffset = 0; + + public StorageCalculator(boolean forArguments, boolean forVariadicFunction) { + this.forArguments = forArguments; + this.forVariadicFunction = forVariadicFunction; + } + + private boolean hasRegister(int type) { + return hasEnoughRegisters(type, 1); + } + + private boolean hasEnoughRegisters(int type, int count) { + return nRegs[type] + count <= MAX_REGISTER_ARGUMENTS; + } + + private static Class adjustCarrierForStack(Class carrier) { + if (carrier == float.class) { + carrier = int.class; + } else if (carrier == double.class) { + carrier = long.class; + } + return carrier; + } + + record StructStorage(long offset, Class carrier, int byteWidth, VMStorage storage) {} + + /* + In the simplest case structs are copied in chunks. i.e. the fields don't matter, just the size. + The struct is split into 8-byte chunks, and those chunks are either passed in registers and/or on the stack. + + Homogeneous float aggregates (HFAs) can be copied in a field-wise manner, i.e. the struct is split into it's + fields and those fields are the chunks which are passed. For HFAs the rules are more complicated and ABI based: + + | enough registers | some registers, but not enough | no registers + ----------------+------------------+---------------------------------+------------------------- + Linux | FW in regs | CW on the stack | CW on the stack + macOS, non-VA | FW in regs | FW on the stack | FW on the stack + macOS, VA | FW in regs | CW on the stack | CW on the stack + Windows, non-VF | FW in regs | CW on the stack | CW on the stack + Windows, VF | FW in regs | CW split between regs and stack | CW on the stack + (where FW = Field-wise copy, CW = Chunk-wise copy, VA is a variadic argument, and VF is a variadic function) + + For regular structs, the rules are as follows: + + | enough registers | some registers, but not enough | no registers + ----------------+------------------+---------------------------------+------------------------- + Linux | CW in regs | CW on the stack | CW on the stack + macOS | CW in regs | CW on the stack | CW on the stack + Windows, non-VF | CW in regs | CW on the stack | CW on the stack + Windows, VF | CW in regs | CW split between regs and stack | CW on the stack + */ + StructStorage[] structStorages(GroupLayout layout, boolean forHFA) { + int numChunks = (int)Utils.alignUp(layout.byteSize(), MAX_COPY_SIZE) / MAX_COPY_SIZE; + + int regType = StorageType.INTEGER; + List scalarLayouts = null; + int requiredStorages = numChunks; + if (forHFA) { + regType = StorageType.VECTOR; + scalarLayouts = TypeClass.scalarLayouts(layout); + requiredStorages = scalarLayouts.size(); + } + + boolean hasEnoughRegisters = hasEnoughRegisters(regType, requiredStorages); + + // For the ABI variants that pack arguments spilled to the + // stack, HFA arguments are spilled as if their individual + // fields had been allocated separately rather than as if the + // struct had been spilled as a whole. + boolean useFieldWiseSpill = requiresSubSlotStackPacking() && !forVarArgs; + boolean isFieldWise = forHFA && (hasEnoughRegisters || useFieldWiseSpill); + if (!isFieldWise) { + requiredStorages = numChunks; + } + + boolean spillPartially = forVariadicFunction && spillsVariadicStructsPartially(); + boolean furtherAllocationFromTheStack = !hasEnoughRegisters && !spillPartially; + if (furtherAllocationFromTheStack) { + // Any further allocations for this register type must + // be from the stack. + nRegs[regType] = MAX_REGISTER_ARGUMENTS; + } + + if (requiresSubSlotStackPacking() && !isFieldWise) { + // Pad to the next stack slot boundary instead of packing + // additional arguments into the unused space. + alignStack(STACK_SLOT_SIZE); + } + + StructStorage[] structStorages = new StructStorage[requiredStorages]; + long offset = 0; + for (int i = 0; i < structStorages.length; i++) { + ValueLayout copyLayout; + long copySize; + if (isFieldWise) { + // We should only get here for HFAs, which can't have padding + copyLayout = (ValueLayout) scalarLayouts.get(i); + copySize = Utils.byteWidthOfPrimitive(copyLayout.carrier()); + } else { + // chunk-wise copy + copySize = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE); + boolean useFloat = false; // never use float for chunk-wise copies + copyLayout = SharedUtils.primitiveLayoutForSize(copySize, useFloat); + } + + VMStorage storage = nextStorage(regType, copyLayout); + Class carrier = copyLayout.carrier(); + if (isFieldWise && storage.type() == StorageType.STACK) { + // copyLayout is a field of an HFA + // Don't use floats on the stack + carrier = adjustCarrierForStack(carrier); + } + structStorages[i] = new StructStorage(offset, carrier, (int) copySize, storage); + offset += copyLayout.byteSize(); + } + + if (requiresSubSlotStackPacking() && !isFieldWise) { + // Pad to the next stack slot boundary instead of packing + // additional arguments into the unused space. + alignStack(STACK_SLOT_SIZE); + } + + return structStorages; + } + + private void alignStack(long alignment) { + stackOffset = Utils.alignUp(stackOffset, alignment); + } + + // allocate a single ValueLayout, either in a register or on the stack + VMStorage nextStorage(int type, ValueLayout layout) { + return hasRegister(type) ? regAlloc(type) : stackAlloc(layout); + } + + private VMStorage regAlloc(int type) { + ABIDescriptor abiDescriptor = abiDescriptor(); + VMStorage[] source = (forArguments ? abiDescriptor.inputStorage : abiDescriptor.outputStorage)[type]; + return source[nRegs[type]++]; + } + + private VMStorage stackAlloc(ValueLayout layout) { + assert forArguments : "no stack returns"; + long stackSlotAlignment = requiresSubSlotStackPacking() && !forVarArgs + ? layout.byteAlignment() + : Math.max(layout.byteAlignment(), STACK_SLOT_SIZE); + long alignedStackOffset = Utils.alignUp(stackOffset, stackSlotAlignment); + + short encodedSize = (short) layout.byteSize(); + assert (encodedSize & 0xFFFF) == layout.byteSize(); + + VMStorage storage = AArch64Architecture.stackStorage(encodedSize, (int)alignedStackOffset); + stackOffset = alignedStackOffset + layout.byteSize(); + return storage; + } + + void adjustForVarArgs() { + // This system passes all variadic parameters on the stack. Ensure + // no further arguments are allocated to registers. + nRegs[StorageType.INTEGER] = MAX_REGISTER_ARGUMENTS; + nRegs[StorageType.VECTOR] = MAX_REGISTER_ARGUMENTS; + forVarArgs = true; + } + } + + abstract class BindingCalculator { + protected final StorageCalculator storageCalculator; + + protected BindingCalculator(boolean forArguments, boolean forVariadicFunction) { + this.storageCalculator = new StorageCalculator(forArguments, forVariadicFunction); + } + + abstract List getBindings(Class carrier, MemoryLayout layout); + + abstract List getIndirectBindings(); + } + + class UnboxBindingCalculator extends BindingCalculator { + protected final boolean forArguments; + protected final boolean forVariadicFunction; + private final boolean useAddressPairs; + + UnboxBindingCalculator(boolean forArguments, boolean forVariadicFunction, boolean useAddressPairs) { + super(forArguments, forVariadicFunction); + this.forArguments = forArguments; + this.forVariadicFunction = forVariadicFunction; + this.useAddressPairs = useAddressPairs; + } + + @Override + List getIndirectBindings() { + return Binding.builder() + .unboxAddress() + .vmStore(INDIRECT_RESULT, long.class) + .build(); + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = getArgumentClassForBindings(layout, forVariadicFunction); + Binding.Builder bindings = Binding.builder(); + + switch (argumentClass) { + case STRUCT_REGISTER, STRUCT_HFA -> { + assert carrier == MemorySegment.class; + boolean forHFA = argumentClass == TypeClass.STRUCT_HFA; + StorageCalculator.StructStorage[] structStorages + = storageCalculator.structStorages((GroupLayout) layout, forHFA); + + for (int i = 0; i < structStorages.length; i++) { + StorageCalculator.StructStorage structStorage = structStorages[i]; + if (i < structStorages.length - 1) { + bindings.dup(); + } + bindings.bufferLoad(structStorage.offset(), structStorage.carrier(), structStorage.byteWidth()) + .vmStore(structStorage.storage(), structStorage.carrier()); + } + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + bindings.copy(layout) + .unboxAddress(); + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, SharedUtils.C_POINTER); + bindings.vmStore(storage, long.class); + } + case POINTER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, (ValueLayout) layout); + if (useAddressPairs) { + bindings.dup() + .segmentBase() + .vmStore(storage, Object.class) + .segmentOffsetAllowHeap() + .vmStore(null, long.class); + } else { + bindings.unboxAddress(); + bindings.vmStore(storage, long.class); + } + } + case INTEGER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, (ValueLayout) layout); + bindings.vmStore(storage, carrier); + } + case FLOAT -> { + boolean forVariadicFunctionArgs = forArguments && forVariadicFunction; + boolean useIntReg = forVariadicFunctionArgs && useIntRegsForVariadicFloatingPointArgs(); + + int type = useIntReg ? StorageType.INTEGER : StorageType.VECTOR; + VMStorage storage = storageCalculator.nextStorage(type, (ValueLayout) layout); + bindings.vmStore(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } + + class BoxBindingCalculator extends BindingCalculator { + BoxBindingCalculator(boolean forArguments) { + super(forArguments, false); + } + + @Override + List getIndirectBindings() { + return Binding.builder() + .vmLoad(INDIRECT_RESULT, long.class) + .boxAddressRaw(Long.MAX_VALUE, 1) + .build(); + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = TypeClass.classifyLayout(layout); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case STRUCT_REGISTER, STRUCT_HFA -> { + assert carrier == MemorySegment.class; + boolean forHFA = argumentClass == TypeClass.STRUCT_HFA; + bindings.allocate(layout); + StorageCalculator.StructStorage[] structStorages + = storageCalculator.structStorages((GroupLayout) layout, forHFA); + + for (StorageCalculator.StructStorage structStorage : structStorages) { + bindings.dup(); + bindings.vmLoad(structStorage.storage(), structStorage.carrier()) + .bufferStore(structStorage.offset(), structStorage.carrier(), structStorage.byteWidth()); + } + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, SharedUtils.C_POINTER); + bindings.vmLoad(storage, long.class) + .boxAddress(layout); + } + case POINTER -> { + AddressLayout addressLayout = (AddressLayout) layout; + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, addressLayout); + bindings.vmLoad(storage, long.class) + .boxAddressRaw(Utils.pointeeByteSize(addressLayout), Utils.pointeeByteAlign(addressLayout)); + } + case INTEGER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, (ValueLayout) layout); + bindings.vmLoad(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.VECTOR, (ValueLayout) layout); + bindings.vmLoad(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/TypeClass.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/TypeClass.class new file mode 100644 index 0000000000000000000000000000000000000000..ba1bfc64356c99de4da88367fcb2af79e6f8f615 GIT binary patch literal 5416 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 carrier = type.carrier(); + if (carrier == boolean.class || carrier == byte.class || carrier == char.class || + carrier == short.class || carrier == int.class || carrier == long.class) { + return INTEGER; + } else if (carrier == float.class || carrier == double.class) { + return FLOAT; + } else if (carrier == MemorySegment.class) { + return POINTER; + } else { + throw new IllegalStateException("Cannot get here: " + carrier.getName()); + } + } + + static boolean isRegisterAggregate(MemoryLayout type) { + return type.byteSize() <= MAX_AGGREGATE_REGS_SIZE * 8; + } + + static List scalarLayouts(GroupLayout gl) { + List out = new ArrayList<>(); + scalarLayoutsInternal(out, gl); + return out; + } + + private static void scalarLayoutsInternal(List out, GroupLayout gl) { + for (MemoryLayout member : gl.memberLayouts()) { + if (member instanceof GroupLayout memberGl) { + scalarLayoutsInternal(out, memberGl); + } else if (member instanceof SequenceLayout memberSl) { + for (long i = 0; i < memberSl.elementCount(); i++) { + out.add(memberSl.elementLayout()); + } + } else { + // padding or value layouts + out.add(member); + } + } + } + + static boolean isHomogeneousFloatAggregate(MemoryLayout type) { + if (!(type instanceof GroupLayout groupLayout)) + return false; + + List scalarLayouts = scalarLayouts(groupLayout); + + final int numElements = scalarLayouts.size(); + if (numElements > 4 || numElements == 0) + return false; + + MemoryLayout baseType = scalarLayouts.get(0); + + if (!(baseType instanceof ValueLayout)) + return false; + + TypeClass baseArgClass = classifyValueType((ValueLayout) baseType); + if (baseArgClass != FLOAT) + return false; + + for (MemoryLayout elem : scalarLayouts) { + if (!(elem instanceof ValueLayout)) + return false; + + TypeClass argClass = classifyValueType((ValueLayout) elem); + if (elem.byteSize() != baseType.byteSize() || + elem.byteAlignment() != baseType.byteAlignment() || + baseArgClass != argClass) { + return false; + } + } + + return true; + } + + private static TypeClass classifyStructType(MemoryLayout layout) { + if (isHomogeneousFloatAggregate(layout)) { + return TypeClass.STRUCT_HFA; + } else if (isRegisterAggregate(layout)) { + return TypeClass.STRUCT_REGISTER; + } + return TypeClass.STRUCT_REFERENCE; + } + + public static TypeClass classifyLayout(MemoryLayout type) { + if (type instanceof ValueLayout) { + return classifyValueType((ValueLayout) type); + } else if (type instanceof GroupLayout) { + return classifyStructType(type); + } else { + throw new IllegalArgumentException("Unsupported layout: " + type); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64CallArranger.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64CallArranger.class new file mode 100644 index 0000000000000000000000000000000000000000..27c5f1540baa4604b999fabaf8a7ce75f281926c GIT binary patch literal 941 zcma)4OK%e~5dOT`CT&RHyep940BKdas)Twe0xdz2Dn$^ns0VJ&#%$dhyB&Kg_)i>w z3lax@06z-hUAAqA8py@=*z-MR#y@|3{{f(bwI%}88VFmML7m~z;qWMu+6mHJMehs= zndyiRWW+h82Ro0W4p%BB;yM$=P=6w|bWa&-?e+aR%wn#AW(!x)VtDpnE+uvTA?g)t z9GCQev$GCEyEl<0e!llY*p%e4GqlSPcFa&PEP6umGJii1^o9?Vzgg*-l&gJCvWTn8 z&>cw25KrbmEBW6xz3{>*r#ZQ1Ao% zD6x9n4&HL9Z*GGczFX5V97%cc^8h40TdW2U2!jXBy^jfH@h-S843qVtMrH= zzq)qiqR6njBE~|~;m|?%(H{U*k6T~gaP^NZeqj%So=2A2xLPqOx zD55K2l=Z(sC+(<&A?Uy4&ljk4@gStJWs~+U;+_fRiL#Za{*Q6PZi%`))?pMUO1IBs z+KF2}W--T5YRj~ylT_%Co*%BR_1~Utt09y0G*0Le{F>I%1d&J*N#8DfO&^=I&m3J7 zqw=&-vaCnvL`a1!PMTR{{Tb{r3y+YrVPG4hB>k@hjA5L-A|`$xFK1*x=@stvGX|gF jSqg?fiXAwZBrJz1Op|u#$YwB~Aubk3dz4=yy@<*uu;ji1 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64Linker.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64Linker.class new file mode 100644 index 0000000000000000000000000000000000000000..5d25f66f7bd451126976a7c387b56af2e49cdbf8 GIT binary patch literal 2439 zcmcgu+fv(B6kP|5g&hS5y(DdtUJ{Z32?&}rX=*~F8VDxBZfnD|Pnm;#00l+z$Z}f# zp&!!6md>=DKJ)|nQJt(K87eM{XYvq_$LDBkpSAa1`*Qs6e}Df2pp0(|7{H)`oQWai z1?=aoJqcVY83V!sPL>KsZ z(s?dlO3R}avi&mHQ`WkQc7s-9zpY5x(aXaOtaSZmNG>Q9R=ZQs7;8dwe^8c zX(|PG%+{*(Tb_zty=3A8d?;|f=jui~arBqB>}Xc;9Z&H@;$A)KZmlryLAYNk;0mr9 z_{hY^_(b4g-!yv}Wh`)^Y*%a5O4)XvIra~=jYgd*OgQXDu4k>wHqBkbbpsP7Zs4ZC z)zb;vlwMakazE%s0);hu(|+dEs!s%NrqXek-IVe~ZQBX_o!G*pi78C8q2l9}YD3^g z-_sR8VoL8|#=xuz3v&V!nQYW|WvE&k467qB)|7tWyUcvzH${Fr|7Uo6R;i|f>G!%< znn$#fsXFJ4jJlx`C?6+%Ar*Q(3SE+vk{mj>u3oSnk^oAJC4qB0DysOMNcv4;KANP> ztSUPk0a>*{v|Kr85oVMvrmEc+TPkeGEsv6MCm?Z~GIaHGPne5#U9vdt`r9fb(f{{2 zYbNFVv9^py0F%DmYx%QF=8Swy%>;y~!)3w#^muoLIxWg9R?>nZVgm{e|1Vo@trE7`)9-~a#s literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64Linker.java b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64Linker.java new file mode 100644 index 00000000..4ffd15ae --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64Linker.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Arm Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.aarch64.linux; + +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.aarch64.CallArranger; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteOrder; +import java.util.Map; + +/** + * ABI implementation based on ARM document "Procedure Call Standard for + * the ARM 64-bit Architecture". + */ +public final class LinuxAArch64Linker extends AbstractLinker { + + static final Map CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT); + + public static LinuxAArch64Linker getInstance() { + final class Holder { + private static final LinuxAArch64Linker INSTANCE = new LinuxAArch64Linker(); + } + + return Holder.INSTANCE; + } + + private LinuxAArch64Linker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.LINUX.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.LINUX.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64CallArranger.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64CallArranger.class new file mode 100644 index 0000000000000000000000000000000000000000..10d2f25203bcd967bbd2fd018cff4e16cf4eb5f0 GIT binary patch literal 941 zcma)4&2AGh5dLPfO=w74DF0L-!2!~$bcKX^DFQ7)ktzimv8adM9LH?kx^}U>m3Su( zzy*l|55PkqoMqdF&_FM?$DZ$JX8hylx9%T6=kW78fwvK(mF5Xc3HlP>4x!zfN|V0Wd?_5a^3WT*L5MqMC4S@FJ*R=BJfWXkyRu^$qo&Ixm& ztEct}EA8d!Rwhe*P&l!v{Tq?HuCZlhL&>|!FdxYKCX8@oh;Y{(N~PR!M&@n7z3VgU zWfvsY!;c|##EaFN9Uai1U{BZ*La10rpAg`VSxq2q@8m?EGYn5jF1&vP=s*lI8 e@rmkS}YX zT!awC3aW@hJdW`MTMVs@+1`D;u<1lOhH|Gr9JTsMo1xj=n6JqYBzB@0wy0dyU)+q9 z8;NmBNWE*NNH2xcxxNO2Y^FU!vU$pXEl}$6nM~J{j)r#Or23-s%)1ZAc${yEs%#sX zTCdHtr?Q!y#CVBU4ArU1I>u+hND4ncJledxysW3jWI**7 q!mmqIejv&z82(c<5a2ms1?*yvWI#vu0}>NI=k}NmCON)j%*cc3T58eaalm$Dkl2k1VId zKlDTT*wUG{(}#XQKdRGpEJMXb@k}1#Vc634K5Os2_T~7WfB*U$KndUFFoa^^#E?Mo-fxD?lcB2!8(uv|Y1hR{+??y`k!&B4SIgDZ4 zz=VlQm=u^zMLEi^Bt6d#L+S76Tt+tRQmrmv4NfF^kin1PeG?zxLxFJ_!z~9t`VP?r zewwPhlCP!Z(F@sr9qcJjpkC@hLtNcrvieX>BZUsbp7c)pE(MysX$i)V4NR{_&W@ZsdAw{Wjg*#4Q5_6Sr|k z;QHBuZA-7KD)J!cMgqBYd)t0lsa0PH+)0$feAF~GLOjwu~D5SDc-<6?iZZWNnz=R|Hz;{{sIBu%^Wc|;H_Pkb2Bs1vi zerq1nN~Y@EH!|vmN}zO-^u=j%Z?bkwS=sk?mkGMUpcuy$3|iC9t6Od8Fy@2jxn$xcV{H5=bI2Fh=m z_d%P3DWBOU1}b`J&Me_XXZOdHQN;6VpeAr@&=JliuasJg5)0f|qr8I!uIQabxxlv} ze2y$~cz}o0d_m1MO8v~VsJ<~iT@D(yx z#A7~ba~k1Gf)G~UQGI~#`IezBe~63s?$7>?_q4+pC3g6{hcFXc^$}=~C&bsNc@*hI z`^)1gmM~09UMy+&mrvubq~JeG#pl(G=k%zlnxh{b1*y7v8hJgDd!`?GOt{T5e0@yf zJY&|Mi9_7z{oVZ&_kP1w&1X#gSkJ;@k>)W@@5B5VrCD0W3T1{?Ls;e0O+ITTUSI-i T^s%1J;TvimV literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.java b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.java new file mode 100644 index 00000000..c60f0152 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.aarch64.macos; + +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.aarch64.CallArranger; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteOrder; +import java.util.Map; + +/** + * ABI implementation for macOS on Apple Silicon. Based on AAPCS with + * changes to va_list and passing arguments on the stack. + */ +public final class MacOsAArch64Linker extends AbstractLinker { + + static final Map CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT); + + public static MacOsAArch64Linker getInstance() { + final class Holder { + private static final MacOsAArch64Linker INSTANCE = new MacOsAArch64Linker(); + } + + return Holder.INSTANCE; + } + + private MacOsAArch64Linker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.MACOS.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.MACOS.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64CallArranger.class b/tests/test_data/std/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64CallArranger.class new file mode 100644 index 0000000000000000000000000000000000000000..18fa12d45208e2fc5b85b51ab52ca924aea9edba GIT binary patch literal 3409 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 CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.JAVA_CHAR); + + public static WindowsAArch64Linker getInstance() { + class Holder { + private static final WindowsAArch64Linker INSTANCE = new WindowsAArch64Linker(); + } + return Holder.INSTANCE; + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.WINDOWS.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.WINDOWS.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIABI.class b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIABI.class new file mode 100644 index 0000000000000000000000000000000000000000..03d74fd09c02aba4ad632b513cd3fdbe51146b7c GIT binary patch literal 1353 zcmb7DSx*yD7(KVs1*QX(iXh0MEIMt4K>@cS0g=WgRZI#b#;0jJg@Iw3lqt{tARiD^ zh(^P+KgxLSObsQHSSPu2xAUFve9Qg$>+25yt9TYeNI>7M>>0M}S#{TRjB2fJ+1svR zmTaSHI!?(f?-{vVe&u<-69Qok5kv)IFV=D^n}rR5bfI1QtR(2r&s5gTy~TRfF%J&1EeA!fZoAvrRu7WE=O55;1A_w5MccK#C4v4{s-|T= zwIw6JsbLr+6z%&J5cv*7RNTVt7{)bBU{YZE-?=QcN`qr~^YK*-0> zbCworQl!t2IERq<&?WpVPqYAq`*^_J97lv^?CEsc`qLwyG4zr9 zfUcXjV8=!=i8!VpY5RF6$>;shJy-P>M&SxSXpFJjRoz!5k|fzkzSWCr6bt hjGbcY1YGDRh{;F;W7UspjLJv33WPsJmiHkn{syOf7q$QZ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIABI.java b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIABI.java new file mode 100644 index 00000000..89062f5c --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIABI.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.fallback; + +/** + * enum which maps the {@code ffi_abi} enum + */ +enum FFIABI { + DEFAULT(LibFallback.defaultABI()); + + private final int value; + + FFIABI(int abi) { + this.value = abi; + } + + int value() { + return value; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIStatus.class b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIStatus.class new file mode 100644 index 0000000000000000000000000000000000000000..2ae18233c20d1e5df2052eb500fd574a5949d745 GIT binary patch literal 1866 zcmb7EZByGu5Pr^YvV{na6G-C%aR^Rq-fU86(wGu#uu~@{(8w_3_CrRNg(DCWBg<(& z_TPA>pIT=IGG*H4bAD7Ndxuj@OFOk@PIr5^`|Pu~d;9*wZ+`$-$F2k)!|ZhaOY}y&EZf5p0%c^VoL8eqHtDfeyTM;k>6a*1s2+{7#t!E7Ll>rcP93reB z!XZXDL?OTNvRd0NZWK%WY)FB^&xSsodnsdQyud#zidT7#!cZN`Cn^wbcWh9Z}4$}<& zRC+gzS%%Ra`@nX7uoEqj_=N5>j7JHsI8RDiL9T|3m@_z}p{-`cEqwtbgXsRg^W9R$V2#wm|sSRf(pu1DTy#5VJKmYaA{3J9tB=E zB4;gzY$`oi<A9 zGYnH}&<{4XqaLa7if;9)_HiFEUfU}J1-(jsWYuZAx=}LuJzn{%4=wOgUdvJne`{iL)f> zPoM;!&|jjNTgWjs^ASKXFxh)$j|jMVkF|B+bl@ zpWxQ7wEQQ&*-J*4p#w?A+ zF8m#2yO27V=|b*cx{KisCQosvc8X-}1ovVy$C!&BBYTW5PVnGQ9;{ykI|+%_b4Xww zcj+n5A%pwK;vp8Hl5~CvRcv9KbibuBgis<#-**yNROT9jxXjYHBS& z)YMv#sHwFOQB%41i>V3Y1=2kTy$6vyC4|@`{|Rz$;1|M5KnRi$z77gO7Q$*s2*Ypj l_zj{w17{A#sG2~54dWiwSBm~=EYa2ZdRMNZO6NZ8d<06;ou2>z literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIStatus.java b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIStatus.java new file mode 100644 index 00000000..5ac6a95e --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIStatus.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.fallback; + +/** + * See doc: + *

+ * typedef enum { + * FFI_OK = 0, + * FFI_BAD_TYPEDEF, + * FFI_BAD_ABI, + * FFI_BAD_ARGTYPE + * } ffi_status; + */ +enum FFIStatus { + FFI_OK, + FFI_BAD_TYPEDEF, + FFI_BAD_ABI, + FFI_BAD_ARGTYPE; + + static FFIStatus of(int code) { + return switch (code) { + case 0 -> FFI_OK; + case 1 -> FFI_BAD_TYPEDEF; + case 2 -> FFI_BAD_ABI; + case 3 -> FFI_BAD_ARGTYPE; + default -> throw new IllegalArgumentException("Unknown status code: " + code); + }; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIType.class b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FFIType.class new file mode 100644 index 0000000000000000000000000000000000000000..82e5a6a76c4f4723d05d6b3d15f8136c160187f7 GIT binary patch literal 9969 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 elements, FFIABI abi, Arena scope) { + MemorySegment elementsSeg = scope.allocate((elements.size() + 1) * ADDRESS.byteSize()); + int i = 0; + for (; i < elements.size(); i++) { + MemoryLayout elementLayout = elements.get(i); + MemorySegment elementType = toFFIType(elementLayout, abi, scope); + elementsSeg.setAtIndex(ADDRESS, i, elementType); + } + // elements array is null-terminated + elementsSeg.setAtIndex(ADDRESS, i, MemorySegment.NULL); + + MemorySegment ffiType = scope.allocate(LAYOUT); + VH_TYPE.set(ffiType, 0L, LibFallback.structTag()); + VH_ELEMENTS.set(ffiType, 0L, elementsSeg); + + return ffiType; + } + + private static final Map, MemorySegment> CARRIER_TO_TYPE = Map.of( + boolean.class, LibFallback.uint8Type(), + byte.class, LibFallback.sint8Type(), + short.class, LibFallback.sint16Type(), + char.class, LibFallback.uint16Type(), + int.class, LibFallback.sint32Type(), + long.class, LibFallback.sint64Type(), + float.class, LibFallback.floatType(), + double.class, LibFallback.doubleType(), + MemorySegment.class, LibFallback.pointerType() + ); + + static MemorySegment toFFIType(MemoryLayout layout, FFIABI abi, Arena scope) { + if (layout instanceof GroupLayout grpl) { + if (grpl instanceof StructLayout strl) { + // libffi doesn't want our padding + List filteredLayouts = strl.memberLayouts().stream() + .filter(Predicate.not(PaddingLayout.class::isInstance)) + .toList(); + MemorySegment structType = make(filteredLayouts, abi, scope); + verifyStructType(strl, filteredLayouts, structType, abi); + return structType; + } + assert grpl instanceof UnionLayout; + // JDK-8301800 + throw new IllegalArgumentException("Fallback linker does not support by-value unions: " + grpl); + } else if (layout instanceof SequenceLayout sl) { + List elements = Collections.nCopies(Math.toIntExact(sl.elementCount()), sl.elementLayout()); + return make(elements, abi, scope); + } + return Objects.requireNonNull(CARRIER_TO_TYPE.get(((ValueLayout) layout).carrier())); + } + + // verify layout against what libffi sets + private static void verifyStructType(StructLayout structLayout, List filteredLayouts, MemorySegment structType, + FFIABI abi) { + try (Arena verifyArena = Arena.ofConfined()) { + MemorySegment offsetsOut = verifyArena.allocate(SIZE_T.byteSize() * filteredLayouts.size()); + LibFallback.getStructOffsets(structType, offsetsOut, abi); + long expectedOffset = 0; + int offsetIdx = 0; + for (MemoryLayout element : structLayout.memberLayouts()) { + if (!(element instanceof PaddingLayout)) { + long ffiOffset = sizeTAtIndex(offsetsOut, offsetIdx++); + if (ffiOffset != expectedOffset) { + throw new IllegalArgumentException("Invalid group layout." + + " Offset of '" + element.name().orElse("") + + "': " + expectedOffset + " != " + ffiOffset); + } + } + expectedOffset += element.byteSize(); + } + } + } + + static ValueLayout layoutFor(int byteSize) { + return switch (byteSize) { + case 1 -> JAVA_BYTE; + case 2 -> JAVA_SHORT; + case 4 -> JAVA_INT; + case 8 -> JAVA_LONG; + default -> throw new IllegalStateException("Unsupported size: " + byteSize); + }; + } + + private static long sizeTAtIndex(MemorySegment segment, int index) { + long offset = SIZE_T.scale(0, index); + if (VH_SIZE_T.varType() == long.class) { + return (long) VH_SIZE_T.get(segment, offset); + } else { + return (int) VH_SIZE_T.get(segment, offset); // 'erase' to long + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker$1Holder.class b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker$1Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..9e4f049705bc098631dabe698f56cd26bedded6c GIT binary patch literal 713 zcmb7CO-sW-5PjR$rl!$q>-RV4K|L51527MSQ7qJWuoOIQl5O2~-9VE1zr;g9!5`p{ z5@%~wJod6P^JeGG+nN3Ne0>K{#k!3QvKDd<#*k;2>hLG-Dz4k^t=|zr%8);kTBhd= z+3lUCg#yEVC+xaXry|x|xveM`vaMb2OSi?9@_Ep8uZB)t>aK`wSjdi}2*<*NgGrPa zjz=ZgI=GHhC}M^}&AV${c-2dW!}_Q+rwqAj6bgnCi4$J$(HC)p`-+fqJqoyL@>rU9 z2=|dDcSi&+x zu`SY?PExJ|Dm~iX8Cj80;)x`^juKj|Q`1_+RmGD;&;#?|mn<{LZXfJ2$s?pn@5S3Yh&Z-W-qt#Wz^@eT=`rHWUnh6drPz aBP@e?QUHo9EMjGVSXd=%)BPgZHQ)=SA+GfR literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker$2Holder.class b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker$2Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..bba3563e5994ef6316012a336c9bea401a48e2fd GIT binary patch literal 3445 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 SBKeZTGi=}{zDEUHxbZ*E{bk$$ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker.class b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker.class new file mode 100644 index 0000000000000000000000000000000000000000..9cec6f1ac02864f178d3d95d6c27214b811cc194 GIT binary patch literal 17622 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker.java b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker.java new file mode 100644 index 00000000..59d3810e --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/fallback/FallbackLinker.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.fallback; + +import java.lang.foreign.AddressLayout; +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.ValueLayout; +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_BOOLEAN; +import static java.lang.foreign.ValueLayout.JAVA_BYTE; +import static java.lang.foreign.ValueLayout.JAVA_CHAR; +import static java.lang.foreign.ValueLayout.JAVA_DOUBLE; +import static java.lang.foreign.ValueLayout.JAVA_FLOAT; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.JAVA_SHORT; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import static java.lang.invoke.MethodHandles.foldArguments; +import java.lang.invoke.MethodType; +import java.lang.ref.Reference; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import jdk.internal.foreign.AbstractMemorySegmentImpl; +import jdk.internal.foreign.MemorySessionImpl; +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.CapturableState; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; + +public final class FallbackLinker extends AbstractLinker { + + private static final MethodHandle MH_DO_DOWNCALL; + private static final MethodHandle MH_DO_UPCALL; + + static { + try { + MH_DO_DOWNCALL = MethodHandles.lookup().findStatic(FallbackLinker.class, "doDowncall", + MethodType.methodType(Object.class, SegmentAllocator.class, Object[].class, FallbackLinker.DowncallData.class)); + MH_DO_UPCALL = MethodHandles.lookup().findStatic(FallbackLinker.class, "doUpcall", + MethodType.methodType(void.class, MethodHandle.class, MemorySegment.class, MemorySegment.class, UpcallData.class)); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + + public static FallbackLinker getInstance() { + class Holder { + static final FallbackLinker INSTANCE = new FallbackLinker(); + } + return Holder.INSTANCE; + } + + public static boolean isSupported() { + return LibFallback.SUPPORTED; + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + MemorySegment cif = makeCif(inferredMethodType, function, options, Arena.ofAuto()); + + int capturedStateMask = options.capturedCallState() + .mapToInt(CapturableState::mask) + .reduce(0, (a, b) -> a | b); + DowncallData invData = new DowncallData(cif, function.returnLayout().orElse(null), + function.argumentLayouts(), capturedStateMask, options.allowsHeapAccess()); + + MethodHandle target = MethodHandles.insertArguments(MH_DO_DOWNCALL, 2, invData); + + int leadingArguments = 1; // address + MethodType type = inferredMethodType.insertParameterTypes(0, SegmentAllocator.class, MemorySegment.class); + if (capturedStateMask != 0) { + leadingArguments++; + type = type.insertParameterTypes(2, MemorySegment.class); + } + target = target.asCollector(1, Object[].class, inferredMethodType.parameterCount() + leadingArguments); + target = target.asType(type); + target = foldArguments(target, 1, SharedUtils.MH_CHECK_SYMBOL); + target = SharedUtils.swapArguments(target, 0, 1); // normalize parameter order + + return target; + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + MemorySegment cif = makeCif(targetType, function, options, Arena.ofAuto()); + + UpcallData invData = new UpcallData(function.returnLayout().orElse(null), function.argumentLayouts(), cif); + MethodHandle doUpcallMH = MethodHandles.insertArguments(MH_DO_UPCALL, 3, invData); + + return (target, scope) -> { + target = MethodHandles.insertArguments(doUpcallMH, 0, target); + return LibFallback.createClosure(cif, target, scope); + }; + } + + private static MemorySegment makeCif(MethodType methodType, FunctionDescriptor function, LinkerOptions options, Arena scope) { + FFIABI abi = FFIABI.DEFAULT; + + MemorySegment argTypes = scope.allocate(function.argumentLayouts().size() * ADDRESS.byteSize()); + List argLayouts = function.argumentLayouts(); + for (int i = 0; i < argLayouts.size(); i++) { + MemoryLayout layout = argLayouts.get(i); + argTypes.setAtIndex(ADDRESS, i, FFIType.toFFIType(layout, abi, scope)); + } + + MemorySegment returnType = methodType.returnType() != void.class + ? FFIType.toFFIType(function.returnLayout().orElseThrow(), abi, scope) + : LibFallback.voidType(); + + if (options.isVariadicFunction()) { + int numFixedArgs = options.firstVariadicArgIndex(); + int numTotalArgs = argLayouts.size(); + return LibFallback.prepCifVar(returnType, numFixedArgs, numTotalArgs, argTypes, abi, scope); + } else { + return LibFallback.prepCif(returnType, argLayouts.size(), argTypes, abi, scope); + } + } + + private record DowncallData(MemorySegment cif, MemoryLayout returnLayout, List argLayouts, + int capturedStateMask, boolean allowsHeapAccess) {} + + private static Object doDowncall(SegmentAllocator returnAllocator, Object[] args, DowncallData invData) { + List acquiredSessions = new ArrayList<>(); + try (Arena arena = Arena.ofConfined()) { + int argStart = 0; + Object[] heapBases = invData.allowsHeapAccess() ? new Object[args.length] : null; + + MemorySegment target = (MemorySegment) args[argStart++]; + MemorySessionImpl targetImpl = ((AbstractMemorySegmentImpl) target).sessionImpl(); + targetImpl.acquire0(); + acquiredSessions.add(targetImpl); + + MemorySegment capturedState = null; + if (invData.capturedStateMask() != 0) { + capturedState = SharedUtils.checkCaptureSegment((MemorySegment) args[argStart++]); + MemorySessionImpl capturedStateImpl = ((AbstractMemorySegmentImpl) capturedState).sessionImpl(); + capturedStateImpl.acquire0(); + acquiredSessions.add(capturedStateImpl); + } + + List argLayouts = invData.argLayouts(); + MemorySegment argPtrs = arena.allocate(argLayouts.size() * ADDRESS.byteSize()); + for (int i = 0; i < argLayouts.size(); i++) { + Object arg = args[argStart + i]; + MemoryLayout layout = argLayouts.get(i); + + if (layout instanceof AddressLayout) { + AbstractMemorySegmentImpl ms = (AbstractMemorySegmentImpl) arg; + MemorySessionImpl sessionImpl = ms.sessionImpl(); + sessionImpl.acquire0(); + acquiredSessions.add(sessionImpl); + if (invData.allowsHeapAccess() && !ms.isNative()) { + heapBases[i] = ms.unsafeGetBase(); + // write the offset to the arg segment, add array ptr to it in native code + layout = JAVA_LONG; + arg = ms.address(); + } + } + + MemorySegment argSeg = arena.allocate(layout); + writeValue(arg, layout, argSeg); + argPtrs.setAtIndex(ADDRESS, i, argSeg); + } + + MemorySegment retSeg = null; + if (invData.returnLayout() != null) { + retSeg = (invData.returnLayout() instanceof GroupLayout ? returnAllocator : arena).allocate(invData.returnLayout); + } + + LibFallback.doDowncall(invData.cif, target, retSeg, argPtrs, capturedState, invData.capturedStateMask(), + heapBases, args.length); + + Reference.reachabilityFence(invData.cif()); + + return readValue(retSeg, invData.returnLayout()); + } finally { + for (MemorySessionImpl session : acquiredSessions) { + session.release0(); + } + } + } + + // note that cif is not used, but we store it here to keep it alive + private record UpcallData(MemoryLayout returnLayout, List argLayouts, MemorySegment cif) {} + + @SuppressWarnings("restricted") + private static void doUpcall(MethodHandle target, MemorySegment retPtr, MemorySegment argPtrs, UpcallData data) throws Throwable { + List argLayouts = data.argLayouts(); + int numArgs = argLayouts.size(); + MemoryLayout retLayout = data.returnLayout(); + try (Arena upcallArena = Arena.ofConfined()) { + MemorySegment argsSeg = argPtrs.reinterpret(numArgs * ADDRESS.byteSize(), upcallArena, null); + MemorySegment retSeg = retLayout != null + ? retPtr.reinterpret(retLayout.byteSize(), upcallArena, null) // restricted + : null; + + Object[] args = new Object[numArgs]; + for (int i = 0; i < numArgs; i++) { + MemoryLayout argLayout = argLayouts.get(i); + MemorySegment argPtr = argsSeg.getAtIndex(ADDRESS, i) + .reinterpret(argLayout.byteSize(), upcallArena, null); // restricted + args[i] = readValue(argPtr, argLayout); + } + + Object result = target.invokeWithArguments(args); + + writeValue(result, data.returnLayout(), retSeg); + } + } + + // where + private static void writeValue(Object arg, MemoryLayout layout, MemorySegment argSeg) { + switch (layout) { + case ValueLayout.OfBoolean bl -> argSeg.set(bl, 0, (Boolean) arg); + case ValueLayout.OfByte bl -> argSeg.set(bl, 0, (Byte) arg); + case ValueLayout.OfShort sl -> argSeg.set(sl, 0, (Short) arg); + case ValueLayout.OfChar cl -> argSeg.set(cl, 0, (Character) arg); + case ValueLayout.OfInt il -> argSeg.set(il, 0, (Integer) arg); + case ValueLayout.OfLong ll -> argSeg.set(ll, 0, (Long) arg); + case ValueLayout.OfFloat fl -> argSeg.set(fl, 0, (Float) arg); + case ValueLayout.OfDouble dl -> argSeg.set(dl, 0, (Double) arg); + case AddressLayout al -> argSeg.set(al, 0, (MemorySegment) arg); + case GroupLayout _ -> + MemorySegment.copy((MemorySegment) arg, 0, argSeg, 0, argSeg.byteSize()); // by-value struct + case null, default -> { + assert layout == null; + } + } + } + + private static Object readValue(MemorySegment seg, MemoryLayout layout) { + if (layout instanceof ValueLayout.OfBoolean bl) { + return seg.get(bl, 0); + } else if (layout instanceof ValueLayout.OfByte bl) { + return seg.get(bl, 0); + } else if (layout instanceof ValueLayout.OfShort sl) { + return seg.get(sl, 0); + } else if (layout instanceof ValueLayout.OfChar cl) { + return seg.get(cl, 0); + } else if (layout instanceof ValueLayout.OfInt il) { + return seg.get(il, 0); + } else if (layout instanceof ValueLayout.OfLong ll) { + return seg.get(ll, 0); + } else if (layout instanceof ValueLayout.OfFloat fl) { + return seg.get(fl, 0); + } else if (layout instanceof ValueLayout.OfDouble dl) { + return seg.get(dl, 0); + } else if (layout instanceof AddressLayout al) { + return seg.get(al, 0); + } else if (layout instanceof GroupLayout) { + return seg; + } + assert layout == null; + return null; + } + + @Override + public Map canonicalLayouts() { + // Avoid eager dependency on LibFallback, so we can safely check LibFallback.SUPPORTED + class Holder { + static final Map CANONICAL_LAYOUTS; + + static { + int wchar_size = LibFallback.wcharSize(); + MemoryLayout wchartLayout = switch(wchar_size) { + case 2 -> JAVA_CHAR; // prefer JAVA_CHAR + default -> FFIType.layoutFor(wchar_size); + }; + + CANONICAL_LAYOUTS = Map.ofEntries( + // specified canonical layouts + Map.entry("bool", JAVA_BOOLEAN), + Map.entry("char", JAVA_BYTE), + Map.entry("float", JAVA_FLOAT), + Map.entry("long long", JAVA_LONG.withByteAlignment(LibFallback.longLongAlign())), + Map.entry("double", JAVA_DOUBLE.withByteAlignment(LibFallback.doubleAlign())), + Map.entry("void*", ADDRESS), + // platform-dependent sizes + Map.entry("size_t", FFIType.SIZE_T), + Map.entry("short", FFIType.layoutFor(LibFallback.shortSize())), + Map.entry("int", FFIType.layoutFor(LibFallback.intSize())), + Map.entry("long", FFIType.layoutFor(LibFallback.longSize())), + Map.entry("wchar_t", wchartLayout), + // JNI types + Map.entry("jboolean", JAVA_BOOLEAN), + Map.entry("jchar", JAVA_CHAR), + Map.entry("jbyte", JAVA_BYTE), + Map.entry("jshort", JAVA_SHORT), + Map.entry("jint", JAVA_INT), + Map.entry("jlong", JAVA_LONG), + Map.entry("jfloat", JAVA_FLOAT), + Map.entry("jdouble", JAVA_DOUBLE) + ); + } + } + + return Holder.CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback$1.class b/tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback$1.class new file mode 100644 index 0000000000000000000000000000000000000000..c81df3feb59f568bc37ef51116b9a8ff0a1d0cbf GIT binary patch literal 1254 zcmb7DTTc@~6#k|yY`ZKiR6x9dRX|%5){1y5k{|&gDPU41k+L=%1YM;Xs<+q5JY!)|uY?3r`E^PS85{`37OfK|NI5kXW#%s?Od8HNt{F*j}Q z)Xbgofv|jr{w3*1f0-eg&F#h!XGm7LZI`)KFG{B_lnxyO8Vm!2NS=czH9cP(G7Q)* zuM}ljan)oP%@(^+O1_d#t&rQ*FvKv~J$UDM+?QTe3i5R7Yf8BkDUB-{MhuK%jA6KI z{mON1!5s$enA;7pQ)L*-?&W#{wJi!d#&J!EOF#Z*V&|3`jXr7qfjC7I5K3~LCM&yQe>)J z+M<&2-AsVma?mk>J3%*+I;JtB;jV#u$TFChVmh5ClBz)!8O>f)1`V^Fa(lvRDCsxN zH%cB8p_-_ySV10??W$W53@Pe>*lrw_g?h`&HfhpD*W&grS2Fl-D`Wn?^ceEROEN7G z)kc7t>FL)+{U^i0l23!T#gE!CN6ux}nprYSl&Fo|Zzw{2-GkaTXleeL_)?EYXKt1W zRWG>>Wr=kv63uzfT+9bkKy_MkEZg;Hptpp-?^X=F2xctlt7ftH2E@08=WnF+-6Op+|n%$|aMrA-76Xbp~mS1PgSw7=|7r_(W)t5B;awBp#7x9MKI8slL?E3Q<~UQ|jjP4O1s%_P>1k g@Hn(u#FJ1y#WRvIy3Nl~2sPtaBB@h=X_EB(1(Jy?egFUf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback$NativeConstants.class b/tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback$NativeConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..9e25d36c6547a94f36c7414ee2eaae79be815b1d GIT binary patch literal 2043 zcmbuA>sA|86vzLETS#)aSH*g%C@Nsvl#7T$TSG`7m?lU9*lLZFWC8=j49-lbwBBv2 z)@!{yh$|nQ&=$uBbXrBOF3RA_^&RX0x&tGb~ScEX|Bn zZAUlOt(aCaVpYvFOImp=mN81HhAq%lts2FOUe#)*SESd}qUkU?(G^0sL=Soe&i|)H z2eX=I?CJ^Iay`xRT!H9ZG8JFR6pHcLw17x+%qJus!ovcc9DujCqZexw_LTC!7)3uG z4dJB3V|ZNP)L{({GPa!Bhsa5mAs!R+?3^Sn$9^^YZ$;b;5rx}TI zAfuBi5@yay#EvuUWuF<97*h=#m{*kY)9)q0+;C}g;+LgG*mG1~DziS&6_O>T+oy#6x&86ppn!hjc0X{t1 z->&D>cwEtx$}{(|#3%Tai&$7*Nl;(J=LJNbo!ykU#m>U}MNAk~20oYg0$(0hJ&{fk zuqe=yuq!&b${3cOt!RBE<^lDajy#?E)^kv$zbSGhIuB%fRUH42!oTE&eX!Q5d%%f>b zRzHs=r8G#Co^I$^L+KQ&=X5fa(s5HtXGkd>3#HWPN~w93Qb#JKCR0jXqm-IJDebFL z+9#z{e$poT(YFW!cjzugDo9&Leuel&{rweP`ETGad`(xm{{p_jw{+Kz?*jNwl`3%8 zN2rbtAALR^spAPB1Iifm@w_rde4J6nIUnQ7nDp_oGG=^SRK~22q%szKyrzt-kJsxc z_*kpsijS*xyyK%>N7aW>hv~zv!|_p5FTdyGMjapd_^giGoQMD?lBJyh{-JL#ZI)<4 zzi7sQXu*hR#kgq0j0hnq+L0AutceJ&iYUrL!Vn#>MHgzK8#hERZi+tK5hu`$?`gdz V+{F({+wmi5guHc9X@0`Ve*qxy$PNGi literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback.class b/tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback.class new file mode 100644 index 0000000000000000000000000000000000000000..ee0558759171377b5b2d0ae74ba1f8548f5a6165 GIT binary patch literal 8249 zcmd5>d3+nkb^e9~uq3#;Xp0mjTcRS_CMD6(70MFtcyIdGqGYyLR^TU%mWk0E6nGC>qdcAY>wph{D=Otwk%AwQ}>ZvDruMl&cUq zn8{__dlVYGx~B~^Da0O4pNeI2u3gAk+1Q*@uru?ym^GV;%~{#(td%+yOJrt;{r>hn zQ5a~9q6MabRVG$rjlyQVP|;463K{oYY#^1gi^V}F=N6o7)-EWRX=l8USm8JwDuw zc5E=vVPYdTDIB`7-HuvrX3^$OimsJ&iwZ4AhK2{G5|c9nhvNz=F6?hLu^C$wqEqqF z$-8DIPmB*KYz=H+S*geE(@x=B(w;wU=iGjoy4A$%^weZ|s*tyvxJ}3{!f{WpW-0VL zOmu0wzytIhCU%zT`}UUcJtpof(|h-q>AOwr5qfkuF*Yz+Chs$`U&D`#O&v}QmFc}E z4hY>GALF`16Xk)sP4vk?^YmE!NSS)j#39kOnT$U?G&VewJT^8lDdOL2;yxLO`U7Mp zd5FmtOdx4s(!>;|6}D7ttnSGv7*;x6powb}8;Rl}oG|dP ziIeyyg`OKSF$$A*jyPv>DSDW~tz9GX7e5&=AJ2FDxy7umdhvV8i z!i!}$jEjzPCLH8x7jtu&nS8;{&!jRGwW(_)9v>O$)|i5cA{eJyQVVwKRMNHF615!a z;^u|LqKPv&%g7dFF|%kf#54;VpU-)`!N6lCz75|_l~z=d$t^mk?AUSJU2xLJtXw)v zEri^2c{W?Rg1V?eP7*+OeF$$d@n(F7LhID{;6Nfl`J z;tY)QR(7B;Uy^7rbT(z@CGr{guBy{Zx`j+`{%|RiP1}Vi9!FynzK0Qa(kjf`Zs&sD z1e;>#nSzs>@088-bqet9CcYQn$B=L3^LCC=x5tmVI;eVltKw|cQaty^@lIj!u9}&? zIR>>=J+lelPpx)tJ*35WkBRr<2YJk{CQ8YgG-S>_5tMk@k+jG4dvaZc zV^E9B)2h=%6zB1A6Q97-T+_3wp|h6c@}YWbR!I^n*^C%-19`IeWBpde$yXijgyxCzuVh(^erP&pt8aE@WtQvFkYHKyl1vqG@~1 zDrH@r0GmsU5O;aI+Ex|w>N_J(q*$2|mDziGz3EXIsCwA9H!#w>-+O4D%Q}|p52T%v z>_{uMCGU^{H?5zV7I~unjN*b*aFdzyRE0r^*K5i$mw4UgGb#GF*Iy;%1pg0Y`I11} z^Oo?RnmwPLwB~hPlvH>rc$D?`95~wlGr(1G3ZxyW5(&rW% z`EIGO<2qc+mqQ_3OgR!7I_m7s6Nw9!11Z;t`Z}XqD}4Mq)b{^IZzfG)ICIucd-foY zla8wkMeggdYi}i>qN+IPmAn7DL)~%><~%8u0`is-%4_#%I61<@NO@J7=Q{RTJEeQ( zeAbz@vR)y}`Y`QG<-M06zLx~6xq92^=6jlA4YWQWQKhEf3j%8h7M3g_#+EAx=Z17w z->$FUXhp!N9}soSjryg`SczhXQaT$&ysXY=xs}o3|Ge$YX=h&}m5`rJX0*#_ic4mG zal~jL7)_CY&YWF-)|n?r(20fluL`lJH%RePOpqd6_U#Q)1XE2BOz-|$j8H1l=&Tfk zczMHrkJB6Q^OH|1G9Ni}GdefMT^BMUBNlDeSbi!gNwj@cBiy-t5IW5zc1!&7! zr)SgF_Nv#3?Yk9jueQPZ<{*b0DdkEYtf`rDx~aTmTwd-P$AqYWf1e` zs9kg!FRD%c$>R39SnXVa@RcgI86Ql$BZK>DAy;b=fW~O8H=v zp%?N6Hb|+OC`sWP8(bOCRx%D|Dt~m4m31=X+AP-0crIrbbp0raX-&;-pP?odZo5k1 z>aD)KVMEapyjxJ6FRLW+p)?gwJJ`({yn%0^4cH)sIC~qxdj+<4lg6uCDEuLxVr&)L z@QxRto@1v0f5cxI2Dagk`D=Or{0aV)Pf;oPNs-CjdI@0N6&NR8K=Tr!pTXLTXnmT4 zD!`~4P53ip{b{#ohCt{7+G>$~ME*JcVkPpHXKQ#KB=RroAvEddO|H$a{$V z>w3uBYmxU7`8V~D-L=U3i2U1n$X&I_0V4md9x_&oJWS-@*F)~DMGg}A5A~3*uSFgq z@*nFV@2W)(5&2K`PP4!EG>;Ma&-IY^)FR_V{!2aNKrM2F$bYSeJW`9ipU8i!hdf$~ zOc43+^^haA$m2x*2mW)VeIBnxjuCkh|K%aoL9F64(6{3f9^j>d{@wLC7|lF4#~j>vjr2@i^MHfo=0qyGYFI;M?I%%PY4yLp8w&N|_(g8#-AK5;#~ z#-2EHAO43ui3xr9DtnE(_ciuH(j#P(=G&)~YG42mS|e$OlJUn7`WiogG#Qu({!@ku zD>Q^S7{1D2V@O6y4kI^3G!i-k_CskH=6oQ5o{rqc<)}>ru_V(t1=> zwdlD$%2cbUG!t93n!{=}ks&Ji6$-jWt@Q={0Gjz7iy^inToyFa5%Eu1B)!EG)jRkl zltk1>t*GzdLhr;byi1FE%wt&=HKx|_j6~F!YGqH(H>QP_^Nnet<@{n==rDP0(?Umr zLgW4FCST~+sER1@nVlDL?gHNU1a@7)TTWcT;|%cM-TKyxc$?grAT$;1QnE7&fX7_9EoBUTtKrNgH@0)IP0~2q(V6i{hx-q$E>`%{|VE zVsjfhLYujTPX51$r=CPqEN=;)dQLC9ik}Ie;bM|NJs-V9uYZx$%V@%W z{1i1`N#*jv7We`sdR4F9=}l8xePeG|{5+`TZ`an+5U`A>d@1pDut=$eQ`g2NTuSV` zfR~@Z<|}xmY#Tr8*@kBgpL@9yuUa`1_#y@V67BEHxC39&lC*jJ)Hd2JD-di`+woZ_ zz2_#V*Kmh{%arLh793!EJEo;3h5{q}(0-sQJ<`)!}JYok(S z`#L^CO-XEzY^I6*eB}(ia_srQ`9-uj6UvY9V#IPX5p{?s8KRj;K=Um3fVNx4_9eXf zJid4VUum5Py@cO9(bzhXT*7ZZk2lIPUa{tx%59wT07B|s(i_x$YCu?Xfp(^X!|byj jR3m6qgK9_}QxA}`ktQXPPX5~Y<}g7YOR6dLAUeJdsjw#; literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback.java b/tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback.java new file mode 100644 index 00000000..58d6baf8 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/fallback/LibFallback.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.fallback; + +import jdk.internal.foreign.abi.SharedUtils; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; + +final class LibFallback { + private LibFallback() {} + + static final boolean SUPPORTED = tryLoadLibrary(); + + @SuppressWarnings("removal") + private static boolean tryLoadLibrary() { + return java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction<>() { + public Boolean run() { + try { + System.loadLibrary("fallbackLinker"); + } catch (UnsatisfiedLinkError ule) { + return false; + } + if (!init()) { + // library failed to initialize. Do not silently mark as unsupported + throw new ExceptionInInitializerError("Fallback library failed to initialize"); + } + return true; + } + }); + } + + static int defaultABI() { return NativeConstants.DEFAULT_ABI; } + + static MemorySegment uint8Type() { return NativeConstants.UINT8_TYPE; } + static MemorySegment sint8Type() { return NativeConstants.SINT8_TYPE; } + static MemorySegment uint16Type() { return NativeConstants.UINT16_TYPE; } + static MemorySegment sint16Type() { return NativeConstants.SINT16_TYPE; } + static MemorySegment sint32Type() { return NativeConstants.SINT32_TYPE; } + static MemorySegment sint64Type() { return NativeConstants.SINT64_TYPE; } + static MemorySegment floatType() { return NativeConstants.FLOAT_TYPE; } + static MemorySegment doubleType() { return NativeConstants.DOUBLE_TYPE; } + static MemorySegment pointerType() { return NativeConstants.POINTER_TYPE; } + static MemorySegment voidType() { return NativeConstants.VOID_TYPE; } + + // platform-dependent types + static int shortSize() { return NativeConstants.SIZEOF_SHORT; } + static int intSize() { return NativeConstants.SIZEOF_INT; } + static int longSize() {return NativeConstants.SIZEOF_LONG; } + static int wcharSize() {return NativeConstants.SIZEOF_WCHAR; } + static int longLongAlign() { return NativeConstants.ALIGNOF_LONG_LONG; } + static int doubleAlign() { return NativeConstants.ALIGNOF_DOUBLE; } + + static short structTag() { return NativeConstants.STRUCT_TAG; } + + private static final MethodType UPCALL_TARGET_TYPE = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class); + + /** + * Do a libffi based downcall. This method wraps the {@code ffi_call} function + * + * @param cif a pointer to a {@code ffi_cif} struct + * @param target the address of the target function + * @param retPtr a pointer to a buffer into which the return value shall be written, or {@code null} if the target + * function does not return a value + * @param argPtrs a pointer to an array of pointers, which each point to an argument value + * @param capturedState a pointer to a buffer into which captured state is written, or {@code null} if no state is + * to be captured + * @param capturedStateMask the bit mask indicating which state to capture + * + * @see jdk.internal.foreign.abi.CapturableState + */ + static void doDowncall(MemorySegment cif, MemorySegment target, MemorySegment retPtr, MemorySegment argPtrs, + MemorySegment capturedState, int capturedStateMask, + Object[] heapBases, int numArgs) { + doDowncall(cif.address(), target.address(), + retPtr == null ? 0 : retPtr.address(), argPtrs.address(), + capturedState == null ? 0 : capturedState.address(), capturedStateMask, + heapBases, numArgs); + } + + /** + * Wrapper for {@code ffi_prep_cif} + * + * @param returnType a pointer to an @{code ffi_type} describing the return type + * @param numArgs the number of arguments + * @param paramTypes a pointer to an array of pointers, which each point to an {@code ffi_type} describing a + * parameter type + * @param abi the abi to be used + * @param scope the scope into which to allocate the returned {@code ffi_cif} struct + * @return a pointer to a prepared {@code ffi_cif} struct + * + * @throws IllegalStateException if the call to {@code ffi_prep_cif} returns a non-zero status code + */ + static MemorySegment prepCif(MemorySegment returnType, int numArgs, MemorySegment paramTypes, FFIABI abi, + Arena scope) throws IllegalStateException { + MemorySegment cif = scope.allocate(NativeConstants.SIZEOF_CIF); + checkStatus(ffi_prep_cif(cif.address(), abi.value(), numArgs, returnType.address(), paramTypes.address())); + return cif; + } + + /** + * Wrapper for {@code ffi_prep_cif_var}. The variadic version of prep_cif + * + * @param returnType a pointer to an @{code ffi_type} describing the return type + * @param numFixedArgs the number of fixed arguments + * @param numTotalArgs the number of total arguments + * @param paramTypes a pointer to an array of pointers, which each point to an {@code ffi_type} describing a + * parameter type + * @param abi the abi to be used + * @param scope the scope into which to allocate the returned {@code ffi_cif} struct + * @return a pointer to a prepared {@code ffi_cif} struct + * + * @throws IllegalStateException if the call to {@code ffi_prep_cif} returns a non-zero status code + */ + static MemorySegment prepCifVar(MemorySegment returnType, int numFixedArgs, int numTotalArgs, MemorySegment paramTypes, FFIABI abi, + Arena scope) throws IllegalStateException { + MemorySegment cif = scope.allocate(NativeConstants.SIZEOF_CIF); + checkStatus(ffi_prep_cif_var(cif.address(), abi.value(), numFixedArgs, numTotalArgs, returnType.address(), paramTypes.address())); + return cif; + } + + /** + * Create an upcallStub-style closure. This method wraps the {@code ffi_closure_alloc} + * and {@code ffi_prep_closure_loc} functions. + *

+ * The closure will end up calling into {@link #doUpcall(long, long, MethodHandle)} + *

+ * The target method handle should have the type {@code (MemorySegment, MemorySegment) -> void}. The first + * argument is a pointer to the buffer into which the native return value should be written. The second argument + * is a pointer to an array of pointers, which each point to a native argument value. + * + * @param cif a pointer to a {@code ffi_cif} struct + * @param target a method handle that points to the target function + * @param arena the scope to which to attach the created upcall stub + * @return the created upcall stub + * + * @throws IllegalStateException if the call to {@code ffi_prep_closure_loc} returns a non-zero status code + * @throws IllegalArgumentException if {@code target} does not have the right type + */ + @SuppressWarnings("restricted") + static MemorySegment createClosure(MemorySegment cif, MethodHandle target, Arena arena) + throws IllegalStateException, IllegalArgumentException { + if (target.type() != UPCALL_TARGET_TYPE) { + throw new IllegalArgumentException("Target handle has wrong type: " + target.type() + " != " + UPCALL_TARGET_TYPE); + } + + long[] ptrs = new long[3]; + checkStatus(createClosure(cif.address(), target, ptrs)); + long closurePtr = ptrs[0]; + long execPtr = ptrs[1]; + long globalTarget = ptrs[2]; + + return MemorySegment.ofAddress(execPtr) + .reinterpret(arena, unused -> freeClosure(closurePtr, globalTarget)); // restricted + } + + // the target function for a closure call + private static void doUpcall(long retPtr, long argPtrs, MethodHandle target) { + try { + target.invokeExact(MemorySegment.ofAddress(retPtr), MemorySegment.ofAddress(argPtrs)); + } catch (Throwable t) { + SharedUtils.handleUncaughtException(t); + } + } + + /** + * Wrapper for {@code ffi_get_struct_offsets} + * + * @param structType a pointer to an {@code ffi_type} representing a struct + * @param offsetsOut a pointer to an array of {@code size_t}, with one element for each element of the struct. + * This is an 'out' parameter that will be filled in by this call + * @param abi the abi to be used + * + * @throws IllegalStateException if the call to {@code ffi_get_struct_offsets} returns a non-zero status code + */ + static void getStructOffsets(MemorySegment structType, MemorySegment offsetsOut, FFIABI abi) + throws IllegalStateException { + checkStatus(ffi_get_struct_offsets(abi.value(), structType.address(), offsetsOut.address())); + } + + private static void checkStatus(int code) { + FFIStatus status = FFIStatus.of(code); + if (status != FFIStatus.FFI_OK) { + throw new IllegalStateException("libffi call failed with status: " + status); + } + } + + private static native boolean init(); + + private static native long sizeofCif(); + + private static native int createClosure(long cif, Object userData, long[] ptrs); + private static native void freeClosure(long closureAddress, long globalTarget); + private static native void doDowncall(long cif, long fn, long rvalue, long avalues, + long capturedState, int capturedStateMask, + Object[] heapBases, int numArgs); + + private static native int ffi_prep_cif(long cif, int abi, int nargs, long rtype, long atypes); + private static native int ffi_prep_cif_var(long cif, int abi, int nfixedargs, int ntotalargs, long rtype, long atypes); + private static native int ffi_get_struct_offsets(int abi, long type, long offsets); + + private static native int ffi_default_abi(); + private static native short ffi_type_struct(); + + private static native long ffi_type_void(); + private static native long ffi_type_uint8(); + private static native long ffi_type_sint8(); + private static native long ffi_type_uint16(); + private static native long ffi_type_sint16(); + private static native long ffi_type_uint32(); + private static native long ffi_type_sint32(); + private static native long ffi_type_uint64(); + private static native long ffi_type_sint64(); + private static native long ffi_type_float(); + private static native long ffi_type_double(); + private static native long ffi_type_pointer(); + private static native int ffi_sizeof_short(); + private static native int ffi_sizeof_int(); + private static native int ffi_sizeof_long(); + private static native int ffi_sizeof_wchar(); + + private static native int alignof_long_long(); + private static native int alignof_double(); + + // put these in a separate class to avoid an UnsatisfiedLinkError + // when LibFallback is initialized but the library is not present + private static final class NativeConstants { + private NativeConstants() {} + + static final int DEFAULT_ABI = ffi_default_abi(); + + static final MemorySegment UINT8_TYPE = MemorySegment.ofAddress(ffi_type_uint8()); + static final MemorySegment SINT8_TYPE = MemorySegment.ofAddress(ffi_type_sint8()); + static final MemorySegment UINT16_TYPE = MemorySegment.ofAddress(ffi_type_uint16()); + static final MemorySegment SINT16_TYPE = MemorySegment.ofAddress(ffi_type_sint16()); + static final MemorySegment SINT32_TYPE = MemorySegment.ofAddress(ffi_type_sint32()); + static final MemorySegment SINT64_TYPE = MemorySegment.ofAddress(ffi_type_sint64()); + static final MemorySegment FLOAT_TYPE = MemorySegment.ofAddress(ffi_type_float()); + static final MemorySegment DOUBLE_TYPE = MemorySegment.ofAddress(ffi_type_double()); + static final MemorySegment POINTER_TYPE = MemorySegment.ofAddress(ffi_type_pointer()); + static final int SIZEOF_SHORT = ffi_sizeof_short(); + static final int SIZEOF_INT = ffi_sizeof_int(); + static final int SIZEOF_LONG = ffi_sizeof_long(); + static final int SIZEOF_WCHAR = ffi_sizeof_wchar(); + + static final int ALIGNOF_LONG_LONG = alignof_long_long(); + static final int ALIGNOF_DOUBLE = alignof_double(); + + static final MemorySegment VOID_TYPE = MemorySegment.ofAddress(ffi_type_void()); + static final short STRUCT_TAG = ffi_type_struct(); + static final long SIZEOF_CIF = sizeofCif(); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$1.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$1.class new file mode 100644 index 0000000000000000000000000000000000000000..babd71ad5ed80206bfc0ee4c6dddc61b3fd4f0d5 GIT binary patch literal 950 zcmb7@T~8B16o%hvOSfGYDTq?R57ZS3NLNs~(U>%~g~ommcEJlS%yc`_E$ePG-D3Pj zUaN^Q#`FjHql{Y!=pz>ldwinnea#4Z49#FsS$+ zg=OyhB`JAuBBZ&+@W`~^d6C;~@V-f<<{wsb%xV&=8MB(_SQE#!EN%3%ff?i&W^Cu+ zuc6Pq(|1@jDAC_5gV6hpGGR?~2eVX?>0xaAYD)eP;S+pT)S z?^L7=r9#LXxULZNF~VN8r0gXFHHu|oAhW1H4(_b)~YJEWJWh@s+ zPEF(@$@E0tB&kj0GRaIVKhj^3#XJ^p6?wu~p}2}|JfXOQ5?)ZOU>`QcBnpI)RxnIp rjq(JIbs9_1UuiU>@s}4;*odb-z$V2Miu8UMJ4I|!)Z_h9lFR%8^{?E* literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$BindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$BindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..ac48e6795d91cfd68adad673462cd70d6b442fa2 GIT binary patch literal 1111 zcmb7D+int36kP|#PNB2~ylYjos6eBmiSY%*R1%{JtrrZ@z8&C54-PZUnKLGR^Ot-u zO*HWX{3zoZirPqgn3vg?IeV{tS^LM&uipW5P|G8OtP7`rQ&l9cbGY$kyt87s~>VCZi9Y4y-bP^u70?QFnJVkLNA0}N)lD?3EWB3 z0Rs!%;kFsaQx#ZNBKAmx9cA~!(MxIMRB_XEuZ)$Q!_w+-b$__h@nsY>PdI*)VnPQZ_Eu9sB}3 CGBvUQ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$Bindings.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$Bindings.class new file mode 100644 index 0000000000000000000000000000000000000000..7a6e3e69c1fa8c1ffc35c2b76cf4f123d3050373 GIT binary patch literal 1868 zcmbVNT~pIQ6g^ugX=|`h0Ywl{L1{oDiYOLQKE?qp=m5h*eM;Mv20~IdDKq>hA7nAJ|cW>@Jch9+ZZ~y!~{S9ClD=Ea#rl4I#932c@d&Z%mTZX-> zZ}O5O$_yRzrfqr)3~l4tog@-SDoClg0hM89ue`6Dw#S8SSo&8-aC6tzjiRYntEJf) zec7%;ujEY<6VMut+mM18j;lp_I94&5}%jVBD39xc9L!XMl5Qzh5AS8>Xp4PhK`>Lp2;YqgtBwp|j8Rz;V^E%NBP>^NzD$tL7rQhA$yv2?Mu} zs(gjJC1F-QM?^!GEyH!Ah7jXRBSypvaUT!pL_t0@^LG+FhKICI#>gx`0^Ky$Mk$}nG)=2?RkTyG;|FaU zGpK<}n4z0y*4P!{y}?jB!F>#3&mg>HZmr zYd@j1Vi6Bv=nn+i6~UdYIMjpVnDCiS;)%ab;VG>*>7GGVgPKnJHkxN>r@BAG3|`<3 T*)rspz!VmU@>?v@KWP6yHORiH literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$BoxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$BoxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..4ac679a8a21159d98396ee222969e0cdfa875955 GIT binary patch literal 6236 zcmbtY33MCP6}@k?j3td@WwD3?2_}f**iMW?uv^6$`=gO8+meG%?PJfMzr6pJ z`|f{#_I-Kt9smpQr3{Hsxgm6FwH`@mMnnx)cSQ|N?~YWfoqBaF7Ob69y+93zn+!vZ zbZdqSb~t1>704(e%pb$jKy!3cvmOcQk#3e4Oor7&)F3z$J$gKF6k%rD7=$&r;f6Rp@L)XmXkg0P(RR5z;CVGc_+ zX3MnRs9{ZM=;)YnAXBm%G``HmoWCiQSg;|NxjkFt?9KhT_> z-QdFE2*@}>!Pjsk2fg4%Be55#AsiiOKV44*dzPuO051(>U>mSt8(`Q5%%y>>aRh07 zi*Wr61r?}d)uRTZPz@7o zyH|@OWN^qQ4^C>zh*@M9QNxWI%n?XE#@up^8+G`)jBhBYN5g1180I|&80TU%s3tT* z+W`?Urm)y?tb)0iM;IUH#8kVr+$^1UASmUMM4)}R08ZB?G|O0^U?CQbFM3}=QEa}$h%(YZOHwd-eaFc?U! z4(3$xQ{={RSRvzh1uN0cxjQIlnVRU~$-R1nDWSZzbw;ZjtFcDLS_LOy9YKIPKNq+6 zsD>6=ozTNf2M5Iry;o1@8#zdZp=-wCsF7Brw7ga1eU=(b{$TglVZDMAMQ+`P1ZHuZQf;tLk4tjTltTDh-=-;D2 z#|DBs-lKOVR_fh7OoMaFTmE0UVFkV5cz8OKU0s?Xz`y~WSKc~8aLX7pmJuUN9gIT; zK}(EiGL|NBK}m*!IM|Njcu)V&KV zIEWYHw=ynKumhJ8rsOr>qNkErR2$fm;=#%734?1}tI%=dYRoCZb!^G%NRJu`aV1e^7I9@_ z=z0Y=;6_HK8jEQW=FpkB4oXYPpy8w`|$eo=_7>=0QGJJ2>|iL_?f=C2e{{Tb}Ig)QnZ4G~>P6xEKnr zQ4L+ZTb*`sqaZXF21Fj7$#*&7(oA9QZ8Ex(qQ+yH-ep>%CmLFz8fve`7bfoVF!5Oc z*!}2(9C~L4kg6R^7l?+>#qq029hWMN*giSP~Y9X-VK+0#Y6O4+Y z&h$N&y*kRe;j}~W4TUQo1Qui`_nAG+$&ESF@?uFWD(2h?p2`;_Q?`t! z39fb~P);aO*lZYqP_fs61Y7Ko4L562s8F@cZVKqq5A;i!TZ z6ga>+87-Lt3w%+w^EU`U@=g|)N5Jb9A4Ryw#((@(0uuIdYbC#n9;Kr4M%XGU57`CR zb^I>je*QmBjM1%d&>nbbFCO5&vh;jBh`;e0uQcV7*?Nd~lJGFMT@tXxE5`Zf5j>jS z&ha9g{4D~~)~bpdV7mb&>Bq!=_?GwMkb3)0OrM!T`K&9=g;Fa&glJJ51-Mzvf3NU* zA)|aJsmAlU+cC}BYCF7DH(@ac4sF{m zfo$)C-B#;#)yaNGz02>~Q|q?XdP+T|?#pnl-&N|FU9Y4U_+*XO^kaElv8}emS8VIY zs(Np!^FmDV$-ZJWJ!{)V@OX=S#pi`;OZ@f}I@Xq!T!_hjyIp!L@$7PxgCxRSKuBHKoAH~qB+Ys%?X{Mcxen$$)dZ*uEy9t{m z+=eBlp>?vW&Sl!Xwu|B7@jf{DrLNdloSt>5cl6^T@$Yvj{DEC%Ml?Ok!LuBd!fAb&F9L0^+=)M4VQnttO)+Num!W2YoDg=o86DpGwo|GiermF4fQ%QX_pSEusNwsYKGrk|cFY zHfe)om(G!#X6Al?$=J)cp99BfJ{p#(plWyu~o9@p^=@;T;@6S+2i z3jczWA}r^5Q_5*9TgY=s9{%q30$zke^0AIW1EcfI{wXZeS@Q0!OygfZ^CQo`6fy%?cNgPVoH0HrM=AvI2MO| zfrT;-l2JEtKWb#WW1CL{>>vK7YnO4ij3wz&9wF{{hggjPEJ8`aaT#0f#7lugT?6oo z&(uRCu?iChFdOb+{W8vwvBhrZ4a#`at^08}|93Rog*r;1$znGU&tZBVb&h0byN<}G zO{H&up)o>DNk$VdVMZP%7dA0M-YIyOM-LuCWmt$ ayhZ#ykMJ2cxA60G{+|7F{1;z1UH=2y!0ROd literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$HfaRegs.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger$HfaRegs.class new file mode 100644 index 0000000000000000000000000000000000000000..9a6b18577b7140ca3ef4c2f23cd1b385b173480b GIT binary patch literal 1833 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger.class new file mode 100644 index 0000000000000000000000000000000000000000..5ed653f5cb11902379c39591ce11f20b05b0a840 GIT binary patch literal 9351 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger.java b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger.java new file mode 100644 index 00000000..d07cd79e --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/CallArranger.java @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.ppc64; + +import jdk.internal.foreign.Utils; +import jdk.internal.foreign.abi.ABIDescriptor; +import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory; +import jdk.internal.foreign.abi.Binding; +import jdk.internal.foreign.abi.CallingSequence; +import jdk.internal.foreign.abi.CallingSequenceBuilder; +import jdk.internal.foreign.abi.DowncallLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.VMStorage; +import jdk.internal.foreign.abi.ppc64.aix.AixCallArranger; +import jdk.internal.foreign.abi.ppc64.linux.ABIv1CallArranger; +import jdk.internal.foreign.abi.ppc64.linux.ABIv2CallArranger; + +import java.lang.foreign.AddressLayout; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Optional; + +import static jdk.internal.foreign.abi.ppc64.PPC64Architecture.*; +import static jdk.internal.foreign.abi.ppc64.PPC64Architecture.Regs.*; + +/** + * For the PPC64 C ABI specifically, this class uses CallingSequenceBuilder + * to translate a C FunctionDescriptor into a CallingSequence, which can then be turned into a MethodHandle. + * + * This includes taking care of synthetic arguments like pointers to return buffers for 'in-memory' returns. + * + * There are minor differences between the ABIs implemented on Linux and AIX + * which are handled in sub-classes. Clients should access these through the provided + * public constants CallArranger.ABIv1/2. + */ +public abstract class CallArranger { + final boolean useABIv2 = useABIv2(); + final boolean isAIX = isAIX(); + + private static final int STACK_SLOT_SIZE = 8; + private static final int MAX_COPY_SIZE = 8; + public static final int MAX_REGISTER_ARGUMENTS = 8; + public static final int MAX_FLOAT_REGISTER_ARGUMENTS = 13; + + // This is derived from the 64-Bit ELF v2 ABI spec, restricted to what's + // possible when calling to/from C code. (v1 is compatible, but uses fewer output registers.) + private final ABIDescriptor C = abiFor( + new VMStorage[] { r3, r4, r5, r6, r7, r8, r9, r10 }, // GP input + new VMStorage[] { f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13 }, // FP intput + new VMStorage[] { r3, r4 }, // GP output + new VMStorage[] { f1, f2, f3, f4, f5, f6, f7, f8 }, // FP output + new VMStorage[] { r0, r2, r11, r12 }, // volatile GP (excluding argument registers) + new VMStorage[] { f0 }, // volatile FP (excluding argument registers) + 16, // Stack is always 16 byte aligned on PPC64 + useABIv2 ? 32 : 48, // ABI header (excluding argument register spill slots) + r11, // scratch reg + r12 // target addr reg, otherwise used as scratch reg + ); + + public record Bindings(CallingSequence callingSequence, boolean isInMemoryReturn) {} + + private record HfaRegs(VMStorage[] first, VMStorage[] second) {} + + protected CallArranger() {} + + public static final CallArranger ABIv1 = new ABIv1CallArranger(); + public static final CallArranger ABIv2 = new ABIv2CallArranger(); + public static final CallArranger AIX = new AixCallArranger(); + + /** + * Select ABI version + */ + protected abstract boolean useABIv2(); + protected abstract boolean isAIX(); + + public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) { + return getBindings(mt, cDesc, forUpcall, LinkerOptions.empty()); + } + + public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall, LinkerOptions options) { + CallingSequenceBuilder csb = new CallingSequenceBuilder(C, forUpcall, options); + + BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true, options.allowsHeapAccess()); + BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false, false) : new BoxBindingCalculator(false); + + boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout()); + if (returnInMemory) { + Class carrier = MemorySegment.class; + MemoryLayout layout = SharedUtils.C_POINTER; + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout)); + } else if (cDesc.returnLayout().isPresent()) { + Class carrier = mt.returnType(); + MemoryLayout layout = cDesc.returnLayout().get(); + csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout)); + } + + for (int i = 0; i < mt.parameterCount(); i++) { + Class carrier = mt.parameterType(i); + MemoryLayout layout = cDesc.argumentLayouts().get(i); + if (options.isVarargsIndex(i)) { + argCalc.storageCalculator.adjustForVarArgs(); + } + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout)); + } + + return new Bindings(csb.build(), returnInMemory); + } + + public MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, false, options); + + MethodHandle handle = new DowncallLinker(C, bindings.callingSequence).getBoundMethodHandle(); + + if (bindings.isInMemoryReturn) { + handle = SharedUtils.adaptDowncallForIMR(handle, cDesc, bindings.callingSequence); + } + + return handle; + } + + public UpcallStubFactory arrangeUpcall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, true, options); + + final boolean dropReturn = true; /* drop return, since we don't have bindings for it */ + return SharedUtils.arrangeUpcallHelper(mt, bindings.isInMemoryReturn, dropReturn, C, + bindings.callingSequence); + } + + private boolean isInMemoryReturn(Optional returnLayout) { + return returnLayout + .filter(GroupLayout.class::isInstance) + .filter(layout -> !TypeClass.isStructHFAorReturnRegisterAggregate(layout, useABIv2)) + .isPresent(); + } + + class StorageCalculator { + private final boolean forArguments; + + private final int[] nRegs = new int[] { 0, 0 }; + private long stackOffset = 0; + + public StorageCalculator(boolean forArguments) { + this.forArguments = forArguments; + } + + VMStorage stackAlloc(long size, long alignment) { + long alignedStackOffset = Utils.alignUp(stackOffset, alignment); + + short encodedSize = (short) size; + assert (encodedSize & 0xFFFF) == size; + + VMStorage storage = PPC64Architecture.stackStorage(encodedSize, (int) alignedStackOffset); + stackOffset = alignedStackOffset + size; + return storage; + } + + VMStorage regAlloc(int type) { + // GP regs always need to get reserved even when float regs are used. + int gpRegCnt = 1; + int fpRegCnt = (type == StorageType.INTEGER) ? 0 : 1; + + // Use stack if not enough registers available. + if (type == StorageType.FLOAT && nRegs[StorageType.FLOAT] + fpRegCnt > MAX_FLOAT_REGISTER_ARGUMENTS) { + type = StorageType.INTEGER; // Try gp reg. + } + if (type == StorageType.INTEGER && nRegs[StorageType.INTEGER] + gpRegCnt > MAX_REGISTER_ARGUMENTS) return null; + + VMStorage[] source = (forArguments ? C.inputStorage : C.outputStorage)[type]; + VMStorage result = source[nRegs[type]]; + + nRegs[StorageType.INTEGER] += gpRegCnt; + nRegs[StorageType.FLOAT] += fpRegCnt; + return result; + } + + // Integers need size for int to long conversion (required by ABI). + // FP loads and stores must use the correct IEEE 754 precision format (32/64 bit). + // Note: Can return a GP reg for a float! + VMStorage nextStorage(int type, boolean is32Bit) { + VMStorage reg = regAlloc(type); + // Stack layout computation: We need to count all arguments in order to get the correct + // offset for the next argument which will really use the stack. + // The reserved space for the Parameter Save Area is determined by the DowncallStubGenerator. + VMStorage stack; + if (!useABIv2 && !isAIX && is32Bit) { + stackAlloc(4, STACK_SLOT_SIZE); // Skip first half of stack slot. + stack = stackAlloc(4, 4); + } else { + stack = stackAlloc(is32Bit ? 4 : 8, STACK_SLOT_SIZE); + } + if (reg == null) return stack; + if (is32Bit) { + reg = new VMStorage(reg.type(), PPC64Architecture.REG32_MASK, reg.indexOrOffset()); + } + return reg; + } + + /* The struct is split into 8-byte chunks, and those chunks are passed in registers or on the stack. + ABIv1 requires shifting if the struct occupies more than one 8-byte chunk and the last one is not full. + Here's an example for passing an 11 byte struct with ABIv1: + offset : 0 .... 32 ..... 64 ..... 96 .... 128 + values : xxxxxxxx|yyyyyyyy|zzzzzz??|???????? (can't touch bits 96..128) + Load into int : V +--------+ + | | + +--------+ | + V V + In register : ????????|??zzzzzz (LSBs are zz...z) + Shift left : zzzzzz00|00000000 (LSBs are 00...0) + Write long : V V + Result : xxxxxxxx|yyyyyyyy|zzzzzz00|00000000 + */ + + // Regular struct, no HFA. + VMStorage[] structAlloc(MemoryLayout layout) { + // Allocate enough gp slots (regs and stack) such that the struct fits in them. + int numChunks = (int) Utils.alignUp(layout.byteSize(), MAX_COPY_SIZE) / MAX_COPY_SIZE; + VMStorage[] result = new VMStorage[numChunks]; + for (int i = 0; i < numChunks; i++) { + result[i] = nextStorage(StorageType.INTEGER, false); + } + return result; + } + + HfaRegs hfaAlloc(List scalarLayouts) { + // Determine count and type. + int count = scalarLayouts.size(); + Class elementCarrier = ((ValueLayout) (scalarLayouts.get(0))).carrier(); + int elementSize = (elementCarrier == float.class) ? 4 : 8; + + // Allocate registers. + int fpRegCnt = count; + // Rest will get put into a struct. Compute number of 64 bit slots. + int structSlots = 0; + boolean needOverlapping = false; // See "no partial DW rule" below. + + int availableFpRegs = MAX_FLOAT_REGISTER_ARGUMENTS - nRegs[StorageType.FLOAT]; + if (count > availableFpRegs) { + fpRegCnt = availableFpRegs; + int remainingElements = count - availableFpRegs; + if (elementCarrier == float.class) { + if ((fpRegCnt & 1) != 0) { + needOverlapping = true; + remainingElements--; // After overlapped one. + } + structSlots = (remainingElements + 1) / 2; + } else { + structSlots = remainingElements; + } + } + + VMStorage[] source = (forArguments ? C.inputStorage : C.outputStorage)[StorageType.FLOAT]; + VMStorage[] result = new VMStorage[fpRegCnt + structSlots], + result2 = new VMStorage[fpRegCnt + structSlots]; // For overlapping. + if (elementCarrier == float.class) { + // Mark elements as single precision (32 bit). + for (int i = 0; i < fpRegCnt; i++) { + VMStorage sourceReg = source[nRegs[StorageType.FLOAT] + i]; + result[i] = new VMStorage(StorageType.FLOAT, PPC64Architecture.REG32_MASK, + sourceReg.indexOrOffset()); + } + } else { + for (int i = 0; i < fpRegCnt; i++) { + result[i] = source[nRegs[StorageType.FLOAT] + i]; + } + } + + nRegs[StorageType.FLOAT] += fpRegCnt; + // Reserve GP regs and stack slots for the packed HFA (when using single precision). + int gpRegCnt = (elementCarrier == float.class) ? ((fpRegCnt + 1) / 2) + : fpRegCnt; + nRegs[StorageType.INTEGER] += gpRegCnt; + stackAlloc(fpRegCnt * elementSize, STACK_SLOT_SIZE); + + if (needOverlapping) { + // "no partial DW rule": Put GP reg or stack slot into result2. + // Note: Can only happen with forArguments = true. + VMStorage overlappingReg; + if (nRegs[StorageType.INTEGER] <= MAX_REGISTER_ARGUMENTS) { + VMStorage allocatedGpReg = C.inputStorage[StorageType.INTEGER][nRegs[StorageType.INTEGER] - 1]; + overlappingReg = new VMStorage(StorageType.INTEGER, + PPC64Architecture.REG64_MASK, allocatedGpReg.indexOrOffset()); + } else { + overlappingReg = new VMStorage(StorageType.STACK, + (short) STACK_SLOT_SIZE, (int) stackOffset - 4); + stackOffset += 4; // We now have a 64 bit slot, but reserved only 32 bit before. + } + result2[fpRegCnt - 1] = overlappingReg; + } + + // Allocate rest as struct. + for (int i = 0; i < structSlots; i++) { + result[fpRegCnt + i] = nextStorage(StorageType.INTEGER, false); + } + + return new HfaRegs(result, result2); + } + + void adjustForVarArgs() { + // PPC64 can pass VarArgs in GP regs. But we're not using FP regs. + nRegs[StorageType.FLOAT] = MAX_FLOAT_REGISTER_ARGUMENTS; + } + } + + abstract class BindingCalculator { + protected final StorageCalculator storageCalculator; + + protected BindingCalculator(boolean forArguments) { + this.storageCalculator = new StorageCalculator(forArguments); + } + + abstract List getBindings(Class carrier, MemoryLayout layout); + } + + // Compute recipe for transfering arguments / return values to C from Java. + class UnboxBindingCalculator extends BindingCalculator { + private final boolean useAddressPairs; + + UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) { + super(forArguments); + this.useAddressPairs = useAddressPairs; + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = TypeClass.classifyLayout(layout, useABIv2, isAIX); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case STRUCT_REGISTER -> { + assert carrier == MemorySegment.class; + VMStorage[] regs = storageCalculator.structAlloc(layout); + final boolean isLargeABIv1Struct = !useABIv2 && + (isAIX || layout.byteSize() > MAX_COPY_SIZE); + long offset = 0; + for (VMStorage storage : regs) { + // Last slot may be partly used. + final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE); + int shiftAmount = 0; + Class type = SharedUtils.primitiveCarrierForSize(size, false); + if (offset + size < layout.byteSize()) { + bindings.dup(); + } else if (isLargeABIv1Struct) { + // Last slot requires shift. + shiftAmount = MAX_COPY_SIZE - (int) size; + } + bindings.bufferLoad(offset, type, (int) size); + if (shiftAmount != 0) { + bindings.shiftLeft(shiftAmount, type) + .vmStore(storage, long.class); + } else { + bindings.vmStore(storage, type); + } + offset += size; + } + } + case STRUCT_HFA -> { + assert carrier == MemorySegment.class; + List scalarLayouts = TypeClass.scalarLayouts((GroupLayout) layout); + HfaRegs regs = storageCalculator.hfaAlloc(scalarLayouts); + final long baseSize = scalarLayouts.get(0).byteSize(); + long offset = 0; + for (int index = 0; index < regs.first().length; index++) { + VMStorage storage = regs.first()[index]; + // Floats are 4 Bytes, Double, GP reg and stack slots 8 Bytes (except maybe last slot). + long size = (baseSize == 4 && + (storage.type() == StorageType.FLOAT || layout.byteSize() - offset < 8)) ? 4 : 8; + Class type = SharedUtils.primitiveCarrierForSize(size, storage.type() == StorageType.FLOAT); + if (offset + size < layout.byteSize()) { + bindings.dup(); + } + bindings.bufferLoad(offset, type) + .vmStore(storage, type); + VMStorage storage2 = regs.second()[index]; + if (storage2 != null) { + // We have a second slot to fill (always 64 bit GP reg or stack slot). + size = 8; + if (offset + size < layout.byteSize()) { + bindings.dup(); + } + bindings.bufferLoad(offset, long.class) + .vmStore(storage2, long.class); + } + offset += size; + } + } + case POINTER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, false); + if (useAddressPairs) { + bindings.dup() + .segmentBase() + .vmStore(storage, Object.class) + .segmentOffsetAllowHeap() + .vmStore(null, long.class); + } else { + bindings.unboxAddress(); + bindings.vmStore(storage, long.class); + } + } + case INTEGER -> { + // ABI requires all int types to get extended to 64 bit. + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, false); + bindings.vmStore(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.FLOAT, carrier == float.class); + bindings.vmStore(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } + + // Compute recipe for transfering arguments / return values from C to Java. + class BoxBindingCalculator extends BindingCalculator { + BoxBindingCalculator(boolean forArguments) { + super(forArguments); + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = TypeClass.classifyLayout(layout, useABIv2, isAIX); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case STRUCT_REGISTER -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout); + VMStorage[] regs = storageCalculator.structAlloc(layout); + final boolean isLargeABIv1Struct = !useABIv2 && + (isAIX || layout.byteSize() > MAX_COPY_SIZE); + long offset = 0; + for (VMStorage storage : regs) { + // Last slot may be partly used. + final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE); + int shiftAmount = 0; + Class type = SharedUtils.primitiveCarrierForSize(size, false); + if (isLargeABIv1Struct && offset + size >= layout.byteSize()) { + // Last slot requires shift. + shiftAmount = MAX_COPY_SIZE - (int) size; + } + bindings.dup(); + if (shiftAmount != 0) { + bindings.vmLoad(storage, long.class) + .shiftRight(shiftAmount, type); + } else { + bindings.vmLoad(storage, type); + } + bindings.bufferStore(offset, type, (int) size); + offset += size; + } + } + case STRUCT_HFA -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout); + List scalarLayouts = TypeClass.scalarLayouts((GroupLayout) layout); + HfaRegs regs = storageCalculator.hfaAlloc(scalarLayouts); + final long baseSize = scalarLayouts.get(0).byteSize(); + long offset = 0; + for (int index = 0; index < regs.first().length; index++) { + // Use second if available since first one only contains one 32 bit value. + VMStorage storage = regs.second()[index] == null ? regs.first()[index] : regs.second()[index]; + // Floats are 4 Bytes, Double, GP reg and stack slots 8 Bytes (except maybe last slot). + final long size = (baseSize == 4 && + (storage.type() == StorageType.FLOAT || layout.byteSize() - offset < 8)) ? 4 : 8; + Class type = SharedUtils.primitiveCarrierForSize(size, storage.type() == StorageType.FLOAT); + bindings.dup() + .vmLoad(storage, type) + .bufferStore(offset, type); + offset += size; + } + } + case POINTER -> { + AddressLayout addressLayout = (AddressLayout) layout; + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, false); + bindings.vmLoad(storage, long.class) + .boxAddressRaw(Utils.pointeeByteSize(addressLayout), Utils.pointeeByteAlign(addressLayout)); + } + case INTEGER -> { + // We could use carrier != long.class for BoxBindingCalculator, but C always uses 64 bit slots. + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, false); + bindings.vmLoad(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.FLOAT, carrier == float.class); + bindings.vmLoad(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/PPC64Architecture$Regs.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/PPC64Architecture$Regs.class new file mode 100644 index 0000000000000000000000000000000000000000..e0892d3373730f34b2474eabf72990c32c39f3e1 GIT binary patch literal 2912 zcma);S8$Y79L3K~0xA4SK8j!{VnGE|mOyBN1%ng~5DCVH;3nB58vG#hvE?jnHm4KImbFZ%O*AyrO{krgZ|O)E_+8!kltY!jygiklpK4Ec z@kWPZN6a2sf6y;#n$uXw<&*8HDdng{RVgAvAM|w?f6!YF^6cS!WS2uxevHHL|NFrH zhC}?*it;u7`2!7y#&WEegA9XXInK+WhQnf6>*e8wBVsw;%cBg#V>!XgV+_Z}a-x?b z4WnW?$;;ynC&Y5HmkGldFN^avW4s<~7#FmBjWBNQw&psmbH@&rvxo; z(+sBtEpyWirw1)}GYzwXmc26!X9g{Qa}0B1Jy!l23}*!`e~pF(LCas0;hdo5?>xi# zLCfDl!-YZ1-(tf>LCasWp(SYfOBvdNmcI@|I%xS@V#vgLocv`Cxu9$OnqF?m`vu** zEt5+Y{#l#;mo6B({gp*+y76MeC9zblRfg5ERIE!4m&H=4))_93r9y2mY>cHcZ8lsH zOGUcMaCIz|Xp7<6SSrxpylsl!zZzh*TZLq z&x5XUD5=Y}`l_l=XH#>#mo}&J3zE$l9_d@3Ye{CBlKHgP;b2LjBh6l!c<@U3uR@yQ zP&TzC6FRn{G1r}MNzF+6rw#a5eUA3^%p2yWx(c&$U2JEYoz155b(v&WSBfS|e8;hM zDp~8msi^i{$^WW-i;1i+k-a6dutYYM$chr#O(IK4WE+XBA(8bXvUWt)jmVl2SuY}M zMP!|btPzp*A+k0^)`iHL5Lpi*Ye8fkh^zsT<1cdTMUK13F&8=BB8OMx)QTKek#j0? zKt)cb$dME|iz0_mL<>Q`iu3^A>zDffH*%ID4rc1 zDxMovix)(L#6{6yF&PaJTce?3dvuuC84VMcGWoLY=wfnW1(OpinUPq-h{ReZB-Z=n zwI$ZMxUI##V03k_sPkvJ~?@hPfp(Nlamkmcy=o;;P$f++qmh!fJNL27Gn=L{C!BWmYeZCH~XK_ieHh!@7(DBM2B-o zyE1gTDlBmWka0t?)D1`09gm!=#WFV)%iVP3T|K(o0ucDG=SyBn9fhjE#E3TxeqSm$=(a<>=j-F|FvUt*&>fKBcfY<9nK(=Nt${0)le T>j$w62gnNkLX{kuA5s1{TWkxL literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/PPC64Architecture$StorageType.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/PPC64Architecture$StorageType.class new file mode 100644 index 0000000000000000000000000000000000000000..069fe7949fdb33dbfe196da4fe2a2ac6f2bea605 GIT binary patch literal 420 zcmb7<%TB^T6o&sJmqGzWR1){D9T$X^n_7zy2@u-2AL>|Jn`tv0OnfyLK7bEpoMF|( zm8+BQ5%p6^A&JO`mQ zTduvx0vQM+&wsRFjCz};=Lhrk@;=zwR)gS%#a_i?mga&m{-bnl4G5i;sPw$3w1YFk z&3}Ut`U@$A@^fBQqB0`2q-_%g)~1O|w9q!>SY31scWdk#?$x+&cu?bGn+PX|-62j7 Qb%b+MU2~H#!bQ9L3nc`~;1sYOI~W`%wTxRsTUVA9M~RSKSq_(8 z{y-o4zz?8rJhTsx&LlHs+P?Q^^oMl1M;5U|a7br(z%!Qi9PRmb&+fN-&fow3{wIJq ze(<9UE)hZyZg?0Dtjgo~8iOk|o)_U|m|ZQeg*C%cO+(hh z%T-g=Dn?i?Y2jK;nVAkREyZW1qo%T=S%lCq)iKGcnsPHsWrm4R`gOp__^v6(MubBg<`731Mnb8*6^DWt#t4Jg zsy01kI278wgg^s0%2V_aL;suHp~M{H0qT^P{DQMnFHSHp3dJZ+a==pzM?x_vwQE0- z@w^uy(p~4eXSnWJ3JTZdG?-vG)zMlsmYP%RimBBo?>_ht4&pp6&^}WcDHqMe6AY)* zotL*!CnDk^!^wM{wYRqx@!=9?L|hKyV_ezGKgnv8(p5#~jHxs9ADUdssQeG}062vS%VG!$0lGD~gG0I^lgq{9g58?)QwmX~1-N|N(u{+6RBFlFY z3sQa3m;QKki9RLfiWItB!qM>K91=V!Nyf5!_}gBFk$d|J+B^*Z|B9$E%}HZgy3s<;r9Zd1_^iMr!NE=xA7ysS4=7qwf~)S8*LwfKySI&LbH zOUx&-MOt5!Qg^8|Sc-q6M%$B2FGh21UwVlG@!Lfyy_j=!g?P2BGW4c3L(MeqmsB$+ zmvoxx;{@09vZ?X0Gbvar8WDb~bHF=v@CZXdt4o%wtnnt!AW&<&OJ{=LUmYGs@~iva+mKWvhh{r06PZPG6&< z4N+&>AEHpVee;(dS?c2Qa$V)e9Gzdus>!Qqe^s&{Q|}|vyDP~(qP^n;Ao2t?qt>ue z22URmrpF#8oqTczRU1~jLT_{2rqR1z)v00Y>Nd#1S2Jx|JvJwzI$cQky?|I-Uy;kz z2U1N|h>c!4lw?a;p`&PQKly8|m?Cjj(VeT1U#d1tMNN`B3Oej0>e#sFvt&E>L7!-h1)cj zCbG|se*7cqn-e7gNTOJnJ^ac;-hODJ?pq!o7v@glt$z1?TFz+TuU^7P~vN?-y4 zCh-|b!KM;EM}bBRcX5xN9N-pda^1kN`)7#4GYGC=710yRoMzJ}~L zcoU-S1eqQ!xI9CztRE-qL$9olJtyd{wpjew7S5w6Q3QCfl{cdbE!5L{qW<&-R3FMv z9bd2W2$Q7%_tiZ#yoK@C9edIig#ea`V*D3C#ZHnBE6^OUf6zlN1DTgNSJ=R$`wvVN zTxX<$a8_!{=SZG#+Mp`=_>l%T3EzCF1g525UBjxulcCH<`hGlKA19fkBdBOI4D1_A{u_jy$&X4N0Oc znW)2SOBP8!k{jD4a>C&q1 INTEGER_REG_SIZE; + case StorageType.FLOAT -> FLOAT_REG_SIZE; + // STACK is deliberately omitted + default -> throw new IllegalArgumentException("Invalid Storage Class: " + cls); + }; + } + + public interface StorageType { + byte INTEGER = 0; + byte FLOAT = 1; + byte STACK = 2; + byte PLACEHOLDER = 3; + } + + public static class Regs { // break circular dependency + public static final VMStorage r0 = integerRegister(0); + public static final VMStorage r1 = integerRegister(1); + public static final VMStorage r2 = integerRegister(2); + public static final VMStorage r3 = integerRegister(3); + public static final VMStorage r4 = integerRegister(4); + public static final VMStorage r5 = integerRegister(5); + public static final VMStorage r6 = integerRegister(6); + public static final VMStorage r7 = integerRegister(7); + public static final VMStorage r8 = integerRegister(8); + public static final VMStorage r9 = integerRegister(9); + public static final VMStorage r10 = integerRegister(10); + public static final VMStorage r11 = integerRegister(11); + public static final VMStorage r12 = integerRegister(12); + public static final VMStorage r13 = integerRegister(13); + public static final VMStorage r14 = integerRegister(14); + public static final VMStorage r15 = integerRegister(15); + public static final VMStorage r16 = integerRegister(16); + public static final VMStorage r17 = integerRegister(17); + public static final VMStorage r18 = integerRegister(18); + public static final VMStorage r19 = integerRegister(19); + public static final VMStorage r20 = integerRegister(20); + public static final VMStorage r21 = integerRegister(21); + public static final VMStorage r22 = integerRegister(22); + public static final VMStorage r23 = integerRegister(23); + public static final VMStorage r24 = integerRegister(24); + public static final VMStorage r25 = integerRegister(25); + public static final VMStorage r26 = integerRegister(26); + public static final VMStorage r27 = integerRegister(27); + public static final VMStorage r28 = integerRegister(28); + public static final VMStorage r29 = integerRegister(29); + public static final VMStorage r30 = integerRegister(30); + public static final VMStorage r31 = integerRegister(31); + + public static final VMStorage f0 = floatRegister(0); + public static final VMStorage f1 = floatRegister(1); + public static final VMStorage f2 = floatRegister(2); + public static final VMStorage f3 = floatRegister(3); + public static final VMStorage f4 = floatRegister(4); + public static final VMStorage f5 = floatRegister(5); + public static final VMStorage f6 = floatRegister(6); + public static final VMStorage f7 = floatRegister(7); + public static final VMStorage f8 = floatRegister(8); + public static final VMStorage f9 = floatRegister(9); + public static final VMStorage f10 = floatRegister(10); + public static final VMStorage f11 = floatRegister(11); + public static final VMStorage f12 = floatRegister(12); + public static final VMStorage f13 = floatRegister(13); + public static final VMStorage f14 = floatRegister(14); + public static final VMStorage f15 = floatRegister(15); + public static final VMStorage f16 = floatRegister(16); + public static final VMStorage f17 = floatRegister(17); + public static final VMStorage f18 = floatRegister(18); + public static final VMStorage f19 = floatRegister(19); + public static final VMStorage f20 = floatRegister(20); + public static final VMStorage f21 = floatRegister(21); + public static final VMStorage f22 = floatRegister(22); + public static final VMStorage f23 = floatRegister(23); + public static final VMStorage f24 = floatRegister(24); + public static final VMStorage f25 = floatRegister(25); + public static final VMStorage f26 = floatRegister(26); + public static final VMStorage f27 = floatRegister(27); + public static final VMStorage f28 = floatRegister(28); + public static final VMStorage f29 = floatRegister(29); + public static final VMStorage f30 = floatRegister(30); + public static final VMStorage f31 = floatRegister(31); + } + + private static VMStorage integerRegister(int index) { + return new VMStorage(StorageType.INTEGER, REG64_MASK, index, "r" + index); + } + + private static VMStorage floatRegister(int index) { + return new VMStorage(StorageType.FLOAT, REG64_MASK, index, "v" + index); + } + + public static VMStorage stackStorage(short size, int byteOffset) { + return new VMStorage(StorageType.STACK, size, byteOffset); + } + + public static ABIDescriptor abiFor(VMStorage[] inputIntRegs, + VMStorage[] inputFloatRegs, + VMStorage[] outputIntRegs, + VMStorage[] outputFloatRegs, + VMStorage[] volatileIntRegs, + VMStorage[] volatileFloatRegs, + int stackAlignment, + int shadowSpace, + VMStorage scratch1, VMStorage scratch2) { + return new ABIDescriptor( + INSTANCE, + new VMStorage[][] { + inputIntRegs, + inputFloatRegs, + }, + new VMStorage[][] { + outputIntRegs, + outputFloatRegs, + }, + new VMStorage[][] { + volatileIntRegs, + volatileFloatRegs, + }, + stackAlignment, + shadowSpace, + scratch1, scratch2, + StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER), + StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER), + StubLocations.CAPTURED_STATE_BUFFER.storage(StorageType.PLACEHOLDER)); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/TypeClass.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/TypeClass.class new file mode 100644 index 0000000000000000000000000000000000000000..d0577e03153231ba6f48152d62ac189b1a56480e GIT binary patch literal 5575 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 Q6C9^v{2Tw_o)Y}`|0TbPxc~qF literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/TypeClass.java b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/TypeClass.java new file mode 100644 index 00000000..b04d4abf --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/TypeClass.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.ppc64; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.ValueLayout; +import java.util.List; +import java.util.ArrayList; + +public enum TypeClass { + STRUCT_REGISTER, + STRUCT_HFA, // Homogeneous Float Aggregate + POINTER, + INTEGER, + FLOAT; + + private static final int MAX_RETURN_AGGREGATE_REGS_SIZE = 2; + + private static TypeClass classifyValueType(ValueLayout type) { + Class carrier = type.carrier(); + if (carrier == boolean.class || carrier == byte.class || carrier == char.class || + carrier == short.class || carrier == int.class || carrier == long.class) { + return INTEGER; + } else if (carrier == float.class || carrier == double.class) { + return FLOAT; + } else if (carrier == MemorySegment.class) { + return POINTER; + } else { + throw new IllegalStateException("Cannot get here: " + carrier.getName()); + } + } + + static boolean isReturnRegisterAggregate(MemoryLayout type) { + return type.byteSize() <= MAX_RETURN_AGGREGATE_REGS_SIZE * 8; + } + + static List scalarLayouts(GroupLayout gl) { + List out = new ArrayList<>(); + scalarLayoutsInternal(out, gl); + return out; + } + + private static void scalarLayoutsInternal(List out, GroupLayout gl) { + for (MemoryLayout member : gl.memberLayouts()) { + if (member instanceof GroupLayout memberGl) { + scalarLayoutsInternal(out, memberGl); + } else if (member instanceof SequenceLayout memberSl) { + for (long i = 0; i < memberSl.elementCount(); i++) { + out.add(memberSl.elementLayout()); + } + } else { + // padding or value layouts + out.add(member); + } + } + } + + static boolean isHomogeneousFloatAggregate(MemoryLayout type, boolean useABIv2) { + List scalarLayouts = scalarLayouts((GroupLayout) type); + + final int numElements = scalarLayouts.size(); + if (numElements > (useABIv2 ? 8 : 1) || numElements == 0) + return false; + + MemoryLayout baseType = scalarLayouts.get(0); + + if (!(baseType instanceof ValueLayout)) + return false; + + TypeClass baseArgClass = classifyValueType((ValueLayout) baseType); + if (baseArgClass != FLOAT) + return false; + + for (MemoryLayout elem : scalarLayouts) { + if (!(elem instanceof ValueLayout)) + return false; + + TypeClass argClass = classifyValueType((ValueLayout) elem); + if (elem.byteSize() != baseType.byteSize() || + elem.byteAlignment() != baseType.byteAlignment() || + baseArgClass != argClass) { + return false; + } + } + + return true; + } + + private static TypeClass classifyStructType(MemoryLayout layout, boolean useABIv2, boolean isAIX) { + if (!isAIX && isHomogeneousFloatAggregate(layout, useABIv2)) { + return TypeClass.STRUCT_HFA; + } + return TypeClass.STRUCT_REGISTER; + } + + static boolean isStructHFAorReturnRegisterAggregate(MemoryLayout layout, boolean useABIv2) { + if (!(layout instanceof GroupLayout) || !useABIv2) return false; + return isHomogeneousFloatAggregate(layout, true) || isReturnRegisterAggregate(layout); + } + + public static TypeClass classifyLayout(MemoryLayout type, boolean useABIv2, boolean isAIX) { + if (type instanceof ValueLayout) { + return classifyValueType((ValueLayout) type); + } else if (type instanceof GroupLayout) { + return classifyStructType(type, useABIv2, isAIX); + } else { + throw new IllegalArgumentException("Unhandled type " + type); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixCallArranger.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixCallArranger.class new file mode 100644 index 0000000000000000000000000000000000000000..51dcd112b83f3db50be5152581a089605996ec12 GIT binary patch literal 508 zcmb7=&q~8U5XQgFpQgrYwfX`c1g+viDP9yI282TJq7?DAN!PkHCS{Y9K9m-`Ym&85QrM-5=ESxk-P0Dut&OB@JY=x2wEm>d=!wcP~>10P0AQ}pWM`0 b_Jh$ma(j-nzR0zoq_ar2e<2yxXZ>66u&`r% literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixCallArranger.java b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixCallArranger.java new file mode 100644 index 00000000..9ee9ad1e --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixCallArranger.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.ppc64.aix; + +import jdk.internal.foreign.abi.ppc64.CallArranger; + +/** + * PPC64 CallArranger specialized for AIX. + */ +public class AixCallArranger extends CallArranger { + + @Override + protected boolean useABIv2() { + return false; + } + + @Override + protected boolean isAIX() { + return true; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker$1Holder.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker$1Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..591a227dcd5dfac5c84029aebe29d52dbe049d9a GIT binary patch literal 718 zcmb7C$w~u35PhADnK&6u+;=_bA$qVC7Z61VLnMJ11B&3WGihVTu_w%o;%|uuLBS93 zqr~dO1&_IOb-n6(^}4D)K40Gfcvx|eLfVGqVh9HZDbj?JFQ!;bRr`y0)8DvQnfV~O~t!ie}9(?^~g)=vC;7McWX-D%E*C@^e}R8 zZH%}WMV{ecV3xJ*N*J_c#E`Al&o4@KugtJh8<^*i!SceEWXO{|S--z)%IHEg1471Y zp)Z0<5h>$;gI02*Vur)POZ`ZulG!6a`0k{09^Oa3JW;0N#Q#=pnhB7yvi5^8R=RyE zlbf*RVjc?&xwcHII!=W4DRr;7KDZ%Lx2m;_ygTDn%Q@ zs4Pv3ZpNb(A*4VzPL>&D;|1)g7apV2giUaqPPhL66PP3~i>cq_)gBp;dxL%Tg5hU4 jhJxXbVha|g2}@xHvt%t=pgAn|5F1Nm9eST5yNtpYQU$8O literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker.class new file mode 100644 index 0000000000000000000000000000000000000000..745bbb7bb012e46397b76343fe7b6dfc4ce06a4d GIT binary patch literal 3552 zcmcgu>r)d~6#rcaY!cUk_@vbu1r>-G5v0{nYX~5rA)yASR9m~*+=PW?H*PiveZTC} zKDC|E@9p$sOJ|_1GktvRpVaAedhTw31c{9O&^6g`wREw1H^kdoFy`MlcO6H>H=P()i88;kb##5H4#zgEy8)jYksEL5A-5L(2*K;e}6vU&c1b49BWUh@=a)rKq<1K0|$~hT69F z$vQGi{Jatx84k=S^GZlpjNFugb7 zDHOs!?7?0M`(!lZQHI9#`vJ3<);WV`d}@pg-*F$Scx1nf19+TadwS945uIE*#|_(2 zcw|*!kA%Yvhu0;?be-oEJ!0jGf_iX4<#}5(4GFCbd)Mhwwxt=l{-P$L;71F5UL0fC zopCe^kgtlW9hl>DX>J9?eY=bf1j%noKF^H|LuXr=)~>j4xeqE{pg6UlQ;0aRfisz& z;i~-rPA^U}YzruMz|3X~+;+4%B}8>I>~9;X{-zhF8JYuyX|t$j0%;!T=@hOED8iRK zBUE}q#*;WhD6~yiUxr;3kt`YJ$039T#`?%dn;AYSB6d#3(>TviXIc)n_pFLCG&9ss zPbbAW;i4Z=2?H_)F~rd1M5Tg+!QUUdaCI;-5Q`*8CD+pxBw;Ux395lMWTzlyMa=F?3b+ zO|@c9;EF~P$wVv~iC>LJrjirmDGHq%ilVLQp;0AI&om${Lj~0i-$-OKay6bzTwpl5 zNyy5|ZEG?cH;tUbo|TcqG-a#99!rcf9NCgPX4n*`8O%!1Wz4}K+*dU*HLX}YGeJ5R zs9>v#VHz5R)6E7tGRlLx3a~P5H^bjUT$gIun$O5nDXLY9U9_lML@PboS7v&tOqHFi zDp!%t=fYGG*b%AnO&Q5O5b zjc5Nc;@&=0FAY2Xlv%V?KBS51V`t?|c0%+a!bgG^N*#hiCdUkeTh2Vg>9gJ)+a!GY zps8=Gl0)X+SB4~fArkXJlUJz}kQQ!DkZ_x!Wh)lSf9lA|EUoCGQs<>Pk71uEcC?!G zRf9Yv_;3vtofPO~Kds{DSpxf>RtB5?*E^@(L{GD3iL#qkL0i|c0_g|Z)HtMmT7h18 zXuK%WPLLB3=1B;N6)o8nz{ChGrn$R;UD$rjcl!=*2LC|A9oz{1j)t?IX3x*q!LWqg z-@+0fkI_7UgGASP4~M4ip=D|XN1Bc~DhaDIp~C z4Z62ryRgpI5e%##CakJ;ta_Z>1e`}JA~;1u%oPkkqao%NhH(cYj-?%B-Cn$k>sX*2 z*;TSx>=yB|qlcclwH7-GM{`gPOe#B)F6Bm?^I21vG?{R9d uLHhcD?rQKMKBCn_R5kdRc86&%FnJS=_=Mj0tlo#uiQ`LJZ_)Zyz3*RpFvNcV literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker.java b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker.java new file mode 100644 index 00000000..503dac3e --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/aix/AixPPC64Linker.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.ppc64.aix; + +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.ppc64.CallArranger; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteOrder; +import java.util.Map; + +public final class AixPPC64Linker extends AbstractLinker { + + static final Map CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT); + + public static AixPPC64Linker getInstance() { + final class Holder { + private static final AixPPC64Linker INSTANCE = new AixPPC64Linker(); + } + + return Holder.INSTANCE; + } + + private AixPPC64Linker() { + // Ensure there is only one instance + } + + @Override + protected void checkStructMember(MemoryLayout member, long offset) { + // special case double members that are not the first member + // see: https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes + // Note: It is possible to enforce 8-byte alignment by #pragma align (natural) + // Therefore, we use normal checks if we are already 8-byte aligned. + if ((offset % 8 != 0) && (member instanceof ValueLayout vl && vl.carrier() == double.class)) { + if (vl.byteAlignment() != 4) { + throw new IllegalArgumentException("double struct member " + vl + " at offset " + offset + " should be 4-byte aligned"); + } + if (vl.order() != ByteOrder.BIG_ENDIAN) { + throw new IllegalArgumentException("double struct member " + vl + " at offset " + offset + " has an unexpected byte order"); + } + } else { + super.checkStructMember(member, offset); + } + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.AIX.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.AIX.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv1CallArranger.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv1CallArranger.class new file mode 100644 index 0000000000000000000000000000000000000000..19d0676464806fea4e469588312dd787b99fc923 GIT binary patch literal 518 zcmbV|!Ab)$5QhKR-R{;}tyb{vLC`7&ixfc-YC$LzFG>+_X&Y?)(rOofB!lc)r-c2^|Hd51l9`++1ZPy1Kj0HwKRQ~&?~ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv1CallArranger.java b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv1CallArranger.java new file mode 100644 index 00000000..a9bdeffd --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv1CallArranger.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.ppc64.linux; + +import jdk.internal.foreign.abi.ppc64.CallArranger; + +/** + * PPC64 CallArranger specialized for ABI v1. + */ +public class ABIv1CallArranger extends CallArranger { + + @Override + protected boolean useABIv2() { + return false; + } + + @Override + protected boolean isAIX() { + return false; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv2CallArranger.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv2CallArranger.class new file mode 100644 index 0000000000000000000000000000000000000000..a3b3d9ab1c6d489b943da33642421dc7547a9bbb GIT binary patch literal 518 zcmbV|&q@O^5XQgkzt*){t>E2*pj8Y=DS{%@1))&9C`G(w+gMZAY{~8xAIgg-!GjOr zLy41Bq*_5RhwsZw<~K9s_3iluK!mjr4%`a78hiu{JLBOkS2~wQi-cdNMyiqKB367d z8MIqG5=qiAM(B|=48f7oDnDj$x3>EgR2kZT@QKpJJ@1@!r~BVqc~Lr)4E3JU@~pUv zrMVDsLYYP{9f+hajI!}((#vmD#&FR4-?&4DYLUrujdJ-b247{J?j=Kbo)%^xPn8|M zKDX)KSWE>rP@#Xb#|5DXNEayLJK7l>b#X(4FpFz+fY3-wce2F3t%cxVv!n@?Q d&hZ|s&XAikr1M3t%#-d^3K literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv2CallArranger.java b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv2CallArranger.java new file mode 100644 index 00000000..82cbaa0d --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/ABIv2CallArranger.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.ppc64.linux; + +import jdk.internal.foreign.abi.ppc64.CallArranger; + +/** + * PPC64 CallArranger specialized for ABI v2. + */ +public class ABIv2CallArranger extends CallArranger { + + @Override + protected boolean useABIv2() { + return true; + } + + @Override + protected boolean isAIX() { + return false; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker$1Holder.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker$1Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..82921a8020b9c208b8da67a7a6942e043739466e GIT binary patch literal 740 zcmbVK$w~u35PhADnK&6WM&rI5^q?N>2rh^lGAIUO6bypL&ZLbU#~zuPh`%Ks0t$YB zA0<}D4Ls&j%d4(e)m8QW@$v@1!@PqO(l#s?eaJB6TjD|RKR>?j? zdTII6MwVft)wtzKCo<9^;MZX!Ra0|OSN#6o-(2T`((OlHG4lM}+gvB>Rz?nNr2CPB zYh%F0Ach$BdSY5!I|+k^j2N=z>P79a>K!p`ReIvuVX(ZgAsL3KO<8T<)n!x@^?;B< zCGs*BG$d|{;R4x7=+^X3L^>?KGAdHo6 zp33AVY`B=hG()Z_ld_Hzp?yl;URv(0G1E|0#>q(-)6U(p)-v(}5yz4~oB5hIO0>Nc z-3_DCv_GU15+5Sd!>Odg`~c%O5$wJ&S!z0W`Y{`EJ20=`XQ1fv=fI>wL` zc>JAH(rt}2H zOO@KLQ7LQ+JS@MJty~)8NNGsxxCC9`UaS?P-tj%N;fFB@B=eSI`Rf9sGqd|COkh&O zl#VNy7MPE<66RGfZQJlX(>YLCj2TZ#$IAkX!%~QT#=s}=zK*N-Kw#1gjcvF;I1Sns z_-Us6(mXb^HhmD`WA{jAx21pRHg`|jG8cJyhI+Bnq%Xv;>sxkq+icU-E!@_S(QyZN z1#Z4(@{Fu~)9%W$dE$0`fz&f&-*{23R-OvnjZiT_Ia6(wUFRV1Fr#A@b8MpE^HOD3 z;LgymOO8)E7qF;dNkp_SPNkSx%HgDr32}goQ`ig4cdG( zL!WUK_NKa^r9{DP(!?ZNOIEtC>eAaa>o!lO%Pv9NH$6-3dxr`C&?17uJ_&F2T77W23>X9gnj7}I06B}xuzxBDqtBk1c>R3_{khO~J_~eox6GXk_IMOTFW~U>$O@_CNh7t*l z&2`wkV8Z{KAsWi6UC!t7Sye@9y4RqLBJ5NRRe{^XK4Dk#8mYD@vCKI&&f8YtnwnIU z%iN9N3nY=k3RZdYfG0O7)sr}d_=QqnjsMBubcOo74tts_luCDO?hk0caxoI9rYXTy z0$<`GS4y2q+$AX!>SpR0_>Q{-&(f#3JioB`JKj?cLo1=fd|+WN)aqHFJ|5w#z-k&f z(F5-Rr)aDy~F zIS27RV^+`9DLxN=_x{BEZ@8}T456P0H0DXt0wyufU4idLuz^j=1hqy` CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT); + + public static LinuxPPC64Linker getInstance() { + final class Holder { + private static final LinuxPPC64Linker INSTANCE = new LinuxPPC64Linker(); + } + + return Holder.INSTANCE; + } + + private LinuxPPC64Linker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.ABIv1.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.ABIv1.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64leLinker$1Holder.class b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64leLinker$1Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..b02686818dcea8477e72178ec232d614fddebc57 GIT binary patch literal 752 zcmbVK$w~u35PhADnK&6u+;=_bK|R zlvo|NgST92dDZo*x~kqkUfuu%Sn!ZR)`jDv4>^WXTigq-g=z7VMq7p{LvBYImF_ZR zmsc)aG%^R*vDq|xwzlvh1T84{;;&*r9Mulr-IuE>N<>_g#QPGm@8yS0Wk?ltT zzKa1LgD5iW^~klfeiZ4Zj2ZIP`q}w@Jvd<4s`bdW&EN!4Q!*5(Rax)cHe`G*8k&&d zS`-R>A!23yZ_r7vRl=~}Yr&uPsc?QLq=9uO?43oOIFyIV)}8o2z%{!a>hZvYI!csj z9n17OYWkSQ3`3zM)2c~QVM0pZUS8?7IoniSCh1X>(Ek0ZF)|LcND@h3&V9`tW!htg zZirEF+9X-lqaz}uL>4E_EVB9x_Sg*%k+fkO946_1J-`S?$;)HxH+iv31{7Z5UOuD$ l37(~3_@gMp!8lT6^!cFX!)n{`?Doi5EExU{FIw#}Kjt zk6*P8ijEh`z_Z=rt{+He&nwyur`T>cmllhz<8^;1TIzpm%UoJ?CD#Wsn3&)2-Ifdl zhRc;&-Kdyr0*|bBL@VVnjGTtNj!V!5?xo@wjZPTY%`o;tAiL~%PPig4I61YG!w5z- zjOn<7ae+cAN*tSMyRH!gwzsF^7&4xe4<883_6s8U866+N`#L_rhXSK^47Tcj?=^`n z@Z+TQ%09GG%jA3taBGy4{W){po*pG%cdD>79t(tA*XhI&1Rkbx^Y-!;xMCWWYNc!%)=SIyuDV^XF@Z6I-OzE1n|7PVZsE3u2_1KE zSK#KGT%M$B$9B8YvXA_3D3E(*>=-YtYUQcG-9$1jP@bsnTE4dzS(wx@g=scY^m(~b z7r4{+>#`Rzp);7(FsGx4`vMcGT-5gMK(@9SR!3m0X?wosFz>P7Jo1v+zrfpz3N;aV zzt_FOJf)RP)i`DBup3AL^DODhiO_3d;E<%m$%%8D@-?d=4xqGB61cP{!?M>2ZLdkp z(j;xB)!5rBgIF2UZxLja?IkPS*9{re?S{*famy!dJ9glxeeW<6?mOgg-0^m0K$_q5 zH!CLL`k9uD+Mg-k?X~;G1#`hL5YYU%-vyYpv>4A$27!EN2V_W@W$7z+)L2SnWbORf zJLX|{x#{*Ma=zwwgQi?}6m?hW(YY&RPWiyhRb(e*K1nla)XSbH1JkuT9m#DrzGXC& zdAp=W+iz+xE;y(@4{ z%`3`z?gsDxS>&*QMV@@YlN*%k$s9xcOewI$|7>)+Kz&|{JHE! zl;A3ZFY%BorA{U8vXmKhKlK2<382wz30 zd6cjm*~{Z=tYDCuyj0Tgub#&@Qt%(A;tLMAZ)j0bHAg!tHd1x{Jo0)XcEyB>Jto{> z8lIezc%MG2XY3fCN56Z2pztfMD?VfDM9)&HW2aUy=0y literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64leLinker.java b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64leLinker.java new file mode 100644 index 00000000..e8305669 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64leLinker.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.ppc64.linux; + +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.ppc64.CallArranger; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteOrder; +import java.util.Map; + +public final class LinuxPPC64leLinker extends AbstractLinker { + + static final Map CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT); + + public static LinuxPPC64leLinker getInstance() { + final class Holder { + private static final LinuxPPC64leLinker INSTANCE = new LinuxPPC64leLinker(); + } + + return Holder.INSTANCE; + } + + private LinuxPPC64leLinker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.ABIv2.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.ABIv2.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture$Regs.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture$Regs.class new file mode 100644 index 0000000000000000000000000000000000000000..b2f4bffc20ec7c18b0481ff8721173e511662c63 GIT binary patch literal 3641 zcma)9d3;pW8U4PO?Im2~atA^}0*FQg1Sb1JP=P2AOoAjBK$bcQlVn1e;LL!4xC7eF z+Fk8#?QU%?ty0@sYj4zT? zkuKd?A%PT?NwJXGF8q}X&&FTJDJHA(z$GEA~`adOJ_#2$<$CLnakvd_qR4D`@09a23wm~<%Y*H z1>AREF0C@nUox7`^`}QOd0ed0v9P=6-%A)M>adVJ@*SvGsr!E(8cHSpJeTqhuQF2YpBx-$2&D#?-|OW$M&?Fx zV<=}s9;JMak#i%tDU|ad7bu@^WML#XhqBnq_5LPHj4X}hmQa#jZt!x0k;X`F4W-%3 zjb3gw(iX{Wp>(K}YHyF7*){(W}>rH+=n~Yo$>j=Bq>&;%@YUIjTN80UPZ}Iw0 zBhQO<#7%j<)$7AXcEvjKj(EMz>tjYTv5vsIq35}tJw~#zj<|ch&h_Ms>65r=_CcEFrdtx1lAHai03iZC`j~jWvFZih=6O*aJ zb9L)OJZR)0e@QTcJAIH>aH$_M^5ICwogSgim-DERk3~B6?&H)M;gd!_73tW!&roNC zlSV!l>Dar^Q)h%P8u?PBWADB~oe`ce^0i3E)_t8iU(Pp;d@ItibKmiLo_qa0BTq#- zcJBMsx&9v-`B9`}=YHb#s5pLR9NrsYJ!GemCiI;85r%)E;f*Ty}wt1C8<3|dm{%GqZ=ZJ zPuXa+KX$O*;;zYEe!}%+vgy8kdxp}vO{t*?D6VI6I5jbt%4PibSS&7#WiWU;&pdPf z*VIDZaK-RMJgO@OCimrr(`z#RiB7^`5_e#j9q)rc5lM9eKB1{D#LiHK1|#NZ)f(hxCPh!`bAj1D43 z1reixh*3a9>nEbs6VcjmM06)2x)BlGhlp-NM0X*gn-I}Gh-el>^adhY0TGq&(HA-qbxlMW z6H&E96e$rkNkj<}QE@~R7!mbEMEMX=EJTzB5tTs151)viIT1fI9lY&PDuH2nO5v(lFTY` zvq@@8-8_={Wv-57LFg8dTwqJxGO~JG=9whwliFTY`>l94w7AK zE8X>EH`-b57P6zZ%H2lx0$c4~O!g8x+r5nJ6}HB`n(QuH>t0LtdOOFxiR{gGu6rxl z+wDB}F0ywQx%Zxs_Z^oH6uT2750|))kbJb%Jx210GWThc&xY=Ck}qKAzD)L2?A()N z-@wj&o9w&Txu?l~fSvm>*-x=^r^tSZo%;>h@33>vko^%m_ZPCiVdqYJhJPSzLW@XC z?DT|&q!rdBbSmjIn@Ff5ondDrbQWo~ote;D(z&)Wq4P=4wX+hsfOMg)O6UcoOKo*R z>q#5!?1Z+Ew%MA5E+<`KYZH1g=_)%Xp_h=Zv2zpJO?sJ~m(V`a%l(g6{f`%Qwi0}; zl*>AC(k(TzUg~hrT`E1&D!p*~plpy$IOOh>jWQ9JwV@2DlVPouUAjQhT8|U$av8%!%4m;_ zqlk9vPMOeA*`s?UtA}J#kKh!0yIiezN>1;Qyxu1TeGn(uM`gdBlxy?}IiOF;K|O`j z>$7q#TKC~#id+{|%Jso~xgl60HwJBTQ?OcY4tnL5V2d0HhUI9Gm1Ds{99oNXEA}AJ UD|MSksnG4f3Y4-1-y!Ay0$7fZkpKVy literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture$StorageType.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture$StorageType.class new file mode 100644 index 0000000000000000000000000000000000000000..439f677bd86f3440e5b49f1296d23118f38b30bf GIT binary patch literal 430 zcmbV{yH3ME5Jm5hhx3FG9)g~lZKBi|2(7AxZt<$$_=%KF|FioJRA9Fm|IFp_7z5m5E7S2*TALQn${5&{_y>rlmF> z&IqIb)Fbp}QVJCmTx+4NPNi?t7J_rC;~EV#EqP8FEz9i+cPw`++_T)T@UiQKlf&%* Sr-vNk+-ArABn)xUZ2tnrsa?AO literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/RISCV64Architecture.class new file mode 100644 index 0000000000000000000000000000000000000000..22b6f2f44e631459db3800ae87c1ce280fcf9db4 GIT binary patch literal 3506 zcmd5;TT|Oc6#f>=*s{eXG$i5Dlq8TCa&ePV(!^Kl60)U9%Kp|Hw}4nyZH!!n%P48F*CK7b&@^lE7>YFG}pE!~VR zS8Q&St*BlwqP9^hZcI%^v#OTNPff<{;)>xAO5Nt8np3g$GS5A&@&G~%lm7=L0EOXf zlcZ{zysVpXyIf!AmXmr?kJ7=|P2;fjL_hA_+! zbSe#|496q;rx0iur$wkfVCX-H4h86pa8SDd<>x(1Lm0t1fi%i+Dw5FDeTKxw^Fryo zP`W^F5K1Be#u?7H#g8Y{8D1;eMwOy1L&ik~mvEUZQ!`pFo=K({F3h!`-jXn}0HO?I zkJ@YR8WWRo71sjzNWmmNK8&B{)C+T!qAqfz#?YOMXJ=EnrTENDHl=9{Rau;jLaJ7T0i8NW|M zshK5mT`uKmgb+bo1SP>(_7J|Un=kh0NN#+aS}JAKe>>t`(-Ao@i-JgbI@Xqdt7{oT z+0^XRjiG-^nyt}eIkv`ylxw!?R84dia}{T)!wa#ROlE( z*r;iaUR)DJnn9wn^^od*(Im_+cVJ$xdP@Zz($S1(o}Nk^#gS0vc9xfo8XXP{HzEg> zmGjmlCWb39PKDTY<8JE|qZM>*E*Hq%}_ zMbcI3POCysqurv>vr#drnwxwVRr-*9;C32%yY4uYXNM~Mrm7W z4%x4x4W}upWpUfRxNve=*voux3kw}OQe?X3G0f1ZF(A%kDmH^iW0v|pBe?@AweP;s zzK6Np@p&50>}dyS7F`)hV}TH&^k?+oObjZ_!#Ftp~aGyhRCnSb` zA_ZWKUa^jNhUgXCMtXxUaZY?r?;yOmgRaGG^z`*^p>JplC$=!Kjrad((m6p30oO51 zNBoF)eeLdp(C7Jbs-#ciB@MeU9j z%fD}dR`30q=U4n>pkEp(6D9pO=0DJ;182Zy#X_9nIGEns03 zD1F2eM$rw5j1ss9_7}Q|Dv;ShWN{M{{@-wA(Kn$jN*A?;e2L`Co;)B?W5BQVclHMc zf&=mzx>A)SndI+wx5GIX)peds`IP(x o6Jk@ambi}5ayIpKpazHjA`|Ka{g~uFk^= INTEGER_REG_SIZE; + case StorageType.FLOAT -> FLOAT_REG_SIZE; + // STACK is deliberately omitted + default -> throw new IllegalArgumentException("Invalid Storage Class: " + cls); + }; + } + + public interface StorageType { + byte INTEGER = 0; + byte FLOAT = 1; + byte STACK = 2; + byte PLACEHOLDER = 3; + } + + public static class Regs { // break circular dependency + public static final VMStorage x0 = integerRegister(0, "zr"); + public static final VMStorage x1 = integerRegister(1, "ra"); + public static final VMStorage x2 = integerRegister(2, "sp"); + public static final VMStorage x3 = integerRegister(3, "gp"); + public static final VMStorage x4 = integerRegister(4, "tp"); + public static final VMStorage x5 = integerRegister(5, "t0"); + public static final VMStorage x6 = integerRegister(6, "t1"); + public static final VMStorage x7 = integerRegister(7, "t2"); + public static final VMStorage x8 = integerRegister(8, "s0/fp"); + public static final VMStorage x9 = integerRegister(9, "s1"); + public static final VMStorage x10 = integerRegister(10, "a0"); + public static final VMStorage x11 = integerRegister(11, "a1"); + public static final VMStorage x12 = integerRegister(12, "a2"); + public static final VMStorage x13 = integerRegister(13, "a3"); + public static final VMStorage x14 = integerRegister(14, "a4"); + public static final VMStorage x15 = integerRegister(15, "a5"); + public static final VMStorage x16 = integerRegister(16, "a6"); + public static final VMStorage x17 = integerRegister(17, "a7"); + public static final VMStorage x18 = integerRegister(18, "s2"); + public static final VMStorage x19 = integerRegister(19, "s3"); + public static final VMStorage x20 = integerRegister(20, "s4"); + public static final VMStorage x21 = integerRegister(21, "s5"); + public static final VMStorage x22 = integerRegister(22, "s6"); + public static final VMStorage x23 = integerRegister(23, "s7"); + public static final VMStorage x24 = integerRegister(24, "s8"); + public static final VMStorage x25 = integerRegister(25, "s9"); + public static final VMStorage x26 = integerRegister(26, "s10"); + public static final VMStorage x27 = integerRegister(27, "s11"); + public static final VMStorage x28 = integerRegister(28, "t3"); + public static final VMStorage x29 = integerRegister(29, "t4"); + public static final VMStorage x30 = integerRegister(30, "t5"); + public static final VMStorage x31 = integerRegister(31, "t6"); + + public static final VMStorage f0 = floatRegister(0, "ft0"); + public static final VMStorage f1 = floatRegister(1, "ft1"); + public static final VMStorage f2 = floatRegister(2, "ft2"); + public static final VMStorage f3 = floatRegister(3, "ft3"); + public static final VMStorage f4 = floatRegister(4, "ft4"); + public static final VMStorage f5 = floatRegister(5, "ft5"); + public static final VMStorage f6 = floatRegister(6, "ft6"); + public static final VMStorage f7 = floatRegister(7, "ft7"); + public static final VMStorage f8 = floatRegister(8, "fs0"); + public static final VMStorage f9 = floatRegister(9, "fs1"); + public static final VMStorage f10 = floatRegister(10, "fa0"); + public static final VMStorage f11 = floatRegister(11, "fa1"); + public static final VMStorage f12 = floatRegister(12, "fa2"); + public static final VMStorage f13 = floatRegister(13, "fa3"); + public static final VMStorage f14 = floatRegister(14, "fa4"); + public static final VMStorage f15 = floatRegister(15, "fa5"); + public static final VMStorage f16 = floatRegister(16, "fa6"); + public static final VMStorage f17 = floatRegister(17, "fa7"); + public static final VMStorage f18 = floatRegister(18, "fs2"); + public static final VMStorage f19 = floatRegister(19, "fs3"); + public static final VMStorage f20 = floatRegister(20, "fs4"); + public static final VMStorage f21 = floatRegister(21, "fs5"); + public static final VMStorage f22 = floatRegister(22, "fs6"); + public static final VMStorage f23 = floatRegister(23, "fs7"); + public static final VMStorage f24 = floatRegister(24, "fs8"); + public static final VMStorage f25 = floatRegister(25, "fs9"); + public static final VMStorage f26 = floatRegister(26, "fs10"); + public static final VMStorage f27 = floatRegister(27, "fs11"); + public static final VMStorage f28 = floatRegister(28, "ft8"); + public static final VMStorage f29 = floatRegister(29, "ft9"); + public static final VMStorage f30 = floatRegister(30, "ft10"); + public static final VMStorage f31 = floatRegister(31, "ft11"); + } + + private static VMStorage integerRegister(int index, String debugName) { + return new VMStorage(StorageType.INTEGER, REG64_MASK, index, debugName); + } + + private static VMStorage floatRegister(int index, String debugName) { + return new VMStorage(StorageType.FLOAT, FP_MASK, index, debugName); + } + + public static VMStorage stackStorage(short size, int byteOffset) { + return new VMStorage(StorageType.STACK, size, byteOffset); + } + + public static ABIDescriptor abiFor(VMStorage[] inputIntRegs, + VMStorage[] inputFloatRegs, + VMStorage[] outputIntRegs, + VMStorage[] outputFloatRegs, + VMStorage[] volatileIntRegs, + VMStorage[] volatileFloatRegs, + int stackAlignment, + int shadowSpace, + VMStorage scratch1, VMStorage scratch2) { + return new ABIDescriptor( + INSTANCE, + new VMStorage[][]{ + inputIntRegs, + inputFloatRegs, + }, + new VMStorage[][]{ + outputIntRegs, + outputFloatRegs, + }, + new VMStorage[][]{ + volatileIntRegs, + volatileFloatRegs, + }, + stackAlignment, + shadowSpace, + scratch1, scratch2, + StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER), + StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER), + StubLocations.CAPTURED_STATE_BUFFER.storage(StorageType.PLACEHOLDER)); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$1.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$1.class new file mode 100644 index 0000000000000000000000000000000000000000..50fab6b3a51af82a2e7e140d1170367a63289e43 GIT binary patch literal 1161 zcmbtTZBNrs7(JJbb(;moi-IVMQr>)_fMc3qG)w7lacpFrXu=2Vx+@fFOKv;VU*u;s zF~%5vfWOF3#^=`QNW?^9(%$De=ehUxoaf$t{r>qFfPs5i^dO-isiGGthQM)G zk8Ir|;d(W&+Rk3dfu^NyX(@)Mib}s!Q&QimQ?vv>Np% zMq{ULu9q#U?L3p!YbvgvS}n<{rea!FhyGX_muFSX$#U*@xn$POs$nX)L2Orjt+~&g zh#`I7p?Y#6!zT*X<>+f#xXfJ3fSYdehpVx^jRe2aa3PN(HmVKX#_}cR@ zH%S+Fo_->h8n8%w+qJ! zrn+!~pwfkt1k+tOMKE___Kd_or@w=O3`Q`D^BBVvW+={L87mYEC}NGGiA`7(8+Z>YEW}J6cPVD$ JPEnFe{{X*;7Ha?i literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$BindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$BindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..c0ba6674cc15bb93e8c192eb4bf338e801aaaed1 GIT binary patch literal 1931 zcmb_dTT|0O6#ljiO$!kyBHr()r7BTGytIN?Tc{Qso62x`U_uEs7!qfjF!o<*y^fCl z0Dp`#>Wh~d$FphG(y9Zaeb_xcdoJJkcF)P%Z!g~fNMSmH0D>|k1#Jj1++JP2r<%5F za9g+36^9#U$yW6xQ{`s4xIQwhTBhwiP;+9^hpusXm6@*g$SoU)NQO z3Ri1dg3yUB8Qlt^=wayoWpHb0)hN0Qp`>Y>?kGbrHZUU)_X^t`3{q@{YN2`x(w`lD$IZzLB!@a+#qmle;xuU>Mpg^FMtPBKbiD zheT#MJ6%Xmr1Kp(f}=9}6&%BHhHV=#Q#M1OW=O;uNUCv=Xw}r2+*q=oHl|=eq>XBY z{GC)`F`u5uYK3%uF(W{oRB-CIr?cX8P=P8=dzyV`GXnit1w%N;5OG!n#il_doro>e z&^1A60!YvTIImy?7a01Aj=fIhnvR_k5~t>&dt>O@7%D-jH0mbZ^|-;{Z9GkG{aUu} zF-jPul(S6fyQqVWX>V=G;01ljB27=uDeBgY&Q0;Zu9V!nCh_v`?bftjPvfFiN{5CLd{p{}lZT&>oFH$F}$@gy;4?$M&aS zk4PDS2-Jxnt?$Y31G@3i57<|8ss|)@jNvMn1dQVvg|2~3QOfJ+si#_?g2Yb^y++?$ zu!>z(9C(4l+MHCyi7Mj0+*ZZuy8HrX9%EPlp@By09-og-RLy5%=Wa1ql^5pfW7&ly^15a=EZ{Q~P2IZfseaUNkgeIHkSm zDa|yj+BdBr|5x*CxsBLnW_p96*(aZ*THq_SN|B3oy=YQ6QU#lGzo835o&#aCyKNAUch{F6s*GjsZrkM# zy3i|}YL@(Wj$V>BuhjDlT}1Ju9YWNZEgya1ieX%OtJe|dgW{o3AQNkLO_casL&l=N zUZ+e*II5x*?zl^~<0{Y?=IVl7t$3+mj=Q{l!M0t;6?)YVk`u>Mh9OGKnMOO`TS*3m zeyzzEo+t1EFBQB}k;M$d;AwzF&2o(j*Zdd;01Pd~V@!sFaI6h$&)(&luehXJWs^I@ z1>4@ORkNYE2VEAD1cvMTRldlbk}#^SEy5-_Q+J%OAn@_=qLVQCndS~EfkDk%78jmN zPPG(29%c&OFpQkiZ$L-E0>eOKRmzgj9g{TXBGm2?q~!dSGfmDsT4P`|!29WDfKJPD zsMDIv`~u629YV?U9isJsL=g-I>c9$yXg}nu;x6vdiHtng%-c!l5!|PJON7Mo66l~Y zI!t&HX_8i{s$`BxjvutWh@ko^0YV4O!;wqOyMXUkGVjHMzF5ToRQ5urD8@Xd<9Ot)6L?H(8@S@zT!Rq06om^egFUf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$BoxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$BoxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..8653bfa478a8c54bb41a196bdc6f30cb2e27972c GIT binary patch literal 7015 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 T!}(bt{*d}$CM-G~1R3fBEO literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$StorageCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$StorageCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..653dbd239e01fa8915d818b338c442c8912bde45 GIT binary patch literal 4435 zcmbtX?ROMc9e!qCvM-syvXB6IfrUocEFp_DMI+K7>~jC|(!miDA+ zWD6&fed4*VH{CP1rM*Wp&2G!mvg5iHh7bM#s#F9JR1i6;9oLd3KP3l7j_Mg(LDhC6 zYuKF%yz!R75W=VqKvhwLMGEfuKeacf?VP2J>$E6SFf~pT)b!FDTDDIg?;Sm%KVnGT~SivNP~(- zG$~LSt!`_)FrjB{o>UHnu^O=e)~HyE+Y~G+#iC!ck5EU()Fvhwk$9@Nx24z5G>E@o z80!%aphZOj8x+)+4ax!AFsUV=nM}|DO7X{2sTOI_Mip(spry@PKCfH0k;~?H8hLHR z)JFr@q+mtKlJ5B(yDTeb1+keq%jROz&6uUz1uL5mBZ+pA&^r{=#`{W#os@R842JPB zYz^S!Dz>3RL3>$?7lOz|PPdggV%UU5!O|H(snt!Pf_OaL+tOE2)L_56vm*orcdF>b zU5sUqL?%yHKH0sacc-4uSjHp)!qeT@5kQZMo!F&dT}6dA9iz2IcCug>tz9=fTv_8n zTf6ZI6?=rLnq0vyi3lTwPX^GZq91z|L}i!@%yM#IQlwBbiN@TRh)bCiI7>He?+_C2 zR&fvZ5gq!(q&=meF3ymOn*8wAF!rlBfI$U8OCRqx&0I#o^0>%Ax$P-@O2rTkDF_+) zyDdFW(94o0>QlH^#i#KZ&c{WWESuN4fCoAPIILi8#b6gB7Ql#tu8RBSS*Z-5=E-3H z)TAC}osO!|!T5zG%v=xG3EL`BUeSn-Y8-(Pz)=;)z&xxf)xbPO_UjWlYpPG1Vp18y zktthG8}}2{q`6cWSy9nB1MCHQ0IJyiz5kvn?w?(C-EgA;>!vei-0S$F^I1)vaPYP zqUNuv_!^$zqMdVOei&@7@*tj4u(;KsHHW<&)1MZ4zajLdDjOKYY0~)vL41?12gCR_ z&IB;6;yVKVi%XH}G0C?qu~9v5FqK7WP1~AX;D?$X60xmi?Lo~f=w89~;-M(;#SgWx z@_aqHQ6gqBDNNs6m>AKm{erYf27S4VW)5nWA?EI)&pu*MYPvFh=ZnMquUGbbos=$3 zQh3O-n>q)?cb0I?pI%j`eGkuJu*c(IUm3U zZsXOE?>?>>rh`j=oQ(^Mpjvc{PLD-DLSt@E#j#KHQ3AlFGI48?cM^+1z$>^tLxjqn zFr1dC*lh^ZH?a=NHkoZg7|-q1^Y)%xo@T1O*{p8K0@SH>iOYH=NYh4lOw{5)Ct`zr?*ByujxwN&%jsRZk# z%72=z<7u{o&*B`v);Y5ABEHWVwMg3)j(&h2x)u!40>LUxt0TckWDctyTZZO2tm{f7 zuApu;N7P+XyGU-HMucqENassxnu=ZnMJ|h+4LIj+vf9b@z?sB&SB|FU#(xbdLsR(UpfEp zf2{NgTO9DLqXod5tkJjV%g=E;-o_pH6*}+^+xXvLFW>v|p7gPkCUvrQt}-X0e>zz7 z_8_Biji!sWS6OWy%G-_W+~=jFM#ks@9TNUV;C-JzfBuDF0IwS( zs=RFthaUkZ-z~^NtY}q?ehKCQv-K87PQ=M8tGdJ@ zTRwg~%Mn{KxoxYX)-N?JmlJ2jcR2FFLjx>cIgJDdBnL17B^GeZsgr^EJ)!aktid1A zfHpl*E|snA3SSnxyshdwd4i5B|tlT9Vdsb;-Tonvv|a@VHS@?Pq{N+ z8)vh4yl;Nnlg@{_S$v(#{qxJuaCrm&iTX#P&+@^KBKHncI+XPn;`p!3>)#f{aM(3+ zJ=%$hU(mQtX7z23JPg_|i-BvGE&)rT$}GM$4JSLVptZz{PJ$kn$!F-*E;jPSm$2a- Y{93*h;!NBd9(f16OX(Ve_Fh%!KULXLqyPW_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$UnboxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger$UnboxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..13ca2c7cec38fad215e9b2625c9f74dd64cd6658 GIT binary patch literal 6967 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≷d!_RN*dCdqhseQ&Puv^JKgr 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 carrier = MemorySegment.class; + MemoryLayout layout = SharedUtils.C_POINTER; + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout, false)); + } else if (cDesc.returnLayout().isPresent()) { + Class carrier = mt.returnType(); + MemoryLayout layout = cDesc.returnLayout().get(); + csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout, false)); + } + + for (int i = 0; i < mt.parameterCount(); i++) { + Class carrier = mt.parameterType(i); + MemoryLayout layout = cDesc.argumentLayouts().get(i); + boolean isVar = options.isVarargsIndex(i); + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout, isVar)); + } + + return new Bindings(csb.build(), returnInMemory); + } + + public static MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, false, options); + + MethodHandle handle = new DowncallLinker(CLinux, bindings.callingSequence).getBoundMethodHandle(); + + if (bindings.isInMemoryReturn) { + handle = SharedUtils.adaptDowncallForIMR(handle, cDesc, bindings.callingSequence); + } + + return handle; + } + + public static UpcallStubFactory arrangeUpcall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, true, options); + final boolean dropReturn = true; /* drop return, since we don't have bindings for it */ + return SharedUtils.arrangeUpcallHelper(mt, bindings.isInMemoryReturn, dropReturn, CLinux, + bindings.callingSequence); + } + + private static boolean isInMemoryReturn(Optional returnLayout) { + return returnLayout + .filter(GroupLayout.class::isInstance) + .filter(g -> TypeClass.classifyLayout(g) == TypeClass.STRUCT_REFERENCE) + .isPresent(); + } + + static class StorageCalculator { + private final boolean forArguments; + // next available register index. 0=integerRegIdx, 1=floatRegIdx + private final int IntegerRegIdx = 0; + private final int FloatRegIdx = 1; + private final int[] nRegs = {0, 0}; + + private long stackOffset = 0; + + public StorageCalculator(boolean forArguments) { + this.forArguments = forArguments; + } + + // Aggregates or scalars passed on the stack are aligned to the greatest of + // the type alignment and XLEN bits, but never more than the stack alignment. + void alignStack(long alignment) { + alignment = Utils.alignUp(Math.clamp(alignment, STACK_SLOT_SIZE, 16), STACK_SLOT_SIZE); + stackOffset = Utils.alignUp(stackOffset, alignment); + } + + VMStorage stackAlloc() { + assert forArguments : "no stack returns"; + VMStorage storage = stackStorage((short) STACK_SLOT_SIZE, (int) stackOffset); + stackOffset += STACK_SLOT_SIZE; + return storage; + } + + Optional regAlloc(int storageClass) { + if (nRegs[storageClass] < MAX_REGISTER_ARGUMENTS) { + VMStorage[] source = (forArguments ? CLinux.inputStorage : CLinux.outputStorage)[storageClass]; + Optional result = Optional.of(source[nRegs[storageClass]]); + nRegs[storageClass] += 1; + return result; + } + return Optional.empty(); + } + + VMStorage getStorage(int storageClass) { + Optional storage = regAlloc(storageClass); + if (storage.isPresent()) { + return storage.get(); + } + // If storageClass is StorageType.FLOAT, and no floating-point register is available, + // try to allocate an integer register. + if (storageClass == StorageType.FLOAT) { + storage = regAlloc(StorageType.INTEGER); + if (storage.isPresent()) { + return storage.get(); + } + } + return stackAlloc(); + } + + VMStorage[] getStorages(MemoryLayout layout, boolean isVariadicArg) { + int regCnt = (int) SharedUtils.alignUp(layout.byteSize(), 8) / 8; + if (isVariadicArg && layout.byteAlignment() == 16 && layout.byteSize() <= 16) { + alignStorage(); + // Two registers or stack slots will be allocated, even layout.byteSize <= 8B. + regCnt = 2; + } + VMStorage[] storages = new VMStorage[regCnt]; + for (int i = 0; i < regCnt; i++) { + // use integer calling convention. + storages[i] = getStorage(StorageType.INTEGER); + } + return storages; + } + + boolean regsAvailable(int integerRegs, int floatRegs) { + return nRegs[IntegerRegIdx] + integerRegs <= MAX_REGISTER_ARGUMENTS && + nRegs[FloatRegIdx] + floatRegs <= MAX_REGISTER_ARGUMENTS; + } + + // Variadic arguments with 2 * XLEN-bit alignment and size at most 2 * XLEN bits + // are passed in an aligned register pair (i.e., the first register in the pair + // is even-numbered), or on the stack by value if none is available. + // After a variadic argument has been passed on the stack, all future arguments + // will also be passed on the stack. + void alignStorage() { + if (nRegs[IntegerRegIdx] + 2 <= MAX_REGISTER_ARGUMENTS) { + nRegs[IntegerRegIdx] = (nRegs[IntegerRegIdx] + 1) & -2; + } else { + nRegs[IntegerRegIdx] = MAX_REGISTER_ARGUMENTS; + stackOffset = Utils.alignUp(stackOffset, 16); + } + } + + @Override + public String toString() { + String nReg = "iReg: " + nRegs[IntegerRegIdx] + ", fReg: " + nRegs[FloatRegIdx]; + String stack = ", stackOffset: " + stackOffset; + return "{" + nReg + stack + "}"; + } + } + + abstract static class BindingCalculator { + protected final StorageCalculator storageCalculator; + + @Override + public String toString() { + return storageCalculator.toString(); + } + + protected BindingCalculator(boolean forArguments) { + this.storageCalculator = new LinuxRISCV64CallArranger.StorageCalculator(forArguments); + } + + abstract List getBindings(Class carrier, MemoryLayout layout, boolean isVariadicArg); + + // When handling variadic part, integer calling convention should be used. + static final Map conventionConverterMap = + Map.ofEntries(Map.entry(FLOAT, INTEGER), + Map.entry(STRUCT_REGISTER_F, STRUCT_REGISTER_X), + Map.entry(STRUCT_REGISTER_XF, STRUCT_REGISTER_X)); + } + + static final class UnboxBindingCalculator extends BindingCalculator { + protected final boolean forArguments; + private final boolean useAddressPairs; + + UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) { + super(forArguments); + this.forArguments = forArguments; + this.useAddressPairs = useAddressPairs; + } + + @Override + List getBindings(Class carrier, MemoryLayout layout, boolean isVariadicArg) { + TypeClass typeClass = TypeClass.classifyLayout(layout); + if (isVariadicArg) { + typeClass = BindingCalculator.conventionConverterMap.getOrDefault(typeClass, typeClass); + } + return getBindings(carrier, layout, typeClass, isVariadicArg); + } + + List getBindings(Class carrier, MemoryLayout layout, TypeClass argumentClass, boolean isVariadicArg) { + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case INTEGER -> { + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER); + bindings.vmStore(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT); + bindings.vmStore(storage, carrier); + } + case POINTER -> { + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER); + if (useAddressPairs) { + bindings.dup() + .segmentBase() + .vmStore(storage, Object.class) + .segmentOffsetAllowHeap() + .vmStore(null, long.class); + } else { + bindings.unboxAddress(); + bindings.vmStore(storage, long.class); + } + } + case STRUCT_REGISTER_X -> { + assert carrier == MemorySegment.class; + + // When no register is available, struct will be passed by stack. + // Before allocation, stack must be aligned. + if (!storageCalculator.regsAvailable(1, 0)) { + storageCalculator.alignStack(layout.byteAlignment()); + } + VMStorage[] locations = storageCalculator.getStorages(layout, isVariadicArg); + int locIndex = 0; + long offset = 0; + while (offset < layout.byteSize()) { + final long copy = Math.min(layout.byteSize() - offset, 8); + VMStorage storage = locations[locIndex++]; + Class type = SharedUtils.primitiveCarrierForSize(copy, false); + if (offset + copy < layout.byteSize()) { + bindings.dup(); + } + bindings.bufferLoad(offset, type, (int) copy) + .vmStore(storage, type); + offset += copy; + } + } + case STRUCT_REGISTER_F -> { + assert carrier == MemorySegment.class; + List descs = getFlattenedFields((GroupLayout) layout); + if (storageCalculator.regsAvailable(0, descs.size())) { + for (int i = 0; i < descs.size(); i++) { + FlattenedFieldDesc desc = descs.get(i); + Class type = desc.layout().carrier(); + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT); + if (i < descs.size() - 1) { + bindings.dup(); + } + bindings.bufferLoad(desc.offset(), type) + .vmStore(storage, type); + } + } else { + // If there is not enough register can be used, then fall back to integer calling convention. + return getBindings(carrier, layout, STRUCT_REGISTER_X, isVariadicArg); + } + } + case STRUCT_REGISTER_XF -> { + assert carrier == MemorySegment.class; + if (storageCalculator.regsAvailable(1, 1)) { + List descs = getFlattenedFields((GroupLayout) layout); + for (int i = 0; i < 2; i++) { + FlattenedFieldDesc desc = descs.get(i); + int storageClass; + if (desc.typeClass() == INTEGER) { + storageClass = StorageType.INTEGER; + } else { + storageClass = StorageType.FLOAT; + } + VMStorage storage = storageCalculator.getStorage(storageClass); + Class type = desc.layout().carrier(); + if (i < 1) { + bindings.dup(); + } + bindings.bufferLoad(desc.offset(), type) + .vmStore(storage, type); + } + } else { + return getBindings(carrier, layout, STRUCT_REGISTER_X, isVariadicArg); + } + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + bindings.copy(layout) + .unboxAddress(); + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER); + bindings.vmStore(storage, long.class); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + + return bindings.build(); + } + } + + static class BoxBindingCalculator extends BindingCalculator { + + BoxBindingCalculator(boolean forArguments) { + super(forArguments); + } + + @Override + List getBindings(Class carrier, MemoryLayout layout, boolean isVariadicArg) { + TypeClass typeClass = TypeClass.classifyLayout(layout); + if (isVariadicArg) { + typeClass = BindingCalculator.conventionConverterMap.getOrDefault(typeClass, typeClass); + } + return getBindings(carrier, layout, typeClass, isVariadicArg); + } + + List getBindings(Class carrier, MemoryLayout layout, TypeClass argumentClass, boolean isVariadicArg) { + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case INTEGER -> { + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER); + bindings.vmLoad(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT); + bindings.vmLoad(storage, carrier); + } + case POINTER -> { + AddressLayout addressLayout = (AddressLayout) layout; + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER); + bindings.vmLoad(storage, long.class) + .boxAddressRaw(Utils.pointeeByteSize(addressLayout), Utils.pointeeByteAlign(addressLayout)); + } + case STRUCT_REGISTER_X -> { + assert carrier == MemorySegment.class; + + // When no register is available, struct will be passed by stack. + // Before allocation, stack must be aligned. + if (!storageCalculator.regsAvailable(1, 0)) { + storageCalculator.alignStack(layout.byteAlignment()); + } + bindings.allocate(layout); + VMStorage[] locations = storageCalculator.getStorages(layout, isVariadicArg); + int locIndex = 0; + long offset = 0; + while (offset < layout.byteSize()) { + final long copy = Math.min(layout.byteSize() - offset, 8); + VMStorage storage = locations[locIndex++]; + Class type = SharedUtils.primitiveCarrierForSize(copy, false); + bindings.dup().vmLoad(storage, type) + .bufferStore(offset, type, (int) copy); + offset += copy; + } + } + case STRUCT_REGISTER_F -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout); + List descs = getFlattenedFields((GroupLayout) layout); + if (storageCalculator.regsAvailable(0, descs.size())) { + for (FlattenedFieldDesc desc : descs) { + Class type = desc.layout().carrier(); + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT); + bindings.dup() + .vmLoad(storage, type) + .bufferStore(desc.offset(), type); + } + } else { + return getBindings(carrier, layout, STRUCT_REGISTER_X, isVariadicArg); + } + } + case STRUCT_REGISTER_XF -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout); + if (storageCalculator.regsAvailable(1, 1)) { + List descs = getFlattenedFields((GroupLayout) layout); + for (int i = 0; i < 2; i++) { + FlattenedFieldDesc desc = descs.get(i); + int storageClass; + if (desc.typeClass() == INTEGER) { + storageClass = StorageType.INTEGER; + } else { + storageClass = StorageType.FLOAT; + } + VMStorage storage = storageCalculator.getStorage(storageClass); + Class type = desc.layout().carrier(); + bindings.dup() + .vmLoad(storage, type) + .bufferStore(desc.offset(), type); + } + } else { + return getBindings(carrier, layout, STRUCT_REGISTER_X, isVariadicArg); + } + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER); + bindings.vmLoad(storage, long.class) + .boxAddress(layout); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + + return bindings.build(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64Linker$1Holder.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64Linker$1Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..4c32592290ada272c91947be0c9a67e5257dcb1f GIT binary patch literal 762 zcmbVK$w~u35PhADnK&6W?z#ZQ1Ao% zD6u+j2XDF5@~Zk(bydB8yu1Mju*61v4N8XXy?47mfPReHpb zT`SdHG#-MfY~SE3OS zGFFL05!HoJ*8c{bw5<|`p#PFTU!cGfI>rPQxg(ZKyYg8nc8@!PZ`-h1_ed($TBVe z&=2Wjn?5wthkigms?&8WL1nPR3=h$Gd~W;f%UXNy^UuG3{SCmvZWbwwX-MlBM@GPW z**Y{FFO-32yGGj&q_giCcEd3Or`tSQTQywA>-}t$)c+5~s#RZG<@`_v`IQ~tZOK4j zqFAoh%(As5P$*qmUm=GHWHsb;T!AidXQU>x(G3H;8Ag5xWY!(e2{#1B<`?QYOkzsI zw2m3f3OpI9WpsR&?Yd?V*xtU1Zpx0PoBmH;lP3bd%$Hu;N4DWog4iAThtk-U;ep?( z9d{%lI6XYUbGzp?L&x_vWw#kPozM^70#p=MrK2u%3kwN#1GaW-ujNXjHi`Fje1H!H zuEwtJbs|T9eaDWDN~J-<@{xPhu-Dioi+*ri$l@b>tl<+KpW-utN0%V&BpGHbvs@_` zEwl8ZWd2y$t5r#1gkdjqTw~Yn(A?+vLc^CjuH%Nlwey74ZMP>&_Oag!1+vf0y7{71 zDL)gqouK1{-Gp$y(k}Vle&0e~$1U7udGxOr%Qb;p7v3&eMiOgC-M_Z%`G`OPga$^Q^x)RwmV7S&8~Lza85 z8ZxNa4VOE!C7;06?Z8p%crzUyI7D&Q@!B#V(Erysb0*>ZKw0)%07-AhB|ki6hBO2L z&5vqcfV_>0ai2@C+;$XnbM)xU z)3B_3Aa`Zi4aq2BCX9N~^JHMTcDF0J%tWt;hOM{N`$e6DA)o6e8g^9CoNK~~%#O>H zUPSe(;d_Cb7hPd(3XE6U9I?WVHNh8EaAeQoxWrWo%g7)L1NXVJ!X0&@zVvH|-#7|< z#s5ry_aWu^)WwnyI4ark#Xq6_&Pl2-n&Sw3gEYRy1J0B CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT); + + public static LinuxRISCV64Linker getInstance() { + final class Holder { + private static final LinuxRISCV64Linker INSTANCE = new LinuxRISCV64Linker(); + } + + return Holder.INSTANCE; + } + + private LinuxRISCV64Linker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return LinuxRISCV64CallArranger.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return LinuxRISCV64CallArranger.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/TypeClass$FieldCounter.class b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/TypeClass$FieldCounter.class new file mode 100644 index 0000000000000000000000000000000000000000..14f75b5eb6637add34b1bdb020e8c0897d207c0d GIT binary patch literal 4758 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 c*A#w^l(W~!(Q^2iw1qep2LJ#7 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/TypeClass.java b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/TypeClass.java new file mode 100644 index 00000000..e00771d2 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/riscv64/linux/TypeClass.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Institute of Software, Chinese Academy of Sciences. + * All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package jdk.internal.foreign.abi.riscv64.linux; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.PaddingLayout; +import java.lang.foreign.SequenceLayout; +import java.lang.foreign.UnionLayout; +import java.lang.foreign.ValueLayout; +import java.util.ArrayList; +import java.util.List; + +public enum TypeClass { + /* + * STRUCT_REFERENCE: Aggregates larger than 2 * XLEN bits are passed by reference and are replaced + * in the argument list with the address. The address will be passed in a register if at least + * one register is available, otherwise it will be passed on the stack. + * + * STRUCT_REGISTER_F: A struct containing just one floating-point real is passed as though it were + * a standalone floating-point real. A struct containing two floating-point reals is passed in two + * floating-point registers, if neither real is more than ABI_FLEN bits wide and at least two + * floating-point argument registers are available. (The registers need not be an aligned pair.) + * Otherwise, it is passed according to the integer calling convention. + * + * STRUCT_REGISTER_XF: A struct containing one floating-point real and one integer (or bitfield), in either + * order, is passed in a floating-point register and an integer register, provided the floating-point real + * is no more than ABI_FLEN bits wide and the integer is no more than XLEN bits wide, and at least one + * floating-point argument register and at least one integer argument register is available. If the struct + * is not passed in this manner, then it is passed according to the integer calling convention. + * + * STRUCT_REGISTER_X: Aggregates whose total size is no more than XLEN bits are passed in a register, with the + * fields laid out as though they were passed in memory. If no register is available, the aggregate is + * passed on the stack. Aggregates whose total size is no more than 2 * XLEN bits are passed in a pair of + * registers; if only one register is available, the first XLEN bits are passed in a register and the + * remaining bits are passed on the stack. If no registers are available, the aggregate is passed on the stack. + * + * See https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc + * */ + INTEGER, + FLOAT, + POINTER, + STRUCT_REFERENCE, + STRUCT_REGISTER_F, + STRUCT_REGISTER_XF, + STRUCT_REGISTER_X; + + private static final int MAX_AGGREGATE_REGS_SIZE = 2; + + /* + * Struct will be flattened while classifying. That is, struct{struct{int, double}} will be treated + * same as struct{int, double} and struct{int[2]} will be treated same as struct{int, int}. + * */ + private record FieldCounter(long integerCnt, long floatCnt, long pointerCnt) { + static final FieldCounter EMPTY = new FieldCounter(0, 0, 0); + static final FieldCounter SINGLE_INTEGER = new FieldCounter(1, 0, 0); + static final FieldCounter SINGLE_FLOAT = new FieldCounter(0, 1, 0); + static final FieldCounter SINGLE_POINTER = new FieldCounter(0, 0, 1); + + static FieldCounter flatten(MemoryLayout layout) { + switch (layout) { + case ValueLayout valueLayout -> { + return switch (classifyValueType(valueLayout)) { + case INTEGER -> FieldCounter.SINGLE_INTEGER; + case FLOAT -> FieldCounter.SINGLE_FLOAT; + case POINTER -> FieldCounter.SINGLE_POINTER; + default -> throw new IllegalStateException("Should not reach here."); + }; + } + case GroupLayout groupLayout -> { + FieldCounter currCounter = FieldCounter.EMPTY; + for (MemoryLayout memberLayout : groupLayout.memberLayouts()) { + if (memberLayout instanceof PaddingLayout) { + continue; + } + currCounter = currCounter.add(flatten(memberLayout)); + } + return currCounter; + } + case SequenceLayout sequenceLayout -> { + long elementCount = sequenceLayout.elementCount(); + if (elementCount == 0) { + return FieldCounter.EMPTY; + } + return flatten(sequenceLayout.elementLayout()).mul(elementCount); + } + default -> throw new IllegalStateException("Cannot get here: " + layout); + } + } + + FieldCounter mul(long m) { + return new FieldCounter(integerCnt * m, + floatCnt * m, + pointerCnt * m); + } + + FieldCounter add(FieldCounter other) { + return new FieldCounter(integerCnt + other.integerCnt, + floatCnt + other.floatCnt, + pointerCnt + other.pointerCnt); + } + } + + public record FlattenedFieldDesc(TypeClass typeClass, long offset, ValueLayout layout) { } + + private static List getFlattenedFieldsInner(long offset, MemoryLayout layout) { + return switch (layout) { + case ValueLayout valueLayout -> { + TypeClass typeClass = classifyValueType(valueLayout); + yield List.of(switch (typeClass) { + case INTEGER, FLOAT -> new FlattenedFieldDesc(typeClass, offset, valueLayout); + default -> throw new IllegalStateException("Should not reach here."); + }); + } + case GroupLayout groupLayout -> { + List fields = new ArrayList<>(); + for (MemoryLayout memberLayout : groupLayout.memberLayouts()) { + if (memberLayout instanceof PaddingLayout) { + offset += memberLayout.byteSize(); + continue; + } + fields.addAll(getFlattenedFieldsInner(offset, memberLayout)); + offset += memberLayout.byteSize(); + } + yield fields; + } + case SequenceLayout sequenceLayout -> { + List fields = new ArrayList<>(); + MemoryLayout elementLayout = sequenceLayout.elementLayout(); + for (long i = 0; i < sequenceLayout.elementCount(); i++) { + fields.addAll(getFlattenedFieldsInner(offset, elementLayout)); + offset += elementLayout.byteSize(); + } + yield fields; + } + case null, default -> throw new IllegalStateException("Cannot get here: " + layout); + }; + } + + public static List getFlattenedFields(GroupLayout layout) { + return getFlattenedFieldsInner(0, layout); + } + + // ValueLayout will be classified by its carrier type. + private static TypeClass classifyValueType(ValueLayout type) { + Class carrier = type.carrier(); + if (carrier == boolean.class || carrier == byte.class || carrier == char.class || + carrier == short.class || carrier == int.class || carrier == long.class) { + return INTEGER; + } else if (carrier == float.class || carrier == double.class) { + return FLOAT; + } else if (carrier == MemorySegment.class) { + return POINTER; + } else { + throw new IllegalStateException("Cannot get here: " + carrier.getName()); + } + } + + private static boolean isRegisterAggregate(MemoryLayout type) { + return type.byteSize() <= MAX_AGGREGATE_REGS_SIZE * 8; + } + + private static TypeClass classifyStructType(GroupLayout layout) { + if (layout instanceof UnionLayout) { + return isRegisterAggregate(layout) ? STRUCT_REGISTER_X : STRUCT_REFERENCE; + } + + if (!isRegisterAggregate(layout)) { + return STRUCT_REFERENCE; + } + + // classify struct by its fields. + FieldCounter counter = FieldCounter.flatten(layout); + if (counter.integerCnt == 0 && counter.pointerCnt == 0 && + (counter.floatCnt == 1 || counter.floatCnt == 2)) { + return STRUCT_REGISTER_F; + } else if (counter.integerCnt == 1 && counter.floatCnt == 1 && + counter.pointerCnt == 0) { + return STRUCT_REGISTER_XF; + } else { + return STRUCT_REGISTER_X; + } + } + + public static TypeClass classifyLayout(MemoryLayout type) { + if (type instanceof ValueLayout vt) { + return classifyValueType(vt); + } else if (type instanceof GroupLayout gt) { + return classifyStructType(gt); + } else { + throw new IllegalArgumentException("Unsupported layout: " + type); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/S390Architecture$Regs.class b/tests/test_data/std/jdk/internal/foreign/abi/s390/S390Architecture$Regs.class new file mode 100644 index 0000000000000000000000000000000000000000..25a477b2eacdf41974e5e2b84dae38026f4a5c29 GIT binary patch literal 1753 zcma)+O>7%g6ot>&PVBfh&QK^2C{SpiNr5;&b=x$dPy%UFoTQCg(?43q&e$2(9mCiu z|43y8D|YPIv1Ega1VV@vE5wo|OO|ZeBF?>Uxt;EM z2VoKi-Eym!gi$*#2aTxQpI?|M*LXRVG`FJxzqFHt9>(m?WEwvR9Cd0rvxu+Ge=w9UNE@V8FhL^ z@TxwUX_@h9!5Jsb_pIPGC(U+Eu8Nb;Uz&xwoZ3 ztwwRUzH_S)CKrN6mv{D7d(EI*50XfAdNViJj+m>;?vdI(j*A`&OU-UNUBy~&CuxQ& zk$Ua>_vB3LT=Mz#us=A{>vJq+HIBn%xf}HRAuGsfz!|v`=NUMFaUB!>8`lUMnO!48 zYh+rDjH!|NG%}b*Cep|#8ks>Ovu9-HjLe#m88b3lMkdF|$QYRwBST_jI*g2kk$EsO z2u3Er$krR#b0d3gWRH#Pt&u%7vX^8Ao}OsD_NmIGM-CnS4&FDmJm6KAffelVD((T? z#yeC6ynF9u?=xEg{>pxj{9TOZ4EGNi9vn7|=MDP{h9`V?_bK1qe%g2UC;bsyf7UM= zr~N&~SznAt{88gEzhpe&j~QQ}^GkQJOlM++&crG`h$=0J4LT5;>P%i#XY!IdlULQ5 zyspk=tvRlsTFc?guS%3Phrex3jaQRV5ihB=P^ z32g8zImear*yQgDYG`oqJGjUhtK)rK!W~@3r(F3QSMdd|;Y-f?SGbO^aRc9S(0@dL qpZV6WobunWh2Ih44^H@>Xd{dFSVM;2`M_Afhh&izme{h7F!B#)&@i|F literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/S390Architecture$StorageType.class b/tests/test_data/std/jdk/internal/foreign/abi/s390/S390Architecture$StorageType.class new file mode 100644 index 0000000000000000000000000000000000000000..79a70fe023460d9dd6e0ad7ee3ea5e2aa75a3dff GIT binary patch literal 415 zcmb7<%}xR_6ot=~pW#;##l*d9YT`NRs}<#tA0 zB(5-Wt=0ebW7+)g|<#=_ayV3s_@q!)JD^J zn0g?FBn_hn5A4%^oQ6?6o=@-Mg+HngT1l}pD>ce;MHu`w8hQajW2USd7uE$hAq@Z5 ziqM&8txS|lYn5e-Qq4N|fLE#F95vLL0`H0jbF;)P=5~oY%-s?n`Z_q;zwP08pM9Ki MwsWQ2eO=~_ORwKB8MnSH*!&)(nO=luQe?|%Xq$2VcL z!4rTt3LpFedzRHzHEyV8IX=6vtQBnm{}tWT?W+Qw*w9=6L4nK5rIomD+L~pmMtrei zX?od=s|$L(Hg@SuT;U^W6_<3I>+6;_sMr-tEo=ElRV{$9z{vkwA3#*#$cAGX!_dmA zk+jP7`$ONjWS7)G8@+Gwx18Y{N!c0=R#iAjJ+Q&&QTQ%)D)u?M8wp!89x^T|Xk~1E5+e|i}o=WEm zTwhQ!cUc-DBfqi9c1%vsCi6{SI!S@?TLoo$Ht*_s$15dGpmSO`wQT+Vf@bB_1%oqP zlHkUiYUy(9PI~PnorFKrI^f%O?}R`^uPL@#T#*f2z{|#Vm#0C|AX>ZgVMeXGMuIkV z6#cQQ#~60XgQBciIjyYMcx1>Dk)84N%nTN`Na|O9Wv^VvCk|(O0)w-QAW%@{% z4re&&=2J4LQn#BGIve9Ajn37I!FFwE>mYky&NOLtIGjityo$(M0a;sHQcINwN>weA zjX@qss$E>-K{U9V{B5ilrFf-ixR;=?QmI=-ZIbS=J#W40jL6FZO=q>5J)_BrtOf8` zV5}wGx2?IsMy#S4)6^{IdZIB>5ts088A=_TWv^<3zzz7(BhOhjj~?8_EzV6-Zo>@6 z*{1Ocu7A&QtZW(QH;sct;pLDk?htW|Z^5_k>qT{Wgz)-bW*Pa{iDn4fQP9p7OJ-;?%F z9RC&@ma$CY%3l^M4uz#;P?DR>;yxvL?q*?9@;Xw5lFWV INTEGER_REG_SIZE; + case StorageType.FLOAT -> FLOAT_REG_SIZE; + // STACK is deliberately omitted + default -> throw new IllegalArgumentException("Invalid Storage Class: " + cls); + }; + } + + public interface StorageType { + byte INTEGER = 0; + byte FLOAT = 1; + byte STACK = 2; + byte PLACEHOLDER = 3; + } + + public static class Regs { // break circular dependency + public static final VMStorage r0 = integerRegister(0); + public static final VMStorage r1 = integerRegister(1); + public static final VMStorage r2 = integerRegister(2); + public static final VMStorage r3 = integerRegister(3); + public static final VMStorage r4 = integerRegister(4); + public static final VMStorage r5 = integerRegister(5); + public static final VMStorage r6 = integerRegister(6); + public static final VMStorage r7 = integerRegister(7); + public static final VMStorage r8 = integerRegister(8); + public static final VMStorage r9 = integerRegister(9); + public static final VMStorage r10 = integerRegister(10); + public static final VMStorage r11 = integerRegister(11); + public static final VMStorage r12 = integerRegister(12); + public static final VMStorage r13 = integerRegister(13); + public static final VMStorage r14 = integerRegister(14); + public static final VMStorage r15 = integerRegister(15); + + public static final VMStorage f0 = floatRegister(0); + public static final VMStorage f1 = floatRegister(1); + public static final VMStorage f2 = floatRegister(2); + public static final VMStorage f3 = floatRegister(3); + public static final VMStorage f4 = floatRegister(4); + public static final VMStorage f5 = floatRegister(5); + public static final VMStorage f6 = floatRegister(6); + public static final VMStorage f7 = floatRegister(7); + public static final VMStorage f8 = floatRegister(8); + public static final VMStorage f9 = floatRegister(9); + public static final VMStorage f10 = floatRegister(10); + public static final VMStorage f11 = floatRegister(11); + public static final VMStorage f12 = floatRegister(12); + public static final VMStorage f13 = floatRegister(13); + public static final VMStorage f14 = floatRegister(14); + public static final VMStorage f15 = floatRegister(15); + } + + private static VMStorage integerRegister(int index) { + return new VMStorage(StorageType.INTEGER, REG64_MASK, index, "r" + index); + } + + private static VMStorage floatRegister(int index) { + return new VMStorage(StorageType.FLOAT, REG64_MASK, index, "f" + index); + } + + public static VMStorage stackStorage(short size, int byteOffset) { + return new VMStorage(StorageType.STACK, size, byteOffset); + } + + public static ABIDescriptor abiFor(VMStorage[] inputIntRegs, + VMStorage[] inputFloatRegs, + VMStorage[] outputIntRegs, + VMStorage[] outputFloatRegs, + VMStorage[] volatileIntRegs, + VMStorage[] volatileFloatRegs, + int stackAlignment, + int shadowSpace, + VMStorage scratch1, VMStorage scratch2) { + return new ABIDescriptor( + INSTANCE, + new VMStorage[][] { + inputIntRegs, + inputFloatRegs, + }, + new VMStorage[][] { + outputIntRegs, + outputFloatRegs, + }, + new VMStorage[][] { + volatileIntRegs, + volatileFloatRegs, + }, + stackAlignment, + shadowSpace, + scratch1, scratch2, + StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER), + StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER), + StubLocations.CAPTURED_STATE_BUFFER.storage(StorageType.PLACEHOLDER)); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$1.class b/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$1.class new file mode 100644 index 0000000000000000000000000000000000000000..ce1df3f8c4134388c43b6532ae45e0879a489fb7 GIT binary patch literal 1065 zcmbVLT~pIQ6g^8z)7BsrK@h)CqO>Z64{>C0oaxjQJC>GdB0lh-+jNCMOqflI`ip#4 zXB@|I_yNBA(Hu04i9{V*n`)X&r;eFwE|D_DnB` zg$%fFz6z!AwgZ#5Ju_NbnKyke=)N_bcl)B^^C)7-9B{uYC|N9)w(6(ayqZH6ISqLo zXP`5z{>$#V5@3^*3iti8lswoL(pX@4VAyZG*xgy@`vx6k{PAG)JQ(D`P#%oLgYlP# zfvsAOs&H1vFbWLAw$pl6abC2nwVLf%Ee7+H##Bv5bezX1gBHq;N3~=~6-zY@7Z@gY z`2jb5l5RFayX)>$J>hpODMP7rOz60%bmV(F>}pxjmvmfKbm3TD)oNLdilrv6>bRyR zwT))2L7EkJUB``tQ_R{CXXv=8xWQ_@S#~tc(0P3|&GxQvV}|TQmx|=Yj}pnXa(IFqoFnheS9V)5w_hIbTKG_jh zYS$Q|6lSY$Q^ONM*eF+=j0${IT<~QEud&}8lyMm=K31z(LvW#3Poy48ot(#F2(n+} zGxXyBSWcU&h|;lOSfvJty?iT% z71|O#+h(VGCM#b(-e_{c8+Y-9*!=0ME@kAvLmkWV!pGbpqD<0RQ#I3ChQ) z9?e{@(7J*mt)Iy8Gf{jYBH;SjBV41C`vTm+O)w9*g>|CdAgqAf^zzQ^bQkw#dmWp! S*XYhi9S=~V^y=91O5XvqhbF`T literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$Bindings.class b/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$Bindings.class new file mode 100644 index 0000000000000000000000000000000000000000..a7ce8538a796032cf3b599f27eef32f63efeac01 GIT binary patch literal 1961 zcmb_dT~pIQ6g^ugDK${2fbt=rg3^Kn#4jwOP)1>BX; z3=jSQf0X0hB!vKN<$(v--J5&Q*>msR+dqF#egnv2DUJx56f~=dqJ^PjS3l4-Q@6IY zbzZbZiJ@iAunc#ep=m6&*@_ri6~tBCfXcAATiVkM%jLq-P3?;73O~b3q6K=VD~huu6ut?Jy*YWT$POf30w<$QjbPy0{V}VnZ*Ol!9c=rb=(>!jR{{*zE2Yq+sbfszDvF%H18i^g$Q;KBulE z??g`u0ooi=<(G_&P(FMVQ|kZARK{$e^j7D{0}Z&yT-zcpkQ`f5IhNy$YG zv&J2F*>+q78pCW|rvG&)^+xsib}ZVq>$pNM`?+yqm|+;EN}PK~7oSdoL7~64L<^qB z@dC37UaH7oj$!C5FQQ_(#y;2l)CB|#t%WKl!%;ZJhIL@?am{yJ)~%Asospbv?^Vi~ zP`ZPs6tVcq9wet0idAQo zf;SAKXYw1!QLxA`*w~e-<3SKUM`SV|vGn)}dh5ma_&%osV|a)$ zLSUpQ6(DKe8HlETLTRKT8o{kY-Z20G literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$BoxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$BoxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..1f4a4c40d30ad9fa288f1876974c35d14e9b0d01 GIT binary patch literal 4498 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 SeV*LQ`y%g8-~;@ztm1!37T*B? literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$StorageCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$StorageCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..5324b0ec1c47437b36bb82050bd90030411e3d8c GIT binary patch literal 2649 zcmb7FZF3V<6n<{A>E>mjFSLcWl=4za8f}9ug0v0N7Lb%dPgtg1IF}fe&otLVx@8SGj&A1+ zM};EL_3Y#F%z%?QWqL-&D>z03l~7fLG=vcmsGil&>IsYC5~=A~x(HPEo3`og5eURO z#>3FCO2ujoRj3v?^z3BMz}lAf@{XP}h(A-XbS?yf_7NlJ3RFxD%RIFj)}T%x>Uw(S zbZTbCH3&zH$ZriA)?%H2Mt%mIT;Ysidps#7BWOaiiuD>=utA{dsQ{08rbTa6w@B@= zIcAQHjCA;cH)_}<1Fvb*UDt3tGjF^5Ojn<_jBEgS{8&Ysz`8O`150lE9VhQZumx%a z0c_I{Lk9u+;ETly#A4~;j?t%rk{upDT=eWy@ti>KvW~tK{@u$ZPLH0SGr|z))X;?l zJ2>Rah1r+SJTN%C&u}x2ImcG?h4BKqRrF}sffohZm&NgqW31M+=L%k_+V-ibJTP(bm> zo-g)6xxG)rejFe!)6N>_QqGbLc^QV~_k;4{43p#7AUiuAgso#cKi) zUkt?}Vp4M}p(lbgj;c7OVI0Q=s><3MvM5r4hOFV5j*%@%G41JIfgcERk`=`!JI47M z%4b&QYmqf!fi0Mz_Xw$CT^hrsAD48R78q0DTGmuN&S+5U%+yQ-=MU zCoe72`?irK=<+R(8g_JBC}ZJXH!dk~7MJkHv;3SJYFE99P!Mx=gpHd(b4J00mB5 z{TY(#58O!F$92GzU20q;k#Rp{#E&_mKf#p$&5wi=c!Mj(^pOZ!yf(#r z4|qPzon-tjYBt?Rm_tD-P ziZ=vXbs}mE-C}?MB%CI{=uZ*BC6;@c!}>FH<8$=l3m?)R|9i3oDTy~phJ=*FTeJc^ z*@Kg`f;`^^orI{25Jd)AgkaE9h4>RO{wG6Du*EurMg}C`Uh`F`%1tPNWV3RuXzr0_ z6)TJ?T`eco>sUjt8o3U1tv?yMfuOj>Rs9ucckujOY`=-HZ|rRD?o}EU>Dk=X-5d0e zoZy+1w3HK!mTC-^%WwC&{E|g{g?e1WPJGSzdmTq`gFW~LIo!nC`1T1Zyb={22jvW_ ziC~s~GgLu6DLF+e!1J47a$jMTwKz>Gf<6@u2#5BHM+gh~tPxeBYQGALJe+}D?C>A- zl^Pj~H!ooKSm$qOT7Ly~50RYcT)@i;A4B)>%2?+uZnwniFj9xn1&keEG)HLmlF%wH zM;E_HO3F3Ii5U2f?0-+|2du`AXvJ-+`!2R(9^1hzxQ|14P^!D1HRV}_B5{=%7%MU$ z_vWbN3dTH0zOwW_R5~FgPz~h~T2&-P%OgbjrZgO8U%W#*_?Ew#TCsp5OM3VTt>tS| o>AQU3lgJCF?d6<+%QF@5Q1IUZXZfz>jz;Hqm?2J|bCu!00irc)N&o-= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$UnboxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger$UnboxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..664f79c362ee12277b5723d4094d421bfe5ecfea GIT binary patch literal 4410 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 d%9pd7CqxxI carrier = MemorySegment.class; + MemoryLayout layout =SharedUtils.C_POINTER; + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout)); + } else if (cDesc.returnLayout().isPresent()) { + Class carrier = mt.returnType(); + MemoryLayout layout = cDesc.returnLayout().get(); + csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout)); + } + + for (int i = 0; i < mt.parameterCount(); i++) { + Class carrier = mt.parameterType(i); + MemoryLayout layout = cDesc.argumentLayouts().get(i); + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout)); + } + + return new Bindings(csb.build(), returnInMemory); + } + + public static MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, false, options); + + MethodHandle handle = new DowncallLinker(CLinux, bindings.callingSequence).getBoundMethodHandle(); + + if (bindings.isInMemoryReturn) { + handle = SharedUtils.adaptDowncallForIMR(handle, cDesc, bindings.callingSequence); + } + + return handle; + } + + public static UpcallStubFactory arrangeUpcall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, true, options); + + final boolean dropReturn = true; /* drop return, since we don't have bindings for it */ + return SharedUtils.arrangeUpcallHelper(mt, bindings.isInMemoryReturn, dropReturn, CLinux, + bindings.callingSequence); + } + + private static boolean isInMemoryReturn(Optional returnLayout) { + return returnLayout + .filter(layout -> layout instanceof GroupLayout) + .isPresent(); + } + + static class StorageCalculator { + private final boolean forArguments; + + private final int[] nRegs = new int[] { 0, 0 }; + private long stackOffset = 0; + + public StorageCalculator(boolean forArguments) { + this.forArguments = forArguments; + } + + VMStorage stackAlloc(long size, long alignment) { + long alignedStackOffset = Utils.alignUp(stackOffset, alignment); + + short encodedSize = (short) size; + assert (encodedSize & 0xFFFF) == size; + + VMStorage storage = stackStorage(encodedSize, (int) alignedStackOffset); + stackOffset = alignedStackOffset + size; + return storage; + } + + VMStorage regAlloc(int type) { + int gpRegCnt = (type == StorageType.INTEGER) ? 1 : 0; + int fpRegCnt = (type == StorageType.FLOAT) ? 1 : 0; + + // Use stack if not enough registers available. + if ((type == StorageType.FLOAT && (nRegs[StorageType.FLOAT] + fpRegCnt) > MAX_FLOAT_REGISTER_ARGUMENTS) + || (type == StorageType.INTEGER && (nRegs[StorageType.INTEGER] + gpRegCnt) > MAX_REGISTER_ARGUMENTS)) return null; + + VMStorage[] source = (forArguments ? CLinux.inputStorage : CLinux.outputStorage)[type]; + VMStorage result = source[nRegs[type]]; + + nRegs[StorageType.INTEGER] += gpRegCnt; + nRegs[StorageType.FLOAT] += fpRegCnt; + return result; + + } + VMStorage getStorage(int type, boolean is32Bit) { + VMStorage reg = regAlloc(type); + if (reg != null) { + if (is32Bit) { + reg = new VMStorage(reg.type(), REG32_MASK, reg.indexOrOffset()); + } + return reg; + } + VMStorage stack; + if (is32Bit) { + stackAlloc(4, STACK_SLOT_SIZE); // Skip first half of stack slot. + stack = stackAlloc(4, 4); + } else + stack = stackAlloc(8, STACK_SLOT_SIZE); + + return stack; + } + } + + abstract static class BindingCalculator { + protected final StorageCalculator storageCalculator; + + protected BindingCalculator(boolean forArguments) { + this.storageCalculator = new LinuxS390CallArranger.StorageCalculator(forArguments); + } + + abstract List getBindings(Class carrier, MemoryLayout layout); + } + + // Compute recipe for transferring arguments / return values to C from Java. + static class UnboxBindingCalculator extends BindingCalculator { + private final boolean useAddressPairs; + + UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) { + super(forArguments); + this.useAddressPairs = useAddressPairs; + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = TypeClass.classifyLayout(layout); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case STRUCT_REGISTER -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false); + bindings.bufferLoad(0, type) + .vmStore(storage, type); + } + case STRUCT_SFA -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT, layout.byteSize() == 4); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), true); + bindings.bufferLoad(0, type) + .vmStore(storage, type); + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + bindings.copy(layout) + .unboxAddress(); + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmStore(storage, long.class); + } + case POINTER -> { + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + if (useAddressPairs) { + bindings.dup() + .segmentBase() + .vmStore(storage, Object.class) + .segmentOffsetAllowHeap() + .vmStore(null, long.class); + } else { + bindings.unboxAddress(); + bindings.vmStore(storage, long.class); + } + } + case INTEGER -> { + // ABI requires all int types to get extended to 64 bit. + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmStore(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT, carrier == float.class); + bindings.vmStore(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } + + // Compute recipe for transferring arguments / return values from C to Java. + static class BoxBindingCalculator extends BindingCalculator { + BoxBindingCalculator(boolean forArguments) { + super(forArguments); + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = TypeClass.classifyLayout(layout); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case STRUCT_REGISTER -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout) + .dup(); + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false); + bindings.vmLoad(storage, type) + .bufferStore(0, type); + } + case STRUCT_SFA -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout) + .dup(); + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT, layout.byteSize() == 4); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), true); + bindings.vmLoad(storage, type) + .bufferStore(0, type); + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmLoad(storage, long.class) + .boxAddress(layout); + } + case POINTER -> { + AddressLayout addressLayout = (AddressLayout) layout; + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmLoad(storage, long.class) + .boxAddressRaw(Utils.pointeeByteSize(addressLayout), Utils.pointeeByteAlign(addressLayout)); + } + case INTEGER -> { + // We could use carrier != long.class for BoxBindingCalculator, but C always uses 64 bit slots. + VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false); + bindings.vmLoad(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.getStorage(StorageType.FLOAT, carrier == float.class); + bindings.vmLoad(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker$1Holder.class b/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker$1Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..39128f8a244ee9b362b94b6ea24a1f354d070405 GIT binary patch literal 729 zcmbVK%T59@6g`EJ!C@4{_j{oWaA7gV7z3IZqJac)0Won|h6=^8lgtdp-!d*tH1Pxc zDB~@@5|?c5*%?SLW=K_(R`Cf# zvQWITk!IK*bZ@!Ru?)5F`ArZ?)ze&b6p!|gO59g^_`n;+wkW6IR)!92Bqx!9Yh%jA zG_nlkF?hE3YJuOCAw#;}Y_(6D)iZ{J#u!Xx2CEu$B}0}Z%I5H{Bg3}n_=MyefhYVc z5h{~^gI3&E5ySB~#eQT{(R9V54vjkMw1Q#i$#Z3D&i(7yt{DZ1JJX&YL`wHAWZVzB zE>^J0km<>|uA^9JkKP^@isPscnLbqG@wx4@_TFn>&fow1`4@l+_H&rPq=t-+DP#po z&pRiE?FQ0!Eyw73zO;{A!)n<^e|=-saBO$*lVPg=2G^XNNWZYQ=Q$ne3rtsQjb^!4 z*%5eXz6DY#k7?vIPc*c`OKQ zq@s-TsbV=!+4n8?NO?4CMbmBXN4L!rfu9%6=hjQha412hUV10e*q6bv*J+;iWGQht zWN&xiwgcO9w`ITW+r7Z^DV0WZ9@b6&>&61A)u2sRzBt z&|luMp=lnChN=*m*9Zo!UB=JzPfIy`h>tW})A2Dr5m-;v^LgYYct0ZvgNCs86A6Rain2#2zGcCW;vw}F8iq|2)EYn2R1}|FDZ(1#f zI}4^q$__2xR_k~(6CB&*Z^3rE(kI1l>YCY-FngpF!?I_%yK$M1PnI!FKtS`NIu~HX z()=6k2m<-Q^2v@;D=@E^QSB%Zjh*v*ZyAH>&9)PF)qKMn_-(msE9$P$qGbPHQ3fz% zHQ5gsNODXL^{VSizv5W^zT`3+JrNpq{;wZj)GFxjf7*wJJyk1bEqRzyiG+@;lU77! zs^NQqTNhnnNeWEWyBx8`7B$TWQ{b9vQXKDdHGvgmk%NI%?yPY~ov1JK3gTCe0uT6~ z4R;?ky33$XM|A&VxTr0WYP33-+{4s#7Gb zP>J%2Bwam^yp!-c6Pq1T{S5=Kbw=MR4OZXWD_jqMw_fA!@3^X%j7XmeC5jBsGGRX;o;4#V^GnAUZcbwhiTyb8(9JZ-rH=Dx~J``1sPdS>|+`nBIc%=XU literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker.java b/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker.java new file mode 100644 index 00000000..9810fbf1 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/LinuxS390Linker.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 IBM Corp. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.s390.linux; + +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteOrder; +import java.util.Map; + +public final class LinuxS390Linker extends AbstractLinker { + + private static final Map CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT); + + public static LinuxS390Linker getInstance() { + final class Holder { + private static final LinuxS390Linker INSTANCE = new LinuxS390Linker(); + } + + return Holder.INSTANCE; + } + + private LinuxS390Linker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return LinuxS390CallArranger.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return LinuxS390CallArranger.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/TypeClass.class b/tests/test_data/std/jdk/internal/foreign/abi/s390/linux/TypeClass.class new file mode 100644 index 0000000000000000000000000000000000000000..a8d0481970c2b248597fa7b5c5dce3ba1a98328d GIT binary patch literal 5176 zcmb7IX?R>!8GdhOxs%CF6VejfQbnWk+f4W`I)Gr65inaqTl zJ0(HUDx%_Etx6FT#Znj45VUQmKyeq`_Z<-x_w|=N6@0&Q@6FsP@xjdV%$#$+bI!NC z-*V2G$DV!gVE|qDmyRk8EB6gwAJ61$tB^CZ@xA$il}YE~=1?YHTyyEg@oXkn8jtr+ zj9Fb-vskQ#hM<8E!W!z5{e8Q;`mgQl-rAGw@9xtOPt1u~yKsvbs1|Nfms@g6hmdOw z7(%X}5wfMbue-OaTPEijsFO*3=Z>CUN*3B#1{xGiC|e!c0t06YEwm-EqoZF|y~w~q zEaJ{(109Lo-AN4>Uo}Uiqc{gkbSyG(F3uzGR5qWpG%Q%rn%HOVH{)3|myYik+GnNg z_9&Y1VjV38mSP$8E-&cLl}4$?eluILcI?$~$qL_Y1$DcRkhBY#T)N#aK^Q3h%MDzB z6&k`DGr5etNkgNbmAkX2b)W_@wCT9ez)D=C;oPz=p3?_JnS?o!FWFQrWflq!!=!(3XE&#OW_Wwo$=>x9cyvzKRy8h_i47E4 z=GQf17R(gGvl<&^_A&-uc{VwcFWA+1smyGy(4&VTot9mlGS^ihERoNptI;hJTPoOX z$>vS6dzsAiF!;)XF3*>SvX+i3G&Gf|9&+2Q(R^VdX{AT4oULPf#iE{U)=Hb%q;1+( z_jt-0voraejvb7~GAGARouy26*eXQPi(TSY=2T!s>p%qkw5`j`ux1p2hqAxTz4t0NR7AbiBgA)wret3gs(?0mb#2qt6R)H?Bm5 z>kOE(Ib!D>Y7_~iM187r_H61f7WX2pW5hrP`!t+a#-S2XFBl_343A{yCaOU^wuM-~ z)7uFRLRa{;~j;9Ig!W|?I=pv6=hMFFmMxINnML6Giw$cp+yNG zsfij^yEdrpveTcMp2AxT`O=uPwOx|!X1rR*YYZH~YiCV1-+B$Tqt@t<vh~};0<`A7tJ%%L_b4yO*_woZLHYcw}a2wvN<1Gf>inmdQ0$p+NmeAcJ zX0g{AXZ{oCJ+k8+2Hq)kE|?=($GbE%Ki^wP>xPn*OS#3P1_yD-zDZ28d zoGlaYGjKZ&(`0wTb8(BOw5p#Ts!n3LunGk4H*hEJqI%}=nbGCe+}1tf(+?WB8y}*W z3ZH6N<&Q^Ciq98bjh#W3u-$@t415Gf2tv_|!5$$WHSke~k3oJu6 zMJ}C9WChX=h7TC{jBshp6q7uDvX&~3GmJ#gF$2eOg2Cij#tKkM*^X(uURcf?ZPW3f zhL&>txuvzEkSK5X9_J-hk8-!M(bQJ7cAu7?qFAbn9iz8WO7z- zNyRW0iR79f6g<5)t#r_;aSdo`tS_W#upMRx+eV|@|5!nbnC>7 zp#O_p9k(jYCvg6|BI9Jb7&RAot~QekJkhJIJOxk#TyK!rU6ys`5_+U*p3#)QV} zQ)I|2T23i2q{}pQZxvxD9eIp-b;CObA{$eDa;ST3hfk>7b_vp)3ZZx+n#`99DQinc z5@(+1qBOWjO33C_%-UvNBlOLSu?+n%QZJ}DeCxH6J@`~V2dAoca zkCV?gIBH=lpXd}Ck74mCoHNOhhHvsWtmc++{Zf1jRcifOwz4DIpv6w0=@c|sUsbXG z+oTxIDtrgu<>-6-hPds3EalA~0mW<;+W@EZSlg20IRAcj{}(46-xn(sr|K%2!#=-1 zP+R&CmBWf6#iXYYBpVJ9!d`!IS76JdT|W$z#~vb_|1Tj^Wzl7GJk2vDhl6%(Dh#zw#_&JoHu=i6%37wWZ z{+>W>pqd8ruyhSRK)C|r8XC-y+1#`M*B`nIOWBSdI*fDJ=Go3?djs1Vw#7qtAQZSS zcptX~l+q1k0<=@;M#OO$Ro>)Nat)RI8Rz*H@MB+$m?N1Jdr+9f8l!BNXjL@k`!JzU~h~RGwYbS7Sb@}Z+Np1~~29D$N z4 carrier = type.carrier(); + if (carrier == boolean.class || carrier == byte.class || carrier == char.class || + carrier == short.class || carrier == int.class || carrier == long.class) { + return INTEGER; + } else if (carrier == float.class || carrier == double.class) { + return FLOAT; + } else if (carrier == MemorySegment.class) { + return POINTER; + } else { + throw new IllegalStateException("Cannot get here: " + carrier.getName()); + } + } + + private static boolean isRegisterAggregate(MemoryLayout type) { + long byteSize = type.byteSize(); + if (byteSize > 8 || byteSize == 3 || byteSize == 5 || byteSize == 6 || byteSize == 7) + return false; + return true; + } + + static List scalarLayouts(GroupLayout gl) { + List out = new ArrayList<>(); + scalarLayoutsInternal(out, gl); + return out; + } + + private static void scalarLayoutsInternal(List out, GroupLayout gl) { + for (MemoryLayout member : gl.memberLayouts()) { + if (member instanceof GroupLayout memberGl) { + scalarLayoutsInternal(out, memberGl); + } else if (member instanceof SequenceLayout memberSl) { + for (long i = 0; i < memberSl.elementCount(); i++) { + out.add(memberSl.elementLayout()); + } + } else { + // padding or value layouts + out.add(member); + } + } + } + + static boolean isSingleFloatAggregate(MemoryLayout type) { + List scalarLayouts = scalarLayouts((GroupLayout) type); + + final int numElements = scalarLayouts.size(); + if (numElements > 1 || numElements == 0) + return false; + + MemoryLayout baseType = scalarLayouts.get(0); + + if (!(baseType instanceof ValueLayout)) + return false; + + TypeClass baseArgClass = classifyValueType((ValueLayout) baseType); + return baseArgClass == FLOAT; + } + + private static TypeClass classifyStructType(MemoryLayout layout) { + + if (!isRegisterAggregate(layout)) { + return TypeClass.STRUCT_REFERENCE; + } + + if (isSingleFloatAggregate(layout)) { + return TypeClass.STRUCT_SFA; + } + return TypeClass.STRUCT_REGISTER; + } + + public static TypeClass classifyLayout(MemoryLayout type) { + if (type instanceof ValueLayout) { + return classifyValueType((ValueLayout) type); + } else if (type instanceof GroupLayout) { + return classifyStructType(type); + } else { + throw new IllegalArgumentException("Unsupported layout: " + type); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/X86_64Architecture$Regs.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/X86_64Architecture$Regs.class new file mode 100644 index 0000000000000000000000000000000000000000..962f9e12582f3c8e48285173c0d3234a2478a55a GIT binary patch literal 2665 zcma)-TU=CC6vn^9b-=A2H{S4)T3BM~fFeq$X{3qa4HWV2FbpsVGdMFS-mT26%&e@; ztW2%6tTbl}vYMVmAgoBK+;Yc_!-a+b+{AwS3Vq$^zY-FQTCX7L6 zbaCKss$1p{M-rh}B+%@ykH$jbhKN5<8}_#s7x`<(6fY?*nivZvX}%X;7$Sl#&u9qYXwWDba0(1&T@y zN)(MFDpYiv!8k<|iAE?YGnlAo646LScN$DmR8CZ+=q`hDMbn5zDVkw0P0=g|Y3(g7 z1zH?c2D7y?x~z~d9{uYx>+))YS-QL?xt!t5H>gpzFv%FtVuOXsmL?eksx?@utS-qI zQN2N(vc@E1NKFQf%9@j`Sf3j)XjaymWTTbE3|f^*p=;=Tr7H{)%G#5RFLkv+yRx+o z(q&!pwXQcFer4YnxU>Om&6&0wp-?H*({j~Q%N zxWj`?=ShPd3U_*t`Rp>-sc^Rknb30vyA|&7AT!!)ut(wkBpks)dC6eE!UG;;Mz0tg zPF?@2FDb3c#s*LGU!lv+JnsKjKOJzXFbS_&KaCl zc;17|=tG0^3NLz)8C^2CsPJ+Uj$}rk8eCR*#e>Y~3xg{kNHySz&AG7?9I~bs%Tp*7@8c`hxPjB zd>pQWPGaaj8yI9*KlvWzB(jJS0J+>CBQL;>!F63S{W`kRvWvClXc05LIRm zRR#`KrVLd^3svR`Ri+44W(QRU234j6RYn6<<^ffP0987lDlJWwHl|AJQl(v~(xTKx zPo))kFYQN_mZM6WQKhq}(o9t8ALH$xsdU-De zOO+a>N?B5+5~)&rRH--WMNg%wcrS${ngXdWWXSbPx$}!UqUl3V!a2g9zmlu|49vh) zxtinxe2s79&WCUR+?;ZdpA^p3RGZm>tfT0fX1mk$Ot-yh`efLCG}mR?fi&0qY#z;x zZiXE~H`L9vx6loDeYSvZgqvlH=!)HJJBIF7x04-9H{LaN0^RLyXL|?TWVef*LO0dz zYAfibr`nkvs62`}X?8BnymY&OW>JP+LKDceL7I@yHqeA6vSoBF5?PdPxkMJHYm>-U z(yfxn*3hk!$Tra3Es@OJtAGJ?gslak?kmZuTj>G4P+}`#m-ElY9o}_!r?PK4jd&li--=%xc z?PuSo`@rpQFVKDDUS~h1`@|h!Kco9xi@|{w!#U|%U?#HUFtn&dUsNGa&dgz$gJM); z0_I{WYJ|+gV$7H0Yyo0&Ag;wCY!_e?g;vkO8A$SHMTtK}Hw+4JKJAOeJ zzoH4hVVRR6XQ4rh(-RSAAfnDtIR}fd+!>FUGX-&{QqI7IXmjeZ!fC}yXSJMvo3P5+ whSknata0|r*>?!*oD*2@oW%y`k{olX_)c<2k!Srt&Bl+S*^;3v*PoE}2X)m6LI3~& literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/X86_64Architecture$StorageType.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/X86_64Architecture$StorageType.class new file mode 100644 index 0000000000000000000000000000000000000000..49cda54e4f0cd288b993c45a04474aa658d31022 GIT binary patch literal 447 zcmb7<%}&BV6otauU6Y-Q96)&}r^H{uh+G5u2JapPUvv`iJ zTG+KwrxTkRxm3}|tMai;XsqO$6p7SJF`BPiwV>g#FRrD%`AcTxF83%|czri6XTA`kgr) zLTRWn+fOs=E`4Gjr$8>(2ex zfA0Jpz!2_55kOEzNI?^tCB(04OIp&@thwa*nX7uS|#j zX;`*iwlp(2TP*9woR!pOjO22EU-HsG|8##}x}2XkY$~Xh^&ZtOmbE!Ocdew$h)PKQ zj|yZc5_Z>3%bKP>r#>-?h+gyRqzPfd1|dx(yfAoLy6J*6{dREk-R-pLd9c3#dZlh z6WPrfI~DA}P6=VV=vpe_k;HltDve>62++qRv~Oe%!}7RrP@}L+j(I1Iq6^(ZQ;&r0 zi9t2H?jWh&Nx`&NFzuro1XJ&17`+lgmj;d}!Z;v7>XmUw!rq1(rU$cU^h&;Llo>F(??n|DOjAIh^TxrZ*J6$S$y#(+ZpWeC%yrA^e4IjNNmfqTS| zJ#VnCjx>(z#@B9&{xK@5t>qWQ&C3SP3+XcN@w`cOEzZIi8=RDDwYqoxVcDAB(oQW$Nr4x>=AR5W=hnR-oa+bYE`w#`Yew8c=4~Fvk!}E zqW$A~#U9f|TdBynE}^es)7`jn^teHY4;G6y2PdsGrrYzyLM4vhiUD+WT=KmVQmxIn zA-eqU6?_Y?#PJFV?+C(81wX?ZalApopQCse@5#8O;C=jM%|vflOT`5}IqJBJ+iA0! zXaXEwVvBz4-`*(W?ClA;)}7U?f~i+}MvKLTYANNLXS~khqpT4Wz0uFU^+k8f&1G2w zwZY2MJfxYX%D0h7`>bW@W#{>!Gh<_3WAfUy2!o6d#jSb2j*ZSN&-?HKaovZ{5})(o^TZ7wewFxw4;S*L4;S)_ zK3vFKK3wn@QL5SVIpSp>ULkI;!Np^i&sa)Sd4eRr62DFRS0KIT9BGNaVj1YebNp3Y z1}x(mF$vG(^ZXUU=cp>cZ)`{NTaZIH5DMNT8bn>ifTQA3m(5c_0er!+>5JrULLhQl z81W^1+0*+bLXN=5jklx2cl{1D?T7oW$ceg}r=w9KaxkNfSqP?HsAuIpVW3jHaETP>8cZ z6kowtJyX-vD9mcPi>|3)ytVVd3UO!FnwY}`qrqr}4p0)^H!Z$qQP6_97rJ|<+-NVtT;C^)~bU INTEGER_REG_SIZE; + case StorageType.VECTOR -> VECTOR_REG_SIZE; + case StorageType.X87 -> X87_REG_SIZE; + // STACK is deliberately omitted + default -> throw new IllegalArgumentException("Invalid Storage Class: " +cls); + }; + } + + // must keep in sync with StorageType in VM code + public interface StorageType { + byte INTEGER = 0; + byte VECTOR = 1; + byte X87 = 2; + byte STACK = 3; + byte PLACEHOLDER = 4; + } + + public static class Regs { // break circular dependency + public static final VMStorage rax = integerRegister(0, "rax"); + public static final VMStorage rcx = integerRegister(1, "rcx"); + public static final VMStorage rdx = integerRegister(2, "rdx"); + public static final VMStorage rbx = integerRegister(3, "rbx"); + public static final VMStorage rsp = integerRegister(4, "rsp"); + public static final VMStorage rbp = integerRegister(5, "rbp"); + public static final VMStorage rsi = integerRegister(6, "rsi"); + public static final VMStorage rdi = integerRegister(7, "rdi"); + public static final VMStorage r8 = integerRegister(8, "r8"); + public static final VMStorage r9 = integerRegister(9, "r9"); + public static final VMStorage r10 = integerRegister(10, "r10"); + public static final VMStorage r11 = integerRegister(11, "r11"); + public static final VMStorage r12 = integerRegister(12, "r12"); + public static final VMStorage r13 = integerRegister(13, "r13"); + public static final VMStorage r14 = integerRegister(14, "r14"); + public static final VMStorage r15 = integerRegister(15, "r15"); + + public static final VMStorage xmm0 = vectorRegister(0, "xmm0"); + public static final VMStorage xmm1 = vectorRegister(1, "xmm1"); + public static final VMStorage xmm2 = vectorRegister(2, "xmm2"); + public static final VMStorage xmm3 = vectorRegister(3, "xmm3"); + public static final VMStorage xmm4 = vectorRegister(4, "xmm4"); + public static final VMStorage xmm5 = vectorRegister(5, "xmm5"); + public static final VMStorage xmm6 = vectorRegister(6, "xmm6"); + public static final VMStorage xmm7 = vectorRegister(7, "xmm7"); + public static final VMStorage xmm8 = vectorRegister(8, "xmm8"); + public static final VMStorage xmm9 = vectorRegister(9, "xmm9"); + public static final VMStorage xmm10 = vectorRegister(10, "xmm10"); + public static final VMStorage xmm11 = vectorRegister(11, "xmm11"); + public static final VMStorage xmm12 = vectorRegister(12, "xmm12"); + public static final VMStorage xmm13 = vectorRegister(13, "xmm13"); + public static final VMStorage xmm14 = vectorRegister(14, "xmm14"); + public static final VMStorage xmm15 = vectorRegister(15, "xmm15"); + public static final VMStorage xmm16 = vectorRegister(16, "xmm16"); + public static final VMStorage xmm17 = vectorRegister(17, "xmm17"); + public static final VMStorage xmm18 = vectorRegister(18, "xmm18"); + public static final VMStorage xmm19 = vectorRegister(19, "xmm19"); + public static final VMStorage xmm20 = vectorRegister(20, "xmm20"); + public static final VMStorage xmm21 = vectorRegister(21, "xmm21"); + public static final VMStorage xmm22 = vectorRegister(22, "xmm22"); + public static final VMStorage xmm23 = vectorRegister(23, "xmm23"); + public static final VMStorage xmm24 = vectorRegister(24, "xmm24"); + public static final VMStorage xmm25 = vectorRegister(25, "xmm25"); + public static final VMStorage xmm26 = vectorRegister(26, "xmm26"); + public static final VMStorage xmm27 = vectorRegister(27, "xmm27"); + public static final VMStorage xmm28 = vectorRegister(28, "xmm28"); + public static final VMStorage xmm29 = vectorRegister(29, "xmm29"); + public static final VMStorage xmm30 = vectorRegister(30, "xmm30"); + public static final VMStorage xmm31 = vectorRegister(31, "xmm31"); + } + + private static VMStorage integerRegister(int index, String debugName) { + return new VMStorage(StorageType.INTEGER, REG64_MASK, index, debugName); + } + + private static VMStorage vectorRegister(int index, String debugName) { + return new VMStorage(StorageType.VECTOR, XMM_MASK, index, debugName); + } + + public static VMStorage stackStorage(short size, int byteOffset) { + return new VMStorage(StorageType.STACK, size, byteOffset); + } + + public static VMStorage x87Storage(int index) { + return new VMStorage(StorageType.X87, STP_MASK, index, "X87(" + index + ")"); + } + + public static ABIDescriptor abiFor(VMStorage[] inputIntRegs, VMStorage[] inputVectorRegs, VMStorage[] outputIntRegs, + VMStorage[] outputVectorRegs, int numX87Outputs, VMStorage[] volatileIntRegs, + VMStorage[] volatileVectorRegs, int stackAlignment, int shadowSpace, + VMStorage scratch1, VMStorage scratch2) { + return new ABIDescriptor( + INSTANCE, + new VMStorage[][] { + inputIntRegs, + inputVectorRegs, + }, + new VMStorage[][] { + outputIntRegs, + outputVectorRegs, + IntStream.range(0, numX87Outputs) + .mapToObj(X86_64Architecture::x87Storage) + .toArray(VMStorage[]::new) + }, + new VMStorage[][] { + volatileIntRegs, + volatileVectorRegs, + }, + stackAlignment, + shadowSpace, + scratch1, scratch2, + StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER), + StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER), + StubLocations.CAPTURED_STATE_BUFFER.storage(StorageType.PLACEHOLDER)); + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/ArgumentClassImpl.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/ArgumentClassImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..7d3710ca0342f821f05db795df1ed812ee9a09c8 GIT binary patch literal 2303 zcmbVNT~iZR7=AXJu$yHAAtH)Uu}CWkmQ+DNK|Z8`#wH|X0Zn`1EMX0c`EWJ~V=p>w zFZwHbt-a|5#hL1~(~j5uQJp^L?ApeWI#bxmdC&WCp7Va3_vO#Oe*FW$D(-0rDVRFg zdz5zTEyt_d)%3%L=eU)6+TL~3PiCgm&99n==@qZit~vGAYSnHwv$e<7C=`TEM9`%` zD;BaFTbWG-H*%+dnip8QiKxU9Nb8wRA?r3_3YltI8Nv6M=oNf~{B}`D`b;FG#r?Ti z!S|auD=oQUNA8vBvc&QCOk5Pgu6!n6*enUr zB@^#slrfI&tmL*cmV%itPZgwrF?^t5)WnCl!WhccM%|&u>fDf z*1UlvQW_>qT*XI>`(J}hyF_DMJ8evn zMr+^k6vV8SU4E3e9|vI>ZZpd+uXuJcALe9Y<&e%z2|y-f$WQgay57u>m6wj z&u8IO!7MV_hSg|$WoOM5RUCM0rc8==zI=@jD#__&EDwtD0+4bvNXl^_DaU}MY<@}E z^pdjGC1q<%%5DbY7eosaG0JZlOT=FxH%co0jAM-ag3GTkc0^9W9j;wcH$?lZoRT4F zKTRr57zriy663F+2>Z|*_McE<`c}wbjodna5gz+in6lxZN-#lHsJaWniB1{K54 zpm7xv)t9JJq6&%TOEf9bge3kHeI#e7AQ=b_6GtdWgo5O?;uwa=jw-XWhCc2`Sj|h& za2Y)ug>jC-bGU**q_|G-o5W3|aU0he&=d-o!5(I@PwCgVh3}{l*&Xl$406Iyk(brl zpsp7&P1j?p`1<)VD+Lt&+~6(`it_ab;gN`d!#^Ud{zSR&s$cjOd6i$t{@^NcK^N2> zby*?K=l|f|32iUvq18ziA{*b>!zvo~~DOsap$55Xnh z{KhL1*VPx8dJa`G(_zVIlDQF)j3JqsF3H3sGpk7^E}1!9GG`=nGw$0BNbXkLHyo7Q jeB8Gjeu;(W7!hscJ88&gGK?quFCPkeWeeNXhp_WE6Eo5t literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/ArgumentClassImpl.java b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/ArgumentClassImpl.java new file mode 100644 index 00000000..7bd9dc61 --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/ArgumentClassImpl.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.x64.sysv; + +public enum ArgumentClassImpl { + POINTER, INTEGER, SSE, SSEUP, X87, X87UP, COMPLEX_X87, NO_CLASS, MEMORY; + + public ArgumentClassImpl merge(ArgumentClassImpl other) { + if (this == other) { + return this; + } + + if (other == NO_CLASS) { + return this; + } + if (this == NO_CLASS) { + return other; + } + + if (this == MEMORY || other == MEMORY) { + return MEMORY; + } + + if (this == POINTER || other == POINTER) { + return POINTER; + } + + if (this == INTEGER || other == INTEGER) { + return INTEGER; + } + + if (this == X87 || this == X87UP || this == COMPLEX_X87) { + return MEMORY; + } + if (other == X87 || other == X87UP || other == COMPLEX_X87) { + return MEMORY; + } + + return SSE; + } + + public boolean isIntegral() { + return this == INTEGER || this == POINTER; + } + + public boolean isPointer() { + return this == POINTER; + } + + public boolean isIndirect() { + return this == MEMORY; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$1.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$1.class new file mode 100644 index 0000000000000000000000000000000000000000..b47a70f3945cc4c77516687ad81056b6340ec1ec GIT binary patch literal 992 zcmb7CT~8B16g@+iZd(^A6`|r6>Z+|M3ytuCF_KEPv9yM+_`uV2JGKMsE}7j{`8&S& ztR}`7!w>LB8SkuB&=+L0nLFp?&b{Y;eE;$F5I_}`9LA6`VOSVPnqg_TyXVLt7AoMr z^D0zA_5z1@r1N(5z7ripL&rVX7ge7}k^M{tU550K`vVa%tdz<-jnlqg%OZoUiJXNq zu>MOxmHYm>QatDhWiK#r@FhkXq)I)|;sa!WP!!WnYhurZ=x6=&U1Fv6`!tZV< z6)LTuXyJlZU_Nivo9@Pz<}O;elyI7P@{7A-;i~4wYmL^rYvLM1{wQ**vn#xqA@jiV zWgz2+iGXbeqZ)Pv!(>ASqB(fo5z6HqpO``;^tivxmDG4dPPAk0?NLWZIM)sb$`duI zUrZgJz@pAgaW?|b4 zIohA$QoVXR^YgS_^R($KU)1}hZ^T^34YD?&cSz9HD4DtYt8RP}b qAoJ2BkIlaiidjm$%D6+;zyh835@rF5WD68w3=Wnb6{$A*@|mANp7DbK literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$BindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$BindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..6b63ce79f96e5a94efeec94bd0927a8c1c81c443 GIT binary patch literal 979 zcmbtTO>Yx15PeRTZjy$!8$Q}npaF`MfFC4;9x* z_;N57L&vbvky^SgL$T59`zSFy8;{66e-?O7Ocr4EcC z9%1%+E;T$6gbg#r$*I6cC0AT!@EWJhei_%X=3~8z4Ft;z97;WsI=K{J2<)Gt42SXm zCf=reqjV$~)?=x~Nj4b>^NJ4?A+6Feb(6cy(3{2! zjGb0@Y0}Q$>poAu-6i2lFU`zQJePSjgR2v?pFfMCbRw)fO0DzpfMI{RW>WoLXf4dF zE`q8REQ}>#3w8JEG@1qaR~T;Q!%0>FUOu{n)W|y~FFy}j=U}bR@L%toqx=!o53|r4 zw638@>o*GgP82_g2)KQ53Af0~zW|%q0`q`v+#%{6!V0)cH}B1?``DfBbv&fKMrS_i Nc!UzASI3@L`UM>>5^?|l literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$Bindings.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$Bindings.class new file mode 100644 index 0000000000000000000000000000000000000000..6b0d00b68f1b1102e2017a3c53356980a1427e1d GIT binary patch literal 2027 zcmbtVYg5}s6g|sJhKLwDP8#x}O-YMIikdXd%j5x06Fg&RCuHah?HAeJg21fkN@mJ` z%709DjR(1(5t12zURBrvw& z?Rak6Q)}*P*$i|`U})A?e)LqJf2zDPj2wn7jMz8_Tj0S)Yt!{rB(?I|?jM1c{+e>V zhVTA$|DGG}hC6Q6Yq#gLCZg1n^S)~NYAqDVH+jzOvi!3nRZ|K$^{!wBBV$`JQJlAt z#~35_!7EhC+o0UE3XI)B)R45zLHCwt%lTZyhfYZ7V814yy9u!yr+i)(YnvL zAAPpkEcv30)`QkBp7ypRdyjCXsWXZYw`@(|B2zkS>rAR5FfpF`ByiiHb?fYtBE&2d zZe%&==%#$>o74-&>Y(js3#Ln$Q@V-af~Q(-8BW%NV6(Gb$w-}Elgvr#_-1!ozK~&4``f&;S(j?t3&ZR| zit*cNkSzPL+nE+$z^*AJbqp!lKDmRzWZ@@)TSw{lNXNn}fg8O|S+yj0+~Gv(<51{F z(Tq;+ie`SrE5{U93xYHFD_Y&;+wWWlxR#uMA)M(wSkARQj5^o%P&j=ij{|Q%$$f$eB3v-9=6@-%IZQW)Y1}3P2R^<_k=*zl z77{T_qdu`CEb$rO42Dm i^2->btgv5lxQ~Z;gvXfYX_1~e`c^TH7kG&UjDG~xT-N#k literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$BoxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$BoxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..b5169ce60fc9c71d0bdae3f4a609d5066edc705c GIT binary patch literal 4651 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 gvR_d43fGuR{SYy|N`(9Qzh18ef~*U#(^b literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$UnboxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/CallArranger$UnboxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..0b35cb010b18e971777bdb6b28aa3ba8867f5998 GIT binary patch literal 4485 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 Xugcft8|4Ag carrier = MemorySegment.class; + MemoryLayout layout = SharedUtils.C_POINTER; + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout)); + } else if (cDesc.returnLayout().isPresent()) { + Class carrier = mt.returnType(); + MemoryLayout layout = cDesc.returnLayout().get(); + csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout)); + } + + for (int i = 0; i < mt.parameterCount(); i++) { + Class carrier = mt.parameterType(i); + MemoryLayout layout = cDesc.argumentLayouts().get(i); + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout)); + } + + if (!forUpcall && options.isVariadicFunction()) { + //add extra binding for number of used vector registers (used for variadic calls) + csb.addArgumentBindings(long.class, C_LONG, + List.of(vmStore(rax, long.class))); + } + + return new Bindings(csb.build(), returnInMemory, argCalc.storageCalculator.nVectorReg); + } + + public static MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, false, options); + + MethodHandle handle = new DowncallLinker(CSysV, bindings.callingSequence).getBoundMethodHandle(); + if (options.isVariadicFunction()) { + handle = MethodHandles.insertArguments(handle, handle.type().parameterCount() - 1, bindings.nVectorArgs); + } + + if (bindings.isInMemoryReturn) { + handle = SharedUtils.adaptDowncallForIMR(handle, cDesc, bindings.callingSequence); + } + + return handle; + } + + public static UpcallStubFactory arrangeUpcall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, true, options); + final boolean dropReturn = true; /* drop return, since we don't have bindings for it */ + return SharedUtils.arrangeUpcallHelper(mt, bindings.isInMemoryReturn, dropReturn, CSysV, + bindings.callingSequence); + } + + private static boolean isInMemoryReturn(Optional returnLayout) { + return returnLayout + .filter(GroupLayout.class::isInstance) + .filter(g -> TypeClass.classifyLayout(g).inMemory()) + .isPresent(); + } + + static class StorageCalculator { + private final boolean forArguments; + + private int nVectorReg = 0; + private int nIntegerReg = 0; + private long stackOffset = 0; + + public StorageCalculator(boolean forArguments) { + this.forArguments = forArguments; + } + + private int maxRegisterArguments(int type) { + return type == StorageType.INTEGER ? + MAX_INTEGER_ARGUMENT_REGISTERS : + MAX_VECTOR_ARGUMENT_REGISTERS; + } + + VMStorage stackAlloc() { + assert forArguments : "no stack returns"; + VMStorage storage = X86_64Architecture.stackStorage((short) STACK_SLOT_SIZE, (int)stackOffset); + stackOffset += STACK_SLOT_SIZE; + return storage; + } + + VMStorage nextStorage(int type) { + int registerCount = registerCount(type); + if (registerCount < maxRegisterArguments(type)) { + VMStorage[] source = + (forArguments ? CSysV.inputStorage : CSysV.outputStorage)[type]; + incrementRegisterCount(type); + return source[registerCount]; + } else { + return stackAlloc(); + } + } + + VMStorage[] structStorages(TypeClass typeClass) { + if (typeClass.inMemory()) { + return typeClass.classes.stream().map(c -> stackAlloc()).toArray(VMStorage[]::new); + } + long nIntegerReg = typeClass.nIntegerRegs(); + + if (this.nIntegerReg + nIntegerReg > MAX_INTEGER_ARGUMENT_REGISTERS) { + //not enough registers - pass on stack + return typeClass.classes.stream().map(c -> stackAlloc()).toArray(VMStorage[]::new); + } + + long nVectorReg = typeClass.nVectorRegs(); + + if (this.nVectorReg + nVectorReg > MAX_VECTOR_ARGUMENT_REGISTERS) { + //not enough registers - pass on stack + return typeClass.classes.stream().map(c -> stackAlloc()).toArray(VMStorage[]::new); + } + + //ok, let's pass on registers + VMStorage[] storage = new VMStorage[(int)(nIntegerReg + nVectorReg)]; + for (int i = 0 ; i < typeClass.classes.size() ; i++) { + boolean sse = typeClass.classes.get(i) == ArgumentClassImpl.SSE; + storage[i] = nextStorage(sse ? StorageType.VECTOR : StorageType.INTEGER); + } + return storage; + } + + int registerCount(int type) { + return switch (type) { + case StorageType.INTEGER -> nIntegerReg; + case StorageType.VECTOR -> nVectorReg; + default -> throw new IllegalStateException(); + }; + } + + void incrementRegisterCount(int type) { + switch (type) { + case StorageType.INTEGER -> nIntegerReg++; + case StorageType.VECTOR -> nVectorReg++; + default -> throw new IllegalStateException(); + } + } + } + + abstract static class BindingCalculator { + protected final StorageCalculator storageCalculator; + + protected BindingCalculator(boolean forArguments) { + this.storageCalculator = new StorageCalculator(forArguments); + } + + abstract List getBindings(Class carrier, MemoryLayout layout); + } + + static class UnboxBindingCalculator extends BindingCalculator { + private final boolean useAddressPairs; + + UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) { + super(forArguments); + this.useAddressPairs = useAddressPairs; + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = TypeClass.classifyLayout(layout); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass.kind()) { + case STRUCT -> { + assert carrier == MemorySegment.class; + VMStorage[] regs = storageCalculator.structStorages(argumentClass); + int regIndex = 0; + long offset = 0; + while (offset < layout.byteSize()) { + final long copy = Math.min(layout.byteSize() - offset, 8); + VMStorage storage = regs[regIndex++]; + if (offset + copy < layout.byteSize()) { + bindings.dup(); + } + boolean useFloat = storage.type() == StorageType.VECTOR; + Class type = SharedUtils.primitiveCarrierForSize(copy, useFloat); + bindings.bufferLoad(offset, type, (int) copy) + .vmStore(storage, type); + offset += copy; + } + } + case POINTER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + if (useAddressPairs) { + bindings.dup() + .segmentBase() + .vmStore(storage, Object.class) + .segmentOffsetAllowHeap() + .vmStore(null, long.class); + } else { + bindings.unboxAddress(); + bindings.vmStore(storage, long.class); + } + } + case INTEGER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + bindings.vmStore(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.VECTOR); + bindings.vmStore(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } + + static class BoxBindingCalculator extends BindingCalculator { + + BoxBindingCalculator(boolean forArguments) { + super(forArguments); + } + + @Override + List getBindings(Class carrier, MemoryLayout layout) { + TypeClass argumentClass = TypeClass.classifyLayout(layout); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass.kind()) { + case STRUCT -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout); + VMStorage[] regs = storageCalculator.structStorages(argumentClass); + int regIndex = 0; + long offset = 0; + while (offset < layout.byteSize()) { + final long copy = Math.min(layout.byteSize() - offset, 8); + VMStorage storage = regs[regIndex++]; + bindings.dup(); + boolean useFloat = storage.type() == StorageType.VECTOR; + Class type = SharedUtils.primitiveCarrierForSize(copy, useFloat); + bindings.vmLoad(storage, type) + .bufferStore(offset, type, (int) copy); + offset += copy; + } + } + case POINTER -> { + AddressLayout addressLayout = (AddressLayout) layout; + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + bindings.vmLoad(storage, long.class) + .boxAddressRaw(Utils.pointeeByteSize(addressLayout), Utils.pointeeByteAlign(addressLayout)); + } + case INTEGER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + bindings.vmLoad(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.VECTOR); + bindings.vmLoad(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker$1Holder.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker$1Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..cc2eee31d7f3d243bb06b5749f4047d797f73202 GIT binary patch literal 707 zcmb7CO-}+b5PgM}g=H1|{?>yY)Pof@8Y3|=L?a2}0Yl=kEES7uH`%U4ewOh-qKQAi zA7z{cKjM)~XXZ`&=5=O1K40Gfl(6a`fus$~#RyUi`L^f??hD=GSB5pH=eI#9RZDZxQ2gm&pPR1f@LJc@DX1uYFGB}5k{M*-+8A{) zh8)A;kR0oUi@T3Wf+czE%YOo3Z{#m|J^~S7CeTYJXigC|9Z3?H=bmjY0nRg(ydDw-33h- z3s_{xwq#V+CKB2srF$Ej!|I83RHcb70z)Hp%Ua8@||L*@leOu_I+ fu?q_`ge5SGIkFb*%{-R+h>c~k4&Bd^T|xc}CnBlQ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker.class new file mode 100644 index 0000000000000000000000000000000000000000..1feba96a22f881b39c588b0550fcc2d32b4316d3 GIT binary patch literal 2321 zcmcgt+fv(B6kP|5g&hS5y`;DFk~j&FV1<%PQ&UpcKyWJT2OH1yDI?p*prA+|Nv8Eb z^h5gCrVq{Zp&!tX>U15+I5M?{X&{{uh;2RY1ORzpU|9I^tB zUUW|k+YP1fT8`24d}$xKhSj!>A0FN}f?;rKG=@Qo3)6N_q+i(B_nfZu1?H=@MzdV2 z>jK#=+qJ`Of!USSRvrsj)Uc%E3YGLzUMTW;5p1Ze?p>v#w63S1t!df1O0 z{po*pG%cb@ehRUBjd0N3BWa#LEamVX-q-Mfjt}vXfRT#Ln4^h&6Sz_-*Xp%urEESo z%iq-xn+*~dBR2?b$2hS1H1aV%(eSB`&v0Gf+8YkfXlhx`K$_Oj8-xP6XXRG;xmmA0 z6}XikVTy2}-ZMS-D6&w{aTB+g`O)=ittoKx!rN6hB#|pv)v%`H4(DLZm!T~T5e6x2uo|!2LmnTXvDtA)d8+E9Xt-Sd0@5&!wEjx%bZ`Gz;}J95vCpqnVWqB2jiYBC5( zArU5mdewEMUvaD;kX&Ztmq5d=z~j_FFKQ5s_8(0{!@jDLaU(uUrbH@_>XKf>1*+j& zfg2ZHVKEBK)q5PV!NxStH&Jk8YvQ=h)eMTrA_oKaxU<0>b)vq^D~O*t3VhE0Y_$7; z@_fKXlA9cr?A+RK(0<`$CKAna1inB9Ut*IpB~BsSrxL1FZ`Vjc9kW~m+MT=WuW?yf zi&ezdwxjE7vB>B;h4BCnBb6E+(Tp;t;W3RVWqdrQDu3&|@=A*GQmS&nZni~p3Zx>9 zsHh0i)$^M76H#YIZpTo6MFO_R@ZF=s>RWn+Ytiqm=nIj=I_W85k#x=C o3D0KmHOd?_l$yaeoL%Q!!BD{xc4%WSo5NE+5mk=QIGWkq--d&5QUCw| literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker.java b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker.java new file mode 100644 index 00000000..b1fce35a --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/SysVx64Linker.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.x64.sysv; + + +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteOrder; +import java.util.Map; + +/** + * ABI implementation based on System V ABI AMD64 supplement v.0.99.6 + */ +public final class SysVx64Linker extends AbstractLinker { + + static final Map CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT); + + public static SysVx64Linker getInstance() { + final class Holder { + private static final SysVx64Linker INSTANCE = new SysVx64Linker(); + } + + return Holder.INSTANCE; + } + + private SysVx64Linker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/TypeClass$1.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/sysv/TypeClass$1.class new file mode 100644 index 0000000000000000000000000000000000000000..f59eada13c1c3c369158206cdfd59be6d4fce1b7 GIT binary patch literal 882 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 W^C7P-98Jmmm* classes; + + private TypeClass(Kind kind, List classes) { + this.kind = kind; + this.classes = classes; + } + + public static TypeClass ofValue(ValueLayout layout) { + final Kind kind; + ArgumentClassImpl argClass = argumentClassFor(layout); + kind = switch (argClass) { + case POINTER -> Kind.POINTER; + case INTEGER -> Kind.INTEGER; + case SSE -> Kind.FLOAT; + default -> throw new IllegalStateException("Unexpected argument class: " + argClass); + }; + return new TypeClass(kind, List.of(argClass)); + } + + public static TypeClass ofStruct(GroupLayout layout) { + return new TypeClass(Kind.STRUCT, classifyStructType(layout)); + } + + boolean inMemory() { + return classes.stream().anyMatch(c -> c == ArgumentClassImpl.MEMORY); + } + + private long numClasses(ArgumentClassImpl clazz) { + return classes.stream().filter(c -> c == clazz).count(); + } + + public long nIntegerRegs() { + return numClasses(ArgumentClassImpl.INTEGER) + numClasses(ArgumentClassImpl.POINTER); + } + + public long nVectorRegs() { + return numClasses(ArgumentClassImpl.SSE); + } + + public Kind kind() { + return kind; + } + + // layout classification + + // The AVX 512 enlightened ABI says "eight eightbytes" + // Although AMD64 0.99.6 states 4 eightbytes + private static final int MAX_AGGREGATE_REGS_SIZE = 8; + static final List COMPLEX_X87_CLASSES = List.of( + ArgumentClassImpl.X87, + ArgumentClassImpl.X87UP, + ArgumentClassImpl.X87, + ArgumentClassImpl.X87UP + ); + + private static List createMemoryClassArray(long size) { + return IntStream.range(0, (int)size) + .mapToObj(i -> ArgumentClassImpl.MEMORY) + .collect(Collectors.toCollection(ArrayList::new)); + } + + private static ArgumentClassImpl argumentClassFor(ValueLayout layout) { + Class carrier = layout.carrier(); + if (carrier == boolean.class || carrier == byte.class || carrier == char.class || + carrier == short.class || carrier == int.class || carrier == long.class) { + return ArgumentClassImpl.INTEGER; + } else if (carrier == float.class || carrier == double.class) { + return ArgumentClassImpl.SSE; + } else if (carrier == MemorySegment.class) { + return ArgumentClassImpl.POINTER; + } else { + throw new IllegalStateException("Cannot get here: " + carrier.getName()); + } + } + + // TODO: handle zero length arrays + private static List classifyStructType(GroupLayout type) { + List[] eightbytes = groupByEightBytes(type); + long nWords = eightbytes.length; + if (nWords > MAX_AGGREGATE_REGS_SIZE) { + return createMemoryClassArray(nWords); + } + + ArrayList classes = new ArrayList<>(); + + for (int idx = 0; idx < nWords; idx++) { + List subclasses = eightbytes[idx]; + ArgumentClassImpl result = subclasses.stream() + .reduce(ArgumentClassImpl.NO_CLASS, ArgumentClassImpl::merge); + classes.add(result); + } + + for (int i = 0; i < classes.size(); i++) { + ArgumentClassImpl c = classes.get(i); + + if (c == ArgumentClassImpl.MEMORY) { + // if any of the eightbytes was passed in memory, pass the whole thing in memory + return createMemoryClassArray(classes.size()); + } + + if (c == ArgumentClassImpl.X87UP) { + if (i == 0) { + throw new IllegalArgumentException("Unexpected leading X87UP class"); + } + + if (classes.get(i - 1) != ArgumentClassImpl.X87) { + return createMemoryClassArray(classes.size()); + } + } + } + + if (classes.size() > 2) { + if (classes.get(0) != ArgumentClassImpl.SSE) { + return createMemoryClassArray(classes.size()); + } + + for (int i = 1; i < classes.size(); i++) { + if (classes.get(i) != ArgumentClassImpl.SSEUP) { + return createMemoryClassArray(classes.size()); + } + } + } + + return classes; + } + + static TypeClass classifyLayout(MemoryLayout type) { + try { + if (type instanceof ValueLayout valueLayout) { + return ofValue(valueLayout); + } else if (type instanceof GroupLayout groupLayout) { + return ofStruct(groupLayout); + } else { + throw new IllegalArgumentException("Unsupported layout: " + type); + } + } catch (UnsupportedOperationException e) { + System.err.println("Failed to classify layout: " + type); + throw e; + } + } + + private static List[] groupByEightBytes(GroupLayout group) { + long offset = 0L; + int nEightbytes; + try { + // alignUp can overflow the value, but it's okay since toIntExact still catches it + nEightbytes = Math.toIntExact(Utils.alignUp(group.byteSize(), 8) / 8); + } catch (ArithmeticException e) { + throw new IllegalArgumentException("GroupLayout is too large: " + group, e); + } + @SuppressWarnings({"unchecked", "rawtypes"}) + List[] groups = new List[nEightbytes]; + for (MemoryLayout l : group.memberLayouts()) { + groupByEightBytes(l, offset, groups); + if (group instanceof StructLayout) { + offset += l.byteSize(); + } + } + return groups; + } + + private static void groupByEightBytes(MemoryLayout layout, + long offset, + List[] groups) { + switch (layout) { + case GroupLayout group -> { + for (MemoryLayout m : group.memberLayouts()) { + groupByEightBytes(m, offset, groups); + if (group instanceof StructLayout) { + offset += m.byteSize(); + } + } + } + case PaddingLayout _ -> { + } + case SequenceLayout seq -> { + MemoryLayout elem = seq.elementLayout(); + for (long i = 0; i < seq.elementCount(); i++) { + groupByEightBytes(elem, offset, groups); + offset += elem.byteSize(); + } + } + case ValueLayout vl -> { + List layouts = groups[(int) offset / 8]; + if (layouts == null) { + layouts = new ArrayList<>(); + groups[(int) offset / 8] = layouts; + } + // if the aggregate contains unaligned fields, it has class MEMORY + ArgumentClassImpl argumentClass = (offset % vl.byteAlignment()) == 0 ? + argumentClassFor(vl) : + ArgumentClassImpl.MEMORY; + layouts.add(argumentClass); + } + case null, default -> throw new IllegalStateException("Unexpected layout: " + layout); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$1.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$1.class new file mode 100644 index 0000000000000000000000000000000000000000..a198a2399c93d21b896e374a32dda01e01183520 GIT binary patch literal 1046 zcmb7?T~8B16o%iWrQ6m)3W6YhRapi6U@2dT(U>%Ki;blv-4!pm!0mQ~fpwS6Zb5&M z*J@&nG2EK?7yK{AGfTBxcmc`Io_XInGxN;M`T6_XF@OqI@)$r$N19;}84dG$oqbaT zF_(esn{PtN#ZF+lZDGD!T{e$I&DYE&#Wc$MLr8q_zMwFc2C?*_xo#8b}N ziFb?Pw(oSq8%$<*?0itK3@KP6l+$&_;cpW_yo&v4-pu&liD+pC;Iw8q$@p z!|8JBBH)eg+cuYu+xE#Bt%siLZ@N+_-7|;m*!A}5F?u?0hh6FMs!%gVPCwqf+MCw3 z0?!X45$vqrndgb%;emA&e><*eb2pr{{8zO07{VkNFb>prQ-k& z3e0cRHVxYirSF=K@q_0}d(Ab>s%<>EJYhVx-J16}FiNK5O!~g*u1P<8QT?;swFUWO zL%NonYS>Oq`ZLn0OJCs7Bh$$;&{EyvJONQrDf@KvBP}qXM!kAydu||*E61iU+wP|H z=bJN&Y3Mkl;joTD3<(Tvn2$`uAs%DCx*@Gl;NW%JwZj_%$=ukoh9d$-Z0z0z^dp0} zG#t}0g0}@O#=6HbBhXh`X)?BJX_HfTZppy%?Rx0>ENvL?sJc!FEbcod}=kCU85R(>T3kyQnFu*q3x%j$->VRICl)Dn8M0O-B*e1xm36?L80o z;hGFv=~?J4>hAT9Dmi8l6gv#8~{&O1C3Txc@Z&PQt8l4J$^vYJW}XY<+|^9LVsV3>&`truIT^AA5<4EqOI5 zFi7>txyHk)^cT&lL(7q}XPM5j>D%gm%a{t+ZSs3J9(C-Z?b>FG?6V7@X>HD$^;W9> z1$J(ewGqpu{S!@LQ_hy@`?l)h!yW726a-tW6D_^KXvbhraj+BG0jc2b5IDAzn5XqN zIhl?yQI6~R8!YT<7kFjwnAy}DPUMBuzgIP zR~w2tx$Rnx7q9`&%5dGQsZD%e;OEYaw)@E2lty#HBKheBdb;6S>eTEwIrgsG{~^Ej z2H}GA&B-8~@dBQ*`W@GmezaJUx<1)^&$X`tnO^Omg6Q42Nnlq))L;o*i{0|Eo2QMQ z;M<=(brQTqfcKsubr|w%NHy{3&4$arL+VZxy?IxmJ;~o7Zqe^Hzy9Kwve@|(TM+re z7PR~}2J$a4y!tDS=AYB}9NIRHZ{cKK{rw4tUt)AMwT&~+aO5SB<|-X*vK8a17r^`0`D+7Cr{REaoE2Bbdim(d-f2jYz&n&t^Sp z)&gfWp)Ar~!cq&$roy}f%EWjf*@80J1;rwiS_EaZ>9z}$H~`BmVudLaT!>Y^Q@k@) oxCqLU!MA+psUcPPcl?dg_5gict_(@&<2jyzc`%JC-!&Zn2cZ)!Ab)$5QhI$-EFs3+jsDw9t?tb*;3FIQCRiRo40fumuzDKN!Hp|^WX#cP~x~& zER-HRP3Gt4pP4TopKtE~GW27#7_w?Q z=Y%PxJGdlKnUb`k)*@IJW1FF0i5I~&S@^@Gl0{(XmNG2Op5f{+|FdLTc%QBazmxCe zvvrGHENmUp$D@u8g4BbSQp?7PHbPXIy$OdbuBY`_g~LCM&Uk}vM)n0x>L literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$Bindings.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$Bindings.class new file mode 100644 index 0000000000000000000000000000000000000000..82a0cf351fc1cc29d7842fc6696bdf97d927aacb GIT binary patch literal 1904 zcmbtV+foxj5Iqwv8*m{I0Ywl{L6d;2D54Ssxs*k!0wPd6;L|16W}$*nENFbkIPbzV7cG|A-FJK`PP_6N(^p#iGHYbGVdeYnvQsKt&f?z6%sHs6)Kzz$I*;h&VktFM&P(;IwhOCgLxr#%lp|#cEcAE zv4nx^NBew%yG3d3dqPG-=55n;qlOUU(^Zft`-O)Y)|)}kIS!XTB&UvvS4NM9cML=4 z@@vS^FvrkW+m)&mXvY{0r5HWj7?Nr}stKef6s?V5G+^)3mp(czsi8}2BJ&e0GkgLq z(|dxJV=~3iAG#~I0oo4)u6TflbfO?1n)y2g9>XKrH^s=TJ_7AD^ahDfF^$oxT(!(8 z+3}sWR~hucC1hx)SvGV{cqj1fzruU)I1Ha6GL?^bX807{)#AGXpEH4RJVA;O7%57J zNQQp~8Ztki)l$(A!qDFfGS>vR)Y4E1ZosgwbOcZRbrjENZKZn#RSjx7=Gz!1P)~J# Yj&Z!iTe2m|FOE@6ljIr9(!Xr?Up#ot82|tP literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$BoxBindingCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$BoxBindingCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..eadabcfc52211046d5289ae822fffc37e568ebbb GIT binary patch literal 4204 zcmbtXTXz%J75vqzFt*+J=!d$YbOgbu{uN zO`Bdq@AvddL+^yNO`C)SLCadDFMVl$K-X$t^V+rA*K{@Qccif-+meA+Yt2RH?6dbi zdw=^od;aw9?|u(p0@s6RfJcE>MI(Fyt@GNV7RhL4I&va0uO}S=->6|4&LII$c+ZRi zzre(N>O#aY9o;syOys;}>qgp)XbB^-d|-cM$uLvaQZ6!~Win&7O;x%biaVCArFD)a z^BIkQf>02YMwY0%*n-1uZIC(I#;8-ffIq%j2|dnCXfcfwtUw(*j3g_pW`z z4x&MHpi@DYimlitFmzWsPpxG2iHw%Z38>EM`%%jlh=*g9;I9UCT3@j2m6*0-<(=r+ zJ$L7K*+#SpJ=m_GSH*qUA<$pfMK^E)N+NG$Qab$^3~yr2l@E=Vq@w}!p5Z@6@*qH7ILEzBE&*e5ON_FDsNPv;ps`4kN2o}01t8- zmQ5gNnIdW@CARjc7{FeEju3;d+m2zGxx+?IOJwwvfHJNMLvB@foNU7WQLwPc;J}>`^W6$oZ*lJ^0vNO!7}8scHgJs5Z*7)Wa`U~TN?roh9@_1 zY-ZXOBreA=u3$pNVH^?IS&3*Z;4?Id6-SR7&oVS*p{XD~fMW_KRZQUt0ST7cd=#J4 zY&~__F*2;TZCTq`FdSo%G-TU`ZnNx4I=jMCvbM_9S1eH0_b{ea9LEWg;Nn8e(g+ld znW<;3vcC#Q~fK3H*$Tr!Xt9rLy0c zWu{5Pr)HmIGTJuSkb!tw#fK!Gg9&SSES0kLTu#A9YF3OpT_UX@&OuX

}?~x4mZY z+yu2`Em`vVcsbdjT6M5Se^jF39L}pqOZ}}?D#kKAmZa~7ig{cRXs-BvQd=Tpho`3Q zAu$RTi113(PMf)WHf!0Ao;s1$ZB0_jk>#YGl`je`BCaAFcWfR^E?ov;!s7=?w)M0* zrt_$&&}jAY}Wm{!e|3 zTddU$hIhhBu{c{|hN&OVFC=vPlsr_p*BIG6Go#st{O=BWojHR(9IMYFbx+7z{SBF1 zC1sA;>AXCjsJSVvJFb`fcepw;C0eUWWi7HTb{R6+l??GX&6S!ca&3LbEA&S$k-ZHo zPAgGGi3 zP2Dc;NN2Fx+ylP4K00gRmT7jmP{B2U$fo7Lu^S=GT}v`+w7a1$(a)Z*0Rms)y|>+hZny*IQuoeO~XqWpl#p=#K0{mv%NPExDNFV4mRNHyl*Kkd6$C!L8}11 z!LhBSMffIO49(ua!?$}H2MgF&z!KUCMGyWgw&O3N7k?Ey@V3~Azl%QnL+rvk;(p-~yM<4L`1U|C zvo8=j=lI3+U3?Ed9&@euK4#hTUPg;McAcL&m+%A5-bQzEOu^d-xU=t+-ZV-?&uxp>gvT+PBh>Z`0)!mSHkyxX_UXV_KO94?h+L5Rd_vbB3!|@6b1fO z)Z2&#^>Jbe5}pnC6<#eqFXGpH4pXawi}(#KH1qiypTqpfe4ShF<2+jZ7{MEO(-&an KUBp|y;C}&7kFKZy literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$StorageCalculator.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger$StorageCalculator.class new file mode 100644 index 0000000000000000000000000000000000000000..d772d63832fd99ee5caf4d0c5865d7e24a7a8d2b GIT binary patch literal 1947 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger.java b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger.java new file mode 100644 index 00000000..cc69e79a --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/CallArranger.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.x64.windows; + +import jdk.internal.foreign.Utils; +import jdk.internal.foreign.abi.ABIDescriptor; +import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory; +import jdk.internal.foreign.abi.Binding; +import jdk.internal.foreign.abi.CallingSequence; +import jdk.internal.foreign.abi.CallingSequenceBuilder; +import jdk.internal.foreign.abi.DowncallLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.VMStorage; +import jdk.internal.foreign.abi.x64.X86_64Architecture; + +import java.lang.foreign.AddressLayout; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Optional; + +import static jdk.internal.foreign.abi.x64.X86_64Architecture.*; +import static jdk.internal.foreign.abi.x64.X86_64Architecture.Regs.*; + +/** + * For the Windowx x64 C ABI specifically, this class uses CallingSequenceBuilder + * to translate a C FunctionDescriptor into a CallingSequence, which can then be turned into a MethodHandle. + * + * This includes taking care of synthetic arguments like pointers to return buffers for 'in-memory' returns. + */ +public class CallArranger { + public static final int MAX_REGISTER_ARGUMENTS = 4; + private static final int STACK_SLOT_SIZE = 8; + + private static final ABIDescriptor CWindows = X86_64Architecture.abiFor( + new VMStorage[] { rcx, rdx, r8, r9 }, + new VMStorage[] { xmm0, xmm1, xmm2, xmm3 }, + new VMStorage[] { rax }, + new VMStorage[] { xmm0 }, + 0, + new VMStorage[] { rax, r10, r11 }, + new VMStorage[] { xmm4, xmm5, + xmm16, xmm17, xmm18, xmm19, xmm20, xmm21, xmm22, xmm23, + xmm24, xmm25, xmm26, xmm27, xmm28, xmm29, xmm30, xmm31 }, + 16, + 32, + r10, r11 // scratch 1 & 2 + ); + + public record Bindings( + CallingSequence callingSequence, + boolean isInMemoryReturn) { + } + + public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) { + return getBindings(mt, cDesc, forUpcall, LinkerOptions.empty()); + } + + public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall, LinkerOptions options) { + class CallingSequenceBuilderHelper { + final CallingSequenceBuilder csb = new CallingSequenceBuilder(CWindows, forUpcall, options); + final BindingCalculator argCalc = + forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true, options.allowsHeapAccess()); + final BindingCalculator retCalc = + forUpcall ? new UnboxBindingCalculator(false, false) : new BoxBindingCalculator(false); + + void addArgumentBindings(Class carrier, MemoryLayout layout, boolean isVararg) { + csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout, isVararg)); + } + + void setReturnBindings(Class carrier, MemoryLayout layout) { + csb.setReturnBindings(carrier, layout, retCalc.getBindings(carrier, layout, false)); + } + } + var csb = new CallingSequenceBuilderHelper(); + + boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout()); + if (returnInMemory) { + Class carrier = MemorySegment.class; + MemoryLayout layout = SharedUtils.C_POINTER; + csb.addArgumentBindings(carrier, layout, false); + if (forUpcall) { + csb.setReturnBindings(carrier, layout); + } + } else if (cDesc.returnLayout().isPresent()) { + csb.setReturnBindings(mt.returnType(), cDesc.returnLayout().get()); + } + + for (int i = 0; i < mt.parameterCount(); i++) { + csb.addArgumentBindings(mt.parameterType(i), cDesc.argumentLayouts().get(i), options.isVarargsIndex(i)); + } + + return new Bindings(csb.csb.build(), returnInMemory); + } + + public static MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, false, options); + + MethodHandle handle = new DowncallLinker(CWindows, bindings.callingSequence).getBoundMethodHandle(); + + if (bindings.isInMemoryReturn) { + handle = SharedUtils.adaptDowncallForIMR(handle, cDesc, bindings.callingSequence); + } + + return handle; + } + + public static UpcallStubFactory arrangeUpcall(MethodType mt, FunctionDescriptor cDesc, LinkerOptions options) { + Bindings bindings = getBindings(mt, cDesc, true, options); + final boolean dropReturn = false; /* need the return value as well */ + return SharedUtils.arrangeUpcallHelper(mt, bindings.isInMemoryReturn, dropReturn, CWindows, + bindings.callingSequence); + } + + private static boolean isInMemoryReturn(Optional returnLayout) { + return returnLayout + .filter(GroupLayout.class::isInstance) + .filter(g -> !TypeClass.isRegisterAggregate(g)) + .isPresent(); + } + + static class StorageCalculator { + private final boolean forArguments; + + private int nRegs = 0; + private long stackOffset = 0; + + public StorageCalculator(boolean forArguments) { + this.forArguments = forArguments; + } + + VMStorage nextStorage(int type) { + if (nRegs >= MAX_REGISTER_ARGUMENTS) { + assert forArguments : "no stack returns"; + // stack + assert stackOffset == Utils.alignUp(stackOffset, STACK_SLOT_SIZE); // should always be aligned + + VMStorage storage = X86_64Architecture.stackStorage((short) STACK_SLOT_SIZE, (int) stackOffset); + stackOffset += STACK_SLOT_SIZE; + return storage; + } + return (forArguments + ? CWindows.inputStorage + : CWindows.outputStorage) + [type][nRegs++]; + } + + public VMStorage extraVarargsStorage() { + assert forArguments; + return CWindows.inputStorage[StorageType.INTEGER][nRegs - 1]; + } + } + + private interface BindingCalculator { + List getBindings(Class carrier, MemoryLayout layout, boolean isVararg); + } + + static class UnboxBindingCalculator implements BindingCalculator { + private final StorageCalculator storageCalculator; + private final boolean useAddressPairs; + + UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) { + this.storageCalculator = new StorageCalculator(forArguments); + assert !useAddressPairs || forArguments; + this.useAddressPairs = useAddressPairs; + } + + @Override + public List getBindings(Class carrier, MemoryLayout layout, boolean isVararg) { + TypeClass argumentClass = TypeClass.typeClassFor(layout, isVararg); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case STRUCT_REGISTER -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false); + bindings.bufferLoad(0, type) + .vmStore(storage, type); + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + bindings.copy(layout) + .unboxAddress(); + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + bindings.vmStore(storage, long.class); + } + case POINTER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + if (useAddressPairs) { + bindings.dup() + .segmentBase() + .vmStore(storage, Object.class) + .segmentOffsetAllowHeap() + .vmStore(null, long.class); + } else { + bindings.unboxAddress(); + bindings.vmStore(storage, long.class); + } + } + case INTEGER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + bindings.vmStore(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.VECTOR); + bindings.vmStore(storage, carrier); + } + case VARARG_FLOAT -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.VECTOR); + if (!INSTANCE.isStackType(storage.type())) { // need extra for register arg + VMStorage extraStorage = storageCalculator.extraVarargsStorage(); + bindings.dup() + .vmStore(extraStorage, carrier); + } + + bindings.vmStore(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } + + static class BoxBindingCalculator implements BindingCalculator { + private final StorageCalculator storageCalculator; + + BoxBindingCalculator(boolean forArguments) { + this.storageCalculator = new StorageCalculator(forArguments); + } + + @Override + public List getBindings(Class carrier, MemoryLayout layout, boolean isVararg) { + TypeClass argumentClass = TypeClass.typeClassFor(layout, isVararg); + Binding.Builder bindings = Binding.builder(); + switch (argumentClass) { + case STRUCT_REGISTER -> { + assert carrier == MemorySegment.class; + bindings.allocate(layout) + .dup(); + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + Class type = SharedUtils.primitiveCarrierForSize(layout.byteSize(), false); + bindings.vmLoad(storage, type) + .bufferStore(0, type); + } + case STRUCT_REFERENCE -> { + assert carrier == MemorySegment.class; + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + bindings.vmLoad(storage, long.class) + .boxAddress(layout); + } + case POINTER -> { + AddressLayout addressLayout = (AddressLayout) layout; + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + bindings.vmLoad(storage, long.class) + .boxAddressRaw(Utils.pointeeByteSize(addressLayout), Utils.pointeeByteAlign(addressLayout)); + } + case INTEGER -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER); + bindings.vmLoad(storage, carrier); + } + case FLOAT -> { + VMStorage storage = storageCalculator.nextStorage(StorageType.VECTOR); + bindings.vmLoad(storage, carrier); + } + default -> throw new UnsupportedOperationException("Unhandled class " + argumentClass); + } + return bindings.build(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/TypeClass.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/TypeClass.class new file mode 100644 index 0000000000000000000000000000000000000000..f3ad0e2e17f0b3eadadaa65ebb201e838d7653e7 GIT binary patch literal 3546 zcmb7G`%@d&89j>xD~ZKmuyJf0qxcn&9m`JqNG;;>u%I{s9Ic=cY3nXxE!Gyh>S|@1 z^pP}an)KbY?t}E*2ItusN@lQIPh0ob{!N)o&%Ih%tCnU4Y2efS?!D)Go$ucJ?@#{r z4*+BMvx*i4C$24CPg=HTy0%eDUUgj4D%we7!Ajmbdpdd3vKO73m1J(EY>t(TN+k*f zVGXTlQ_!jBva@5kE7|nKq@GJ>6`ag$4=p9&A{wFsuInM(csiS&9!rbKb`6@CR4>m= zPSb|a?ay)9uvIEp)BpnVFHCShY*TZlTfUMzSN>i7O8$_GowndkJ}XZX`3C z))kz3VY`0E(1-mh_G)+(2WYiWa%__}2L?0Oj2lL>WZ1>z%)&LZ;H6@S<1rNnH5|fW zdf!-(wyVqZe01=;kuUTD(Gp7tma!3Cvi%}lNz4F zX$3nQV55#xG7Xzl$>lGnITZ+_zW1!yd#))Tqbr^n#b?CCd75nCjV&3jQ6NX77!tG3 zkbI3|zvYF)`i*H(qiK!hKH6Op=xjLl>Ru zLdjI|tb+cAww}2ubJ=lMbhEf@+MbH3rbUybl36rLx@UN1`c}a#dzNFXm{G8&fmEy0 zXw@n$nr;l!cutg+eH9uQoQojG*v1UocD#7e^x{jVYo3pbWpf%nkLOu^qg*!aMFmf6 zQT-rqnhcRZ^LRnU7c_hkUusH)tQBcMbJNE1{}9~gm2lz98Vs>H;yE>K3>g%J`*dgb zR_>6CS5Z{4q`|^91qT{=XwGPzjFAP>L$_X}8_dV0Rvu#F(^CHtuK$R{*#54D3P|A| ztCBT~R)yplDHdH8!6U$-phsJoOAXEolp7ju;uiB>5Qm?2bw##^I1LqKx55atPimei z-`3%pQt{%JO*!E@)p9Kl!mF=o_&UC!pu6rBQ(i52pW;@Hn>7S+f^65VmlYgr)W;|D zh+C`*u0P~+1h4Q6oV6>}a+xh@F2+mpAgQtRTY{yp{TDg?GxF2O`4S2dw2HWoMi7la zi=Z=t?g(}Z-H$Z<7;lQxTpptp1y2nOZu>lE@6@-4$DBo0w=-ke=5%#=!E|#5yI#S? zV7-0nZ#$JNTE;0Dr8&d31gwu8wq<*D2hK^~0uP`m(_3;DFY^doHc4ZK81|Mdim1-J z+VH9_y$gGil>GsOI@SN4memb5v5l@(WYa2_nB^KFcqqQUdc1xJ;Hxol0DwO>Da5UhixHX5i z+XEu@nC?{Ff;nypI_wbbCL=f@I%D`G$r$H(qz>;D&m(}6?;0ujgprcZ7Ag5uk&+J- zplhFak8o#{-=E-3;{24OgOuVE+d%Io_B}w~I!6j_^M9M1i*x-U{0uE}{b@?EBi5}X z?xFty6tTXgY5mWs(Q2#k3;dF!RsOYd+sk4ppAZO1uv3&FPN|7w`|sk&U-(j$20GUH^I}aiaR;4!t3unezJadwDc!Wn+g@^f8WvL&M~+xHf$Imna2YI!TtV$Xte)OI2{DW@CqpIYYE5v@;_O?sVdgv?I_% zP}&*SJ9yW}eT{Jm=guYmg~Tef!~-Py?xDKQ@yaS9H1}1O>7|Ed`X=j>*u<-{M&A}S zs@d;l7Xdo$=g6m7?7 carrier = type.carrier(); + if (carrier == boolean.class || carrier == byte.class || carrier == char.class || + carrier == short.class || carrier == int.class || carrier == long.class) { + return INTEGER; + } else if (carrier == float.class || carrier == double.class) { + if (isVararg) { + return VARARG_FLOAT; + } else { + return FLOAT; + } + } else if (carrier == MemorySegment.class) { + return POINTER; + } else { + throw new IllegalStateException("Cannot get here: " + carrier.getName()); + } + } + + static boolean isRegisterAggregate(MemoryLayout type) { + long size = type.byteSize(); + return size == 1 + || size == 2 + || size == 4 + || size == 8; + } + + private static TypeClass classifyStructType(MemoryLayout layout) { + if (isRegisterAggregate(layout)) { + return STRUCT_REGISTER; + } + return STRUCT_REFERENCE; + } + + static TypeClass typeClassFor(MemoryLayout type, boolean isVararg) { + if (type instanceof ValueLayout) { + return classifyValueType((ValueLayout) type, isVararg); + } else if (type instanceof GroupLayout) { + return classifyStructType(type); + } else { + throw new IllegalArgumentException("Unsupported layout: " + type); + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker$1Holder.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker$1Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..ac703af32923debcb8e7f9e91772212708b0fe4a GIT binary patch literal 740 zcmbVK$xg#C5Pfb#Q_=usDf@DO18~3~u?SH>r~*-`lmn=UqnnuG5^O06%WokLl|bSH z_$b7rEg*61#n1D`^JY9VpI>hu07_VJkV4vq<)RN6hI~^z3LXgE;OF(G^kRlgQE3$) zFr=4PYBsVATTTCtD;>*Fi-6ylP^yOJqOSP!_9lN)+BZ)Tzv>`S6{YWF=)gw0A33-- z23!nch+)4crKOEi6ZkS@$d;=Ymq*poF~d%!C#^jOt7Lr1Fhpg_>cf3qhL@rq5HnIS zo(O6pREgast@u_&42Qj?`zf8$W{Y0X?W}WQ9zsu^s3dFQf8*AYnNWSl+6zpibmL6M zx5jrdjTweqL&jwt#X@@&yt};8TVY8-RT;&nCZd_UWvyjc3Pco1`fR4tZ>-bwQnWXW zQq%nCmRPhn#N_G530cCdw!mK6?qNC;Hz;_7PPg*_qZlJAi^6a4Vp|Nzy~Dn4q5l<5 jBEj${u>lL?#HBESNkWTOY6`P$#>O0>L+^8h^T>Y#QcJi3 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker.class b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker.class new file mode 100644 index 0000000000000000000000000000000000000000..673457d7505ead069d8f2e7a9a2318dc07d78f6b GIT binary patch literal 2473 zcmcgu+g1}-82&bd42dHkt+gk6GAbYtsi?I9Yz(K^khD#pt5>c`vVoCtPu652`4UA^c7^r5=??U@88X+~ULn2Y)M{PQ2b|FHAVzkmG=pnzHmBN#Q1FfoRt!0OZH zQPx(z^pxdf_gzog2P$jT?d;F@mb1sUYP!em?2jQOt7NMq>1CF-U8gBMf$?IwTFaLU z8v^%BZ)7W%#yC<2(k3pz6u22{C0}p*p4ITf7zC0lwzB;-fzg@Sy)-5;X<*94B}@w} z#afBxRj?cg?4T>Vy@5EwxybmBu*1}*TiMKCvdSF>TW9x z^w+l>Xk149CCY^1RsBwVlXY{wlUxe#;{yX9n)nDG3*3#xCR(P!_7k{N$d@bSVj*98 zQp*2S*{xMsz7W5TZ#&r?t3_9z;8O#infM%E2wZ(x$zHMcET2r5d#PV1_>98uV3d zMN5f-+oXv}PNpn(p4FvSv+52x(EVp-d;nEzcXn3QH=42vBm{A;Wu=rL0Y5}ojO6fGH7`#l69gRb_jKz1$cA@ z-)#o0e^aNpdWvhOxcLIN{=gNDWC;31ATiJKEMSuRc$9yzG(_vzAWcwe1e-j~5nYY> b7N)RGACHqMe9PNuhqO%k9qIR^)nw{FhgYE4 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker.java b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker.java new file mode 100644 index 00000000..30e4a5bd --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/abi/x64/windows/Windowsx64Linker.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.x64.windows; + +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteOrder; +import java.util.Map; + +/** + * ABI implementation based on Windows ABI AMD64 supplement v.0.99.6 + */ +public final class Windowsx64Linker extends AbstractLinker { + + static final Map CANONICAL_LAYOUTS = + SharedUtils.canonicalLayouts(ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.JAVA_CHAR); + + public static Windowsx64Linker getInstance() { + final class Holder { + private static final Windowsx64Linker INSTANCE = new Windowsx64Linker(); + } + + return Holder.INSTANCE; + } + + private Windowsx64Linker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.arrangeUpcall(targetType, function, options); + } + + @Override + public Map canonicalLayouts() { + return CANONICAL_LAYOUTS; + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/layout/AbstractGroupLayout$Kind.class b/tests/test_data/std/jdk/internal/foreign/layout/AbstractGroupLayout$Kind.class new file mode 100644 index 0000000000000000000000000000000000000000..55e94cb4b81962d1e50cdbafd4ab6ca58d9a9074 GIT binary patch literal 1499 zcmbVM?N8HS5dS?}$F@>nOx{IQ1l>RwDlg*Z1PKZ{!ML%6_^I2px>*WCKvEDun?PGO_hM@$CorFB1uDr{Aq8Q^ z3T$nxZ*H)qU4eoQf#6tvIkUBz6oZj3G~F`nLTx1rB=;y zVzaQP6`iDv9`pv$r=TAL0-gUHR!z4;)$FT=t8MNG%*7g_R}8gUO*R;^j;)*JWMc*f z@bHHeT*NT(meNh#NelEfLe(SJ<9TLbM8RcTA%04lp;vNhSs;2oO$dPyt_eV3|`M5nQDa+MV@KSu2p)j+N9F7Q)iO1tCI+4Y2sDK zwaKfuSvh&SfK<__Uza}?C&O9;m3+0S)@n{u)pFKy?V|QbXFdj+tlTt@A=R*1f z>ICsXAn~6Z2`KBPsoCDFYTP|9^3n|5c@KRKq@_V#XMiNFB3U9ldL)K;5lIh_eHv5b zpCE0NBtP;YB%{z0+zaO{Y^ZaK?a)cZe6DPQE3c>!qGyb>9qSU-_ zhjU|=-T;NYV^>45IQ4~T95A^h2G=@7vzH*vP<5bk2J z9=1xP@iYFNqM}#*(a~d!9l`IZH>7CHQ-dd%ID*U#)Szk&9ME^`Ek@u{?pjUvkR%@; TQn>HQG?qy6)(WJtyfp9!d^la0 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/AbstractGroupLayout.class b/tests/test_data/std/jdk/internal/foreign/layout/AbstractGroupLayout.class new file mode 100644 index 0000000000000000000000000000000000000000..b5fa454e1a7c12e5718ed95d9057636856a8b05e GIT binary patch literal 4446 zcmb_fYj+#f72Vg8HL@~^9XW9lu(1h&+Oiu#8bYvK8pjY~Bim_Z+&Y1fu{4&)9?gi+ z$YA=QFX#hkp{2B;^j)AI`hl)R;)JfY^lMjtQ&;z$8Ch4clVx}HgQPoW?m1_leIEDf zU;p{!?*Jz7rxe-{(-7Cuj)XvFrL>y09N+XD!_F?bo@textZl5jbw4}4So1xj=;wn+ zfy9{QSpH)IM+T>+@+-!gk*)idot>@vmP`HI(0m7y=+KbTu?M<9b|>ba^xS&2;Um6k zIVFKp`CV!rdy0CwJ=lj%4P83+BQ3D6i7{{0d`3`otLw8%0)vAJ{t4H%&7zDUH>8NA zN=^oJK*vG!2qaD0teB2p6X@D*-(ej`a2H=zEa&XHZ;sm}Qz{6EDG9AtM<4DX4DxCk z6@j}4RfnN8TL@m}(oEQZj(c%bpxvle?RA0vmi>p%v>8b)+{7RLon{x8WQpC!|_Dsx6zARY2)8%|lqZ#m^$ z5)YEMOG%vI&$B6<#KRg+>39UEN!*smq9nQ=v!kuJtW<|~m!b#*!xPJfS1_Nin@-Wp zDGqle--e7$mjUmiI&v7J^I}*|0uQS6MhR%@L-g;PXxyNYW3iG{#yeVG8;e3m)+|=z35t0<9r893i=1je^XnJ$TqD{c* zyjwKvdBd~hb0m!W%NCh^Xt%H!OHy)NuwJ6+xMNiKb3lQ)d9X2Gt&Z2L4d=T)smA8= z0gdW#XgE^&k9t-z{?7l0an<^5vb%jwRK-nLL-Q=riYb#576((1ZaJTV160;&)G9$E zNTF))Hb9sf-wk~+Ck+eAR3t5X3%*fYoi?gb9VFNgBv&Bi`pc#l6d=#e;Gy-1iTaJ$ zc3U%J8JUo7Ht~$?Ar8;RbPT4*Mb4aQ(_eN=7YvW}#ETVad3`KDx@$*4nNUq$vx2y{ zXKF`w!vr-dFI8~sUeP>f$&NbQxaBGRdR#gc*fV3+e6~L`%pkfim|n&5eX~@kFBWa1 zRx@iFek?F@r)j_x)*Cm-$x7AM@Rq>voiv_yco7Q$O9c{o)^+_F&z)+>Y^@7#-*V(N z=BL6|BrvUZEvf2gkLtZMfnTQZ9)6|a*E)WK-?kj2mb2!r zn%TTjSu7buX)N*D%&AEZSp&_df2*z|r7)=ThEuZ5+OfRruGXvS?IZ%AU~W;I<0w+M z@BC%x^3J*{6OrW!!?p{SZ?X;aNyjn0iLe$pLFFA>!yg6iZ&qy!p4KQed?0YoowxF^ z4=ITc@aSvfoj8WH{ByxoT3*W`U~}Du3cBR=o9iS$?Qke_xw?r2QvB`9+}qQBq+7>(wEY651JN!IFY-z5I>;bG8+EL6R~Xn!{4?`a zd@TxRoc^T8_RPoV{)meZb|Mfy9>5GCwMQ_etENP{3eA3!8z|B~#!xz&e&_~1cN34c;ZuD6I=;~KpGKV8d30i$YBT(QkXNuA--1O- zBo-m>GErzX+K|Nc_S4~^x8K9wzhYt`{lo^I{70sL15=+ODLux6MC}Xq7D&?^x-lPk z3sca$nV??Yr0$}RCI|AJ^!rVIVi4UC8Q&rqyjn(Nd_+JJ$Y^HxeViEnCz4l@9j5o` z%member layouts. There are two ways in which member layouts + * can be combined: if member layouts are laid out one after the other, the resulting group layout is said to be a struct + * (see {@link MemoryLayout#structLayout(MemoryLayout...)}); conversely, if all member layouts are laid out at the same starting offset, + * the resulting group layout is said to be a union (see {@link MemoryLayout#unionLayout(MemoryLayout...)}). + * + * @implSpec + * This class is immutable, thread-safe and value-based. + */ +abstract sealed class AbstractGroupLayout & MemoryLayout> + extends AbstractLayout + permits StructLayoutImpl, UnionLayoutImpl { + + private final Kind kind; + private final List elements; + final long minByteAlignment; + + AbstractGroupLayout(Kind kind, List elements, long byteSize, long byteAlignment, long minByteAlignment, Optional name) { + super(byteSize, byteAlignment, name); // Subclassing creates toctou problems here + this.kind = kind; + this.elements = List.copyOf(elements); + this.minByteAlignment = minByteAlignment; + } + + /** + * Returns the member layouts associated with this group. + * + * @apiNote the order in which member layouts are returned is the same order in which member layouts have + * been passed to one of the group layout factory methods (see {@link MemoryLayout#structLayout(MemoryLayout...)}, + * {@link MemoryLayout#unionLayout(MemoryLayout...)}). + * + * @return the member layouts associated with this group. + */ + public final List memberLayouts() { + return elements; // "elements" are already unmodifiable. + } + + /** + * {@inheritDoc} + */ + @Override + public final String toString() { + return decorateLayoutString(elements.stream() + .map(Object::toString) + .collect(Collectors.joining(kind.delimTag, "[", "]"))); + } + + @Override + public L withByteAlignment(long byteAlignment) { + if (byteAlignment < minByteAlignment) { + throw new IllegalArgumentException("Invalid alignment constraint"); + } + return super.withByteAlignment(byteAlignment); + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean equals(Object other) { + return this == other || + other instanceof AbstractGroupLayout otherGroup && + super.equals(other) && + kind == otherGroup.kind && + elements.equals(otherGroup.elements); + } + + /** + * {@inheritDoc} + */ + @Override + public final int hashCode() { + return Objects.hash(super.hashCode(), kind, elements); + } + + @Override + public final boolean hasNaturalAlignment() { + return byteAlignment() == minByteAlignment; + } + + /** + * The group kind. + */ + enum Kind { + /** + * A 'struct' kind. + */ + STRUCT(""), + /** + * A 'union' kind. + */ + UNION("|"); + + final String delimTag; + + Kind(String delimTag) { + this.delimTag = delimTag; + } + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/layout/AbstractLayout$1Holder.class b/tests/test_data/std/jdk/internal/foreign/layout/AbstractLayout$1Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..69abec255abb07d19d24918eb6ff61601af801bd GIT binary patch literal 1676 zcmb7FSx*yD6#gzPOk0M^e`N)vm4?ou2%#@Y}E_azZ8bH zdDupHw2iW3Qe30y82Zq!;e?KpNH7fSfF{UxkU)mk1=B8{CNj+=GUZhP?e{Oxx4c z)h4&hXF_F_k}8I?IOmSRC`0$woE4Xpe8T4~kxrHvQpDPGe4a))Bg@n+9eL9hv$fTE zp^C0GhIn352bZ`q-FrX`J4+@F&V~Q*vYEv+&6}&8ILC12KlDkjs}Tw{UjV1mALs{M zaq4!V2wG&^u!5DqD2lDA+N~7irLEv_V`YX{0^_lQtSLiGnQk`rH@3!zTVTps);26z zr5^QxXt>QVy!Q&|n8FnVFQOhqxTaA z-l6T@H=La#EUBL#Je@vTFQ)@gJZ(( u_6GemG#MIBM-j$Nx;9}Fx9A3dhdpwg( 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 & MemoryLayout> + permits AbstractGroupLayout, PaddingLayoutImpl, SequenceLayoutImpl, ValueLayouts.AbstractValueLayout { + + private final long byteSize; + private final long byteAlignment; + private final Optional name; + + AbstractLayout(long byteSize, long byteAlignment, Optional name) { + this.byteSize = MemoryLayoutUtil.requireByteSizeValid(byteSize, true); + this.byteAlignment = requirePowerOfTwoAndGreaterOrEqualToOne(byteAlignment); + this.name = Objects.requireNonNull(name); + } + + public final L withName(String name) { + return dup(byteAlignment(), Optional.of(name)); + } + + @SuppressWarnings("unchecked") + public final L withoutName() { + return name.isPresent() ? dup(byteAlignment(), Optional.empty()) : (L) this; + } + + public final Optional name() { + return name; + } + + public L withByteAlignment(long byteAlignment) { + return dup(byteAlignment, name); + } + + public final long byteAlignment() { + return byteAlignment; + } + + public final long byteSize() { + return byteSize; + } + + public boolean hasNaturalAlignment() { + return byteSize == byteAlignment; + } + + // the following methods have to copy the same Javadoc as in MemoryLayout, or subclasses will just show + // the Object methods javadoc + + /** + * {@return the hash code value for this layout} + */ + @Override + public int hashCode() { + return Objects.hash(name, byteSize, byteAlignment); + } + + /** + * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified + * object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of + * the same kind, have the same size, name and alignment constraints. Furthermore, depending on the layout kind, additional + * conditions must be satisfied: + *

    + *
  • two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order}, + * and {@linkplain ValueLayout#carrier() carrier}
  • + *
  • two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and + * if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal
  • + *
  • two group layouts are considered equal if they are of the same type (see {@link StructLayout}, + * {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal
  • + *
+ * + * @param other the object to be compared for equality with this layout. + * @return {@code true} if the specified object is equal to this layout. + */ + @Override + public boolean equals(Object other) { + return other instanceof AbstractLayout otherLayout && + name.equals(otherLayout.name) && + byteSize == otherLayout.byteSize && + byteAlignment == otherLayout.byteAlignment; + } + + /** + * {@return the string representation of this layout} + */ + @Override + public abstract String toString(); + + abstract L dup(long byteAlignment, Optional name); + + String decorateLayoutString(String s) { + if (name().isPresent()) { + s = String.format("%s(%s)", s, name().get()); + } + if (!hasNaturalAlignment()) { + s = byteAlignment() + "%" + s; + } + return s; + } + + private static long requirePowerOfTwoAndGreaterOrEqualToOne(long value) { + if (!Utils.isPowerOfTwo(value) || // value must be a power of two + value < 1) { // value must be greater or equal to 1 + throw new IllegalArgumentException("Invalid alignment: " + value); + } + return value; + } + + public long scale(long offset, long index) { + Utils.checkNonNegativeArgument(offset, "offset"); + Utils.checkNonNegativeArgument(index, "index"); + return Math.addExact(offset, Math.multiplyExact(byteSize(), index)); + } + + public MethodHandle scaleHandle() { + class Holder { + static final MethodHandle MH_SCALE; + static { + try { + MH_SCALE = MethodHandles.lookup().findVirtual(MemoryLayout.class, "scale", + MethodType.methodType(long.class, long.class, long.class)); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + } + return Holder.MH_SCALE.bindTo(this); + } + + + public long byteOffset(PathElement... elements) { + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::offset, + Set.of(LayoutPath.SequenceElement.class, LayoutPath.SequenceElementByRange.class, LayoutPath.DereferenceElement.class), + elements); + } + + public MethodHandle byteOffsetHandle(PathElement... elements) { + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::offsetHandle, + Set.of(LayoutPath.DereferenceElement.class), + elements); + } + + public VarHandle varHandle(PathElement... elements) { + Objects.requireNonNull(elements); + if (this instanceof ValueLayout vl && elements.length == 0) { + return vl.varHandle(); // fast path + } + return varHandleInternal(elements); + } + + public VarHandle varHandleInternal(PathElement... elements) { + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::dereferenceHandle, + Set.of(), elements); + } + + public VarHandle arrayElementVarHandle(PathElement... elements) { + return MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle()); + } + + public MethodHandle sliceHandle(PathElement... elements) { + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::sliceHandle, + Set.of(LayoutPath.DereferenceElement.class), + elements); + } + + public MemoryLayout select(PathElement... elements) { + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::layout, + Set.of(LayoutPath.SequenceElementByIndex.class, LayoutPath.SequenceElementByRange.class, LayoutPath.DereferenceElement.class), + elements); + } + + private static Z computePathOp(LayoutPath path, Function finalizer, + Set> badTypes, PathElement... elements) { + Objects.requireNonNull(elements); + for (PathElement e : elements) { + Objects.requireNonNull(e); + if (badTypes.contains(e.getClass())) { + throw new IllegalArgumentException("Invalid selection in layout path: " + e); + } + @SuppressWarnings("unchecked") + UnaryOperator pathOp = (UnaryOperator) e; + path = pathOp.apply(path); + } + return finalizer.apply(path); + } +} diff --git a/tests/test_data/std/jdk/internal/foreign/layout/MemoryLayoutUtil.class b/tests/test_data/std/jdk/internal/foreign/layout/MemoryLayoutUtil.class new file mode 100644 index 0000000000000000000000000000000000000000..58b856d49c35c407d17735edb0f6a2b671c58eec GIT binary patch literal 826 zcmb7CU2hUW6g|U7mqq$TORE(rQa_fqlo;Q{nAk>>5~>dWQ{tn0YLHX`V1dy<)>bf}wB`w6B!ta`jYq!@ls%v-fQ=Ff#BRBpFsO;_60A zzq=bs)e$-g7tsV}8J70_Q?6tu-x?Z`Kan5AqrAPHPhkOzRGSY5!tXGYyxL{5O7V(o z%3rY*OO|4pA?sED9k`OhDy}mmOmN;M!?JfZg-9K&S($D!Wd7C;iF1o#yVp4`OWz3X zb5%YHw2)n&6deYkDIbV_pog^ycx|L&i0uU(!7yKwzIYM#TSC9$Ek&MmEogJq;96Qd zb;isadBU($`=25e8c2(`q10lRWUiCS4J$fB+^aT=RT|yOZ~Y96pv#pC-Zg~|2sasK z>xQ?F5BOl(MY0}*x-Fhd+h^wTOgr{R;Q_L=S@wz0OS=Vz9HEDFGCJd%W3X?N>vj6t zH3S93u#P-gsq-M*MuCuv4cwU$7$S?3uat8?euk6%1edHY$eqDCJcD~U#W~a!Xp%{XNn5JR zH~)bz_1)!*5Bfq_cIm3G{wSB{%uK=rrYZFSl6!OSK6~%8@16PQ-#`8WFpck`2p}jS zB%=eJ0^M8cV>Ml~^iq1UYUxHrEeUjJ<*KzK(3c#_9{xQOMHmqYQ5nY|3yf?P9;Wq* zrJ1xjyW)#f(o1TgpjV1ndo)|F5_;!ty`o#=0;iL6bAI?kD^bL_LYIKj z4t#Qb+cMR><)BMAA#lp(TT&~ESP6*M!7IC_|HuRt(4v=T<2fOyK&Z^<}~ zGsH`+R<%lj1SK6-9+Zr0glEbHw%zELaSrDN!s|PhmeZeUc9A(oA7Jzg0{zLkb{KIC z%D9Bfgkc#DbAjH5|DLjTy{j^k7@`FQEpM2rr8y2X_FXxW078l(C1V&PBwl+|Q%l0d zDJezG6p$XPrJA<5!8x1tdgHDjei_`B@Bw2`Tw?neS))=E=xMc-Cuz?FCM8VCl=Y7q zb)9(IT1a7tnR3zlo;Ej>67eu*I4E~%B^977hA}H+4xdm{3$?1iOwvEL*>+hybP#O& z=VdHlk$67Qt<5P4&t!=XPg$#20%==bo3qs#|BQrB1rqxvHBMqnWo}tc#xgz^IL1Zk zkS?fY>e?uW?da7Q=nEP5uu8pWAO~f_8y_c+e0GkGE8)Jt`NJyawX$LEI60@zI7#cu z>J@FFR$kZ4Wp%woD!Q{qUM;Ptrp{w`GGuM))cAB;9xXQUO_iYwVou;VpJ`89LKWMt zUcZ}*Qq@|2r`q7)`qFaK-u490^=h1|Mskz^)vB4KXT<-G^xZkMA|M;qre?ZY=q9&^ zY|Fl*Zq!Lx&QkLa=hdof)0%It{Y$;El|6Lo7Fd*8@|a0i@tQ!upiAIV>uL5)FPSs# zOY+S!MpxOqM$s=UsU|g(o?MiU!IsPRRpoE`=bIm*_9gwQeS`k$ys0K}7kxP#Sajov z6b@|rzHQ4|?-J^Hn-hEZq>N`g`FfQF(VS5;^V*Eg=d|w-$S5Zi*XXv5L12mAR=Vg_ zh3;V*eMzG!bRtNfQ6&-GgQ!FLokjtC#dGut3?f30&y!X{kAh2yz(0%lqfyj|8A4^1 z{T+W|bTz2d@%A2WWDoD>_V6KdaGL1IyycPE->gJWU$<=!KrgSfC-ws2RmMq- zP!!lKM~Q_v#A?;G_CItz@z>QB%B$;XlS`|vwg8895sDMR9XuoB1Nino DO{XmA literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/PaddingLayoutImpl.java b/tests/test_data/std/jdk/internal/foreign/layout/PaddingLayoutImpl.java new file mode 100644 index 00000000..63973e1c --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/layout/PaddingLayoutImpl.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.internal.foreign.layout; + +import java.lang.foreign.PaddingLayout; +import java.util.Objects; +import java.util.Optional; + +public final class PaddingLayoutImpl extends AbstractLayout implements PaddingLayout { + + private PaddingLayoutImpl(long byteSize) { + this(byteSize, 1, Optional.empty()); + } + + private PaddingLayoutImpl(long byteSize, long byteAlignment, Optional name) { + super(byteSize, byteAlignment, name); + } + + @Override + public String toString() { + return decorateLayoutString("x" + byteSize()); + } + + @Override + public boolean equals(Object other) { + return this == other || + other instanceof PaddingLayoutImpl otherPadding && + super.equals(other) && + byteSize() == otherPadding.byteSize(); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), byteSize()); + } + + @Override + PaddingLayoutImpl dup(long byteAlignment, Optional name) { + return new PaddingLayoutImpl(byteSize(), byteAlignment, name); + } + + @Override + public boolean hasNaturalAlignment() { + return true; + } + + public static PaddingLayout of(long byteSize) { + return new PaddingLayoutImpl(byteSize); + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/layout/SequenceLayoutImpl.class b/tests/test_data/std/jdk/internal/foreign/layout/SequenceLayoutImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..d9fb4aaeaddd6f9fa3d17463f2914ededea750b0 GIT binary patch literal 6923 zcmb_g3v^V~72R(>d6UT_#DOFP4M`+mm=J=ZK{JSf6lu~VP=i=Vt$j&el7Y$0I3FNt z{oAV5+A3N>t=6j4Dt=l`f)vEoPyMypuWfDZ&;G3a|CVdnbf5R$B=eFX$Xc>k^CtJ* zd+t8_>~qe&^TPk0I0&E_|1E$EZWSI4UgRm5w?*Hk*GKede|=vpVTAjm_3g%BEHTuk z55>|c1v9#bQpTzXUkn;i{_U<=)ar*1`6~Px3ZN+nm^RX>aHM`+JQa>b^@swmF&Iw` zDJZE~)Hd~f$d5wIR8gei7z7k7+0whUJ{(OM2`(N-5-~B3BR6HWG~P64a|$s^LVOq+o7N>t|CiNd?;WgdShF%}De`V%rs* zK`bIkGg?zE+xs3q*eXs|P&pB{jH;bZ_|bsnDo)jK8X6TGGqL5m?kz@7int0BlwCMs zbi|?^=?Epa&_-tNZA}Yh!?A}{tWa?L1b~)E#OT)}s}lWb3DcS#J%*VieuS`61apR& zR2wBDR%uv`W(8_rL{FuRsDkQD`ZzpxIuk0uGOW>XrYKpn%V@`QQsgYvGf-*lAZIBu zmSml1tQ699$-!=h+hH*yx$Hv97`f1^!9X9Sm2^}z1#6C6#Ilu^*tAf%mnux9?Y9G=pJ3&9f*sfs* zSl3lXH*Kt=H?y1}ki8h93vrQ(PiVLpmpBY&f{;fi$g33aDS-}kWew%XG&^MC>SY=( z#}$leuhA1r=qbBNWOi}nti3Fo$#F~NxJtt(@hOUuvC*Y4Ipm)~v037HmDKxdHGCS^ zQCI_da-ccZYnW-=;>TxjgNn}zO`pqD7E_xoY;XNWLRw-=HU@i~oHgJk4LfnO0*@G# znYox~@!|7SekQ?~Wma>hYNJW^7WPpAxJ$!s+(ro7!>NJQ&MsbW#%!9N>+Dj*RtUFz zd_ii%ol=*M*mf70CGCqE?#7qMO>a7`U~OjEq-K1y{YRkOEB@W5VA+v;ai)o!ALvgx zzO3PXd__Tl@WZoChd#&{E|F9|8e+=vpoYD8h)NJcmX)R)qCQHyg?L26qjJ9TL``HK zOJp2maw!!A+6EQl>UeTAcaMj~PK+FNE$W9Faa-_^y&>ydWO zE|EpbVGYm7v>DrA0gsBTM;Y_xcI#uwupGFURYXn@ohiL%Yr7sdW3S?Ax+HC#;pGXn z$2v9oWh8S*R5q*lE=zZg@Lf>dV)#D`v>W4$ep}XE=o?=BxHVWy*V_k z;N0JV#Vy{GMR;@aiOlY`Grjno)cN0Qcmwwp;g1SVIzn-tx@~A?9{%LV z+xWAJzi9X?{^mHGhojqKTaEfQlUgFu`$V#^=NOzNLIJS zVq4SkY^vyb!jIAu_%T1zx)B$^|7GHE1L z{8Pb#DbsVgr{dp^p9~zBZ6B;=fghs|UEg#>s+;mGIm2*zDxxSp;dxRU0a#S;+$;dvAJi!qc_H&H42Yw2~dOiid zH~1J9JYr4|zw^w&26KDMh}Yg;k^A2GV%PZMs=bpIpPqB^*KxpJyqaDM^1@)n6J(fp z>keVrWC$&$6$u+>jx$h55JLN9IEW`LdoGm>_&MvX+EJWxPVK?nDA!H1rd z8TmW!K$Q&bM+Z%=4}5qSo$_KB=L}I0F}vzKgLQmtqqs z+>R^wZHU*9t8pE!!Hu{UxAKy4C$ALu;RZa#k>_y}zRx?t8+^WrTg;&JaiL&M8eN;ucw$b z&*ONG*3jOIv=c-@U<|XNswh57QO%@)!Evfp<>TyO^QErM$!6)fi;{;%Lcx zH&a5AX9*?H-^7oBj=HB%xC?VBw!%hFMVW^$!cFoR=-4y%WID)2CIJ!*0gr2SG>l$Ti#q>?PL{q<7O-=;STS5=b{sSM%=>&d(Ddk9r36n`PG zaXv$jMdE8`W2;|M(JmK*gZ!h4;#56*;Bl`A2IAfWNNjQ+y9>TRY7b;`)hM=gZt}>o z&QV-2j7ujRuxiRML5~o`D4O_`LS|*uS{rT!-^K6>!3fAx;VExY#wa2tRUwaZCg~Td zc$NP-o@bBeImT7WPLaE;?b6L8MDjZnti2b@YE9Oc){^!1VC@L5+=cl9eX-?UsetEq z`hB$vyKHwK$459omQpz&CfGA4UXWNQCx3PX_0D{MUr}>K(ShaRT`f)x3)^-{P7KW<>V}> ztKAf?2qLf_g_}ft;$TG`o6AIOEK4trJ0Wc<(^vw8W;K?8S5 zLTbCzXR}^aAsd=KZRhQnVOFzSq)Y`XMsTa6cJPW#ps%pJzKS_yaY7zd<8Z2MI3f=> zlsVk(M|jQNvyFQSjivPS_K9sXqMeAMQX-D7_$cE&hv1qH zlh49LkM`nq8;Bg2Bz^KFJs-%?inAHY&+XLD-XEv-;^&6}HLX`UK)KklGO5wRl$4Ma ziUhku8M7Exzs*)cP{_z%kd50xVI6#xJL literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/SequenceLayoutImpl.java b/tests/test_data/std/jdk/internal/foreign/layout/SequenceLayoutImpl.java new file mode 100644 index 00000000..16cffdad --- /dev/null +++ b/tests/test_data/std/jdk/internal/foreign/layout/SequenceLayoutImpl.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.internal.foreign.layout; + +import jdk.internal.foreign.Utils; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.SequenceLayout; +import java.util.Objects; +import java.util.Optional; + +public final class SequenceLayoutImpl extends AbstractLayout implements SequenceLayout { + + private final long elemCount; + private final MemoryLayout elementLayout; + + private SequenceLayoutImpl(long elemCount, MemoryLayout elementLayout) { + this(elemCount, elementLayout, elementLayout.byteAlignment(), Optional.empty()); + } + + private SequenceLayoutImpl(long elemCount, MemoryLayout elementLayout, long byteAlignment, Optional name) { + super(Math.multiplyExact(elemCount, elementLayout.byteSize()), byteAlignment, name); + this.elemCount = elemCount; + this.elementLayout = elementLayout; + } + + /** + * {@return the element layout associated with this sequence layout} + */ + public MemoryLayout elementLayout() { + return elementLayout; + } + + /** + * {@return the element count of this sequence layout} + */ + public long elementCount() { + return elemCount; + } + + /** + * Returns a sequence layout with the same element layout, alignment constraints and name as this sequence layout, + * but with the specified element count. + * + * @param elementCount the new element count. + * @return a sequence layout with the given element count. + * @throws IllegalArgumentException if {@code elementCount < 0}. + */ + public SequenceLayout withElementCount(long elementCount) { + return Utils.wrapOverflow(() -> + new SequenceLayoutImpl(elementCount, elementLayout, byteAlignment(), name())); + } + + /** + * Re-arrange the elements in this sequence layout into a multi-dimensional sequence layout. + * The resulting layout is a sequence layout where element layouts in the flattened projection of this + * sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts + * according to the provided element counts. This transformation preserves the layout size; + * that is, multiplying the provided element counts must yield the same element count + * as the flattened projection of this sequence layout. + *

+ * For instance, given a sequence layout of the kind: + * {@snippet lang = java: + * var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT)); + *} + * calling {@code seq.reshape(2, 6)} will yield the following sequence layout: + * {@snippet lang = java: + * var reshapeSeq = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(6, ValueLayout.JAVA_INT)); + *} + *

+ * If one of the provided element count is the special value {@code -1}, then the element + * count in that position will be inferred from the remaining element counts and the + * element count of the flattened projection of this layout. For instance, a layout equivalent to + * the above {@code reshapeSeq} can also be computed in the following ways: + * {@snippet lang = java: + * var reshapeSeqImplicit1 = seq.reshape(-1, 6); + * var reshapeSeqImplicit2 = seq.reshape(2, -1); + *} + * + * @param elementCounts an array of element counts, of which at most one can be {@code -1}. + * @return a sequence layout where element layouts in the flattened projection of this + * sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts. + * @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one + * or more element count is {@code <= 0} (but other than {@code -1}) or, if, after any required inference, + * multiplying the element counts does not yield the same element count as the flattened projection of this + * sequence layout. + */ + public SequenceLayout reshape(long... elementCounts) { + Objects.requireNonNull(elementCounts); + if (elementCounts.length == 0) { + throw new IllegalArgumentException(); + } + SequenceLayout flat = flatten(); + long expectedCount = flat.elementCount(); + + long actualCount = 1; + int inferPosition = -1; + for (int i = 0; i < elementCounts.length; i++) { + if (elementCounts[i] == -1) { + if (inferPosition == -1) { + inferPosition = i; + } else { + throw new IllegalArgumentException("Too many unspecified element counts"); + } + } else if (elementCounts[i] <= 0) { + throw new IllegalArgumentException("Invalid element count: " + elementCounts[i]); + } else { + actualCount = elementCounts[i] * actualCount; + } + } + + // infer an unspecified element count (if any) + if (inferPosition != -1) { + long inferredCount = expectedCount / actualCount; + elementCounts[inferPosition] = inferredCount; + actualCount = actualCount * inferredCount; + } + + if (actualCount != expectedCount) { + throw new IllegalArgumentException("Element counts do not match expected size: " + expectedCount); + } + + MemoryLayout res = flat.elementLayout(); + for (int i = elementCounts.length - 1; i >= 0; i--) { + res = MemoryLayout.sequenceLayout(elementCounts[i], res); + } + return (SequenceLayoutImpl) res; + } + + /** + * Returns a flattened sequence layout. The element layout of the returned sequence layout + * is the first non-sequence element layout found by recursively traversing the element layouts of this sequence layout. + * This transformation preserves the layout size; nested sequence layout in this sequence layout will + * be dropped and their element counts will be incorporated into that of the returned sequence layout. + * For instance, given a sequence layout of the kind: + * {@snippet lang = java: + * var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT)); + *} + * calling {@code seq.flatten()} will yield the following sequence layout: + * {@snippet lang = java: + * var flattenedSeq = MemoryLayout.sequenceLayout(12, ValueLayout.JAVA_INT); + *} + * + * @return a sequence layout with the same size as this layout (but, possibly, with different + * element count), whose element layout is not a sequence layout. + */ + public SequenceLayout flatten() { + long count = elementCount(); + MemoryLayout elemLayout = elementLayout(); + while (elemLayout instanceof SequenceLayoutImpl elemSeq) { + count = count * elemSeq.elementCount(); + elemLayout = elemSeq.elementLayout(); + } + return MemoryLayout.sequenceLayout(count, elemLayout); + } + + @Override + public String toString() { + boolean max = (Long.MAX_VALUE / Math.max(1, elementLayout.byteSize())) == elemCount; + return decorateLayoutString(String.format("[%s:%s]", + max ? "*" : elemCount, elementLayout)); + } + + @Override + public boolean equals(Object other) { + return this == other || + other instanceof SequenceLayoutImpl otherSeq && + super.equals(other) && + elemCount == otherSeq.elemCount && + elementLayout.equals(otherSeq.elementLayout); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), elemCount, elementLayout); + } + + @Override + SequenceLayoutImpl dup(long byteAlignment, Optional name) { + return new SequenceLayoutImpl(elementCount(), elementLayout, byteAlignment, name); + } + + @Override + public SequenceLayoutImpl withByteAlignment(long byteAlignment) { + if (byteAlignment < elementLayout.byteAlignment()) { + throw new IllegalArgumentException("Invalid alignment constraint"); + } + return super.withByteAlignment(byteAlignment); + } + + @Override + public boolean hasNaturalAlignment() { + return byteAlignment() == elementLayout.byteAlignment(); + } + + public static SequenceLayout of(long elementCount, MemoryLayout elementLayout) { + return new SequenceLayoutImpl(elementCount, elementLayout); + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/layout/StructLayoutImpl.class b/tests/test_data/std/jdk/internal/foreign/layout/StructLayoutImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f843e6f73b95d6646abb7c5375882328eb10ba56 GIT binary patch literal 4420 zcmbVOX;%|h7=A8)~ zl2HdYL;q6pT0}EUHESq(WIml$wFM)hE34_e85y3-nOP-ap3SE7nYdUxd`>fx4DPAv zi!`$MDnJlN8(z}jK*Ry z$I|(XsildLXy=TCT@1&o0h}_k`GjflGoH%mJ~Y5DV-Fe`8d7R%PR&}IIfllLPKO)e znTt2cXhwj+Gq-B0Q`$|Hp|+zl=B2IuGFote!JpEM5!xNrDMKmMFd0~k>psazJjf6t zCbk$;Jz5cz&?ciDhZuI1>Jbc$3PLf{S%yFf;Bk9BT8|?*D&c7v9q6R6HY^lG7^Fod zH>s`=P>SU;*ElBQIJy{IhFESY*wz(eA##3hNllnh2@!^;ggvobsL2U6mCmkOMAjpW z9vQuyvIb6BkrWC24DB1*mBvwZV zW;7W~xJH@ahAb;XmGZeAyAo0i2R9m}(2kBXf%vP=J~*zR_1hCX^f{6 ziaw)cHU8UPbeW49jlytM7*3M-P^Av^sJhCVm~{Q+qmIuML0gk!r&u;rPo+RsGX*fc z4tYL~Pg%b=9X-)OLgJjX1t(5LyRo>acZ#NkV&=2N20yDxCbUzhK&*4lk+aI@l2fth ztaFB8wqoU07T+%aHR*YV-trhq##bQ-XZDB$7tb6+@NwLdWKJA@bz;cUaGx@j#I*?} zW0%f!xp!w|1?Oc9I)`LIqzs>bLZ!}2UQn`BLv+MZg^gAuk_Wr>o@6*A<`K_%NkNsl zZ!b9qH^JC%hweBgwnBY-Wdx4)rTny21W+o|w?+S@TAL71k|H{=EBY@J+A0BMYPYtO zF$ZcYsVXUUrcTVI!Dxl5c1jVyzNvIRn^4bad?q$KH@S&09|{cexM8T-QC-R9R4PCh zziFd~&L$5S=IHjmi>~f;)1#+Bziz_^FTMStU%`$A1FnF(#j_6S7h0=Dnw~zA1P)_2 z-MljNH3&C7{kV=Sz4=!TCfVj+%{U;W{dB210GC*!Yp1P|$1VW6(1?miAP+{HBi z3NbuHc);D-;=Ye=hU?xtchUL)eX|d6Vs;(RG!CrcREv8JLu(ja$JsxHWQ^e+&JDHM zTKDkM$dCX2BtmR$YrBVOJ2scd!BLT;EZ32!(vfEC@MEEK`JK37-|Q)X*2;4INv@;$sX{#Bv3n7j0Q|7vj=)5Z4!#_(;Qw(^ implements StructLayout { + + private StructLayoutImpl(List elements, long byteSize, long byteAlignment, long minByteAlignment, Optional name) { + super(Kind.STRUCT, elements, byteSize, byteAlignment, minByteAlignment, name); + } + + @Override + StructLayoutImpl dup(long byteAlignment, Optional name) { + return new StructLayoutImpl(memberLayouts(), byteSize(), byteAlignment, minByteAlignment, name); + } + + public static StructLayout of(List elements) { + long size = 0; + long align = 1; + for (MemoryLayout elem : elements) { + if (size % elem.byteAlignment() != 0) { + throw new IllegalArgumentException("Invalid alignment constraint for member layout: " + elem); + } + size = Math.addExact(size, elem.byteSize()); + align = Math.max(align, elem.byteAlignment()); + } + return new StructLayoutImpl(elements, size, align, align, Optional.empty()); + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/layout/UnionLayoutImpl.class b/tests/test_data/std/jdk/internal/foreign/layout/UnionLayoutImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f513eb79da899c87bec6a8783695ba287e98d70e GIT binary patch literal 3987 zcmbVOU3U{z6x}yXGfg^$fF)8C`T=N~+J@4K+Cc3G0u5=41}Yy4owh?eC7Hxz0u&$o z1O5Sjfv@UvQP8zqJo~0U#|L!Zn@OC6Y5MVynVWmhId|`U&OLMgeEr)W0A}%R7y-0t z2uVVnG1r9a(5r)NbFq}e3Al3kQ&Ye$n;w;|N@V<^X21)Dx2sIM{ZNn%p zm`@3mT<%JbAsruJSRiPt>F!$WoMEpg7gsjTRVSq(DR4@~Q`5DIoHz4@(pFW-PK=;C zg7X;DFs|c6T&R&yF7t-7!AF6o%Wrwv4E zCBPVFzUXW7qxPO7R z4Bb?kRCi9`jbOpZvm{4kzV^VQnk1#mqK+H*oE0SlRijL~ zb*fU8bxM}Kp4wMj4Ow3fo+iZ-n=Pyn^5KkSn+p|r25%ZGInEr-6jqJgl2Nkce|IwI zY*;*sa4xa7o~{Z`t~r?^FIj z;i152GX+^pl2e0Vp4?G_pv;>8U-A4c{iQmT_W$Wz31Fg zasTZbZT7l-qt|JF_DvZd@TK2mG`>gvO>W<{EO4L87R#wczxCuqHKfUuPeFT(sBR=% zsFYUCE0%19-JUfWU__o90e#N4&C+bnD3?u^UQk~6Fv{;y2L!J15_yO>NM1Skyvcvx zBZ4sB(ZnwhLw&JeEY#Dn4ee*nwc!?@5n2LgaF|zsC5|Q$;xmdbahq>Bx`VrnEl0<2 zLRm-ou|9#In&bV)^|*(xh~jI`#$2mAxbJ%2!vn4@b1eXaPkuT%k_aCXfs7RU9bI=4 z&vBT)w|W!5;_cyWyz>)RsyIU`(xAfF$2qx64P#8@q>pIRPCcWDPBB+GH_#~2$XscO-r?uC+$xghi4$%~b@%xnkn7*EvuDYp2I5M6+M>e implements UnionLayout { + + private UnionLayoutImpl(List elements, long byteSize, long byteAlignment, long minByteAlignment, Optional name) { + super(Kind.UNION, elements, byteSize, byteAlignment, minByteAlignment, name); + } + + @Override + UnionLayoutImpl dup(long byteAlignment, Optional name) { + return new UnionLayoutImpl(memberLayouts(), byteSize(), byteAlignment, minByteAlignment, name); + } + + public static UnionLayout of(List elements) { + long size = 0; + long align = 1; + for (MemoryLayout elem : elements) { + size = Math.max(size, elem.byteSize()); + align = Math.max(align, elem.byteAlignment()); + } + return new UnionLayoutImpl(elements, size, align, align, Optional.empty()); + } + +} diff --git a/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$AbstractValueLayout$1VarHandleCache.class b/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$AbstractValueLayout$1VarHandleCache.class new file mode 100644 index 0000000000000000000000000000000000000000..e7eb7f846d9022cb8ea79f0c6be26e6b8c729b8f GIT binary patch literal 1158 zcmbtTU2hUW6g>kA3v?~CRs3$NMTDBT^%+7!um%m00njzbiO6nFvx>oO-$T3utph!#4c75eWK_Ha2JD1xo561`mv;Y(7JXT@g;ggW4^UH~i4`aI}zHS|P>yJNvn z=(c;$o&9$Q?L&s5^E)q+Z!qMKh@I;wpit+kw|Q|)DxIgXAk|oKOEvY61!XtWZnTKH zU0bS@M!nBqbo?P@R&=Biz35~hf;W8N5wh<1F84@K#^)Jm=&=kLdQ0j4`GizSHs-DD zF|?LqCZ_V$w9iiGsh19f9{a;X9`F-Ey{9sAP1l>vRpH2w0$03{ap`LdO$eXH4W$R# zSFY!WQjIQnOgvy{E;C6Mc2J@Dn9h63uvx4BtLKz)PlUSbhuXwrhT8wiGgvQ`5<$n~ zVJN8bjlWDb!|LUDC8Lc!`Zp>1q6~N9pF_4prxex_G=p`r8-%4P| znk5+ch#Rz)XIIL&Nhb=$E!<9s0V|2iP)zK*8++;EhZ1tQmypC7I|%`>@(t$ObL79E p5G%0-rB5($pRg1*u|?LvHXhco>8z;PtD(Xg#N&|LL`UM*jKDqz^ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$AbstractValueLayout.class b/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$AbstractValueLayout.class new file mode 100644 index 0000000000000000000000000000000000000000..2c7d3ed39065bf628283f7a7dbda9f675f5af403 GIT binary patch literal 7744 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfAddressImpl.class b/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfAddressImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..d276401d850fbd87006d41dc37b95f45e2695b59 GIT binary patch literal 6127 zcmbtYi(ed975*+P47(i?vOpS)2{f-ROPV!J(zGdly54d{>G?(E*Z_nhy1=R4=# z%Nzf>@*02?{w<-7p>t8Wpd|8&KA)H~imEoRCq~sJqqv+==a*F7j39&t35_x&G%@ro z=FTTH-BgRZl6P0+m1U!BCZ?2pSxsA?O9zs(C9|kxP0t`hW1psLWq`L~xq~Sw=IqG2FXpRO55WT&}2= zO2bQqJcDd1#d*~fm>Ie}p!{rz8NCtm+ahBJq6|&51T&*OsWQ~Zx<~j=ZJecchEY4Z z;9vsCw#^3z%TsW>j9us;0@WwVO1{L-1c2Uimz1?Rc*p0VJ*u!VMIbaN;oiWKutg)%)Pxhn%tg&ynDnTJ13D$6 z7kvy-RWFr`>X>3`7t~}nOL}9t&r7^l@)k!M1~O(*)8|R+oRfYT_hW#9C{q44vTW#M zttX7gkxcJna&mU-c4WK7~wGMgM6 zoEXYvW-`NPhh|PsPYz`m7%5{EkI8rkhuNSm70l%@&f=VecglDd9(UmQqNY&O!;_Qg zp_!qv!Qtc>Lz^JcH;d%?ZYUCFWn_^f1y!pfwV?23$9cWYG}6XJl9^JX$U?DHcd7{_ z`Ov}A!5p`+z$-*!*hN2iQstT;H|LR;u*BzaRK{e*VX3yf*6bh28Xg>@?#3FzS7of=Yg9no9-Sw~tQK>GGrToJ-;i+$-=sWoL&C~H zuv#{6SHia$_EZJy5av1FNcb+p-i=elc}fIIZ9wdp+tZq^j+K{Y)#9Y+fzh;)Rq|6x zQRCn3!H~J2(cW>QCIuc0r2~FZkmyI;X6A3D)V=*4mkW+pn=Ie_zK!jmzn7Gjq1{0- zX}4og0+r^R;kI<_3G~)I#c(m$hX8kLz_qnhlgI|cT;TmZ>LJ2z8?=37OeK4MR4Leb zOL_I?XvHgpUT?2*CispSL~f&~dWMdPvTkZi>XcT}NE}IBH%vNQ7&>X=kY5|l*+-mp zGISEr_$h>}wc2&%J+(0G_jRzFAvxj9x+%rZN?(v%A$10Ae$L^?-vBqmK_sV^vPG?6 z8pJ(IQAaJA>#|_CT?TE_;^6exD1M(1oL1!-q_A2>Rq9f?Gqmq7skHG^CJy-bWrvaV zSv~I6hK+qQOzaCb?}v44lg9n4?r_rUD^mX)2llN~=wG)#7`9I*4Eq8RtebStCWBkI zY~}yTHMOG6D#hP>`|T^OkJI&Hh-8d%F{?hH@ni4~4|Am>d?%qzY)mbg4;dv>!r$qj zyjd)Cw;k4X`?8~wI9mf`Onu7-8As{l5(2|}o&BfJbq2ajN=+g5d&8uSIBQMd2!0=PD zN7r+D=M>Em7QU)8-m`|CE7;X@9T5V-fmHC86-c2M5US@(y>z9}$_DAyp0Z%=6ee6) zo%k7ECI_742Gs2tpk~Og;kM5dVc}eMG+aaHbbWjccT{jNGaceiGZpj*pgcJu_+iV7 zAhg5wLgx%zwu#IUkvxc41&QeK=zSHO?5W`Gk8xg!)+DEvUPGMYhir1|JjowNgq^{5 z_J}8%m>W$Dzo7Ioykg^dm7WZ%SaZV(i*VMvV;kIwaHayoX~x5LICqmd&QFs_LYiwq zz!mGydDb`CFa>25BI1|0VgtLMzHvM47O=~hc$&Xh1yeo_gwYv~(RNE#JW9Gk*v77r zh^bKUXiKt>;!0k|^z&%iUBOIWJgSOJ(zkh@MxwidMarbHit;Fr;&tr3isk7wy!Y@b zJ`nvdz475yd~_8bA3a=E`(APbmP0*L(ah$kA{TI!Y4l%=MPyjs0@)>i*pb&`0$1@X zf_an_b`7r)S6p~9>fWT~Z(=|~p=E&T?$ zYH1B$xrHfPON8YTe(PfK#P#)C81QoCiR*W+Eq`3!+A>F%@O#&mAJ^7xt>6!~wAXP| z(^QqCXYqOv7Rr5112^I5kFG60N8i~pM=SVKa9lM_RpYvZKf74`9M?3kF)nw{l; fqN&4Q@i*&v1OK3Bltx0hfq#aYXd}OYf1%^QT=G0w literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfBooleanImpl.class b/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfBooleanImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..505a4cfedb422468da13adf383bb03f6ae4f2079 GIT binary patch literal 4044 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfCharImpl.class b/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfCharImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f1fa261e9f8da6b368da2ecd905712e3f0608184 GIT binary patch literal 4000 zcmbtWTUX;$7~Q8=+6hx`gEBfd2DL3nXJ9~wBEsN|1D1<|DC2EX8fdUhFimy!xA+%) zP#^3pUCZUOkF(bJ;DbNK<#&=aP2iBW$XX=n$vOMmdw<{ga{m1H*WUrGqMSeo;W#1^ zqKGjJAIsm$xr(eEPo?Su1%~IYbFol8Dxkps+wvpF)XFegtP}V zRnI+Wn97z>QjGlix;Z%9ZZ zLnx-cV;ZV<#4ys5X;qayYDJusFoic665pw2*-9kCu23rZ^grq;A4iU1qFuYKdi2!X zgq?dX;jV-k%u=;;TD-GfbPt#Y=@+mbmaVIFTWT;h0C|C@4^yq)H* z1c(v<-IuU{JbBB3Y?NhhA{=Xb!j0n{hHHV=#PKe}^|Mnpl&WqtY@yU5?2<_pR885e zSBr|VD;Fyybf};o$dx_WQ2B3XFk+Tfs-w9;3q0wmIr-sxlN^ZZeA`oLiJAdJf6<>c zwod#s%XVjlZ$}c~sGnrxq(#*6*EfIBj_NJvCBjJTP?^YP-5}AeymamvLa@vpgDKnz zqDCi%xS+Km{gB$XFg6vI`*Apb3y~A5aJh(jKDbzY70}udo!KZPMLh{Y%n38nfjzCeEvD_=`ZQ}? z$l%nZdtHhsU}Av^4^Htf!KE4Q46dZKWr7^ty4NJW_e58}#B$^Swg7dQ+*H zkM)`v#{omSTQ&^Rnx-knDnDf@RMW!(aSX}!iG{w-_7B{p^FtE!g`soV5S{Mm5JT5x z`c*|Ao$`QG_Ghrk5yWqfMVd(bL_=Y$&^1XDffu-pzwm&bvWU<%Md!r#=+2)W;t@gf zr}y#Lnw`QL)@j}cG%7jo)=;344H^kyldg1@aVQ)jW>JuSLu!B0ia+=x&9LLgto46; zVoPpp$&D?!v86My`A9qV782OThlILJG44}ri#v~0PbQU%lZF;tDL_V;JF7N;qc#~IsIWmqPzV+u)@z<4z(QJIkjlEiR(WE z;6-gbT1+Q0htM6m^Ss5flTC~Vt&VxvL@C|?2#C&W0v4|ascN&BB6mZUyR!}pvZaaa zAD9jT@Y>=MnZd4$6{d>d7T;*%&PA~1@v$Rn#<8}Kti9I(s?T+I0edbN+g(f7+Z_PT z(e;Uo<=3^?vquZ~)W!1i>K$ty`(lp*q1qlz;faU~ zglg+rz!xqTzsG?9XLY$f@JoDU?dhkGt$PtAx?iOlPofAV(ntNYh(nA~(_X|;Eb$+x C-nk+G literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfDoubleImpl.class b/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfDoubleImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..96708ef75521ec0ec0ec3d58bc8f7f5779ff9b54 GIT binary patch literal 4023 zcmbtWYg5}s6g`XIjwpr@TGHl42=#;F1OjQWOCcm_a1Ew~x+Q(eSYT0Ga%DLkeog;C zKeYW&XWE%gKlevva#xaN2^86;%wS2Y-E+@5_wLpH_v){I0BoWb!w3Qq1Otd^w3lReUi^dVhr3eH8qj-xUe^UK1D=WIB zDPlc)q-v6UtPtj@+SapWvEG)7#(iscqtenf@lbaRGKBN8BI|1mYsqsV%>hMLvyV=7 zsiajUEmtU*qitQTXG=|8Rw-;QRgNIRuskrA(vc~6tI@2-F@_1Q<}$;)#o|m*@0f91 z!Bhlq3wQ_93=@WBE@BKJsnOI=8K#mcFAyI4T>14FNZC ziy>MQTeVHKN~sSdQ(OGiZ2_~mL#dH|YK!$2!xd+0N|h7oP|u~F^QrF(NFqfjy1J)p zvU1EY*%fM(l{soe%m|pr2Mn>FWxZx3lVRUeEIIW*YAP2&mSL_}zulU2)ZJ`1|6Ig9 z0gG6on&-rLrES!ygd38gGh~wme>UBsHjCU4x-4J?4;U_SJlX|2VuRdW;J*0C@&I}$ zU==xXmjjt7>&{eI<_?7$!AA_&e9ejAV}|SJr)*0NRXa6>Qll`7W~?YH(oVZkk+gl$ z=pYkC^-!#rMNQ_<)?iSt$y7-Xd@XP!sAXq}?@;m}r1I@g<>l2B7)C4Zys-i?R1D*- z6|Q|rfKzUor_C-^%VF32ycyM5(rbhf+oM7e^|nU&?PjKb=kNqel^I@m?gp=h=M8aT zb4S#pUITUupyIN>5q=wq+>i&RpYtzSR~>Zsg=3InCAKBnTh(1rqa4$>hiWThY}G-@ zrd@5SkFvb?t{XJgOkZZCXleKuwCYwr88m0vGcSD-OY3fX({{E2nl0YqjZJ|gb+cYwQ9r~p+jz!@JVS|G3H^vS!M*Q*LXoeX-%-6HDBer127VOx9 z9a}gTn~(Hjmk`4)J|on1it&(Q8{B#9G|7L7$qtP0BZho4{DKj_D}@V2Vx1&>Zb?`o z0o=t{n)Ck?S2=$tz>EVRX7S&nIimqWqO19z*Z`fvENWT0a%!P;2iJe~!3&vqw3yCm z7NNUz<(UYlGabzMtqwcbgeYDD1VpDe4;FKNs(LKu$=wmd-6e|!+0sG!Uo7|mIBl_s zEMnir3Q$FGi*Iyr_aay;_`(vkXjvO2Yw!1girVh3qHJ?9-8FQ5*azSZy1ulr+`95Z zd$fwLY%Djg;jvb5;O&twRL`S%Jon;4x%UNlgGXQ6SZ2O?CBpM8rKS{biGP79!CXIFiKstf+I{*)6U~K9D5B7dA3Oa literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfFloatImpl.class b/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts$OfFloatImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..5115f7f94d166979118b14fe9beb8e5aa86ab4d6 GIT binary patch literal 4009 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 CO~6P1 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts.class b/tests/test_data/std/jdk/internal/foreign/layout/ValueLayouts.class new file mode 100644 index 0000000000000000000000000000000000000000..c46c880ff580b54a648fc25d9f842ef62034628d GIT binary patch literal 3767 zcmbtX`BxKH7`>0hAt5e+pthx2MTJ;RUCBKlN#$sQ;gI?6y!UJ~LsLzGis8|ny==;J z?lII6ZK;yRw-C5sWq2IO}alEH5q}_f|A-A zf%!RVk#Wm*{8)>13PO_GQv#bxNSo{Lk=r`UytyIBZi8gEv7k8nS!M~jtgYCrV2kAU zw7`ZE_%VXVu6>s57=YZ`B)9g0%=Hw|%()@Ru3NI}DJZ!C z%S`yui#`R>=@a3v=rklOQ-+6x6|-*ziKW^g|YVn{()lG`cJTEd!o0X%x0 zvs_j$M!SNS1eWHuL-z0))Fv%^DxxJOHIs`xj9m&wB-P!e9e`c2n60H!9@i~JbIrJU z2PsL83M|i&>^BT8p&DIwA}#6l9*k;9N4HD`FAFTn^@}*RZYH|Zy1_HnkG&|b!fOKc zyUbKNndH9LV#}hcZR?udwoJCa5rB#@s*;*aYGzDeZHBR{6kfQ3v$|je3PlW>f_MN4 zj2G+`S4aeugysyXlbXQ7=6sRLM3xjL0@x>=s~pRF>&G5UN&%%r)z3s{L_t!Zx!C%l z(Dhg`QkXxWo7zx%a!j*_RTiW`?SK_kjSCC>@uK&2&RlWCkOkU&G>M5dD2$z=Mw%jq)d2zD~?+=!z__YJDa%$$7@ zO1kQ#Z6>Av9`@2_rg8IEG`o-TM4aRJBUajuYJIxQc1>PeYMrcFCT>VeIox|(lazwP z0v*L>y{T&~<;Y7wUQ`7~1&Us`nIbf;XEp3l&6uI}sL^q<4)mL*X1lr5SQc{&?l=lg z3arj;z!|cTyUHjyEzo%1&H}!>@tM7FJbOt|a9*J4zP=nt_U2~J8uZWJBotgK!e91w z{XL^P9KWmf3O*KC`5*#rch+sj(Vb34kQIC?u;M`h*qOy1j=N8ee^)aVd|AZ!Zg+S5 zjKvgWl}*97MWjIXc2nRPfp9!0J_>%|{rf>v@cQ#W%euNnQ=kiVGt@4{ys-4J9u|L2 z$WIyn_=5rh`-wt)3O*}?w;_IWn{9r}W}p)(eh0h`aF8bQ;Q-!b2s(>4RJcK>gMUET zy+(cof5+S#sG?nWllBtNeoWd=cy^PtTRi(oX|MO}P11hGvpb~S<=NY%-S620H-oh= zdS>M29qbvsgT14-@k;HhxA1!K7NUIIf_@vu-=tarIh7IAlj>nqiX-rgqo@(b&>)VZ zQJlbXaS|=!6xNB;XccGBCeETuoI{^Dk3n&P@_v!(IZfTW1WjDVgt$VvxQev6=BB2> zn?4SrmLmbvn8I63*W0wcv`w?^9in&nUkzVFwfFJkJ-#Tz`zXf;uJs{4;&U-O4fAf( z%bQ^<@70aG_bintegral types + * (either signed or unsigned) and floating-point types. Each value layout has a size, an alignment (expressed in bytes), + * a {@linkplain ByteOrder byte order}, and a carrier, that is, the Java type that should be used when + * {@linkplain MemorySegment#get(ValueLayout.OfInt, long) accessing} a memory region using the value layout. + *

+ * This class defines useful value layout constants for Java primitive types and addresses. + * The layout constants in this class make implicit alignment and byte-ordering assumption: all layout + * constants in this class are byte-aligned, and their byte order is set to the {@linkplain ByteOrder#nativeOrder() platform default}, + * thus making it easy to work with other APIs, such as arrays and {@link java.nio.ByteBuffer}. + * + * @implSpec This class and its subclasses are immutable, thread-safe and value-based. + */ +public final class ValueLayouts { + + // Suppresses default constructor, ensuring non-instantiability. + private ValueLayouts() {} + + abstract static sealed class AbstractValueLayout & ValueLayout> extends AbstractLayout { + + static final int ADDRESS_SIZE_BYTES = Unsafe.ADDRESS_SIZE; + + private final Class carrier; + private final ByteOrder order; + @Stable + private VarHandle handle; + + AbstractValueLayout(Class carrier, ByteOrder order, long byteSize, long byteAlignment, Optional name) { + super(byteSize, byteAlignment, name); + this.carrier = carrier; + this.order = order; + assertCarrierSize(carrier, byteSize); + } + + /** + * {@return the value's byte order} + */ + public final ByteOrder order() { + return order; + } + + /** + * Returns a value layout with the same carrier, alignment constraints and name as this value layout, + * but with the specified byte order. + * + * @param order the desired byte order. + * @return a value layout with the given byte order. + */ + public final V withOrder(ByteOrder order) { + Objects.requireNonNull(order); + return dup(order, byteAlignment(), name()); + } + + @Override + public String toString() { + char descriptor = carrier.descriptorString().charAt(0); + if (order == ByteOrder.LITTLE_ENDIAN) { + descriptor = Character.toLowerCase(descriptor); + } + return decorateLayoutString(String.format("%s%d", descriptor, byteSize())); + } + + @Override + public boolean equals(Object other) { + return this == other || + other instanceof AbstractValueLayout otherValue && + super.equals(other) && + carrier.equals(otherValue.carrier) && + order.equals(otherValue.order); + } + + /** + * {@return the carrier associated with this value layout} + */ + public final Class carrier() { + return carrier; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), order, carrier); + } + + @Override + final V dup(long byteAlignment, Optional name) { + return dup(order(), byteAlignment, name); + } + + abstract V dup(ByteOrder order, long byteAlignment, Optional name); + + static void assertCarrierSize(Class carrier, long byteSize) { + assert isValidCarrier(carrier); + assert carrier != MemorySegment.class + // MemorySegment byteSize must always equal ADDRESS_SIZE_BYTES + || byteSize == ADDRESS_SIZE_BYTES; + assert !carrier.isPrimitive() || + // Primitive class byteSize must always correspond + byteSize == (carrier == boolean.class ? 1 : + Utils.byteWidthOfPrimitive(carrier)); + } + + static boolean isValidCarrier(Class carrier) { + // void.class is not valid + return carrier == boolean.class + || carrier == byte.class + || carrier == short.class + || carrier == char.class + || carrier == int.class + || carrier == long.class + || carrier == float.class + || carrier == double.class + || carrier == MemorySegment.class; + } + + @ForceInline + public final VarHandle varHandle() { + final class VarHandleCache { + private static final Map HANDLE_MAP = new ConcurrentHashMap<>(); + } + if (handle == null) { + // this store to stable field is safe, because return value of 'makeMemoryAccessVarHandle' has stable identity + handle = VarHandleCache.HANDLE_MAP.computeIfAbsent(self().withoutName(), _ -> varHandleInternal()); + } + return handle; + } + + @SuppressWarnings("unchecked") + final V self() { + return (V) this; + } + } + + public static final class OfBooleanImpl extends AbstractValueLayout implements ValueLayout.OfBoolean { + + private OfBooleanImpl(ByteOrder order, long byteAlignment, Optional name) { + super(boolean.class, order, Byte.BYTES, byteAlignment, name); + } + + @Override + OfBooleanImpl dup(ByteOrder order, long byteAlignment, Optional name) { + return new OfBooleanImpl(order, byteAlignment, name); + } + + public static OfBoolean of(ByteOrder order) { + return new OfBooleanImpl(order, Byte.BYTES, Optional.empty()); + } + } + + public static final class OfByteImpl extends AbstractValueLayout implements ValueLayout.OfByte { + + private OfByteImpl(ByteOrder order, long byteAlignment, Optional name) { + super(byte.class, order, Byte.BYTES, byteAlignment, name); + } + + @Override + OfByteImpl dup(ByteOrder order, long byteAlignment, Optional name) { + return new OfByteImpl(order, byteAlignment, name); + } + + public static OfByte of(ByteOrder order) { + return new OfByteImpl(order, Byte.BYTES, Optional.empty()); + } + } + + public static final class OfCharImpl extends AbstractValueLayout implements ValueLayout.OfChar { + + private OfCharImpl(ByteOrder order, long byteAlignment, Optional name) { + super(char.class, order, Character.BYTES, byteAlignment, name); + } + + @Override + OfCharImpl dup(ByteOrder order, long byteAlignment, Optional name) { + return new OfCharImpl(order, byteAlignment, name); + } + + public static OfChar of(ByteOrder order) { + return new OfCharImpl(order, Character.BYTES, Optional.empty()); + } + } + + public static final class OfShortImpl extends AbstractValueLayout implements ValueLayout.OfShort { + + private OfShortImpl(ByteOrder order, long byteAlignment, Optional name) { + super(short.class, order, Short.BYTES, byteAlignment, name); + } + + @Override + OfShortImpl dup(ByteOrder order, long byteAlignment, Optional name) { + return new OfShortImpl(order, byteAlignment, name); + } + + public static OfShort of(ByteOrder order) { + return new OfShortImpl(order, Short.BYTES, Optional.empty()); + } + } + + public static final class OfIntImpl extends AbstractValueLayout implements ValueLayout.OfInt { + + private OfIntImpl(ByteOrder order, long byteAlignment, Optional name) { + super(int.class, order, Integer.BYTES, byteAlignment, name); + } + + @Override + OfIntImpl dup(ByteOrder order, long byteAlignment, Optional name) { + return new OfIntImpl(order, byteAlignment, name); + } + + public static OfInt of(ByteOrder order) { + return new OfIntImpl(order, Integer.BYTES, Optional.empty()); + } + } + + public static final class OfFloatImpl extends AbstractValueLayout implements ValueLayout.OfFloat { + + private OfFloatImpl(ByteOrder order, long byteAlignment, Optional name) { + super(float.class, order, Float.BYTES, byteAlignment, name); + } + + @Override + OfFloatImpl dup(ByteOrder order, long byteAlignment, Optional name) { + return new OfFloatImpl(order, byteAlignment, name); + } + + public static OfFloat of(ByteOrder order) { + return new OfFloatImpl(order, Float.BYTES, Optional.empty()); + } + } + + public static final class OfLongImpl extends AbstractValueLayout implements ValueLayout.OfLong { + + private OfLongImpl(ByteOrder order, long byteAlignment, Optional name) { + super(long.class, order, Long.BYTES, byteAlignment, name); + } + + @Override + OfLongImpl dup(ByteOrder order, long byteAlignment, Optional name) { + return new OfLongImpl(order, byteAlignment, name); + } + + public static OfLong of(ByteOrder order) { + return new OfLongImpl(order, Long.BYTES, Optional.empty()); + } + } + + public static final class OfDoubleImpl extends AbstractValueLayout implements ValueLayout.OfDouble { + + private OfDoubleImpl(ByteOrder order, long byteAlignment, Optional name) { + super(double.class, order, Double.BYTES, byteAlignment, name); + } + + @Override + OfDoubleImpl dup(ByteOrder order, long byteAlignment, Optional name) { + return new OfDoubleImpl(order, byteAlignment, name); + } + + public static OfDouble of(ByteOrder order) { + return new OfDoubleImpl(order, Double.BYTES, Optional.empty()); + } + + } + + public static final class OfAddressImpl extends AbstractValueLayout implements AddressLayout { + + private final MemoryLayout targetLayout; + + private OfAddressImpl(ByteOrder order, long byteSize, long byteAlignment, MemoryLayout targetLayout, Optional name) { + super(MemorySegment.class, order, byteSize, byteAlignment, name); + this.targetLayout = targetLayout; + } + + @Override + OfAddressImpl dup(ByteOrder order, long byteAlignment, Optional name) { + return new OfAddressImpl(order, byteSize(), byteAlignment,targetLayout, name); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && + Objects.equals(((OfAddressImpl)other).targetLayout, this.targetLayout); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), targetLayout); + } + + @Override + @CallerSensitive + public AddressLayout withTargetLayout(MemoryLayout layout) { + Reflection.ensureNativeAccess(Reflection.getCallerClass(), AddressLayout.class, "withTargetLayout"); + Objects.requireNonNull(layout); + return new OfAddressImpl(order(), byteSize(), byteAlignment(), layout, name()); + } + + @Override + public AddressLayout withoutTargetLayout() { + return new OfAddressImpl(order(), byteSize(), byteAlignment(), null, name()); + } + + @Override + public Optional targetLayout() { + return Optional.ofNullable(targetLayout); + } + + public static AddressLayout of(ByteOrder order) { + return new OfAddressImpl(order, ADDRESS_SIZE_BYTES, ADDRESS_SIZE_BYTES, null, Optional.empty()); + } + + @Override + public String toString() { + char descriptor = 'A'; + if (order() == ByteOrder.LITTLE_ENDIAN) { + descriptor = Character.toLowerCase(descriptor); + } + String str = decorateLayoutString(String.format("%s%d", descriptor, byteSize())); + if (targetLayout != null) { + str += ":" + targetLayout; + } + return str; + } + } + + /** + * Creates a value layout of given Java carrier and byte order. The type of resulting value layout is determined + * by the carrier provided: + *

    + *
  • {@link ValueLayout.OfBoolean}, for {@code boolean.class}
  • + *
  • {@link ValueLayout.OfByte}, for {@code byte.class}
  • + *
  • {@link ValueLayout.OfShort}, for {@code short.class}
  • + *
  • {@link ValueLayout.OfChar}, for {@code char.class}
  • + *
  • {@link ValueLayout.OfInt}, for {@code int.class}
  • + *
  • {@link ValueLayout.OfFloat}, for {@code float.class}
  • + *
  • {@link ValueLayout.OfLong}, for {@code long.class}
  • + *
  • {@link ValueLayout.OfDouble}, for {@code double.class}
  • + *
  • {@link AddressLayout}, for {@code MemorySegment.class}
  • + *
+ * @param carrier the value layout carrier. + * @param order the value layout's byte order. + * @return a value layout with the given Java carrier and byte-order. + * @throws IllegalArgumentException if the carrier type is not supported. + */ + public static ValueLayout valueLayout(Class carrier, ByteOrder order) { + Objects.requireNonNull(carrier); + Objects.requireNonNull(order); + if (carrier == boolean.class) { + return ValueLayouts.OfBooleanImpl.of(order); + } else if (carrier == char.class) { + return ValueLayouts.OfCharImpl.of(order); + } else if (carrier == byte.class) { + return ValueLayouts.OfByteImpl.of(order); + } else if (carrier == short.class) { + return ValueLayouts.OfShortImpl.of(order); + } else if (carrier == int.class) { + return ValueLayouts.OfIntImpl.of(order); + } else if (carrier == float.class) { + return ValueLayouts.OfFloatImpl.of(order); + } else if (carrier == long.class) { + return ValueLayouts.OfLongImpl.of(order); + } else if (carrier == double.class) { + return ValueLayouts.OfDoubleImpl.of(order); + } else if (carrier == MemorySegment.class) { + return ValueLayouts.OfAddressImpl.of(order); + } else { + throw new IllegalArgumentException("Unsupported carrier: " + carrier.getName()); + } + } +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/BMPSet.class b/tests/test_data/std/jdk/internal/icu/impl/BMPSet.class new file mode 100644 index 0000000000000000000000000000000000000000..5411af0a5fc5e525f6f4a0428e2626feb3b9d6d9 GIT binary patch literal 6132 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/BMPSet.java b/tests/test_data/std/jdk/internal/icu/impl/BMPSet.java new file mode 100644 index 00000000..e10bc3db --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/BMPSet.java @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * + ****************************************************************************** + */ + +package jdk.internal.icu.impl; + +import jdk.internal.icu.text.UnicodeSet.SpanCondition; +import jdk.internal.icu.util.OutputInt; + +/** + * Helper class for frozen UnicodeSets, implements contains() and span() optimized for BMP code points. + * + * Latin-1: Look up bytes. + * 2-byte characters: Bits organized vertically. + * 3-byte characters: Use zero/one/mixed data per 64-block in U+0000..U+FFFF, with mixed for illegal ranges. + * Supplementary characters: Call contains() on the parent set. + */ +public final class BMPSet { + + /** + * One boolean ('true' or 'false') per Latin-1 character. + */ + private boolean[] latin1Contains; + + /** + * One bit per code point from U+0000..U+07FF. The bits are organized vertically; consecutive code points + * correspond to the same bit positions in consecutive table words. With code point parts lead=c{10..6} + * trail=c{5..0} it is set.contains(c)==(table7FF[trail] bit lead) + * + * Bits for 0..7F (non-shortest forms) are set to the result of contains(FFFD) for faster validity checking at + * runtime. + */ + private int[] table7FF; + + /** + * One bit per 64 BMP code points. The bits are organized vertically; consecutive 64-code point blocks + * correspond to the same bit position in consecutive table words. With code point parts lead=c{15..12} + * t1=c{11..6} test bits (lead+16) and lead in bmpBlockBits[t1]. If the upper bit is 0, then the lower bit + * indicates if contains(c) for all code points in the 64-block. If the upper bit is 1, then the block is mixed + * and set.contains(c) must be called. + * + * Bits for 0..7FF (non-shortest forms) and D800..DFFF are set to the result of contains(FFFD) for faster + * validity checking at runtime. + */ + private int[] bmpBlockBits; + + /** + * Inversion list indexes for restricted binary searches in findCodePoint(), from findCodePoint(U+0800, U+1000, + * U+2000, .., U+F000, U+10000). U+0800 is the first 3-byte-UTF-8 code point. Code points below U+0800 are + * always looked up in the bit tables. The last pair of indexes is for finding supplementary code points. + */ + private int[] list4kStarts; + + /** + * The inversion list of the parent set, for the slower contains() implementation for mixed BMP blocks and for + * supplementary code points. The list is terminated with list[listLength-1]=0x110000. + */ + private final int[] list; + private final int listLength; // length used; list may be longer to minimize reallocs + + public BMPSet(final int[] parentList, int parentListLength) { + list = parentList; + listLength = parentListLength; + latin1Contains = new boolean[0x100]; + table7FF = new int[64]; + bmpBlockBits = new int[64]; + list4kStarts = new int[18]; + + /* + * Set the list indexes for binary searches for U+0800, U+1000, U+2000, .., U+F000, U+10000. U+0800 is the + * first 3-byte-UTF-8 code point. Lower code points are looked up in the bit tables. The last pair of + * indexes is for finding supplementary code points. + */ + list4kStarts[0] = findCodePoint(0x800, 0, listLength - 1); + int i; + for (i = 1; i <= 0x10; ++i) { + list4kStarts[i] = findCodePoint(i << 12, list4kStarts[i - 1], listLength - 1); + } + list4kStarts[0x11] = listLength - 1; + + initBits(); + } + + public boolean contains(int c) { + if (c <= 0xff) { + return (latin1Contains[c]); + } else if (c <= 0x7ff) { + return ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0); + } else if (c < 0xd800 || (c >= 0xe000 && c <= 0xffff)) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + return (0 != twoBits); + } else { + // Look up the code point in its 4k block of code points. + return containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1]); + } + } else if (c <= 0x10ffff) { + // surrogate or supplementary code point + return containsSlow(c, list4kStarts[0xd], list4kStarts[0x11]); + } else { + // Out-of-range code points get false, consistent with long-standing + // behavior of UnicodeSet.contains(c). + return false; + } + } + + /** + * Span the initial substring for which each character c has spanCondition==contains(c). It must be + * spanCondition==0 or 1. + * + * @param start The start index + * @param outCount If not null: Receives the number of code points in the span. + * @return the limit (exclusive end) of the span + * + * NOTE: to reduce the overhead of function call to contains(c), it is manually inlined here. Check for + * sufficient length for trail unit for each surrogate pair. Handle single surrogates as surrogate code points + * as usual in ICU. + */ + public final int span(CharSequence s, int start, SpanCondition spanCondition, + OutputInt outCount) { + char c, c2; + int i = start; + int limit = s.length(); + int numSupplementary = 0; + if (SpanCondition.NOT_CONTAINED != spanCondition) { + // span + while (i < limit) { + c = s.charAt(i); + if (c <= 0xff) { + if (!latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) == 0) { + break; + } + } else if (c < 0xd800 || + c >= 0xdc00 || (i + 1) == limit || (c2 = s.charAt(i + 1)) < 0xdc00 || c2 >= 0xe000) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits == 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (!containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + if (!containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + ++numSupplementary; + ++i; + } + ++i; + } + } else { + // span not + while (i < limit) { + c = s.charAt(i); + if (c <= 0xff) { + if (latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0) { + break; + } + } else if (c < 0xd800 || + c >= 0xdc00 || (i + 1) == limit || (c2 = s.charAt(i + 1)) < 0xdc00 || c2 >= 0xe000) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits != 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + if (containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + ++numSupplementary; + ++i; + } + ++i; + } + } + if (outCount != null) { + int spanLength = i - start; + outCount.value = spanLength - numSupplementary; // number of code points + } + return i; + } + + /** + * Symmetrical with span(). + * Span the trailing substring for which each character c has spanCondition==contains(c). It must be s.length >= + * limit and spanCondition==0 or 1. + * + * @return The string index which starts the span (i.e. inclusive). + */ + public final int spanBack(CharSequence s, int limit, SpanCondition spanCondition) { + char c, c2; + + if (SpanCondition.NOT_CONTAINED != spanCondition) { + // span + for (;;) { + c = s.charAt(--limit); + if (c <= 0xff) { + if (!latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) == 0) { + break; + } + } else if (c < 0xd800 || + c < 0xdc00 || 0 == limit || (c2 = s.charAt(limit - 1)) < 0xd800 || c2 >= 0xdc00) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits == 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (!containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + if (!containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + --limit; + } + if (0 == limit) { + return 0; + } + } + } else { + // span not + for (;;) { + c = s.charAt(--limit); + if (c <= 0xff) { + if (latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0) { + break; + } + } else if (c < 0xd800 || + c < 0xdc00 || 0 == limit || (c2 = s.charAt(limit - 1)) < 0xd800 || c2 >= 0xdc00) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits != 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + if (containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + --limit; + } + if (0 == limit) { + return 0; + } + } + } + return limit + 1; + } + + /** + * Set bits in a bit rectangle in "vertical" bit organization. start> 6; // Named for UTF-8 2-byte lead byte with upper 5 bits. + int trail = start & 0x3f; // Named for UTF-8 2-byte trail byte with lower 6 bits. + + // Set one bit indicating an all-one block. + int bits = 1 << lead; + if ((start + 1) == limit) { // Single-character shortcut. + table[trail] |= bits; + return; + } + + int limitLead = limit >> 6; + int limitTrail = limit & 0x3f; + + if (lead == limitLead) { + // Partial vertical bit column. + while (trail < limitTrail) { + table[trail++] |= bits; + } + } else { + // Partial vertical bit column, + // followed by a bit rectangle, + // followed by another partial vertical bit column. + if (trail > 0) { + do { + table[trail++] |= bits; + } while (trail < 64); + ++lead; + } + if (lead < limitLead) { + bits = ~((1 << lead) - 1); + if (limitLead < 0x20) { + bits &= (1 << limitLead) - 1; + } + for (trail = 0; trail < 64; ++trail) { + table[trail] |= bits; + } + } + // limit<=0x800. If limit==0x800 then limitLead=32 and limitTrail=0. + // In that case, bits=1<= 0x100) { + break; + } + do { + latin1Contains[start++] = true; + } while (start < limit && start < 0x100); + } while (limit <= 0x100); + + // Set table7FF[]. + while (start < 0x800) { + set32x64Bits(table7FF, start, limit <= 0x800 ? limit : 0x800); + if (limit > 0x800) { + start = 0x800; + break; + } + + start = list[listIndex++]; + if (listIndex < listLength) { + limit = list[listIndex++]; + } else { + limit = 0x110000; + } + } + + // Set bmpBlockBits[]. + int minStart = 0x800; + while (start < 0x10000) { + if (limit > 0x10000) { + limit = 0x10000; + } + + if (start < minStart) { + start = minStart; + } + if (start < limit) { // Else: Another range entirely in a known mixed-value block. + if (0 != (start & 0x3f)) { + // Mixed-value block of 64 code points. + start >>= 6; + bmpBlockBits[start & 0x3f] |= 0x10001 << (start >> 6); + start = (start + 1) << 6; // Round up to the next block boundary. + minStart = start; // Ignore further ranges in this block. + } + if (start < limit) { + if (start < (limit & ~0x3f)) { + // Multiple all-ones blocks of 64 code points each. + set32x64Bits(bmpBlockBits, start >> 6, limit >> 6); + } + + if (0 != (limit & 0x3f)) { + // Mixed-value block of 64 code points. + limit >>= 6; + bmpBlockBits[limit & 0x3f] |= 0x10001 << (limit >> 6); + limit = (limit + 1) << 6; // Round up to the next block boundary. + minStart = limit; // Ignore further ranges in this block. + } + } + } + + if (limit == 0x10000) { + break; + } + + start = list[listIndex++]; + if (listIndex < listLength) { + limit = list[listIndex++]; + } else { + limit = 0x110000; + } + } + } + + /** + * Same as UnicodeSet.findCodePoint(int c) except that the binary search is restricted for finding code + * points in a certain range. + * + * For restricting the search for finding in the range start..end, pass in lo=findCodePoint(start) and + * hi=findCodePoint(end) with 0<=lo<=hi= hi || c >= list[hi - 1]) + return hi; + // invariant: c >= list[lo] + // invariant: c < list[hi] + for (;;) { + int i = (lo + hi) >>> 1; + if (i == lo) { + break; // Found! + } else if (c < list[i]) { + hi = i; + } else { + lo = i; + } + } + return hi; + } + + private final boolean containsSlow(int c, int lo, int hi) { + return (0 != (findCodePoint(c, lo, hi) & 1)); + } +} + diff --git a/tests/test_data/std/jdk/internal/icu/impl/CharTrie.class b/tests/test_data/std/jdk/internal/icu/impl/CharTrie.class new file mode 100644 index 0000000000000000000000000000000000000000..686df2b376fdd697f74e03f583979a19bf272bbe GIT binary patch literal 2255 zcmb7F-*XdH7(F*hyKTCqG^H&x4J_q{O$rUv2-?yj1`4SuAT8AbTDHkHUD)h)k_~ov z;6cGrADz($nZXgA;e{7xq#ebPM`wKT)jz_&z+u31che;NdT=tkd-vYG-*>)q&Uf?Y zlV5)akcJaR06_&I6-{Us=)01?nlx?KDA~G|G;@`tSzNJ_vnA6IXg*@vraK{!9?V|R zujxtCNoMSoiaX<$481s(ef8$u$8}eq)@^g8V(G3i7M}~F1+5CgD%zk5Y=8OQ^s-*^ zlZVZ6{UtaUzo1}~z<`It((OVrV_8N)w~mzxm7-z0CsuRDifcM{3pNWRWPYt+UNdYh z?-*sxc3f@IupGOfxsIl5IVRFvmN^_oJ0g;fE`jc9pkvn&(*o{2`9Wtirnz}WoTNQ($MOsFAO~oMM0_}{FHS~Nv zKsugLFeK2sA)X|qLBKE)*e@#|7TEf7iQ{t;!T}WrF~Sr+ct3*#-~mjjc%xx8YuE*M znFS_rSjC%oi*(Q~d8wuVmGt-+Q*i|20-b)yx>Xo<=zkbX!BJ@@=}u3y(-q6|cr;24 zjyNW;e|Fi>mQ2ISYtMR9Gi}XXHp`myoyMol5MfLpBH2Bz;shoI)GE6k_fnm7Jl%#< zAj4BC-jy=OUvNmRm!4|}fz1pz=~#Ih%x6>PnpSZdXZ&2}^p7`$Y#Pi^N#>Lup%1dA zZJe$Y7md=azG!hKl67*@6(v)?S0_WVCIRggTyFH%m_VCZ?`gKcOIuxFleBGJCYoW! z)pJ*;^%XCnf(rs&8%Ap|nLxNEL|MUyjbELqtqj~7`_u2bnM$eT6nH?@xla3BTXZZVyCvPUSi+1` zDdmhwQ_|hO!QHSdmvUun+bE?iy<9fP_@-y=g`HG3z{5Ad9~;>l@hIT43Cw_I&Y$Jm zbp-hXwkC%5twSW%pnQw=hiIRVbgZNE(NA0p;yvCY2=RWLJ12Q|okTCDaE>#YzaKN0 zT@K2yc!Ms8b0~dLP_~j*Z;v+0@BoTdIMKl_W{s1i+ z>A8!(#LwuBwp>p&twuNRxN&)$@6rC${X}#P+sFHFL-i-_LE&KFKBM@Udsr!OfrtMk zM44j%i#)cLJlqN9jzYm@j1VI*TB~3bI_Ctxj8s=;1+54UJVr#&8lAE`t8kApmE7JY zAxJ=bQ!;*ilzG+5H@_PO9 zL?ZTE(*yJd4~4ozvAfv9+1~EZzBL>=e={WRJ^d#kXC4p)pHW`P)B_CE_1nt|fKPb; z6kWJUFWkZ|e8$|jkizFY7{5RUUwT+mL=mH0Ir1P?pQ@prs;b+HW5~lG?k*fAqa#Ev zS!ze%31SKoLi~%K28p+zfaNM@w;5E19U;omKcw9z<|A*feBYnh``qr@EhuJn>M^dqko43_^~E0Gt_{O!1U;rb5}SDaEC9i d4_rZ@^D(ybuM<}pH~wi0V`;`Cy literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/CharTrie.java b/tests/test_data/std/jdk/internal/icu/impl/CharTrie.java new file mode 100644 index 00000000..e320f670 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/CharTrie.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ****************************************************************************** + */ + +package jdk.internal.icu.impl; + +import jdk.internal.icu.text.UTF16; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * Trie implementation which stores data in char, 16 bits. + * @author synwee + * @see com.ibm.icu.impl.Trie + * @since release 2.1, Jan 01 2002 + */ + + // note that i need to handle the block calculations later, since chartrie + // in icu4c uses the same index array. +public class CharTrie extends Trie +{ + // public constructors --------------------------------------------- + + /** + *

Creates a new Trie with the settings for the trie data.

+ *

Unserialize the 32-bit-aligned input stream and use the data for the + * trie.

+ * @param inputStream file input stream to a ICU data file, containing + * the trie + * @param dataManipulate object which provides methods to parse the char + * data + * @throws IOException thrown when data reading fails + * @draft 2.1 + */ + public CharTrie(InputStream inputStream, + DataManipulate dataManipulate) throws IOException + { + super(inputStream, dataManipulate); + + if (!isCharTrie()) { + throw new IllegalArgumentException( + "Data given does not belong to a char trie."); + } + } + + // public methods -------------------------------------------------- + + /** + * Gets the value associated with the codepoint. + * If no value is associated with the codepoint, a default value will be + * returned. + * @param ch codepoint + * @return offset to data + */ + public final char getCodePointValue(int ch) + { + int offset; + + // fastpath for U+0000..U+D7FF + if(0 <= ch && ch < UTF16.LEAD_SURROGATE_MIN_VALUE) { + // copy of getRawOffset() + offset = (m_index_[ch >> INDEX_STAGE_1_SHIFT_] << INDEX_STAGE_2_SHIFT_) + + (ch & INDEX_STAGE_3_MASK_); + return m_data_[offset]; + } + + // handle U+D800..U+10FFFF + offset = getCodePointOffset(ch); + + // return -1 if there is an error, in this case we return the default + // value: m_initialValue_ + return (offset >= 0) ? m_data_[offset] : m_initialValue_; + } + + /** + * Gets the value to the data which this lead surrogate character points + * to. + * Returned data may contain folding offset information for the next + * trailing surrogate character. + * This method does not guarantee correct results for trail surrogates. + * @param ch lead surrogate character + * @return data value + */ + public final char getLeadValue(char ch) + { + return m_data_[getLeadOffset(ch)]; + } + + // protected methods ----------------------------------------------- + + /** + *

Parses the input stream and stores its trie content into a index and + * data array

+ * @param inputStream data input stream containing trie data + * @exception IOException thrown when data reading fails + */ + protected final void unserialize(InputStream inputStream) + throws IOException + { + DataInputStream input = new DataInputStream(inputStream); + int indexDataLength = m_dataOffset_ + m_dataLength_; + m_index_ = new char[indexDataLength]; + for (int i = 0; i < indexDataLength; i ++) { + m_index_[i] = input.readChar(); + } + m_data_ = m_index_; + m_initialValue_ = m_data_[m_dataOffset_]; + } + + /** + * Gets the offset to the data which the surrogate pair points to. + * @param lead lead surrogate + * @param trail trailing surrogate + * @return offset to data + * @draft 2.1 + */ + protected final int getSurrogateOffset(char lead, char trail) + { + if (m_dataManipulate_ == null) { + throw new NullPointerException( + "The field DataManipulate in this Trie is null"); + } + + // get fold position for the next trail surrogate + int offset = m_dataManipulate_.getFoldingOffset(getLeadValue(lead)); + + // get the real data from the folded lead/trail units + if (offset > 0) { + return getRawOffset(offset, (char)(trail & SURROGATE_MASK_)); + } + + // return -1 if there is an error, in this case we return the default + // value: m_initialValue_ + return -1; + } + + // private data members -------------------------------------------- + + /** + * Default value + */ + private char m_initialValue_; + /** + * Array of char data + */ + private char m_data_[]; +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/CharacterIteratorWrapper.class b/tests/test_data/std/jdk/internal/icu/impl/CharacterIteratorWrapper.class new file mode 100644 index 0000000000000000000000000000000000000000..d9767767f4d0a64d8e9e6832ac9c03c37cd74a00 GIT binary patch literal 2194 zcmb7FT~ixn6n@@(up!wBM8LL5T3RX+qNHl23W%1JYBU9vFM&Gkk}P3ivm2L92X)4d zqnCc&d!ZN3c+-nIql2|GZSS1%hxj9$T72H!oe;ow#*1X%_k2C)Jm;Ln7eE15 z;s_zEAfh6QHi5y7%4XiMT-~uWGjEg|c~{?d^Yevu&C$vf7x~j%+Yx9RH!Q=Q5C{)u z7Zk(^n_(1oOeCslN#M3>LEm1f z@mW_ZZ(i2wK|oO!5JiD@_PeB8Rd=0t!|xokiyHpmC{)j}`P`qul|nH~k5E~f7ARRW zOtWZFvLbKx+8PId2Qvt#1``_0V4I_FHB1@^7CF$;p+^(R^y9O3!zt^R3`tGq(9Q%) zHZ0qMQ(V*#-xJJ8t}0LMJV)_5|1a=nQ!e$rLpu<;KajWsWoZZP_l9!6BK|WqVN6Or zeSi@}a2_!ZOeaRs!!ap%Ixhk)Vv09udx=N_Z}80LE{#J95(zySN|XguuZFvn>(g%?SO?2v$)0 ziM`tW(P^^lfB>L zST6lVNc2SKeGOYM68&lSFL~>U_!(#R26BKq1Z=YnAK@fE=3Dj?ZpEie^9J7K^C~{W zCO-GdnP8%m{J^|JjohGGv#=W8!>l(%HO$dB#CS`X=PAsn(^%js66{dqALN8cJV0Fh z&8`dieh#>}5wM%#0>5$}iBit5;Z=eA=;99NZk5C>4~HK?Ozhj|FS*NK;V8bQ<{PB& ot(S8jZDMTqA{ULHTmrn$%;dOdg6!pHb5WKR#uHfPErgYS0fe5Ta{vGU literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/CharacterIteratorWrapper.java b/tests/test_data/std/jdk/internal/icu/impl/CharacterIteratorWrapper.java new file mode 100644 index 00000000..79a6264d --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/CharacterIteratorWrapper.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk.internal.icu.impl; + +import java.text.CharacterIterator; + +import jdk.internal.icu.text.UCharacterIterator; + +/** + * This class is a wrapper around CharacterIterator and implements the + * UCharacterIterator protocol + * @author ram + */ + +public class CharacterIteratorWrapper extends UCharacterIterator { + + private CharacterIterator iterator; + + public CharacterIteratorWrapper(CharacterIterator iter){ + if(iter==null){ + throw new IllegalArgumentException(); + } + iterator = iter; + } + + /** + * @see UCharacterIterator#current() + */ + public int current() { + int c = iterator.current(); + if(c==CharacterIterator.DONE){ + return DONE; + } + return c; + } + + /** + * @see UCharacterIterator#getLength() + */ + public int getLength() { + return (iterator.getEndIndex() - iterator.getBeginIndex()); + } + + /** + * @see UCharacterIterator#getIndex() + */ + public int getIndex() { + return iterator.getIndex(); + } + + /** + * @see UCharacterIterator#next() + */ + public int next() { + int i = iterator.current(); + iterator.next(); + if(i==CharacterIterator.DONE){ + return DONE; + } + return i; + } + + /** + * @see UCharacterIterator#previous() + */ + public int previous() { + int i = iterator.previous(); + if(i==CharacterIterator.DONE){ + return DONE; + } + return i; + } + + /** + * @see UCharacterIterator#setIndex(int) + */ + public void setIndex(int index) { + iterator.setIndex(index); + } + + /** + * @see UCharacterIterator#getText(char[]) + */ + public int getText(char[] fillIn, int offset){ + int length =iterator.getEndIndex() - iterator.getBeginIndex(); + int currentIndex = iterator.getIndex(); + if(offset < 0 || offset + length > fillIn.length){ + throw new IndexOutOfBoundsException(Integer.toString(length)); + } + + for (char ch = iterator.first(); ch != CharacterIterator.DONE; ch = iterator.next()) { + fillIn[offset++] = ch; + } + iterator.setIndex(currentIndex); + + return length; + } + + /** + * Creates a clone of this iterator. Clones the underlying character iterator. + * @see UCharacterIterator#clone() + */ + public Object clone(){ + try { + CharacterIteratorWrapper result = (CharacterIteratorWrapper) super.clone(); + result.iterator = (CharacterIterator)this.iterator.clone(); + return result; + } catch (CloneNotSupportedException e) { + return null; // only invoked if bad underlying character iterator + } + } +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/ICUBinary$1.class b/tests/test_data/std/jdk/internal/icu/impl/ICUBinary$1.class new file mode 100644 index 0000000000000000000000000000000000000000..bb320a1c3d68c9d1df4a6aa3649e4f3e763c71f4 GIT binary patch literal 1069 zcmaiz?@!Y}7{|XiHoDCUWuW*IL?&(nslG8WBP83@xMUy^-1}R1Y&W|rUautlSDFAO zzVHw5k1{^(rYwrmqPjg6N%0k*k2Ga~HgYE}cDkHSwzAL@R zmBS<7Z8qN5rQ-Ue_>3WY%>AMc0>d!Z8t`N8`dszghR?&W8uPL?a>z5-u}~T@+~cOt zP?!+!8!c6@num?+7G`YB!eMYOXm2|M;ZcO?Evcm0W|%6K+j$f)Z(+g44cugyy^trt z8RmP!yc1y%X;0Kb3L^NBpG{xQ#m$P)CYkv2?l8!aati zB!N(Pk(TDf-P7_|`l2VgHP6U^cCSrF9yREaRN4&bM$i>hQA;YZ8x1=`AMlP(ozHMUV z_ml3wrbaN#{609FajU4nSIYB)kY>LlOh4#as4y&FQHG5TJfXeGa6d*;i|$Kqi1wes zDw=Hl#E5!ycqlaGmE9Ggc@uf^6ccte=5ZHqKyGzTnztT1sJ=p3{T@4hV?^8E;;}L;6~!I|YZ<>1@$6#yuxb zthXztL_39bj=4{X?t;~xVA&&|>qFw#DDnY(6kaOjgm20;5%o~I$p4{YyJaq= zHYyNC5}a~$&d^&`S{}5n>oPu0r3l4p6o{}UVwLia(=nGSAuLt@)7Cm+L?t`Ih?0g>7conT>Tn{aIuu5%B^e&B%3MV}&TZINM4<;0Fi`c=dL l%M7wN1FL(B{}&7~u`rC0HjZMPvB(}5qnKcpW1P(9-T`}KktF~C literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/ICUBinary.class b/tests/test_data/std/jdk/internal/icu/impl/ICUBinary.class new file mode 100644 index 0000000000000000000000000000000000000000..8de7540d52cc8c4063df2d84247b048298b9f6fb GIT binary patch literal 7632 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 root = ICUBinary.class; + + try (@SuppressWarnings("removal") InputStream is = AccessController.doPrivileged(new PrivilegedAction() { + public InputStream run() { + return root.getResourceAsStream(itemPath); + } + })) { + + // is.available() may return 0, or 1, or the total number of bytes in the stream, + // or some other number. + // Do not try to use is.available() == 0 to find the end of the stream! + byte[] bytes; + int avail = is.available(); + if (avail > 32) { + // There are more bytes available than just the ICU data header length. + // With luck, it is the total number of bytes. + bytes = new byte[avail]; + } else { + bytes = new byte[128]; // empty .res files are even smaller + } + // Call is.read(...) until one returns a negative value. + int length = 0; + for(;;) { + if (length < bytes.length) { + int numRead = is.read(bytes, length, bytes.length - length); + if (numRead < 0) { + break; // end of stream + } + length += numRead; + } else { + // See if we are at the end of the stream before we grow the array. + int nextByte = is.read(); + if (nextByte < 0) { + break; + } + int capacity = 2 * bytes.length; + if (capacity < 128) { + capacity = 128; + } else if (capacity < 0x4000) { + capacity *= 2; // Grow faster until we reach 16kB. + } + bytes = Arrays.copyOf(bytes, capacity); + bytes[length++] = (byte) nextByte; + } + } + return ByteBuffer.wrap(bytes, 0, length); + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Same as readHeader(), but returns a VersionInfo rather than a compact int. + */ + public static VersionInfo readHeaderAndDataVersion(ByteBuffer bytes, + int dataFormat, + Authenticate authenticate) + throws IOException { + return getVersionInfoFromCompactInt(readHeader(bytes, dataFormat, authenticate)); + } + + private static final byte BIG_ENDIAN_ = 1; + public static final byte[] readHeader(InputStream inputStream, + byte dataFormatIDExpected[], + Authenticate authenticate) + throws IOException + { + DataInputStream input = new DataInputStream(inputStream); + char headersize = input.readChar(); + int readcount = 2; + //reading the header format + byte magic1 = input.readByte(); + readcount ++; + byte magic2 = input.readByte(); + readcount ++; + if (magic1 != MAGIC1 || magic2 != MAGIC2) { + throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_); + } + + input.readChar(); // reading size + readcount += 2; + input.readChar(); // reading reserved word + readcount += 2; + byte bigendian = input.readByte(); + readcount ++; + byte charset = input.readByte(); + readcount ++; + byte charsize = input.readByte(); + readcount ++; + input.readByte(); // reading reserved byte + readcount ++; + + byte dataFormatID[] = new byte[4]; + input.readFully(dataFormatID); + readcount += 4; + byte dataVersion[] = new byte[4]; + input.readFully(dataVersion); + readcount += 4; + byte unicodeVersion[] = new byte[4]; + input.readFully(unicodeVersion); + readcount += 4; + if (headersize < readcount) { + throw new IOException("Internal Error: Header size error"); + } + input.skipBytes(headersize - readcount); + + if (bigendian != BIG_ENDIAN_ || charset != CHAR_SET_ + || charsize != CHAR_SIZE_ + || !Arrays.equals(dataFormatIDExpected, dataFormatID) + || (authenticate != null + && !authenticate.isDataVersionAcceptable(dataVersion))) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_); + } + return unicodeVersion; + } + + /** + * Reads an ICU data header, checks the data format, and returns the data version. + * + *

Assumes that the ByteBuffer position is 0 on input. + * The buffer byte order is set according to the data. + * The buffer position is advanced past the header (including UDataInfo and comment). + * + *

See C++ ucmndata.h and unicode/udata.h. + * + * @return dataVersion + * @throws IOException if this is not a valid ICU data item of the expected dataFormat + */ + public static int readHeader(ByteBuffer bytes, int dataFormat, Authenticate authenticate) + throws IOException { + assert bytes.position() == 0; + byte magic1 = bytes.get(2); + byte magic2 = bytes.get(3); + if (magic1 != MAGIC1 || magic2 != MAGIC2) { + throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_); + } + + byte isBigEndian = bytes.get(8); + byte charsetFamily = bytes.get(9); + byte sizeofUChar = bytes.get(10); + if (isBigEndian < 0 || 1 < isBigEndian || + charsetFamily != CHAR_SET_ || sizeofUChar != CHAR_SIZE_) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_); + } + bytes.order(isBigEndian != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + + int headerSize = bytes.getChar(0); + int sizeofUDataInfo = bytes.getChar(4); + if (sizeofUDataInfo < 20 || headerSize < (sizeofUDataInfo + 4)) { + throw new IOException("Internal Error: Header size error"); + } + // TODO: Change Authenticate to take int major, int minor, int milli, int micro + // to avoid array allocation. + byte[] formatVersion = new byte[] { + bytes.get(16), bytes.get(17), bytes.get(18), bytes.get(19) + }; + if (bytes.get(12) != (byte)(dataFormat >> 24) || + bytes.get(13) != (byte)(dataFormat >> 16) || + bytes.get(14) != (byte)(dataFormat >> 8) || + bytes.get(15) != (byte)dataFormat || + (authenticate != null && !authenticate.isDataVersionAcceptable(formatVersion))) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_ + + String.format("; data format %02x%02x%02x%02x, format version %d.%d.%d.%d", + bytes.get(12), bytes.get(13), bytes.get(14), bytes.get(15), + formatVersion[0] & 0xff, formatVersion[1] & 0xff, + formatVersion[2] & 0xff, formatVersion[3] & 0xff)); + } + + bytes.position(headerSize); + return // dataVersion + ((int)bytes.get(20) << 24) | + ((bytes.get(21) & 0xff) << 16) | + ((bytes.get(22) & 0xff) << 8) | + (bytes.get(23) & 0xff); + } + + public static void skipBytes(ByteBuffer bytes, int skipLength) { + if (skipLength > 0) { + bytes.position(bytes.position() + skipLength); + } + } + + public static byte[] getBytes(ByteBuffer bytes, int length, int additionalSkipLength) { + byte[] dest = new byte[length]; + bytes.get(dest); + if (additionalSkipLength > 0) { + skipBytes(bytes, additionalSkipLength); + } + return dest; + } + + public static String getString(ByteBuffer bytes, int length, int additionalSkipLength) { + CharSequence cs = bytes.asCharBuffer(); + String s = cs.subSequence(0, length).toString(); + skipBytes(bytes, length * 2 + additionalSkipLength); + return s; + } + + public static char[] getChars(ByteBuffer bytes, int length, int additionalSkipLength) { + char[] dest = new char[length]; + bytes.asCharBuffer().get(dest); + skipBytes(bytes, length * 2 + additionalSkipLength); + return dest; + } + + public static int[] getInts(ByteBuffer bytes, int length, int additionalSkipLength) { + int[] dest = new int[length]; + bytes.asIntBuffer().get(dest); + skipBytes(bytes, length * 4 + additionalSkipLength); + return dest; + } + + /** + * Returns a VersionInfo for the bytes in the compact version integer. + */ + public static VersionInfo getVersionInfoFromCompactInt(int version) { + return VersionInfo.getInstance( + version >>> 24, (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); + } + + // private variables ------------------------------------------------- + + /** + * Magic numbers to authenticate the data file + */ + private static final byte MAGIC1 = (byte)0xda; + private static final byte MAGIC2 = (byte)0x27; + + /** + * File format authentication values + */ + private static final byte CHAR_SET_ = 0; + private static final byte CHAR_SIZE_ = 2; + + /** + * Error messages + */ + private static final String MAGIC_NUMBER_AUTHENTICATION_FAILED_ = + "ICUBinary data file error: Magic number authentication failed"; + private static final String HEADER_AUTHENTICATION_FAILED_ = + "ICUBinary data file error: Header authentication failed"; +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$ComposeNormalizer2.class b/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$ComposeNormalizer2.class new file mode 100644 index 0000000000000000000000000000000000000000..4b0b575ad252af110647dcf7e923ec41a0e7e519 GIT binary patch literal 2308 zcmbVOU31$+6g_LZQS68~Nokxkfwm;Hw$s)S=m)qhO-xHg(}c#UJ2AW{@+MZJtc*UG zDZ@|Vg_)8JbcP?m4Ddi-$_sBi@FSSsm0Vflpo}LkmUgxGoO|w`yX#;7`}r3DH9X28 zg|vcv7lYy^ihjSPBfIwy>VoY~h(Z zzU{jVtSO;KRpc?okdYD?&JUK>2qth+!J8^hVUl6;iT;gVv2?LhskL>d&cF7#FgWS8 zxY+U94C!J?%V7%B3Qnt-!7RgkvXWi_7!)HE!_c6b{Vz{d)0)kJ5}#k^w$tK{DR!3q z?QQN%58$LDM)c!%N2AO$#-v4VMqLaz{YFH~b% zq$`IxoR==W5R|-;!#R}XxXf^SK+DC79M(YJvUpW15!e(isqq$Is79(Xq=ZS;-8Kw{ta#n!4C{&V zkD%%~{m@2J?-Pyd5Y1F1~MKPv8Uk{g6fv<-J7Dk@CU;Sb6qGC_m6Jg)8(s8hrYVmj8|%{=ik5I~y*?HC(3= z1>z%&5tw}YmC|bS$5#>fPFH=h}es` z8;E204EMTB_i3Xf)8WePV>;CR(u18Z390^cN937nPL&g`So5A|;hDjVgP p#pk$B5NWIgnjT;^c&?F!fYUUe!Wz~y@*lw(>X@c`V+tFXeg!0{Pk8_U literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$DecomposeNormalizer2.class b/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$DecomposeNormalizer2.class new file mode 100644 index 0000000000000000000000000000000000000000..6ebad8b62093ac513342102461a9fca128833a9e GIT binary patch literal 1774 zcmbVNT~8BH5IxgYO50UvLB3U#iv0kpDDqKIOV!u}Nd!_NZ_D;V7q+`~w>8n<{6PdHTtgRO{-AW2QT3WI zby>@(NznOO4%X}H-Q z*<>+YoRTK={aTsePb3Rr^y6j_0}=)?M2LF_d!8d9R62{7u*Je$$doM< zE){ruLl|aBn5w?NTHo6fX0{R5h=fs$5n?V`PA}!ERiT#%o1UyYS0ydlTHKa!2jhgn zvTQYqvTD@zl5Boj6?=xs@&yuwfj%@gSZP z=DbNd6pPT?esA!ICy$Q@Ab9GLJ^A=~mv_(j)IRS@rN4u|@|zF$_-Ri`;D{~1VS?WV z8diwoKJVBblaLrAfCor4v9{RS&);IHBLvg_^a-vLrjF6K-Hv<0bLiB;9dCHJxG^M= zVmwAc8dJ;~z%<614BNa5@VAJ=FgAUR;dbbs9QrQ@I@K_Bp(8GI1T)Au2}K+dKf^y{ zi5il;;xz2!qpfKWr}2dk8|v8V0l!<6iMljV%sLqm9%H--xx#)nWXOgbJ;tqes6Q=G rAr~ryCzxXhKb|_&^H^}!MPzv$;d37ru^g~}D~njcFqg9*FEIQcrrEy( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$NFCSingleton.class b/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$NFCSingleton.class new file mode 100644 index 0000000000000000000000000000000000000000..809ab7c8e332ae6a9b5614bdca1e96aee6a6b26e GIT binary patch literal 734 zcma)4+fKqj5IqBED^@`iFDTwk&~j1MN7_yK;D zaf$}vjcl@K=Xz#l=j;3Z6M%!wEK*1t$XFP|I3eHmo;_Q6`rf{3wS^xO#%of`_?VEc z>^2RUgv0jjqb+qTLhUJA`dwRgo|NqdVW)bc)MaohqU|B6A@#iyaiC3PIg!5evoK&K zq*H`qrT$Obh(mTh+HFoChrEFq3kA#)4n`t9bNW;S^TKUhpSaE`p;jL$e6WLlq9a1a z;hqS&y41q$c3L95_F9THg?iw7s_BI?k^hvL_(4X5>S&w;B{P#*^VQ$HvyGq|`r=IX zh=%65pUjJ$T@l6SK@=NUC2Wn*BEh=QT7-`BqDXL&^Fw+2J+q%XP#6yQGg7=Ugi`Vy z{7UiRm0`^sOEx1hj_tjHUV7#t--#Ji#yr2RUk5B;ktGvL{ooy>Sp!Ucz_=+)ykYVc l(@7Fu4ZeSqtg=&yr4*L2(!(;=7z?a1P{ul2bBr4({Q#VVvjzYF literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$NFKCSingleton.class b/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$NFKCSingleton.class new file mode 100644 index 0000000000000000000000000000000000000000..b9d4b920fdf071fc494baa5c3a6d619380343b30 GIT binary patch literal 738 zcma)4+e*Vg5IxgY6KiU<-s}Aa>Vxs}rbUpTDAxGUQt&a2t8U$HBuV`*@j+1V1Nwg{u`qx^!f3;L_H5q--|`oBJn9T?MxyTJMo6Qr{~P2iioIkkNOKeijC- zgf&N)+${g|R^pJokG5(<$Ya#Nn1uqy34499o?SW}GJ<*GR;nkib4nY*qr4~*T;)_x-cHkmoZDR)cKJV2yfuVk z@+168@!_>$%>+v}BQXwazky!b=1IO2GiU`<{I-4_FpU|OOw4wIH;`rxko$mfQy6-~ n@GC}=B)lDb|0Y>wry@%!%wfKb3s_<-u*Sdwmf4zTTtV>%P=sQ1(;jW~}tAs+R$FnQ#?mhS1vuD@-^RM6k0MNk0Bw~mwNTe`@ zX@;v$x`V22y4*HZqpEA;s>`3c)wX31RYU)Y+v^O|8@j2xcNpTu(q0l5Fry%u!Yon@ zm!GKLt5riad)1C>>t=6rtQ%c!Gt4;LZE>^b_8AhzrXQJ3VIB(vsg6e6>@wUewk8OT zzG`>)cVlj9yjGGXBG5GjOAOa0VNJu}J=Lh&z44Hn?$%R{k6hg{lUPK27MGA!a9JeI zFvQKcDZyJg#!okSjQrtlW7FkEmg zzbqnEJX>rniDg_9yHsFUk?HwSHA$XFecSp$6jCeg&Ejpmqu|{XiYPH;C-ute(heBG z-q5Bt6_jZ!&R9VojttKV>vhA}vAW#3-nOh!#2kqRjWf)*bd$Ho!vk(V@+DnrS(<9> zskScOgTaK`*BypityjoZBTtzpzGP_0n#i@u%0!KGR^`C01RZy5jUgwg8o?wFQ~54K zURn`FXPE1_sy5hBM?tmQ=bO6DgGGcZ#4lAk#0HX@#t2t|T&p;#TRS!TCR-{90m zw2M|Dp+y9cxkV!wrXK6I&}Q245-}|FxOz+^sE#Ap&7V3vcn>Rd z8;j2jNJUIjTcNiq^^E$dm1D49=^=(yYQ;2Y!3}Ct{sLOMMsJLu)~OZ2198DqpR1Ig zAzg_dL8+9FFn9PIi~GmOyr8+bhqr_TJy$958j^&tfSVrn6+b?}CL|hv-^-W7Eqp-u zA9@&U!Aty6koaeU6MzMgIA1CMhKn&Awx45pfAt7&tRCa)i;#mTH-$O64}C6KdIxS( zTcgnpr11&ee|J4TD+HUS(cAdgV^#>66+&hOVpa>7DTwVT$j=e44TAAyIS6FQlq=6L zQ?C4@B54nQn^=5CKW|M*jZBy`gFB>w*oh22C0#-_W@&K#Rr2jpzAq`?!~dV}F6u#j zf|Br3j2((rGR#*VY}TI*%ZOo<{tgJA-NV*tjKnXeFur*S#xyNjFXXebgeCK@U?5{sRega5gGXx*}Iy3`qXlLj?;Gel^akX#0 zFCK`J%h0|im2}@Q_@l9cjsU|zODXRi6)_!)YmH;ofI9x+Vb4l!pt6>iC|!bub25C-A* zKEnn^@PuMnHYb#;x1+pXoJP`DJyP(e3=?+;pHEs=)-H=$2%{MH=$l}OQM~_g9xDV9 z!IX|?2BL@&(7Vl=fhIkK%~PIuw}fjesv|##LX6%MziCRjO*0I&`1?>-uB?cyFC|fR zsX;t&vj*m1G6cnilwtT1!PjjP41Kp%yFg^5s7?%B8L33BUMUJ^hZil9gfn)DTLtb& z?|d%o+)VBy_qNlSt-V|_yX9%Mke>Am#nL>^7^d#Yx78k`&nTScev&nYwR>!uHM*nN zUS!29>5qFkyc7L zDT~)?f^ha(Mj zoTfJ%rq3~Yv!@uOi=mlgJkG^WF}gc@g0Uk^enT)DpE<(JcXFp;5zC0fk9l%9jsV5# zfX2Ep!ot+QJy>M@SZ2LgVSQAJ0lXx=1p+fdL%BfKJ_2gs6_&`y3dxrVu$RO-omOe} tb_voWdT8GR-(OPk>4@lf4W=XBMuzKj<-=Pf8|x@GXbq7`ghnuhp?|@9Wh(#x literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$Normalizer2WithImpl.class b/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes$Normalizer2WithImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..a736a551bb114e6cbc98a7961102a5b19dc63f83 GIT binary patch literal 2933 zcmbtW-*XdH7(KU1n;+dmDWyOWEKsq@1|m^F2p}a;iKbNu7F&O@O>Wbr+fCSP90tdq zZ@xI=sEoep3%>B6Gg?NO(RcqS$8$H^?WUof&N$O-c60YT-}%mWzI*%6zkmJ(pnzHu zJ&42*)zFJRfx~yI%URQQrDGdb)~vL$uDs`FXX?(1VVU=(lN0DWZ`!7NQ6MsrnoS^% zL<~s{{m=x?bj6!14a zJ~XnHVb`)n%aS$2nsjQd6=}Oy?^R^OHS2Z~1BfKC3qvvN)-a4c0(;lP%C2MDwaYEj zs!B&7(UfjU+BJ8Hd?t#i*%i?F6Sy?7Jt<1-$diqRw5!H~CG#YoWNVISIEryrX0LTn z;0A#M;lgC{+e+9~X*pT|^SI?Sb` z8zl2|lJlw1N@s{_^r*^wLPHiW2n+?8LpjUgoE`Pg{|^Cjcrk{TG@Qa|f${BFMqsce z-7A!2rBQF1%B})?XuGcZ@=4_IvWBxb$5t{(P0&f^Q6{BnayYNyf?Dk5VxgcUctyh{ zObYC3HVpfE%d9LHmSkmlPBsM&Y^p%2D3Idn#$6zo;?NAHW=WvHi5A#dGHp52T3L|J zO=UkSU#eFOYu0c~_3Zx`b(c)0Kf49~mb*k=pvN`^N}KZUlFpy)e7C4;E8NGLPK7QF z#df%YRdUyI1@?#D=ro?dK-o1a%hN`~FLi1=6hreG<`?>z8%HQ<$3oviOYJkQyNLo=Jf+tn@Is(=`fEZ193MNXNX^HgkLqZ4Wu5s1&QgV*X!HwGp?y1BoD zK+-7MwsbsBYG`%`oSfYHu{F4H-;W;V@b&O;Wo_zAQxC52x&skjO+;}A2`u9(pGMkmGwxMBF%H*=%EGy`7k$hx5c4ASjQ$Y)PcSg| z7(4&YL{>4F)}LTxF8v!~8T}9J6L^e6t2mtbg-{VM=?KXI4PNi^v}|GsE>dWD$;aBT zL2@0h;dLejbd)enYBL^=81VSK;q&>9U{Nk)I{0)GnMv!%Nrs>2LWB;n8sI)LJ|dxy zu@|3U44>i{KI4J%xkoJB#t(>P0%92wdy~Y*sM2-ZU;%3sqfvDj5?T{Fd0kP-f$q=)yjPsL;px-h@mHYU$cpXb*!geR$< z3AH$#Ik={(uCG#Wuf?~$9v|1&dpwFha{Y#qeoILoU=-i;w0=Mxe%M6LwfZuCeQYLf z;q6X2dB_r$|03bEPxAt$Q0`7B#~oP3$&Gsc?(P{fZ33?QN*s^b_21x7Z_ zCuYtu-HlvrZBtslz~H>?+Wu{UNM`b095KW-By$J7o(|Bh6yJ`5m*(<*>70+S&F*yVpt z$0sZ#XV@SL!3;8VaTM+s-)ZyxE3xS zO9u(ja8uxVC^gS(_FTa{B5F*`=_p{HBgLrI?mjeX%hiQS`N85c^Kv5$eI~faaDjKT z$blkoykfi3*lMiF){432aA&OIS*CN(Y}snv*^K&+Y)+p6*Jc;C4>~eg_f6|@)oga; zhFK+}RNO0+z?Dq6{E|tay40l`o41_KyiC-+triP!2Ml{EIj!!2z>p!^epRYK+8QbX zH^U`-f8O1<{YPqO3g~6mm93&VrLMya_SBF+dcf>e1lesG76^a$*rrt41LnqZ}t61is{IBUl6J><&bBY8zVi z4U(%Oe#&TGG zDk0t06Xg6I_XbeL_rwvhpXJCL=X;sL67r~WcaFPBnl@OG6tPAeC*EaEvcw;Vv&3a$ No>=Gk5^*IO{|^D`HlzRm literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes.java b/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes.java new file mode 100644 index 00000000..7922bb46 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/Norm2AllModes.java @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk.internal.icu.impl; + +import java.io.IOException; + +import jdk.internal.icu.text.Normalizer2; +import jdk.internal.icu.util.VersionInfo; + +public final class Norm2AllModes { + // Public API dispatch via Normalizer2 subclasses -------------------------- *** + + // Normalizer2 implementation for the old UNORM_NONE. + public static final class NoopNormalizer2 extends Normalizer2 { + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if(dest!=src) { + dest.setLength(0); + return dest.append(src); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if(dest!=src) { + try { + return dest.append(src); + } catch(IOException e) { + throw new InternalError(e.toString(), e); + } + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + if(first!=second) { + return first.append(second); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + if(first!=second) { + return first.append(second); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public String getDecomposition(int c) { + return null; + } + + // No need to override the default getRawDecomposition(). + @Override + public boolean isNormalized(CharSequence s) { return true; } + + @Override + public int spanQuickCheckYes(CharSequence s) { return s.length(); } + + @Override + public boolean hasBoundaryBefore(int c) { return true; } + } + + // Intermediate class: + // Has NormalizerImpl and does boilerplate argument checking and setup. + public abstract static class Normalizer2WithImpl extends Normalizer2 { + public Normalizer2WithImpl(NormalizerImpl ni) { + impl=ni; + } + + // normalize + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if(dest==src) { + throw new IllegalArgumentException(); + } + dest.setLength(0); + normalize(src, new NormalizerImpl.ReorderingBuffer(impl, dest, src.length())); + return dest; + } + + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if(dest==src) { + throw new IllegalArgumentException(); + } + NormalizerImpl.ReorderingBuffer buffer= + new NormalizerImpl.ReorderingBuffer(impl, dest, src.length()); + normalize(src, buffer); + buffer.flush(); + return dest; + } + + protected abstract void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer); + + // normalize and append + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, true); + } + + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, false); + } + + public StringBuilder normalizeSecondAndAppend( + StringBuilder first, CharSequence second, boolean doNormalize) { + if(first==second) { + throw new IllegalArgumentException(); + } + normalizeAndAppend( + second, doNormalize, + new NormalizerImpl.ReorderingBuffer(impl, first, first.length()+second.length())); + return first; + } + + protected abstract void normalizeAndAppend( + CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer); + + @Override + public String getDecomposition(int c) { + return impl.getDecomposition(c); + } + + @Override + public int getCombiningClass(int c) { + return impl.getCC(impl.getNorm16(c)); + } + + // quick checks + @Override + public boolean isNormalized(CharSequence s) { + return s.length()==spanQuickCheckYes(s); + } + + public final NormalizerImpl impl; + } + + public static final class DecomposeNormalizer2 extends Normalizer2WithImpl { + public DecomposeNormalizer2(NormalizerImpl ni) { + super(ni); + } + + @Override + protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { + impl.decompose(src, 0, src.length(), buffer); + } + + @Override + protected void normalizeAndAppend( + CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) { + impl.decomposeAndAppend(src, doNormalize, buffer); + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return impl.decompose(s, 0, s.length(), null); + } + + @Override + public boolean hasBoundaryBefore(int c) { return impl.hasDecompBoundaryBefore(c); } + } + + public static final class ComposeNormalizer2 extends Normalizer2WithImpl { + public ComposeNormalizer2(NormalizerImpl ni, boolean fcc) { + super(ni); + onlyContiguous=fcc; + } + + @Override + protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { + impl.compose(src, 0, src.length(), onlyContiguous, true, buffer); + } + + @Override + protected void normalizeAndAppend( + CharSequence src, boolean doNormalize, NormalizerImpl.ReorderingBuffer buffer) { + impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer); + } + + @Override + public boolean isNormalized(CharSequence s) { + // 5: small destCapacity for substring normalization + return impl.compose(s, 0, s.length(), + onlyContiguous, false, + new NormalizerImpl.ReorderingBuffer(impl, new StringBuilder(), 5)); + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true)>>>1; + } + + @Override + public boolean hasBoundaryBefore(int c) { return impl.hasCompBoundaryBefore(c); } + + private final boolean onlyContiguous; + } + + // instance cache ---------------------------------------------------------- *** + + private Norm2AllModes(NormalizerImpl ni) { + impl=ni; + comp=new ComposeNormalizer2(ni, false); + decomp=new DecomposeNormalizer2(ni); + } + + public final NormalizerImpl impl; + public final ComposeNormalizer2 comp; + public final DecomposeNormalizer2 decomp; + + private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) { + if(singleton.exception!=null) { + throw singleton.exception; + } + return singleton.allModes; + } + + public static Norm2AllModes getNFCInstance() { + return getInstanceFromSingleton(NFCSingleton.INSTANCE); + } + + public static Norm2AllModes getNFKCInstance() { + return getInstanceFromSingleton(NFKCSingleton.INSTANCE); + } + + public static final NoopNormalizer2 NOOP_NORMALIZER2=new NoopNormalizer2(); + + private static final class Norm2AllModesSingleton { + private Norm2AllModesSingleton(String name) { + try { + @SuppressWarnings("deprecation") + String DATA_FILE_NAME = "/jdk/internal/icu/impl/data/icudt" + + VersionInfo.ICU_DATA_VERSION_PATH + "/" + name + ".nrm"; + NormalizerImpl impl=new NormalizerImpl().load(DATA_FILE_NAME); + allModes=new Norm2AllModes(impl); + } catch (RuntimeException e) { + exception=e; + } + } + + private Norm2AllModes allModes; + private RuntimeException exception; + } + + private static final class NFCSingleton { + private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfc"); + } + + private static final class NFKCSingleton { + private static final Norm2AllModesSingleton INSTANCE=new Norm2AllModesSingleton("nfkc"); + } +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$Hangul.class b/tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$Hangul.class new file mode 100644 index 0000000000000000000000000000000000000000..aa47418a2a0b09a47cae01383432b8b6b4d2d175 GIT binary patch literal 1555 zcmb7EOLN;)7(Lf7)sB-ocHB0`q&x!HaT7ync)1O69n%PG878hXunCH+Ql*OIk!4`` z87#YOGm}j=tUAC9?D+%y1%3nroGaV0GIRk8U47^1yWiv7PxrUKe)v&*SHP<`VZR0j$ro1dzk z!z0u11roO{$MUxXqNQ>#3Y>wnK!txFEMDc3tV=kimoJL8JvCefyTm6I9QQrl`*Al7jEl=O1T za!hS>d}w;zvB=q$Yv^`Q_biDgWXykP4F%R)|6>?x0++1ecrci+q?W&+Xa+^w^L67< zTOUk0&lYMktwhI>44hb*p8QbT7kn}k}K(npM&3`ej0*yrMLGkM~0^x%Q%30!%8 z5P{U5JMs+kBTEif?&3sm$WdVjnmP1$-J!3bF0lGv+Nad2iFVbEK;p?e+Wum=b8w}b!^a1j~(dxCQ*{D-XtS8-(!Pvb2ghS zJjHw=n|cBzc8XZ^jBFIMNL!&uS-j1HfLnaxh-9`o7}z`yx<3iJQphIzwI~DU3yYPL zCs-(Cii5}hN|2&IP-m#Sp(HC8lN5s_@8I1@<$q8H`QK?l5*hdo7rRzjTtp$0x4-=U zN6baAPplIUrnvYR@%S0p)8dp$oV9;O?(-YZkpDF(`7|5 mgvg)R6n|rZSGyvQO$qYf;kO93@L}-YW*#}F^4Paoc-5Y|xz0(nxBfRck3?gluvPLG6j>nN6j*_UI+M!JJXJwmAYt8H+j@8J? zZlVOrgcq~ZnvK)CHqw5o9gJO18K-0E6d`D&7Yqw6ZB%?(VbOA)HAG?qz6TAlN$ zF>pPd5q4X%i~OgzJ;JKa-bp7r%4Rw>w`~&&+voM2GlICh@e#c9I-zpxWIQ;OqiOZ> zaXPlKdav{T7Vj2&nU9n(*H)SPkY-NcF`;&!HVI+V7-buY%reD)7v7!eCShx~&fl4G z&c9Q|D+pdVp~Tzw_~WHBn`ag=5@X@nH_+FKJLEHWgA!Eu9^M4t0T!6?W5FXn^W@e< z45&Q!cf}Wo;0l3%%?_WF{)m`~$O?yY;8Y~PRk6r2OKdH`n}5p>4a-bCtYCG5YglKj QvPEDGPneakfv3gNZ^0j@MgRZ+ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$NextCCArgs.class b/tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$NextCCArgs.class new file mode 100644 index 0000000000000000000000000000000000000000..8fc3c98cb80f40a442e48482e6b9891ac50c2d02 GIT binary patch literal 525 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 GYX1+aAupi- literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$UTF16Plus.class b/tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl$UTF16Plus.class new file mode 100644 index 0000000000000000000000000000000000000000..91c98516e7f9d53a5ff097585ede196ec5e1574e GIT binary patch literal 1068 zcmb7DO-~a+7=C7VwuN>n1uQ}fqKHyzV8w&P)S#w;*rcLKk%Jn|bUVVpc8j}P4<0!2 zE4)BF=%p7=Mi2Y|e}TWiUt!dDO64PwL^qk4=ly!#cb?t-`t!>HfD*1HV8D!n+prL0 zNN)idbJe<&2;ch(;+uc@FaFnbo87#WE@E8{ImA@-eESJxY=w3!R&oFXU4hb4Y zB8Vs_=Bb9#zzA>racj_V6G&8>t-zJbN-H&VTHQH497E5F45RzaFp4A3F!e8jG1z6_ zmqE!BVJJ!G-lG?Vd8Ft|(hmnoff(&+vK%@YomSx!*hc~e258q|usaweY#%0I2yS zjtkV9nqz`4t)(jBA|d@Iinv5k`e6x8l8<-LWkOb09J9~X2~!j>a0OR8=QL*MOb}TL I(=42h4FpL511bs01A-xmSpZQH6_>j2 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl.java b/tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl.java new file mode 100644 index 00000000..291653f9 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/NormalizerImpl.java @@ -0,0 +1,2193 @@ +/* + * Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2015, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ +package jdk.internal.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import jdk.internal.icu.lang.UCharacter; +import jdk.internal.icu.text.Normalizer2; +import jdk.internal.icu.text.UTF16; +import jdk.internal.icu.util.CodePointTrie; +import jdk.internal.icu.util.VersionInfo; + +// Original filename in ICU4J: Normalizer2Impl.java +public final class NormalizerImpl { + public static final class Hangul { + /* Korean Hangul and Jamo constants */ + public static final int JAMO_L_BASE=0x1100; /* "lead" jamo */ + public static final int JAMO_V_BASE=0x1161; /* "vowel" jamo */ + public static final int JAMO_T_BASE=0x11a7; /* "trail" jamo */ + + public static final int HANGUL_BASE=0xac00; + public static final int HANGUL_END=0xd7a3; + + public static final int JAMO_L_COUNT=19; + public static final int JAMO_V_COUNT=21; + public static final int JAMO_T_COUNT=28; + + public static final int HANGUL_COUNT=JAMO_L_COUNT*JAMO_V_COUNT*JAMO_T_COUNT; + public static final int HANGUL_LIMIT=HANGUL_BASE+HANGUL_COUNT; + + public static boolean isHangul(int c) { + return HANGUL_BASE<=c && c + * If dest is a StringBuilder, then the buffer writes directly to it. + * Otherwise, the buffer maintains a StringBuilder for intermediate text segments + * until no further changes are necessary and whole segments are appended. + * append() methods that take combining-class values always write to the StringBuilder. + * Other append() methods flush and append to the Appendable. + */ + public static final class ReorderingBuffer implements Appendable { + public ReorderingBuffer(NormalizerImpl ni, Appendable dest, int destCapacity) { + impl=ni; + app=dest; + if (app instanceof StringBuilder) { + appIsStringBuilder=true; + str=(StringBuilder)dest; + // In Java, the constructor subsumes public void init(int destCapacity) + str.ensureCapacity(destCapacity); + reorderStart=0; + if(str.length()==0) { + lastCC=0; + } else { + setIterator(); + lastCC=previousCC(); + // Set reorderStart after the last code point with cc<=1 if there is one. + if(lastCC>1) { + while(previousCC()>1) {} + } + reorderStart=codePointLimit; + } + } else { + appIsStringBuilder=false; + str=new StringBuilder(); + reorderStart=0; + lastCC=0; + } + } + + public boolean isEmpty() { return str.length()==0; } + public int length() { return str.length(); } + public int getLastCC() { return lastCC; } + + public StringBuilder getStringBuilder() { return str; } + + public boolean equals(CharSequence s, int start, int limit) { + return UTF16Plus.equal(str, 0, str.length(), s, start, limit); + } + + public void append(int c, int cc) { + if(lastCC<=cc || cc==0) { + str.appendCodePoint(c); + lastCC=cc; + if(cc<=1) { + reorderStart=str.length(); + } + } else { + insert(c, cc); + } + } + public void append(CharSequence s, int start, int limit, boolean isNFD, + int leadCC, int trailCC) { + if(start==limit) { + return; + } + if(lastCC<=leadCC || leadCC==0) { + if(trailCC<=1) { + reorderStart=str.length()+(limit-start); + } else if(leadCC<=1) { + reorderStart=str.length()+1; // Ok if not a code point boundary. + } + str.append(s, start, limit); + lastCC=trailCC; + } else { + int c=Character.codePointAt(s, start); + start+=Character.charCount(c); + insert(c, leadCC); // insert first code point + while(startcc;) {} + // insert c at codePointLimit, after the character with prevCC<=cc + if(c<=0xffff) { + str.insert(codePointLimit, (char)c); + if(cc<=1) { + reorderStart=codePointLimit+1; + } + } else { + str.insert(codePointLimit, Character.toChars(c)); + if(cc<=1) { + reorderStart=codePointLimit+2; + } + } + } + + private final NormalizerImpl impl; + private final Appendable app; + private final StringBuilder str; + private final boolean appIsStringBuilder; + private int reorderStart; + private int lastCC; + + // private backward iterator + private void setIterator() { codePointStart=str.length(); } + private void skipPrevious() { // Requires 0=codePointStart) { + return 0; + } + int c=str.codePointBefore(codePointStart); + codePointStart-=Character.charCount(c); + return impl.getCCFromYesOrMaybeCP(c); + } + private int codePointStart, codePointLimit; + } + + // TODO: Propose as public API on the UTF16 class. + // TODO: Propose widening UTF16 methods that take char to take int. + // TODO: Propose widening UTF16 methods that take String to take CharSequence. + public static final class UTF16Plus { + /** + * Is this code point a lead surrogate (U+d800..U+dbff)? + * @param c code unit or code point + * @return true or false + */ + public static boolean isLeadSurrogate(int c) { return (c & 0xfffffc00) == 0xd800; } + /** + * Assuming c is a surrogate code point (UTF16.isSurrogate(c)), + * is it a lead surrogate? + * @param c code unit or code point + * @return true or false + */ + public static boolean isSurrogateLead(int c) { return (c&0x400)==0; } + + /** + * Compares two CharSequence subsequences for binary equality. + * @param s1 first sequence + * @param start1 start offset in first sequence + * @param limit1 limit offset in first sequence + * @param s2 second sequence + * @param start2 start offset in second sequence + * @param limit2 limit offset in second sequence + * @return true if s1.subSequence(start1, limit1) contains the same text + * as s2.subSequence(start2, limit2) + */ + public static boolean equal(CharSequence s1, int start1, int limit1, + CharSequence s2, int start2, int limit2) { + if((limit1-start1)!=(limit2-start2)) { + return false; + } + if(s1==s2 && start1==start2) { + return true; + } + while(start1>DELTA_SHIFT)-MAX_DELTA-1; + + // Read the normTrie. + int offset=inIndexes[IX_NORM_TRIE_OFFSET]; + int nextOffset=inIndexes[IX_EXTRA_DATA_OFFSET]; + int triePosition = bytes.position(); + normTrie = CodePointTrie.Fast16.fromBinary(bytes); + int trieLength = bytes.position() - triePosition; + if(trieLength>(nextOffset-offset)) { + throw new InternalError("Normalizer2 data: not enough bytes for normTrie"); + } + ICUBinary.skipBytes(bytes, (nextOffset-offset)-trieLength); // skip padding after trie bytes + + // Read the composition and mapping data. + offset=nextOffset; + nextOffset=inIndexes[IX_SMALL_FCD_OFFSET]; + int numChars=(nextOffset-offset)/2; + if(numChars!=0) { + maybeYesCompositions=ICUBinary.getString(bytes, numChars, 0); + extraData=maybeYesCompositions.substring((MIN_NORMAL_MAYBE_YES-minMaybeYes)>>OFFSET_SHIFT); + } + + // smallFCD: new in formatVersion 2 + offset=nextOffset; + smallFCD=new byte[0x100]; + bytes.get(smallFCD); + + return this; + } catch(IOException e) { + throw new InternalError(e); + } + } + public NormalizerImpl load(String name) { + return load(ICUBinary.getRequiredData(name)); + } + + // The trie stores values for lead surrogate code *units*. + // Surrogate code *points* are inert. + public int getNorm16(int c) { + return UTF16Plus.isLeadSurrogate(c) ? INERT : normTrie.get(c); + } + public int getRawNorm16(int c) { return normTrie.get(c); } + public boolean isAlgorithmicNoNo(int norm16) { return limitNoNo<=norm16 && norm16=MIN_NORMAL_MAYBE_YES) { + return getCCFromNormalYesOrMaybe(norm16); + } + if(norm16> OFFSET_SHIFT) & 0xff; + } + public static int getCCFromYesOrMaybe(int norm16) { + return norm16>=MIN_NORMAL_MAYBE_YES ? getCCFromNormalYesOrMaybe(norm16) : 0; + } + public int getCCFromYesOrMaybeCP(int c) { + if (c < minCompNoMaybeCP) { return 0; } + return getCCFromYesOrMaybe(getNorm16(c)); + } + + /** + * Returns the FCD data for code point c. + * @param c A Unicode code point. + * @return The lccc(c) in bits 15..8 and tccc(c) in bits 7..0. + */ + public int getFCD16(int c) { + if(c>8]; + if(bits==0) { return false; } + return ((bits>>((lead>>5)&7))&1)!=0; + } + + /** Gets the FCD value from the regular normalization data. */ + public int getFCD16FromNormData(int c) { + int norm16=getNorm16(c); + if (norm16 >= limitNoNo) { + if(norm16>=MIN_NORMAL_MAYBE_YES) { + // combining mark + norm16=getCCFromNormalYesOrMaybe(norm16); + return norm16|(norm16<<8); + } else if(norm16>=minMaybeYes) { + return 0; + } else { // isDecompNoAlgorithmic(norm16) + int deltaTrailCC = norm16 & DELTA_TCCC_MASK; + if (deltaTrailCC <= DELTA_TCCC_1) { + return deltaTrailCC >> OFFSET_SHIFT; + } + // Maps to an isCompYesAndZeroCC. + c=mapAlgorithmic(c, norm16); + norm16=getRawNorm16(c); + } + } + if(norm16<=minYesNo || isHangulLVT(norm16)) { + // no decomposition or Hangul syllable, all zeros + return 0; + } + // c decomposes, get everything from the variable-length extra data + int mapping=norm16>>OFFSET_SHIFT; + int firstUnit=extraData.charAt(mapping); + int fcd16=firstUnit>>8; // tccc + if((firstUnit&MAPPING_HAS_CCC_LCCC_WORD)!=0) { + fcd16|=extraData.charAt(mapping-1)&0xff00; // lccc + } + return fcd16; + } + + /** + * Gets the decomposition for one code point. + * @param c code point + * @return c's decomposition, if it has one; returns null if it does not have a decomposition + */ + public String getDecomposition(int c) { + int norm16; + if(c>OFFSET_SHIFT; + int length=extraData.charAt(mapping++)&MAPPING_LENGTH_MASK; + return extraData.substring(mapping, mapping+length); + } + + // Fixed norm16 values. + public static final int MIN_YES_YES_WITH_CC=0xfe02; + public static final int JAMO_VT=0xfe00; + public static final int MIN_NORMAL_MAYBE_YES=0xfc00; + public static final int JAMO_L=2; // offset=1 hasCompBoundaryAfter=false + public static final int INERT=1; // offset=0 hasCompBoundaryAfter=true + + // norm16 bit 0 is comp-boundary-after. + public static final int HAS_COMP_BOUNDARY_AFTER=1; + public static final int OFFSET_SHIFT=1; + + // For algorithmic one-way mappings, norm16 bits 2..1 indicate the + // tccc (0, 1, >1) for quick FCC boundary-after tests. + public static final int DELTA_TCCC_0=0; + public static final int DELTA_TCCC_1=2; + public static final int DELTA_TCCC_GT_1=4; + public static final int DELTA_TCCC_MASK=6; + public static final int DELTA_SHIFT=3; + + public static final int MAX_DELTA=0x40; + + // Byte offsets from the start of the data, after the generic header. + public static final int IX_NORM_TRIE_OFFSET=0; + public static final int IX_EXTRA_DATA_OFFSET=1; + public static final int IX_SMALL_FCD_OFFSET=2; + public static final int IX_RESERVED3_OFFSET=3; + public static final int IX_TOTAL_SIZE=7; + public static final int MIN_CCC_LCCC_CP=0x300; + // Code point thresholds for quick check codes. + public static final int IX_MIN_DECOMP_NO_CP=8; + public static final int IX_MIN_COMP_NO_MAYBE_CP=9; + + // Norm16 value thresholds for quick check combinations and types of extra data. + + /** Mappings & compositions in [minYesNo..minYesNoMappingsOnly[. */ + public static final int IX_MIN_YES_NO=10; + /** Mappings are comp-normalized. */ + public static final int IX_MIN_NO_NO=11; + public static final int IX_LIMIT_NO_NO=12; + public static final int IX_MIN_MAYBE_YES=13; + + /** Mappings only in [minYesNoMappingsOnly..minNoNo[. */ + public static final int IX_MIN_YES_NO_MAPPINGS_ONLY=14; + /** Mappings are not comp-normalized but have a comp boundary before. */ + public static final int IX_MIN_NO_NO_COMP_BOUNDARY_BEFORE=15; + /** Mappings do not have a comp boundary before. */ + public static final int IX_MIN_NO_NO_COMP_NO_MAYBE_CC=16; + /** Mappings to the empty string. */ + public static final int IX_MIN_NO_NO_EMPTY=17; + + public static final int IX_MIN_LCCC_CP=18; + public static final int IX_COUNT=20; + + public static final int MAPPING_HAS_CCC_LCCC_WORD=0x80; + public static final int MAPPING_HAS_RAW_MAPPING=0x40; + // unused bit 0x20; + public static final int MAPPING_LENGTH_MASK=0x1f; + + public static final int COMP_1_LAST_TUPLE=0x8000; + public static final int COMP_1_TRIPLE=1; + public static final int COMP_1_TRAIL_LIMIT=0x3400; + public static final int COMP_1_TRAIL_MASK=0x7ffe; + public static final int COMP_1_TRAIL_SHIFT=9; // 10-1 for the "triple" bit + public static final int COMP_2_TRAIL_SHIFT=6; + public static final int COMP_2_TRAIL_MASK=0xffc0; + + // higher-level functionality ------------------------------------------ *** + + /** + * Decomposes s[src, limit[ and writes the result to dest. + * limit can be NULL if src is NUL-terminated. + * destLengthEstimate is the initial dest buffer capacity and can be -1. + */ + public void decompose(CharSequence s, int src, int limit, StringBuilder dest, + int destLengthEstimate) { + if(destLengthEstimate<0) { + destLengthEstimate=limit-src; + } + dest.setLength(0); + ReorderingBuffer buffer=new ReorderingBuffer(this, dest, destLengthEstimate); + decompose(s, src, limit, buffer); + } + + // Dual functionality: + // buffer!=NULL: normalize + // buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes + public int decompose(CharSequence s, int src, int limit, + ReorderingBuffer buffer) { + int minNoCP=minDecompNoCP; + + int prevSrc; + int c=0; + int norm16=0; + + // only for quick check + int prevBoundary=src; + int prevCC=0; + + for(;;) { + // count code units below the minimum or with irrelevant data for the quick check + for(prevSrc=src; src!=limit;) { + if( (c=s.charAt(src))=limit) { + break; + } + c=Character.codePointAt(s, src); + cc=getCC(getNorm16(c)); + }; + buffer.append(s, 0, src, false, firstCC, prevCC); + buffer.append(s, src, limit); + } + + // Very similar to composeQuickCheck(): Make the same changes in both places if relevant. + // doCompose: normalize + // !doCompose: isNormalized (buffer must be empty and initialized) + public boolean compose(CharSequence s, int src, int limit, + boolean onlyContiguous, + boolean doCompose, + ReorderingBuffer buffer) { + int prevBoundary=src; + int minNoMaybeCP=minCompNoMaybeCP; + + for (;;) { + // Fast path: Scan over a sequence of characters below the minimum "no or maybe" code point, + // or with (compYes && ccc==0) properties. + int prevSrc; + int c = 0; + int norm16 = 0; + for (;;) { + if (src == limit) { + if (prevBoundary != limit && doCompose) { + buffer.append(s, prevBoundary, limit); + } + return true; + } + if( (c=s.charAt(src))=minNoNo. + // The current character is either a "noNo" (has a mapping) + // or a "maybeYes" (combines backward) + // or a "yesYes" with ccc!=0. + // It is not a Hangul syllable or Jamo L because those have "yes" properties. + + // Medium-fast path: Handle cases that do not require full decomposition and recomposition. + if (!isMaybeOrNonZeroCC(norm16)) { // minNoNo <= norm16 < minMaybeYes + if (!doCompose) { + return false; + } + // Fast path for mapping a character that is immediately surrounded by boundaries. + // In this case, we need not decompose around the current character. + if (isDecompNoAlgorithmic(norm16)) { + // Maps to a single isCompYesAndZeroCC character + // which also implies hasCompBoundaryBefore. + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous) || + hasCompBoundaryBefore(s, src, limit)) { + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + buffer.append(mapAlgorithmic(c, norm16), 0); + prevBoundary = src; + continue; + } + } else if (norm16 < minNoNoCompBoundaryBefore) { + // The mapping is comp-normalized which also implies hasCompBoundaryBefore. + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous) || + hasCompBoundaryBefore(s, src, limit)) { + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + int mapping = norm16 >> OFFSET_SHIFT; + int length = extraData.charAt(mapping++) & MAPPING_LENGTH_MASK; + buffer.append(extraData, mapping, mapping + length); + prevBoundary = src; + continue; + } + } else if (norm16 >= minNoNoEmpty) { + // The current character maps to nothing. + // Simply omit it from the output if there is a boundary before _or_ after it. + // The character itself implies no boundaries. + if (hasCompBoundaryBefore(s, src, limit) || + hasCompBoundaryAfter(s, prevBoundary, prevSrc, onlyContiguous)) { + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + prevBoundary = src; + continue; + } + } + // Other "noNo" type, or need to examine more text around this character: + // Fall through to the slow path. + } else if (isJamoVT(norm16) && prevBoundary != prevSrc) { + char prev=s.charAt(prevSrc-1); + if(c= 0) { + int syllable = Hangul.HANGUL_BASE + + (l*Hangul.JAMO_V_COUNT + (c-Hangul.JAMO_V_BASE)) * + Hangul.JAMO_T_COUNT + t; + --prevSrc; // Replace the Jamo L as well. + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + buffer.append((char)syllable); + prevBoundary = src; + continue; + } + // If we see L+V+x where x!=T then we drop to the slow path, + // decompose and recompose. + // This is to deal with NFKC finding normal L and V but a + // compatibility variant of a T. + // We need to either fully compose that combination here + // (which would complicate the code and may not work with strange custom data) + // or use the slow path. + } + } else if (Hangul.isHangulLV(prev)) { + // The current character is a Jamo Trailing consonant, + // compose with previous Hangul LV that does not contain a Jamo T. + if (!doCompose) { + return false; + } + int syllable = prev + c - Hangul.JAMO_T_BASE; + --prevSrc; // Replace the Hangul LV as well. + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + buffer.append((char)syllable); + prevBoundary = src; + continue; + } + // No matching context, or may need to decompose surrounding text first: + // Fall through to the slow path. + } else if (norm16 > JAMO_VT) { // norm16 >= MIN_YES_YES_WITH_CC + // One or more combining marks that do not combine-back: + // Check for canonical order, copy unchanged if ok and + // if followed by a character with a boundary-before. + int cc = getCCFromNormalYesOrMaybe(norm16); // cc!=0 + if (onlyContiguous /* FCC */ && getPreviousTrailCC(s, prevBoundary, prevSrc) > cc) { + // Fails FCD test, need to decompose and contiguously recompose. + if (!doCompose) { + return false; + } + } else { + // If !onlyContiguous (not FCC), then we ignore the tccc of + // the previous character which passed the quick check "yes && ccc==0" test. + int n16; + for (;;) { + if (src == limit) { + if (doCompose) { + buffer.append(s, prevBoundary, limit); + } + return true; + } + int prevCC = cc; + c = Character.codePointAt(s, src); + n16 = normTrie.get(c); + if (n16 >= MIN_YES_YES_WITH_CC) { + cc = getCCFromNormalYesOrMaybe(n16); + if (prevCC > cc) { + if (!doCompose) { + return false; + } + break; + } + } else { + break; + } + src += Character.charCount(c); + } + // p is after the last in-order combining mark. + // If there is a boundary here, then we continue with no change. + if (norm16HasCompBoundaryBefore(n16)) { + if (isCompYesAndZeroCC(n16)) { + src += Character.charCount(c); + } + continue; + } + // Use the slow path. There is no boundary in [prevSrc, src[. + } + } + + // Slow path: Find the nearest boundaries around the current character, + // decompose and recompose. + if (prevBoundary != prevSrc && !norm16HasCompBoundaryBefore(norm16)) { + c = Character.codePointBefore(s, prevSrc); + norm16 = normTrie.get(c); + if (!norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + prevSrc -= Character.charCount(c); + } + } + if (doCompose && prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + int recomposeStartIndex=buffer.length(); + // We know there is not a boundary here. + decomposeShort(s, prevSrc, src, false /* !stopAtCompBoundary */, onlyContiguous, + buffer); + // Decompose until the next boundary. + src = decomposeShort(s, src, limit, true /* stopAtCompBoundary */, onlyContiguous, + buffer); + recompose(buffer, recomposeStartIndex, onlyContiguous); + if(!doCompose) { + if(!buffer.equals(s, prevSrc, src)) { + return false; + } + buffer.remove(); + } + prevBoundary=src; + } + } + + /** + * Very similar to compose(): Make the same changes in both places if relevant. + * doSpan: spanQuickCheckYes (ignore bit 0 of the return value) + * !doSpan: quickCheck + * @return bits 31..1: spanQuickCheckYes (==s.length() if "yes") and + * bit 0: set if "maybe"; otherwise, if the span length<s.length() + * then the quick check result is "no" + */ + public int composeQuickCheck(CharSequence s, int src, int limit, + boolean onlyContiguous, boolean doSpan) { + int qcResult=0; + int prevBoundary=src; + int minNoMaybeCP=minCompNoMaybeCP; + + for(;;) { + // Fast path: Scan over a sequence of characters below the minimum "no or maybe" code point, + // or with (compYes && ccc==0) properties. + int prevSrc; + int c = 0; + int norm16 = 0; + for (;;) { + if(src==limit) { + return (src<<1)|qcResult; // "yes" or "maybe" + } + if( (c=s.charAt(src))=minNoNo. + // The current character is either a "noNo" (has a mapping) + // or a "maybeYes" (combines backward) + // or a "yesYes" with ccc!=0. + // It is not a Hangul syllable or Jamo L because those have "yes" properties. + + int prevNorm16 = INERT; + if (prevBoundary != prevSrc) { + prevBoundary = prevSrc; + if (!norm16HasCompBoundaryBefore(norm16)) { + c = Character.codePointBefore(s, prevSrc); + int n16 = getNorm16(c); + if (!norm16HasCompBoundaryAfter(n16, onlyContiguous)) { + prevBoundary -= Character.charCount(c); + prevNorm16 = n16; + } + } + } + + if(isMaybeOrNonZeroCC(norm16)) { + int cc=getCCFromYesOrMaybe(norm16); + if (onlyContiguous /* FCC */ && cc != 0 && + getTrailCCFromCompYesAndZeroCC(prevNorm16) > cc) { + // The [prevBoundary..prevSrc[ character + // passed the quick check "yes && ccc==0" test + // but is out of canonical order with the current combining mark. + } else { + // If !onlyContiguous (not FCC), then we ignore the tccc of + // the previous character which passed the quick check "yes && ccc==0" test. + for (;;) { + if (norm16 < MIN_YES_YES_WITH_CC) { + if (!doSpan) { + qcResult = 1; + } else { + return prevBoundary << 1; // spanYes does not care to know it's "maybe" + } + } + if (src == limit) { + return (src<<1) | qcResult; // "yes" or "maybe" + } + int prevCC = cc; + c = Character.codePointAt(s, src); + norm16 = getNorm16(c); + if (isMaybeOrNonZeroCC(norm16)) { + cc = getCCFromYesOrMaybe(norm16); + if (!(prevCC <= cc || cc == 0)) { + break; + } + } else { + break; + } + src += Character.charCount(c); + } + // src is after the last in-order combining mark. + if (isCompYesAndZeroCC(norm16)) { + prevBoundary = src; + src += Character.charCount(c); + continue; + } + } + } + return prevBoundary<<1; // "no" + } + } + public void composeAndAppend(CharSequence s, + boolean doCompose, + boolean onlyContiguous, + ReorderingBuffer buffer) { + int src=0, limit=s.length(); + if(!buffer.isEmpty()) { + int firstStarterInSrc=findNextCompBoundary(s, 0, limit, onlyContiguous); + if(0!=firstStarterInSrc) { + int lastStarterInDest=findPreviousCompBoundary(buffer.getStringBuilder(), + buffer.length(), onlyContiguous); + StringBuilder middle=new StringBuilder((buffer.length()-lastStarterInDest)+ + firstStarterInSrc+16); + middle.append(buffer.getStringBuilder(), lastStarterInDest, buffer.length()); + buffer.removeSuffix(buffer.length()-lastStarterInDest); + middle.append(s, 0, firstStarterInSrc); + compose(middle, 0, middle.length(), onlyContiguous, true, buffer); + src=firstStarterInSrc; + } + } + if(doCompose) { + compose(s, src, limit, onlyContiguous, true, buffer); + } else { + buffer.append(s, src, limit); + } + } + // Dual functionality: + // buffer!=NULL: normalize + // buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes + public int makeFCD(CharSequence s, int src, int limit, ReorderingBuffer buffer) { + // Note: In this function we use buffer->appendZeroCC() because we track + // the lead and trail combining classes here, rather than leaving it to + // the ReorderingBuffer. + // The exception is the call to decomposeShort() which uses the buffer + // in the normal way. + + // Tracks the last FCD-safe boundary, before lccc=0 or after properly-ordered tccc<=1. + // Similar to the prevBoundary in the compose() implementation. + int prevBoundary=src; + int prevSrc; + int c=0; + int prevFCD16=0; + int fcd16=0; + + for(;;) { + // count code units with lccc==0 + for(prevSrc=src; src!=limit;) { + if((c=s.charAt(src))1) { + --prevBoundary; + } + } + } else { + int p=src-1; + if( Character.isLowSurrogate(s.charAt(p)) && prevSrc

1) { + prevBoundary=p; + } + } + if(buffer!=null) { + // The last lccc==0 character is excluded from the + // flush-and-append call in case it needs to be modified. + buffer.flushAndAppendZeroCC(s, prevSrc, prevBoundary); + buffer.append(s, prevBoundary, src); + } + // The start of the current character (c). + prevSrc=src; + } else if(src==limit) { + break; + } + + src+=Character.charCount(c); + // The current character (c) at [prevSrc..src[ has a non-zero lead combining class. + // Check for proper order, and decompose locally if necessary. + if((prevFCD16&0xff)<=(fcd16>>8)) { + // proper order: prev tccc <= current lccc + if((fcd16&0xff)<=1) { + prevBoundary=src; + } + if(buffer!=null) { + buffer.appendZeroCC(c); + } + prevFCD16=fcd16; + continue; + } else if(buffer==null) { + return prevBoundary; // quick check "no" + } else { + /* + * Back out the part of the source that we copied or appended + * already but is now going to be decomposed. + * prevSrc is set to after what was copied/appended. + */ + buffer.removeSuffix(prevSrc-prevBoundary); + /* + * Find the part of the source that needs to be decomposed, + * up to the next safe boundary. + */ + src=findNextFCDBoundary(s, src, limit); + /* + * The source text does not fulfill the conditions for FCD. + * Decompose and reorder a limited piece of the text. + */ + decomposeShort(s, prevBoundary, src, false, false, buffer); + prevBoundary=src; + prevFCD16=0; + } + } + return src; + } + + public boolean hasDecompBoundaryBefore(int c) { + return c < minLcccCP || (c <= 0xffff && !singleLeadMightHaveNonZeroFCD16(c)) || + norm16HasDecompBoundaryBefore(getNorm16(c)); + } + public boolean norm16HasDecompBoundaryBefore(int norm16) { + if (norm16 < minNoNoCompNoMaybeCC) { + return true; + } + if (norm16 >= limitNoNo) { + return norm16 <= MIN_NORMAL_MAYBE_YES || norm16 == JAMO_VT; + } + // c decomposes, get everything from the variable-length extra data + int mapping=norm16>>OFFSET_SHIFT; + int firstUnit=extraData.charAt(mapping); + // true if leadCC==0 (hasFCDBoundaryBefore()) + return (firstUnit&MAPPING_HAS_CCC_LCCC_WORD)==0 || (extraData.charAt(mapping-1)&0xff00)==0; + } + public boolean hasDecompBoundaryAfter(int c) { + if (c < minDecompNoCP) { + return true; + } + if (c <= 0xffff && !singleLeadMightHaveNonZeroFCD16(c)) { + return true; + } + return norm16HasDecompBoundaryAfter(getNorm16(c)); + } + public boolean norm16HasDecompBoundaryAfter(int norm16) { + if(norm16 <= minYesNo || isHangulLVT(norm16)) { + return true; + } + if (norm16 >= limitNoNo) { + if (isMaybeOrNonZeroCC(norm16)) { + return norm16 <= MIN_NORMAL_MAYBE_YES || norm16 == JAMO_VT; + } + // Maps to an isCompYesAndZeroCC. + return (norm16 & DELTA_TCCC_MASK) <= DELTA_TCCC_1; + } + // c decomposes, get everything from the variable-length extra data + int mapping=norm16>>OFFSET_SHIFT; + int firstUnit=extraData.charAt(mapping); + // decomp after-boundary: same as hasFCDBoundaryAfter(), + // fcd16<=1 || trailCC==0 + if(firstUnit>0x1ff) { + return false; // trailCC>1 + } + if(firstUnit<=0xff) { + return true; // trailCC==0 + } + // if(trailCC==1) test leadCC==0, same as checking for before-boundary + // true if leadCC==0 (hasFCDBoundaryBefore()) + return (firstUnit&MAPPING_HAS_CCC_LCCC_WORD)==0 || (extraData.charAt(mapping-1)&0xff00)==0; + } + public boolean isDecompInert(int c) { return isDecompYesAndZeroCC(getNorm16(c)); } + + public boolean hasCompBoundaryBefore(int c) { + return c=minMaybeYes; } + private static boolean isInert(int norm16) { return norm16==INERT; } + private static boolean isJamoVT(int norm16) { return norm16==JAMO_VT; } + private int hangulLVT() { return minYesNoMappingsOnly|HAS_COMP_BOUNDARY_AFTER; } + private boolean isHangulLV(int norm16) { return norm16==minYesNo; } + private boolean isHangulLVT(int norm16) { + return norm16==hangulLVT(); + } + private boolean isCompYesAndZeroCC(int norm16) { return norm16=MIN_YES_YES_WITH_CC || norm16=limitNoNo; } + + // For use with isCompYes(). + // Perhaps the compiler can combine the two tests for MIN_YES_YES_WITH_CC. + // static uint8_t getCCFromYes(uint16_t norm16) { + // return norm16>=MIN_YES_YES_WITH_CC ? getCCFromNormalYesOrMaybe(norm16) : 0; + // } + private int getCCFromNoNo(int norm16) { + int mapping=norm16>>OFFSET_SHIFT; + if((extraData.charAt(mapping)&MAPPING_HAS_CCC_LCCC_WORD)!=0) { + return extraData.charAt(mapping-1)&0xff; + } else { + return 0; + } + } + int getTrailCCFromCompYesAndZeroCC(int norm16) { + if(norm16<=minYesNo) { + return 0; // yesYes and Hangul LV have ccc=tccc=0 + } else { + // For Hangul LVT we harmlessly fetch a firstUnit with tccc=0 here. + return extraData.charAt(norm16>>OFFSET_SHIFT)>>8; // tccc from yesNo + } + } + + // Requires algorithmic-NoNo. + private int mapAlgorithmic(int c, int norm16) { + return c+(norm16>>DELTA_SHIFT)-centerNoNoDelta; + } + + // Requires minYesNo>OFFSET_SHIFT); } + + /** + * @return index into maybeYesCompositions, or -1 + */ + private int getCompositionsListForDecompYes(int norm16) { + if(norm16>OFFSET_SHIFT; + } + } + /** + * @return index into maybeYesCompositions + */ + private int getCompositionsListForComposite(int norm16) { + // A composite has both mapping & compositions list. + int list=((MIN_NORMAL_MAYBE_YES-minMaybeYes)+norm16)>>OFFSET_SHIFT; + int firstUnit=maybeYesCompositions.charAt(list); + return list+ // mapping in maybeYesCompositions + 1+ // +1 to skip the first unit with the mapping length + (firstUnit&MAPPING_LENGTH_MASK); // + mapping length + } + + // Decompose a short piece of text which is likely to contain characters that + // fail the quick check loop and/or where the quick check loop's overhead + // is unlikely to be amortized. + // Called by the compose() and makeFCD() implementations. + // Public in Java for collation implementation code. + private int decomposeShort( + CharSequence s, int src, int limit, + boolean stopAtCompBoundary, boolean onlyContiguous, + ReorderingBuffer buffer) { + while(src= limitNoNo) { + if (isMaybeOrNonZeroCC(norm16)) { + buffer.append(c, getCCFromYesOrMaybe(norm16)); + return; + } + // Maps to an isCompYesAndZeroCC. + c=mapAlgorithmic(c, norm16); + norm16=getRawNorm16(c); + } + if (norm16 < minYesNo) { + // c does not decompose + buffer.append(c, 0); + } else if(isHangulLV(norm16) || isHangulLVT(norm16)) { + // Hangul syllable: decompose algorithmically + Hangul.decompose(c, buffer); + } else { + // c decomposes, get everything from the variable-length extra data + int mapping=norm16>>OFFSET_SHIFT; + int firstUnit=extraData.charAt(mapping); + int length=firstUnit&MAPPING_LENGTH_MASK; + int leadCC, trailCC; + trailCC=firstUnit>>8; + if((firstUnit&MAPPING_HAS_CCC_LCCC_WORD)!=0) { + leadCC=extraData.charAt(mapping-1)>>8; + } else { + leadCC=0; + } + ++mapping; // skip over the firstUnit + buffer.append(extraData, mapping, mapping+length, true, leadCC, trailCC); + } + } + + /** + * Finds the recomposition result for + * a forward-combining "lead" character, + * specified with a pointer to its compositions list, + * and a backward-combining "trail" character. + * + *

If the lead and trail characters combine, then this function returns + * the following "compositeAndFwd" value: + *

+     * Bits 21..1  composite character
+     * Bit      0  set if the composite is a forward-combining starter
+     * 
+ * otherwise it returns -1. + * + *

The compositions list has (trail, compositeAndFwd) pair entries, + * encoded as either pairs or triples of 16-bit units. + * The last entry has the high bit of its first unit set. + * + *

The list is sorted by ascending trail characters (there are no duplicates). + * A linear search is used. + * + *

See normalizer2impl.h for a more detailed description + * of the compositions list format. + */ + private static int combine(String compositions, int list, int trail) { + int key1, firstUnit; + if(trail(firstUnit=compositions.charAt(list))) { + list+=2+(firstUnit&COMP_1_TRIPLE); + } + if(key1==(firstUnit&COMP_1_TRAIL_MASK)) { + if((firstUnit&COMP_1_TRIPLE)!=0) { + return (compositions.charAt(list+1)<<16)|compositions.charAt(list+2); + } else { + return compositions.charAt(list+1); + } + } + } else { + // trail character is 3400..10FFFF + // result entry has 3 units + key1=COMP_1_TRAIL_LIMIT+(((trail>>COMP_1_TRAIL_SHIFT))&~COMP_1_TRIPLE); + int key2=(trail<(firstUnit=compositions.charAt(list))) { + list+=2+(firstUnit&COMP_1_TRIPLE); + } else if(key1==(firstUnit&COMP_1_TRAIL_MASK)) { + if(key2>(secondUnit=compositions.charAt(list+1))) { + if((firstUnit&COMP_1_LAST_TUPLE)!=0) { + break; + } else { + list+=3; + } + } else if(key2==(secondUnit&COMP_2_TRAIL_MASK)) { + return ((secondUnit&~COMP_2_TRAIL_MASK)<<16)|compositions.charAt(list+2); + } else { + break; + } + } else { + break; + } + } + } + return -1; + } + + /* + * Recomposes the buffer text starting at recomposeStartIndex + * (which is in NFD - decomposed and canonically ordered), + * and truncates the buffer contents. + * + * Note that recomposition never lengthens the text: + * Any character consists of either one or two code units; + * a composition may contain at most one more code unit than the original starter, + * while the combining mark that is removed has at least one code unit. + */ + private void recompose(ReorderingBuffer buffer, int recomposeStartIndex, + boolean onlyContiguous) { + StringBuilder sb=buffer.getStringBuilder(); + int p=recomposeStartIndex; + if(p==sb.length()) { + return; + } + + int starter, pRemove; + int compositionsList; + int c, compositeAndFwd; + int norm16; + int cc, prevCC; + boolean starterIsSupplementary; + + // Some of the following variables are not used until we have a forward-combining starter + // and are only initialized now to avoid compiler warnings. + compositionsList=-1; // used as indicator for whether we have a forward-combining starter + starter=-1; + starterIsSupplementary=false; + prevCC=0; + + for(;;) { + c=sb.codePointAt(p); + p+=Character.charCount(c); + norm16=getNorm16(c); + cc=getCCFromYesOrMaybe(norm16); + if( // this character combines backward and + isMaybe(norm16) && + // we have seen a starter that combines forward and + compositionsList>=0 && + // the backward-combining character is not blocked + (prevCC=0) { + // The starter and the combining mark (c) do combine. + int composite=compositeAndFwd>>1; + + // Remove the combining mark. + pRemove=p-Character.charCount(c); // pRemove & p: start & limit of the combining mark + sb.delete(pRemove, p); + p=pRemove; + // Replace the starter with the composite. + if(starterIsSupplementary) { + if(composite>0xffff) { + // both are supplementary + sb.setCharAt(starter, UTF16.getLeadSurrogate(composite)); + sb.setCharAt(starter+1, UTF16.getTrailSurrogate(composite)); + } else { + sb.setCharAt(starter, (char)c); + sb.deleteCharAt(starter+1); + // The composite is shorter than the starter, + // move the intermediate characters forward one. + starterIsSupplementary=false; + --p; + } + } else if(composite>0xffff) { + // The composite is longer than the starter, + // move the intermediate characters back one. + starterIsSupplementary=true; + sb.setCharAt(starter, UTF16.getLeadSurrogate(composite)); + sb.insert(starter+1, UTF16.getTrailSurrogate(composite)); + ++p; + } else { + // both are on the BMP + sb.setCharAt(starter, (char)composite); + } + + // Keep prevCC because we removed the combining mark. + + if(p==sb.length()) { + break; + } + // Is the composite a starter that combines forward? + if((compositeAndFwd&1)!=0) { + compositionsList= + getCompositionsListForComposite(getRawNorm16(composite)); + } else { + compositionsList=-1; + } + + // We combined; continue with looking for compositions. + continue; + } + } + + // no combination this time + prevCC=cc; + if(p==sb.length()) { + break; + } + + // If c did not combine, then check if it is a starter. + if(cc==0) { + // Found a new starter. + if((compositionsList=getCompositionsListForDecompYes(norm16))>=0) { + // It may combine with something, prepare for it. + if(c<=0xffff) { + starterIsSupplementary=false; + starter=p-1; + } else { + starterIsSupplementary=true; + starter=p-2; + } + } + } else if(onlyContiguous) { + // FCC: no discontiguous compositions; any intervening character blocks. + compositionsList=-1; + } + } + buffer.flush(); + } + + /** + * Does c have a composition boundary before it? + * True if its decomposition begins with a character that has + * ccc=0 && NFC_QC=Yes (isCompYesAndZeroCC()). + * As a shortcut, this is true if c itself has ccc=0 && NFC_QC=Yes + * (isCompYesAndZeroCC()) so we need not decompose. + */ + private boolean hasCompBoundaryBefore(int c, int norm16) { + return c> OFFSET_SHIFT) <= 0x1ff); + } + + private int findPreviousCompBoundary(CharSequence s, int p, boolean onlyContiguous) { + while(p>0) { + int c=Character.codePointBefore(s, p); + int norm16 = getNorm16(c); + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + break; + } + p-=Character.charCount(c); + if(hasCompBoundaryBefore(c, norm16)) { + break; + } + } + return p; + } + private int findNextCompBoundary(CharSequence s, int p, int limit, boolean onlyContiguous) { + while(p= 0x0009 && c <= 0x000D) || + (c >= 0x0020 && c <= 0x002F) || + (c >= 0x003A && c <= 0x0040) || + (c >= 0x005B && c <= 0x0060) || + (c >= 0x007B && c <= 0x007E); + } + + public static String canonicalDecomposeWithSingleQuotation(String string) { + Normalizer2 impl = Normalizer2.getNFDInstance(); + char[] src = string.toCharArray(); + int srcIndex = 0; + int srcLimit = src.length; + char[] dest = new char[src.length * 3]; //MAX_BUF_SIZE_DECOMPOSE = 3 + int destIndex = 0; + int destLimit = dest.length; + + int prevSrc; + String norm; + int reorderStartIndex, length; + char c1, c2; + int cp; + int minNoMaybe = 0x00c0; + int cc, prevCC, trailCC; + char[] p; + int pStart; + + // initialize + reorderStartIndex = 0; + prevCC = 0; + norm = null; + cp = 0; + pStart = 0; + + cc = trailCC = -1; // initialize to bogus value + c1 = 0; + for (;;) { + prevSrc=srcIndex; + //quick check (1)less than minNoMaybe (2)no decomp (3)hangual + while (srcIndex != srcLimit && + ((c1 = src[srcIndex]) < minNoMaybe || + (norm = impl.getDecomposition(cp = string.codePointAt(srcIndex))) == null || + (c1 >= '\uac00' && c1 <= '\ud7a3'))) { // Hangul Syllables + prevCC = 0; + srcIndex += (cp < 0x10000) ? 1 : 2; + } + + // copy these code units all at once + if (srcIndex != prevSrc) { + length = srcIndex - prevSrc; + if ((destIndex + length) <= destLimit) { + System.arraycopy(src,prevSrc,dest,destIndex,length); + } + + destIndex += length; + reorderStartIndex = destIndex; + } + + // end of source reached? + if (srcIndex == srcLimit) { + break; + } + + // cp already contains *src and norm32 is set for it, increment src + srcIndex += (cp < 0x10000) ? 1 : 2; + + if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + c2 = 0; + length = 1; + + if (Character.isHighSurrogate(c1) + || Character.isLowSurrogate(c1)) { + norm = null; + } + } else { + length = 2; + c2 = src[srcIndex-1]; + } + + // get the decomposition and the lead and trail cc's + if (norm == null) { + // cp does not decompose + cc = trailCC = UCharacter.getCombiningClass(cp); + p = null; + pStart = -1; + } else { + + pStart = 0; + p = norm.toCharArray(); + length = p.length; + int cpNum = norm.codePointCount(0, length); + cc= UCharacter.getCombiningClass(norm.codePointAt(0)); + trailCC= UCharacter.getCombiningClass(norm.codePointAt(cpNum-1)); + if (length == 1) { + // fastpath a single code unit from decomposition + c1 = p[pStart]; + c2 = 0; + p = null; + pStart = -1; + } + } + + if((destIndex + length * 3) >= destLimit) { // 2 SingleQuotations + // buffer overflow + char[] tmpBuf = new char[destLimit * 2]; + System.arraycopy(dest, 0, tmpBuf, 0, destIndex); + dest = tmpBuf; + destLimit = dest.length; + } + + // append the decomposition to the destination buffer, assume length>0 + { + int reorderSplit = destIndex; + if (p == null) { + // fastpath: single code point + if (needSingleQuotation(c1)) { + //if we need single quotation, no need to consider "prevCC" + //and it must NOT be a supplementary pair + dest[destIndex++] = '\''; + dest[destIndex++] = c1; + dest[destIndex++] = '\''; + trailCC = 0; + } else if(cc != 0 && cc < prevCC) { + // (c1, c2) is out of order with respect to the preceding + // text + destIndex += length; + trailCC = insertOrdered(dest, reorderStartIndex, + reorderSplit, destIndex, c1, c2, cc); + } else { + // just append (c1, c2) + dest[destIndex++] = c1; + if(c2 != 0) { + dest[destIndex++] = c2; + } + } + } else { + // general: multiple code points (ordered by themselves) + // from decomposition + if (needSingleQuotation(p[pStart])) { + dest[destIndex++] = '\''; + dest[destIndex++] = p[pStart++]; + dest[destIndex++] = '\''; + length--; + do { + dest[destIndex++] = p[pStart++]; + } while(--length > 0); + } else if (cc != 0 && cc < prevCC) { + destIndex += length; + trailCC = mergeOrdered(dest, reorderStartIndex, + reorderSplit, p, pStart, + pStart+length); + } else { + // just append the decomposition + do { + dest[destIndex++] = p[pStart++]; + } while (--length > 0); + } + } + } + prevCC = trailCC; + if(prevCC == 0) { + reorderStartIndex = destIndex; + } + } + + return new String(dest, 0, destIndex); + } + + /** + * simpler, single-character version of mergeOrdered() - + * bubble-insert one single code point into the preceding string + * which is already canonically ordered + * (c, c2) may or may not yet have been inserted at src[current]..src[p] + * + * it must be p=current+lengthof(c, c2) i.e. p=current+(c2==0 ? 1 : 2) + * + * before: src[start]..src[current] is already ordered, and + * src[current]..src[p] may or may not hold (c, c2) but + * must be exactly the same length as (c, c2) + * after: src[start]..src[p] is ordered + * + * @return the trailing combining class + */ + private static int/*unsigned byte*/ insertOrdered(char[] source, + int start, + int current, int p, + char c1, char c2, + int/*unsigned byte*/ cc) { + int back, preBack; + int r; + int prevCC, trailCC=cc; + + if (start=prevCC + preBack=back=current; + + PrevArgs prevArgs = new PrevArgs(); + prevArgs.current = current; + prevArgs.start = start; + prevArgs.src = source; + prevArgs.c1 = c1; + prevArgs.c2 = c2; + + // get the prevCC + prevCC=getPrevCC(prevArgs); + preBack = prevArgs.current; + + if(cc=prevCC) { + break; + } + back=preBack; + } + + // this is where we are right now with all these indicies: + // [start]..[pPreBack] 0..? code points that we can ignore + // [pPreBack]..[pBack] 0..1 code points with prevCC<=cc + // [pBack]..[current] 0..n code points with >cc, move up to insert (c, c2) + // [current]..[p] 1 code point (c, c2) with cc + + // move the code units in between up + r=p; + do { + source[--r]=source[--current]; + } while (back!=current); + } + } + + // insert (c1, c2) + source[current] = c1; + if (c2!=0) { + source[(current+1)] = c2; + } + + // we know the cc of the last code point + return trailCC; + } + /** + * merge two UTF-16 string parts together + * to canonically order (order by combining classes) their concatenation + * + * the two strings may already be adjacent, so that the merging is done + * in-place if the two strings are not adjacent, then the buffer holding the + * first one must be large enough + * the second string may or may not be ordered in itself + * + * before: [start]..[current] is already ordered, and + * [next]..[limit] may be ordered in itself, but + * is not in relation to [start..current[ + * after: [start..current+(limit-next)[ is ordered + * + * the algorithm is a simple bubble-sort that takes the characters from + * src[next++] and inserts them in correct combining class order into the + * preceding part of the string + * + * since this function is called much less often than the single-code point + * insertOrdered(), it just uses that for easier maintenance + * + * @return the trailing combining class + */ + private static int /*unsigned byte*/ mergeOrdered(char[] source, + int start, + int current, + char[] data, + int next, + int limit) { + int r; + int /*unsigned byte*/ cc, trailCC=0; + boolean adjacent; + + adjacent= current==next; + NextCCArgs ncArgs = new NextCCArgs(); + ncArgs.source = data; + ncArgs.next = next; + ncArgs.limit = limit; + + if(start!=current) { + + while(ncArgs.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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Punycode.java b/tests/test_data/std/jdk/internal/icu/impl/Punycode.java new file mode 100644 index 00000000..6fe1ebcc --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/Punycode.java @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 2003-2004, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +// +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/text/Punycode.java +// - move from package com.ibm.icu.text to package sun.net.idn +// - use ParseException instead of StringPrepParseException +// 2007-08-14 Martin Buchholz +// - remove redundant casts +// +package jdk.internal.icu.impl; + +import java.text.ParseException; +import jdk.internal.icu.lang.UCharacter; +import jdk.internal.icu.text.UTF16; + +/** + * Ported code from ICU punycode.c + * @author ram + */ + +/* Package Private class */ +public final class Punycode { + + /* Punycode parameters for Bootstring */ + private static final int BASE = 36; + private static final int TMIN = 1; + private static final int TMAX = 26; + private static final int SKEW = 38; + private static final int DAMP = 700; + private static final int INITIAL_BIAS = 72; + private static final int INITIAL_N = 0x80; + + /* "Basic" Unicode/ASCII code points */ + private static final int HYPHEN = 0x2d; + private static final int DELIMITER = HYPHEN; + + private static final int ZERO = 0x30; + private static final int NINE = 0x39; + + private static final int SMALL_A = 0x61; + private static final int SMALL_Z = 0x7a; + + private static final int CAPITAL_A = 0x41; + private static final int CAPITAL_Z = 0x5a; + + // TODO: eliminate the 256 limitation + private static final int MAX_CP_COUNT = 256; + + private static int adaptBias(int delta, int length, boolean firstTime){ + if(firstTime){ + delta /=DAMP; + }else{ + delta /= 2; + } + delta += delta/length; + + int count=0; + for(; delta>((BASE-TMIN)*TMAX)/2; count+=BASE) { + delta/=(BASE-TMIN); + } + + return count+(((BASE-TMIN+1)*delta)/(delta+SKEW)); + } + + /** + * @return the numeric value of a basic code point (for use in representing integers) + * in the range 0 to BASE-1, or a negative value if cp is invalid. + */ + private static final int decodeDigit(int cp) { + if(cp<='Z') { + if(cp<='9') { + if(cp<'0') { + return -1; + } else { + return cp-'0'+26; // 0..9 -> 26..35 + } + } else { + return cp-'A'; // A-Z -> 0..25 + } + } else if(cp<='z') { + return cp-'a'; // a..z -> 0..25 + } else { + return -1; + } + }; + + private static char asciiCaseMap(char b, boolean uppercase) { + if(uppercase) { + if(SMALL_A<=b && b<=SMALL_Z) { + b-=(SMALL_A-CAPITAL_A); + } + } else { + if(CAPITAL_A<=b && b<=CAPITAL_Z) { + b+=(SMALL_A-CAPITAL_A); + } + } + return b; + } + + /** + * digitToBasic() returns the basic code point whose value + * (when used for representing integers) is d, which must be in the + * range 0 to BASE-1. The lowercase form is used unless the uppercase flag is + * nonzero, in which case the uppercase form is used. + */ + private static char digitToBasic(int digit, boolean uppercase) { + /* 0..25 map to ASCII a..z or A..Z */ + /* 26..35 map to ASCII 0..9 */ + if(digit<26) { + if(uppercase) { + return (char)(CAPITAL_A+digit); + } else { + return (char)(SMALL_A+digit); + } + } else { + return (char)((ZERO-26)+digit); + } + } + + // ICU-13727: Limit input length for n^2 algorithm + // where well-formed strings are at most 59 characters long. + private static final int ENCODE_MAX_CODE_UNITS = 1000; + private static final int DECODE_MAX_CHARS = 2000; + + /** + * Converts Unicode to Punycode. + * The input string must not contain single, unpaired surrogates. + * The output will be represented as an array of ASCII code points. + * + * @param src + * @param caseFlags + * @return + * @throws ParseException + */ + public static StringBuffer encode(StringBuffer src, boolean[] caseFlags) throws ParseException{ + + int[] cpBuffer = new int[MAX_CP_COUNT]; + int n, delta, handledCPCount, basicLength, destLength, bias, j, m, q, k, t, srcCPCount; + char c, c2; + int srcLength = src.length(); + if (srcLength > ENCODE_MAX_CODE_UNITS) { + throw new RuntimeException( + "input too long: " + srcLength + " UTF-16 code units"); + } + int destCapacity = MAX_CP_COUNT; + char[] dest = new char[destCapacity]; + StringBuffer result = new StringBuffer(); + /* + * Handle the basic code points and + * convert extended ones to UTF-32 in cpBuffer (caseFlag in sign bit): + */ + srcCPCount=destLength=0; + + for(j=0; j0) { + if(destLength state to , but guard against overflow: + */ + if(m-n>(0x7fffffff-handledCPCount-delta)/(handledCPCount+1)) { + throw new RuntimeException("Internal program error"); + } + delta+=(m-n)*(handledCPCount+1); + n=m; + + /* Encode a sequence of same code points n */ + for(j=0; jTMAX) { + t=TMAX; + } + */ + + t=k-bias; + if(t=(bias+TMAX)) { + t=TMAX; + } + + if(q DECODE_MAX_CHARS) { + throw new RuntimeException("input too long: " + srcLength + " characters"); + } + StringBuffer result = new StringBuffer(); + int n, destLength, i, bias, basicLength, j, in, oldi, w, k, digit, t, + destCPCount, firstSupplementaryIndex, cpLength; + char b; + int destCapacity = MAX_CP_COUNT; + char[] dest = new char[destCapacity]; + + /* + * Handle the basic code points: + * Let basicLength be the number of input code points + * before the last delimiter, or 0 if there is none, + * then copy the first basicLength code points to the output. + * + * The two following loops iterate backward. + */ + for(j=srcLength; j>0;) { + if(src.charAt(--j)==DELIMITER) { + break; + } + } + destLength=basicLength=destCPCount=j; + + while(j>0) { + b=src.charAt(--j); + if(!isBasic(b)) { + throw new ParseException("Illegal char found", -1); + } + + if(j0 ? basicLength+1 : 0; in=srcLength) { + throw new ParseException("Illegal char found", -1); + } + + digit=decodeDigit(src.charAt(in++)); + if(digit<0) { + throw new ParseException("Invalid char found", -1); + } + if(digit>(0x7fffffff-i)/w) { + /* integer overflow */ + throw new ParseException("Illegal char found", -1); + } + + i+=digit*w; + t=k-bias; + if(t=(bias+TMAX)) { + t=TMAX; + } + if(digit0x7fffffff/(BASE-t)) { + /* integer overflow */ + throw new ParseException("Illegal char found", -1); + } + w*=BASE-t; + } + + /* + * Modification from sample code: + * Increments destCPCount here, + * where needed instead of in for() loop tail. + */ + ++destCPCount; + bias=adaptBias(i-oldi, destCPCount, (oldi==0)); + + /* + * i was supposed to wrap around from (incremented) destCPCount to 0, + * incrementing n each time, so we'll fix that now: + */ + if(i/destCPCount>(0x7fffffff-n)) { + /* integer overflow */ + throw new ParseException("Illegal char found", -1); + } + + n+=i/destCPCount; + i%=destCPCount; + /* not needed for Punycode: */ + /* if (decode_digit(n) <= BASE) return punycode_invalid_input; */ + + if(n>0x10ffff || isSurrogate(n)) { + /* Unicode code point overflow */ + throw new ParseException("Illegal char found", -1); + } + + /* Insert n at position i of the output: */ + cpLength=UTF16.getCharCount(n); + if((destLength+cpLength)1) { + firstSupplementaryIndex=codeUnitIndex; + } else { + ++firstSupplementaryIndex; + } + } else { + codeUnitIndex=firstSupplementaryIndex; + codeUnitIndex=UTF16.moveCodePointOffset(dest, 0, destLength, codeUnitIndex, i-codeUnitIndex); + } + + /* use the UChar index codeUnitIndex instead of the code point index i */ + if(codeUnitIndexH**w=K;~8@Wo_(YKuRt<0KcYdIdP{A*6h7KmIiEW?=;2quzC z3Yr8)*0pfj49Az^!Bcp1F{v0TNrnWt*y^(_IRO4g?&>pp?LM%FWxLP595UCKWY!ytwP!a1{K z=>jJbNne`ttLu8snNTn+aJHU(M%vDmoP|ocT(TWKUz4~6XK+@*Xbk5N7Z`qFCM>0? zTSaHhEu|{`lQE<)#s@jpecBNSCDdd_!7G%e&cV%gzT(UmW=a(+zgeRYMH;Uv7?0sK zTomZ^yEuALXZJKYrD_3XRaJk&UR|R&k5qCE)%M{l2MaOB$g@V zsabp0pd6KrRoz~cy(7?-E#)+GNwW>P_YOnOnnC}|jpcoDk4#XWO^4LGeAV&D3bZab zTJG)*t?VKxm=Wlxr~NF|;A*8H(AyBe>jwqb1bUu#t3G5`F{^Vv*W+7&R28oy1)8Z_ z)~m17(Cg8V#lfbOWm~^zlqyoy&H6)@gyJeRUv$kP38}Zrjwl$WsagVol?->KLV;ca z(S=gQ&gs_-DgB6VOd4nHg3J%YoSpz*K>_|aw(g3f#CsGR1+?+{7I$AFYdOXlQpWUiCU2PBha>^YK|Cz%hAA(J7^ zBgo9UWca4=$b7=PRIrK4^zUZHF83fz7^giQ+IR<6c=9O~`K$&Pq2GIW-?eY@RG6Y= z1Y%a9w}6T`uTuXN+RC`6Q@^2`|Mq>12s}ckT+6e4Bm&q8?9isFeigOAM2mc{87^w9 z8pDSbgc#)E^%~G6?j%sO1|mZS+=7xA*Pr`BMZHjhsy?Hd_9BEOt>>M;@HvNT&e@vt zDpisoap_#6@Cdzfom%GM?a&=|*)i#U#dN>MD8BK*#1E%C%J?^Gc+0Gm#2b`&4}CD9 z{O#jmzUAlhKHKLzAI#ukn0|(xV}Di4XHY@eBtv}<(9u`RYuh(ReTQbJi@bnsbmDuQ z#1E|Ck1keqW`;a029zH@f=tnx6Uy(eU_*c8!QQ8uGR}AnakBpbTKWg>j6K;#`vJ}` z5B!b`d${yeS_B8i`uA};jDdO^^)LkR6JG~A9N3>Zq`&a1vg?vbRfE^ajN>L22u(mN dl2(9Taen@K*^*N{RS@_aJ)(ssx3~>p=|2zN$&dg5 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/ReplaceableUCharacterIterator.java b/tests/test_data/std/jdk/internal/icu/impl/ReplaceableUCharacterIterator.java new file mode 100644 index 00000000..cf58f614 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/ReplaceableUCharacterIterator.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk.internal.icu.impl; + +import jdk.internal.icu.text.Replaceable; +import jdk.internal.icu.text.ReplaceableString; +import jdk.internal.icu.text.UCharacterIterator; + +/** + * DLF docs must define behavior when Replaceable is mutated underneath + * the iterator. + * + * This and ICUCharacterIterator share some code, maybe they should share + * an implementation, or the common state and implementation should be + * moved up into UCharacterIterator. + * + * What are first, last, and getBeginIndex doing here?!?!?! + */ +public class ReplaceableUCharacterIterator extends UCharacterIterator { + + // public constructor ------------------------------------------------------ + + /** + * Public constructor + * @param str text which the iterator will be based on + */ + public ReplaceableUCharacterIterator(String str){ + if(str==null){ + throw new IllegalArgumentException(); + } + this.replaceable = new ReplaceableString(str); + this.currentIndex = 0; + } + + /** + * Public constructor + * @param buf buffer of text on which the iterator will be based + */ + public ReplaceableUCharacterIterator(StringBuffer buf){ + if(buf==null){ + throw new IllegalArgumentException(); + } + this.replaceable = new ReplaceableString(buf); + this.currentIndex = 0; + } + + // public methods ---------------------------------------------------------- + + /** + * Creates a copy of this iterator, does not clone the underlying + * Replaceableobject + * @return copy of this iterator + */ + public Object clone(){ + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; // never invoked + } + } + + /** + * Returns the current UTF16 character. + * @return current UTF16 character + */ + public int current(){ + if (currentIndex < replaceable.length()) { + return replaceable.charAt(currentIndex); + } + return DONE; + } + + /** + * Returns the length of the text + * @return length of the text + */ + public int getLength(){ + return replaceable.length(); + } + + /** + * Gets the current currentIndex in text. + * @return current currentIndex in text. + */ + public int getIndex(){ + return currentIndex; + } + + /** + * Returns next UTF16 character and increments the iterator's currentIndex by 1. + * If the resulting currentIndex is greater or equal to the text length, the + * currentIndex is reset to the text length and a value of DONECODEPOINT is + * returned. + * @return next UTF16 character in text or DONE if the new currentIndex is off the + * end of the text range. + */ + public int next(){ + if (currentIndex < replaceable.length()) { + return replaceable.charAt(currentIndex++); + } + return DONE; + } + + + /** + * Returns previous UTF16 character and decrements the iterator's currentIndex by + * 1. + * If the resulting currentIndex is less than 0, the currentIndex is reset to 0 and a + * value of DONECODEPOINT is returned. + * @return next UTF16 character in text or DONE if the new currentIndex is off the + * start of the text range. + */ + public int previous(){ + if (currentIndex > 0) { + return replaceable.charAt(--currentIndex); + } + return DONE; + } + + /** + * Sets the currentIndex to the specified currentIndex in the text and returns that + * single UTF16 character at currentIndex. + * This assumes the text is stored as 16-bit code units. + * @param currentIndex the currentIndex within the text. + * @exception IllegalArgumentException is thrown if an invalid currentIndex is + * supplied. i.e. currentIndex is out of bounds. + */ + public void setIndex(int currentIndex) { + if (currentIndex < 0 || currentIndex > replaceable.length()) { + throw new IllegalArgumentException(); + } + this.currentIndex = currentIndex; + } + + public int getText(char[] fillIn, int offset){ + int length = replaceable.length(); + if(offset < 0 || offset + length > fillIn.length){ + throw new IndexOutOfBoundsException(Integer.toString(length)); + } + replaceable.getChars(0,length,fillIn,offset); + return length; + } + + // private data members ---------------------------------------------------- + + /** + * Replaceable object + */ + private Replaceable replaceable; + /** + * Current currentIndex + */ + private int currentIndex; + +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/StringPrepDataReader.class b/tests/test_data/std/jdk/internal/icu/impl/StringPrepDataReader.class new file mode 100644 index 0000000000000000000000000000000000000000..b99ed459f3cbe8524934c4d84a6c081c7ef0922b GIT binary patch literal 1886 zcmb7FTT>fl7=FIZVM*B16eumFv4XASfW(St5Xk}TRv<`1oS5l!mSly6u*qyTopv1W zoN@dYjyJvWLaS{Z?equuU-Sn!o}O>B#L&TUyhy%x-}Cdl@3;H&pFchYkjHiu3IZyE z8bSyQ#14!*My6@ldzs?yfmwG2!b_HIxyu59M6wdW5F#p~8it_>qz)Q~8OwG}$2OW7 ztKQ96N9|^&G_?UWgE^tfvCf5H~frxV%_W4YGri0-E~>lG>#T)x%L0Zb2Zy__f6Zi>V|7B zCTlr~Yh1&532LNkTlH4Mte8&6YS}6-2wXU>BLNN6iedtjlDkU+7f7V@4n-aSMbJwOmq{hN~K`;YEQVX~^#zB$xxrOCSjiNeN_Z zknqatc1bU8%FwiiIlLsG%23_rj2Wq`$Oz2+AL7_mo;(rMx@DW2-J@O8DI2>@YDU*v zb)#7^97{g?%AmV%by(wHrgPfXED8);|BP1Pe4nj>DbOprdbe)2UCyhc;w@r79++P2 zTZowS)$+-TfUx+}1tM0%Hgfk|lZ|OdM!U_$_1jfyd4V$}*Qg(E7;RrUzGu2}PHQda z$Z-7?ArT2K5!b}(NTaXL)@4gQLcGC!#18KCwu-oV>^IE2vUVt;Cu{5{+%)Yycb|@y z?VFSuXLD2F982$Q#=Vo2{sLEA%YU$I%Q1p zoJPf~o?^CP_OOU0dIK~4K4$O^K?_f}jCWaog>nSS?-&-pk)go`vjiqQR_1xipx^_{ ze#5f|KJ4kLUddk4pkGMvrCji1KV}P(jM;Qxf#HFLFA-0Nq!^+&nhr}bOi>NqM=2D42IoroEi&YQD3cW*6uC2)a);NIP6hCJQIhgp=ljsJyoEo4qRrIL*bxr~q zvI{V=9tUDncg73yfv8Q)NlG+YEb?_SjGFKbNmFI>wP*ijFNPQ zINY&k`8*upGvosv!UiNAazi&fWWaUx$xt;AE0wFk*jBk3ifxyxVM^aY^(Preferences>Java>Code Generation>Code and Comments + */ +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/impl/StringPrepDataReader.java +// - move from package com.ibm.icu.impl to package sun.net.idn +// +package jdk.internal.icu.impl; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +import jdk.internal.icu.impl.ICUBinary; + + +/** + * @author ram + * + * To change the template for this generated type comment go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +public final class StringPrepDataReader implements ICUBinary.Authenticate { + + /** + *

private constructor.

+ * @param inputStream ICU uprop.dat file input stream + * @exception IOException throw if data file fails authentication + * @draft 2.1 + */ + public StringPrepDataReader(InputStream inputStream) + throws IOException{ + + unicodeVersion = ICUBinary.readHeader(inputStream, DATA_FORMAT_ID, this); + + + dataInputStream = new DataInputStream(inputStream); + + } + + public void read(byte[] idnaBytes, + char[] mappingTable) + throws IOException{ + + // Read the bytes that make up the idnaTrie + dataInputStream.read(idnaBytes); + + // Read the extra data + for(int i=0;iy_|mltg%QjA{5Qx%UB;3Trg$Jc|BpbJ tm)=Xib{v8P!s4DOArQv;4nRsbMWWjnsm>8*$ZncruA1wmBH=N~{s04uKxhB} literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Trie$DefaultGetFoldingOffset.class b/tests/test_data/std/jdk/internal/icu/impl/Trie$DefaultGetFoldingOffset.class new file mode 100644 index 0000000000000000000000000000000000000000..3c45eb98e8866265700ed9d9c68692fba829f34e GIT binary patch literal 617 zcmaJ;Jx>Bb5Pi$n!HJ@%pkQHP0Ty0jjE%+yf|4K<5^5J%aB&Xm*jq&TUI5f7BP6{g{;q15BfXyglH!Dgtg<8j09 zxt6m)aU&QKHFrpmYe_BI!L%>DF7GRfzPWRK8uEalv|0i~wyCx7YKr^5 zAic#E+hW+N|JnzRVbP(eFI_E0kB&v&26+x4BTSyYfxSlQEZHy(JYth&=PH&NLI6PpEh-eW3UuEw z?i%r;VXwzCD|gI-Bhd1iWn0b_0sqM8vVxF6zpG@GXl69|>^lN)B$z9STxs-VxqEME19;F+Af$bSSyYRl=bA2wo2yO znpHG4vr;KnE^9It+J+0N88v5v$E<=O8E9(;^;XBUt)gjEP0cm0S!>$8a!uPX?wT64 zwNkn2XtgcknycD#7D5=n2^kelpsx`XH^2;fiz ze0ENs$>q6+;Gw-q&mKoZcsh|w|D|(}|qEFp<~!rZ1!ti%n%8!xL^OXZ6{IL~dy@ zMaKpX0o0vnTJB;^9MWiTY&shdIDSaQ^^Y9RPv)=bZb(?iNWOeL{U41sy3AxJ%d5;% zmu!%QT4}|s&0+N7gY4oAbt&OHRRkX8a`sTfx^j5?*MG=Jj!C{BUqL zhiz5C+g{L2bBA|I*&RA;_QD3!ktCl+EA4lPY#SNf8)e>G`-^he>(sYs$EwP1skaGl zk6T>ImTQ%QIm2m9U**oY^oSu{FsshIDf7eltGaEQm1NPVR!xeX&ks=EGt)1hkb#q| zn*f_5j6p1;kJ6VY`S3dBn;!WV|b97MsRze?Hk$V^2k3Z)ft!)Rr#Sxmu|J?aHueN3AE7h$ z48u2{;tZu&>|;d2KJ5GqO5hO!{wEk|po}%1@z~j2O#X@{{jm9a8J+yCl9YoE+(i%G zLKOEHn)|$ozK%)kQ0E&+;ag0^I}GN#u<#zwzK=3bUZ~T@7QRY}j-Wy`UJHD4h~gva z3Tj056Z=h~_tDli_jz)UCisCQ6x>trKtUVNwTCiX*`vat9Uqqk8OhWM>;wYx4xrR4 zFDR}soRkB!1IFxQyc!*By?^^caC@-(#Ln%2#F zmPzBq)uLHeC`q2Vt)A|E!ATiAsgVYQ1N&4;~zN2 zcNw!Ib(E&n@?!L!gSu5jBX5)?8?O_MViuJi1RrvmmK3SaqWEPwC#}vJf?=&JiLtR-l zVbY55<9p|WMgty%%q=@H=~7VZ$_>LZ5KMd5ReqDm&+rCjm6$SHL($06&k^)Lme}20 zJFUM!w|rIZQwX{{fdex~WIu`(W~IRY9Ba_TCQgZxClfA trie is a kind of compressed, serializable table of values + * associated with Unicode code points (0..0x10ffff).

+ *

This class defines the basic structure of a trie and provides methods + * to retrieve the offsets to the actual data.

+ *

Data will be the form of an array of basic types, char or int.

+ *

The actual data format will have to be specified by the user in the + * inner static interface com.ibm.icu.impl.Trie.DataManipulate.

+ *

This trie implementation is optimized for getting offset while walking + * forward through a UTF-16 string. + * Therefore, the simplest and fastest access macros are the + * fromLead() and fromOffsetTrail() methods. + * The fromBMP() method are a little more complicated; they get offsets even + * for lead surrogate codepoints, while the fromLead() method get special + * "folded" offsets for lead surrogate code units if there is relevant data + * associated with them. + * From such a folded offsets, an offset needs to be extracted to supply + * to the fromOffsetTrail() methods. + * To handle such supplementary codepoints, some offset information are kept + * in the data.

+ *

Methods in com.ibm.icu.impl.Trie.DataManipulate are called to retrieve + * that offset from the folded value for the lead surrogate unit.

+ *

For examples of use, see com.ibm.icu.impl.CharTrie or + * com.ibm.icu.impl.IntTrie.

+ * @author synwee + * @see com.ibm.icu.impl.CharTrie + * @see com.ibm.icu.impl.IntTrie + * @since release 2.1, Jan 01 2002 + */ +public abstract class Trie +{ + // public class declaration ---------------------------------------- + + /** + * Character data in com.ibm.impl.Trie have different user-specified format + * for different purposes. + * This interface specifies methods to be implemented in order for + * com.ibm.impl.Trie, to surrogate offset information encapsulated within + * the data. + */ + public static interface DataManipulate + { + /** + * Called by com.ibm.icu.impl.Trie to extract from a lead surrogate's + * data + * the index array offset of the indexes for that lead surrogate. + * @param value data value for a surrogate from the trie, including the + * folding offset + * @return data offset or 0 if there is no data for the lead surrogate + */ + public int getFoldingOffset(int value); + } + + // default implementation + private static class DefaultGetFoldingOffset implements DataManipulate { + public int getFoldingOffset(int value) { + return value; + } + } + + // protected constructor ------------------------------------------- + + /** + * Trie constructor for CharTrie use. + * @param inputStream ICU data file input stream which contains the + * trie + * @param dataManipulate object containing the information to parse the + * trie data + * @throws IOException thrown when input stream does not have the + * right header. + */ + protected Trie(InputStream inputStream, + DataManipulate dataManipulate) throws IOException + { + DataInputStream input = new DataInputStream(inputStream); + // Magic number to authenticate the data. + int signature = input.readInt(); + m_options_ = input.readInt(); + + if (!checkHeader(signature)) { + throw new IllegalArgumentException("ICU data file error: Trie header authentication failed, please check if you have the most updated ICU data file"); + } + + if(dataManipulate != null) { + m_dataManipulate_ = dataManipulate; + } else { + m_dataManipulate_ = new DefaultGetFoldingOffset(); + } + m_isLatin1Linear_ = (m_options_ & + HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_) != 0; + m_dataOffset_ = input.readInt(); + m_dataLength_ = input.readInt(); + unserialize(inputStream); + } + + // protected data members ------------------------------------------ + + /** + * Lead surrogate code points' index displacement in the index array. + *
{@code
+     * 0x10000-0xd800=0x2800
+     * 0x2800 >> INDEX_STAGE_1_SHIFT_
+     * }
+ */ + protected static final int LEAD_INDEX_OFFSET_ = 0x2800 >> 5; + /** + * Shift size for shifting right the input index. 1..9 + */ + protected static final int INDEX_STAGE_1_SHIFT_ = 5; + /** + * Shift size for shifting left the index array values. + * Increases possible data size with 16-bit index values at the cost + * of compactability. + * This requires blocks of stage 2 data to be aligned by + * DATA_GRANULARITY. + * 0..INDEX_STAGE_1_SHIFT + */ + protected static final int INDEX_STAGE_2_SHIFT_ = 2; + /** + * Number of data values in a stage 2 (data array) block. + */ + protected static final int DATA_BLOCK_LENGTH=1< + * getRawOffset(0, ch); + *

+ * will do. Otherwise if it is a supplementary character formed by + * surrogates lead and trail. Then we would have to call getRawOffset() + * with getFoldingIndexOffset(). See getSurrogateOffset(). + * @param offset index offset which ch is to start from + * @param ch index to be used after offset + * @return offset to the data + */ + protected final int getRawOffset(int offset, char ch) + { + return (m_index_[offset + (ch >> INDEX_STAGE_1_SHIFT_)] + << INDEX_STAGE_2_SHIFT_) + + (ch & INDEX_STAGE_3_MASK_); + } + + /** + * Gets the offset to data which the BMP character points to + * Treats a lead surrogate as a normal code point. + * @param ch BMP character + * @return offset to data + */ + protected final int getBMPOffset(char ch) + { + return (ch >= UTF16.LEAD_SURROGATE_MIN_VALUE + && ch <= UTF16.LEAD_SURROGATE_MAX_VALUE) + ? getRawOffset(LEAD_INDEX_OFFSET_, ch) + : getRawOffset(0, ch); + // using a getRawOffset(ch) makes no diff + } + + /** + * Gets the offset to the data which this lead surrogate character points + * to. + * Data at the returned offset may contain folding offset information for + * the next trailing surrogate character. + * @param ch lead surrogate character + * @return offset to data + */ + protected final int getLeadOffset(char ch) + { + return getRawOffset(0, ch); + } + + /** + * Internal trie getter from a code point. + * Could be faster(?) but longer with + * {@code if((c32)<=0xd7ff) { (result)=_TRIE_GET_RAW(trie, data, 0, c32); }} + * Gets the offset to data which the codepoint points to + * @param ch codepoint + * @return offset to data + */ + protected final int getCodePointOffset(int ch) + { + // if ((ch >> 16) == 0) slower + if (ch < 0) { + return -1; + } else if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE) { + // fastpath for the part of the BMP below surrogates (D800) where getRawOffset() works + return getRawOffset(0, (char)ch); + } else if (ch < UTF16.SUPPLEMENTARY_MIN_VALUE) { + // BMP codepoint + return getBMPOffset((char)ch); + } else if (ch <= UCharacter.MAX_VALUE) { + // look at the construction of supplementary characters + // trail forms the ends of it. + return getSurrogateOffset(UTF16.getLeadSurrogate(ch), + (char)(ch & SURROGATE_MASK_)); + } else { + // return -1 if there is an error, in this case we return + return -1; + } + } + + /** + *

Parses the inputstream and creates the trie index with it.

+ *

This is overwritten by the child classes. + * @param inputStream input stream containing the trie information + * @exception IOException thrown when data reading fails. + */ + protected void unserialize(InputStream inputStream) throws IOException + { + //indexLength is a multiple of 1024 >> INDEX_STAGE_2_SHIFT_ + m_index_ = new char[m_dataOffset_]; + DataInputStream input = new DataInputStream(inputStream); + for (int i = 0; i < m_dataOffset_; i ++) { + m_index_[i] = input.readChar(); + } + } + + /** + * Determines if this is a 16 bit trie + * @return true if this is a 16 bit trie + */ + protected final boolean isCharTrie() + { + return (m_options_ & HEADER_OPTIONS_DATA_IS_32_BIT_) == 0; + } + + // private data members -------------------------------------------- + + /** + * Latin 1 option mask + */ + protected static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200; + /** + * Constant number to authenticate the byte block + */ + protected static final int HEADER_SIGNATURE_ = 0x54726965; + /** + * Header option formatting + */ + private static final int HEADER_OPTIONS_SHIFT_MASK_ = 0xF; + protected static final int HEADER_OPTIONS_INDEX_SHIFT_ = 4; + protected static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100; + + /** + * Flag indicator for Latin quick access data block + */ + private boolean m_isLatin1Linear_; + + /** + *

Trie options field.

+ *

options bit field:
+ * 9 1 = Latin-1 data is stored linearly at data + DATA_BLOCK_LENGTH
+ * 8 0 = 16-bit data, 1=32-bit data
+ * 7..4 INDEX_STAGE_1_SHIFT // 0..INDEX_STAGE_2_SHIFT
+ * 3..0 INDEX_STAGE_2_SHIFT // 1..9
+ */ + private int m_options_; + + // private methods --------------------------------------------------- + + /** + * Authenticates raw data header. + * Checking the header information, signature and options. + * @param signature This contains the options and type of a Trie + * @return true if the header is authenticated valid + */ + private final boolean checkHeader(int signature) + { + // check the signature + // Trie in big-endian US-ASCII (0x54726965). + // Magic number to authenticate the data. + if (signature != HEADER_SIGNATURE_) { + return false; + } + + if ((m_options_ & HEADER_OPTIONS_SHIFT_MASK_) != + INDEX_STAGE_1_SHIFT_ || + ((m_options_ >> HEADER_OPTIONS_INDEX_SHIFT_) & + HEADER_OPTIONS_SHIFT_MASK_) + != INDEX_STAGE_2_SHIFT_) { + return false; + } + return true; + } +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/Trie2$1.class b/tests/test_data/std/jdk/internal/icu/impl/Trie2$1.class new file mode 100644 index 0000000000000000000000000000000000000000..4009d3c340c0cb25ed2badb661dd2d96d5c8d3c1 GIT binary patch literal 558 zcmaJ;yG{Z@6g?MKmY1TaAfnO2M6hs!g^k9BXe0qFB=o~Ffx%^#?8C3Ju`;pn1N#c+MbD^6IQ*BTqPAM;Qt)mOZgp$bewA{jnsJx=PD_ zJRiwmAVwa0%3a?T-cSU}*ej8`8ay5V8xV!_25oo0uSQkp=lux34?0bWWBf~U<)O-_kVkg?26o6(#cN9&o~FCHCkbN~PV literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Trie2$Range.class b/tests/test_data/std/jdk/internal/icu/impl/Trie2$Range.class new file mode 100644 index 0000000000000000000000000000000000000000..3ca56ef32b7e4f646eb53c400271132196ba1c90 GIT binary patch literal 1128 zcmaKqOHWfl6vzM5-qKPo6v{)OA|R-3L5hG+@DZCB8Vedh7VL(0LN8oy@%EO)kD_ka zv0-Ckkhn0eT=;d|`2hbjt>TKs%sF!&Gru|Kd^`E{89*Kn;|L)fg=Hgx7J<$!xhHe3 z^fq(PHnvnL5NKI&JSTV{5Kd>-ba>20E8+sNO%>!_S*rT} z9koFELB3j6&#O!l5C!e-vvEPYZRM5!IkjWJ#-MgY_M}@kH(j(bgi8YLu9D@Iy6;yv zWuSP`dK@DdjpDM6F^mhO&H-Z;bafVGtzrsP(79J_Ttix*twQt5d`0@RGkiH+C}fO3 zYhyzDquO8a0-bZ+#+0_jwC(Y04PxmJ2qcP*rh6tW+dBWB%4DSriYWs zJ;zgyQcy;+A0ggT31OPMb_3sWgS*`bzzk-2VtdiST_+zfI!yU=;w!o)ju6dq9iiGDE^H8z{0r~{N&F=L zZw%nX;EXh$Y~t{7%;6@1257lO#1L*X&xVy0zc3d?;*tL09gH`j-!Vd0YUUWj3n>kF zj4MXz{j2mJBV#P7H%+W#OfIC(*alf3hzKmvf_4!_pNL^tv|?Js4P#&9g(joLLA=X9 q2t$@a=#B7?VH}J553iahwqIYTDuu9%(2pCZrhBl0IN!56%QX(y@(L zBDLZNu&7iv6=e~rLRBl_&=!fRt4fu+=&lk~x0P7*sV-U+((jH9NvLF5Gv~}b_dM=* z9@pPJ{^~w}30NLTINWe*aG^^$3wCJjB4s#sPrtCx+E5{5K%<2lBk*B2KJA~M*}s~y@&d#mlc zS3@7R3wR2~m2#@ATZBR+9M}vf>pL{;RAP6|%$wzjX)o6z8U_*N+Pq$xqLvNWtQ*4u zy*93uvYCrb6;qY;{AA9^8-?=Zm9()~Hj4!>hTw4kKf;UM*yF}t4g0WPAlLwGI>;Jy zt)z!E9L5oW zHhMf}74v8JjHZ~BoS~3cAxx-!5)&F;R{Ok9tRz!B)`L|KOX3v`#}#OsN(#@X`Bb7; zHJnf)%_w9x2u^C4QUcdyRXb|yw1(GI)?0Gxb518e5j%-98qQ*d5vjxp?1(hZyIrqw zH{K8ktR-o!j}nnaWfN~CTn}@6P=%yU#&S-Y1!Jm`pEIm8`dp4Hfn+hQ=Vo-vRNwVQ zr|MvVp@uFtbbVYvUe2>0P8#L;VrE*m^t{1|Kr3G2dg`KmSZ179va;>Q$gmcOB`Z9A ziREAS?X@$+{3cT@`w2d2rd~n$%zU6rPs+>|bhbASa^n9RYAbf>KS6b@;gMV%Q|U> z!0T|6eWgKWxK1Ni-F7W3Q1$A@#&nbk?~%Y&KN;FpeZe=wl^t;M z2N8}gW8emS_b|j*cYPhb!^rL+d=r~glx@+#2xE1OISx9;x!(36vLr%nTSn|4X)yF9 zo|jNkdzmyGTE>B~pyHgFn`m0XH6;x?FKpE5{z%Cd>awSbORL|iB|bgZmodJhsp2BZ^%(uE<(*)2U7mtG{K53{lr8R z24Kl8xGLN5p4^HLWEXD9AU>5Ld?9;rU-sb}*^lpK7!TwQ{459XP)6~$9Kwnm7B0C< zbjT6WBV%^@qqY3i(?5U}=qy*>a(IL}a*`LyKS+~vAj1>vgx1>rm^XtES}@Sp9P*iN zw5(F%WDjr^47`PnuI{i}mEb(BsDg?R2ByB9q~iv*k<^PsQ*7Y$$93FpKSioZ>B&($ zQmtmA9;u3j|7bd!9f#>s-4zt84*G;&EJ=*kQX81OP2(cS3K(ZD4u%4gx6rAULMqp_ z1bg0>Vrli4kTbL9dOJHC@&KA-oYj8_0eKi9d4$P1ied75<>VTGyfdHl&nOIBWGq|J zi>wV`0AU--8h~CnJuCc=B-&m6BW$JldfYKm1(J)clv1@)Yh@b&@o*giuDUBHOncV? gF4;7PyiIqbK-$H8N#3_b@-3u`90{YO?>2e<1Eqj4`Tzg` literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Trie2$UTrie2Header.class b/tests/test_data/std/jdk/internal/icu/impl/Trie2$UTrie2Header.class new file mode 100644 index 0000000000000000000000000000000000000000..74457b19bb3784ac68a31244ebda3e944c74649a GIT binary patch literal 579 zcma)(&rSj{5XQd|bYWQ)@h_r@2M@@>O}J{jU<@P#4xsnK7AUS=((M{w%ae%*AHat) z4(pn5GG6A_e)F}R&U}8oe*kFV)WsTd4)Pw>u|X)$#k253p{IU-G?!yb*tk|&*&9Nx ze(~U-K&a1yM_*|xjTWJ=#)+?<7NI{hN;c2$Q?#WBq#+bzHPyl6v z?XJ?YmpqN68H!QJN~If(Mff0$TJAG3Z)b|DX>|Ylrz?Uxh!QiFcWQa7oBsE5**8L= zCu7@=V(Z|TQ2XOfg4fYnnpP;{SaJp4YU6MQhX(_WKoKrSpp?CeUpYzgKmgAc-`&bCcnnSg^hAKvvF#M;K(94`-zpy$44utL> hiijYUf)9}Jv=PbHL@cv`1f8#@=!vHCDG>OHI&bZ|IdT91 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Trie2.class b/tests/test_data/std/jdk/internal/icu/impl/Trie2.class new file mode 100644 index 0000000000000000000000000000000000000000..9a26149dfc3ede8200ecb79445cbd4419edfe7b0 GIT binary patch literal 5212 zcma)AdsJNI5&wP5E(^;|An0NUd05}NG$y+Z9gNlMgt!b zT8W(;w)RA<gSKrN7{ri6 zS|1Wo=DmVtU_?X>saz(A)-Q}P1GX>%I$AU2TMQ&H&LSDMM$CysRx^6cUAv@;na1zm zK32Izn*+3vGO!D`DiqmlH)b|P1)G_N7pcK1nTf2Os1G{|*e^2lVm=kRUF78hNMk}u z;5LQuyr!Ek-Y+)3J=p8VJ_EPo4kqqw?e>`2F&5Cco#c_#gu|=D5{LZ;?!w)qv&0m< zH6#}tSo*{p1?){nMc|NuPl%?XF*7qJ-P4cz6qe1m&4vK(m1g}wzMbjH*83hzu<0%D zk8KNghT?tK#=?EQ(fIb(NPlO%EgXx+ds?Gg*}>XV$xPNv<_@@kS41hd;;f2xhr43& z2BDUmPYnsx$D*7o8`tzgh0F7nd)Oj7JK}9U*T%!W9i7+58{(19-Yv0iQBcjR$Pvsj zL-DpqU;9><$ThrE&Jz*WW%Xu-#SW{ZHP$+3>8xj(m0u!#e~vc2M^VOG@iMovE!$dq z`y;K}!m$Bidli;A>`1gdzZXWft1H?WqeKx;@PZP#-6~YhvCEAzA~TUFVkDM10{yYB ztK*?ICtP_G@6XR02+lFk;Bt*I%!j$HwIi+#=&;OqFNx`GPYp9?N+WjC>YW%Lw9+wC zXHj`1H6$&AHw$rx=*^DVtiomURZKJQ(4n+tX05JtYCJk~H7RU3?|yWy!g)IjwUyYJ zHhZ))Ic%G(Ep-E(j%ha*>dx4jPMdq9y!^Tb`+^JJ%+Fv zc&!ZG!ZxS(=*Ktn^NcR5*jPHXI~S3_%zd2kCU`!)qOxe9>X4QNTyja%*(bPnG$m+7CZ3gu9u}-wnm0l~8 z?XjdDc-VhbxN^RZ?7IE@c!zy(K4E=Qyp+Sqq?K+@n3;^EtKlAYY2T%iDLUt7V+^$p zZ#9@#{N0ZgoI-hZvt>bM84Wo+Xvk?nLyiaIoI0ul6(wUeY1^8lQ!lxB*}1yO9&Xi#S277%$-@1Ixt)%Xzp(fO@p{6pABf zQ95uMi+a`)E1yQi+9_1Lz!l&a%cBU{=@{X1W=e>#Y7!gQoWzo6;rC9$ThLOw>==qq zqIwdAB%i_+*R3u8Ak|D_!C726P`>&!*1RUV*G(hjz>N;P+JVguY;j;KeF&A6?my<} z=nx%e(M3PId+XLtBV0#`jnn86c(rfOG)SI8^E5stuw@$C1h$rykQJ?~n?kRDcpBU5 z2B!F!LeCCC2phdYuW)xXdh3GTSAEkMC}{KreZo7AO9=*oK5@SPkWWpX`S;VoeMd3Pl6eJ>;dPeAPssTVOX3}t!9Vdh{>}7%566`k zPpbuZMg{Slx*X4|wS*zOsG4v>b>Stoo$w}1DHGEwiBsw>oKXkyiaJbqgzzZN>TK+0 z@^6L5`#HwZP4ndV|AA5bU$no6oqi~#Dg(>UVI3T% zEPNI6zYS@BuX&XW*?L_24x>bO`0?@GTooZiC?!}_dlEZOAt_bn(dVSAP*u39u*j*x z?`fGgw4PfXJuS55Aw6&w>4Dlcr;$BhQ?1rik&|*XQ6ArCV^+xN`~fxm5I-U=?csIG z77{kqP9eJV40bpAs=Uncpf~6{j*8l#_Z042_9O}?QGCcNi5>Kc=u;?MDpKBI(UQx$ zmC`Fb76P78RCvZv?XhtM-&cDQ2zkb_(Ua2twd5?$_}7FtbpxXp_%YvPk4?<8O6o1e z8vK-RUhd*5{ETlteXjg((YyR+P?z{h$oV-lJhz`JLisBwKOl~&*)V%{Q;;7zj^GxW z5kn} zE0b+92G0RT?I14m+{36Ha@kusV{fI7gV_7^jJ@5C zz4i0ia~WSe>&dJG6;eK)!*t+&I`9Bid5)mL^PtO#^)pVa*X731i7g<1!(5@a%z&K5 zz3jV(U&c { + + /** + * Create a Trie2 from its serialized form. Inverse of utrie2_serialize(). + * + * Reads from the current position and leaves the buffer after the end of the trie. + * + * The serialized format is identical between ICU4C and ICU4J, so this function + * will work with serialized Trie2s from either. + * + * The actual type of the returned Trie2 will be either Trie2_16 or Trie2_32, depending + * on the width of the data. + * + * To obtain the width of the Trie2, check the actual class type of the returned Trie2. + * Or use the createFromSerialized() function of Trie2_16 or Trie2_32, which will + * return only Tries of their specific type/size. + * + * The serialized Trie2 on the stream may be in either little or big endian byte order. + * This allows using serialized Tries from ICU4C without needing to consider the + * byte order of the system that created them. + * + * @param bytes a byte buffer to the serialized form of a UTrie2. + * @return An unserialized Trie2, ready for use. + * @throws IllegalArgumentException if the stream does not contain a serialized Trie2. + * @throws IOException if a read error occurs in the buffer. + * + */ + public static Trie2 createFromSerialized(ByteBuffer bytes) throws IOException { + // From ICU4C utrie2_impl.h + // * Trie2 data structure in serialized form: + // * + // * UTrie2Header header; + // * uint16_t index[header.index2Length]; + // * uint16_t data[header.shiftedDataLength<<2]; -- or uint32_t data[...] + // * @internal + // */ + // typedef struct UTrie2Header { + // /** "Tri2" in big-endian US-ASCII (0x54726932) */ + // uint32_t signature; + + // /** + // * options bit field: + // * 15.. 4 reserved (0) + // * 3.. 0 UTrie2ValueBits valueBits + // */ + // uint16_t options; + // + // /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH */ + // uint16_t indexLength; + // + // /** (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT */ + // uint16_t shiftedDataLength; + // + // /** Null index and data blocks, not shifted. */ + // uint16_t index2NullOffset, dataNullOffset; + // + // /** + // * First code point of the single-value range ending with U+10ffff, + // * rounded up and then shifted right by UTRIE2_SHIFT_1. + // */ + // uint16_t shiftedHighStart; + // } UTrie2Header; + + ByteOrder outerByteOrder = bytes.order(); + try { + UTrie2Header header = new UTrie2Header(); + + /* check the signature */ + header.signature = bytes.getInt(); + switch (header.signature) { + case 0x54726932: + // The buffer is already set to the trie data byte order. + break; + case 0x32697254: + // Temporarily reverse the byte order. + boolean isBigEndian = outerByteOrder == ByteOrder.BIG_ENDIAN; + bytes.order(isBigEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); + header.signature = 0x54726932; + break; + default: + throw new IllegalArgumentException("Buffer does not contain a serialized UTrie2"); + } + + header.options = bytes.getChar(); + header.indexLength = bytes.getChar(); + header.shiftedDataLength = bytes.getChar(); + header.index2NullOffset = bytes.getChar(); + header.dataNullOffset = bytes.getChar(); + header.shiftedHighStart = bytes.getChar(); + + if ((header.options & UTRIE2_OPTIONS_VALUE_BITS_MASK) != 0) { + throw new IllegalArgumentException("UTrie2 serialized format error."); + } + + Trie2 This; + This = new Trie2_16(); + This.header = header; + + /* get the length values and offsets */ + This.indexLength = header.indexLength; + This.dataLength = header.shiftedDataLength << UTRIE2_INDEX_SHIFT; + This.index2NullOffset = header.index2NullOffset; + This.dataNullOffset = header.dataNullOffset; + This.highStart = header.shiftedHighStart << UTRIE2_SHIFT_1; + This.highValueIndex = This.dataLength - UTRIE2_DATA_GRANULARITY; + This.highValueIndex += This.indexLength; + + // Allocate the Trie2 index array. If the data width is 16 bits, the array also + // includes the space for the data. + + int indexArraySize = This.indexLength; + indexArraySize += This.dataLength; + This.index = new char[indexArraySize]; + + /* Read in the index */ + int i; + for (i=0; i iterator() { + return iterator(defaultValueMapper); + } + + private static ValueMapper defaultValueMapper = new ValueMapper() { + public int map(int in) { + return in; + } + }; + + /** + * Create an iterator over the value ranges from this Trie2. + * Values from the Trie2 are passed through a caller-supplied remapping function, + * and it is the remapped values that determine the ranges that + * will be produced by the iterator. + * + * + * @param mapper provides a function to remap values obtained from the Trie2. + * @return an Iterator + */ + public Iterator iterator(ValueMapper mapper) { + return new Trie2Iterator(mapper); + } + + /** + * When iterating over the contents of a Trie2, an instance of TrieValueMapper may + * be used to remap the values from the Trie2. The remapped values will be used + * both in determining the ranges of codepoints and as the value to be returned + * for each range. + * + * Example of use, with an anonymous subclass of TrieValueMapper: + * + * + * ValueMapper m = new ValueMapper() { + * int map(int in) {return in & 0x1f;}; + * } + * for (Iterator iter = trie.iterator(m); i.hasNext(); ) { + * Trie2EnumRange r = i.next(); + * ... // Do something with the range r. + * } + * + */ + public interface ValueMapper { + public int map(int originalVal); + } + + //-------------------------------------------------------------------------------- + // + // Below this point are internal implementation items. No further public API. + // + //-------------------------------------------------------------------------------- + + /** + * Trie2 data structure in serialized form: + * + * UTrie2Header header; + * uint16_t index[header.index2Length]; + * uint16_t data[header.shiftedDataLength<<2]; -- or uint32_t data[...] + * + * For Java, this is read from the stream into an instance of UTrie2Header. + * (The C version just places a struct over the raw serialized data.) + * + * @internal + */ + static class UTrie2Header { + /** "Tri2" in big-endian US-ASCII (0x54726932) */ + int signature; + + /** + * options bit field (uint16_t): + * 15.. 4 reserved (0) + * 3.. 0 UTrie2ValueBits valueBits + */ + int options; + + /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH (uint16_t) */ + int indexLength; + + /** (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT (uint16_t) */ + int shiftedDataLength; + + /** Null index and data blocks, not shifted. (uint16_t) */ + int index2NullOffset, dataNullOffset; + + /** + * First code point of the single-value range ending with U+10ffff, + * rounded up and then shifted right by UTRIE2_SHIFT_1. (uint16_t) + */ + int shiftedHighStart; + } + + // + // Data members of UTrie2. + // + UTrie2Header header; + char index[]; // Index array. Includes data for 16 bit Tries. + int data16; // Offset to data portion of the index array, if 16 bit data. + // zero if 32 bit data. + int data32[]; // NULL if 16b data is used via index + + int indexLength; + int dataLength; + int index2NullOffset; // 0xffff if there is no dedicated index-2 null block + int initialValue; + + /** Value returned for out-of-range code points and illegal UTF-8. */ + int errorValue; + + /* Start of the last range which ends at U+10ffff, and its value. */ + int highStart; + int highValueIndex; + + int dataNullOffset; + + /** + * Trie2 constants, defining shift widths, index array lengths, etc. + * + * These are needed for the runtime macros but users can treat these as + * implementation details and skip to the actual public API further below. + */ + + static final int UTRIE2_OPTIONS_VALUE_BITS_MASK=0x000f; + + + /** Shift size for getting the index-1 table offset. */ + static final int UTRIE2_SHIFT_1=6+5; + + /** Shift size for getting the index-2 table offset. */ + static final int UTRIE2_SHIFT_2=5; + + /** + * Difference between the two shift sizes, + * for getting an index-1 offset from an index-2 offset. 6=11-5 + */ + static final int UTRIE2_SHIFT_1_2=UTRIE2_SHIFT_1-UTRIE2_SHIFT_2; + + /** + * Number of index-1 entries for the BMP. 32=0x20 + * This part of the index-1 table is omitted from the serialized form. + */ + static final int UTRIE2_OMITTED_BMP_INDEX_1_LENGTH=0x10000>>UTRIE2_SHIFT_1; + + /** Number of entries in an index-2 block. 64=0x40 */ + static final int UTRIE2_INDEX_2_BLOCK_LENGTH=1<>UTRIE2_SHIFT_2. (There are 1024=0x400 lead surrogates.) + */ + static final int UTRIE2_LSCP_INDEX_2_OFFSET=0x10000>>UTRIE2_SHIFT_2; + static final int UTRIE2_LSCP_INDEX_2_LENGTH=0x400>>UTRIE2_SHIFT_2; + + /** Count the lengths of both BMP pieces. 2080=0x820 */ + static final int UTRIE2_INDEX_2_BMP_LENGTH=UTRIE2_LSCP_INDEX_2_OFFSET+UTRIE2_LSCP_INDEX_2_LENGTH; + + /** + * The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820. + * Length 32=0x20 for lead bytes C0..DF, regardless of UTRIE2_SHIFT_2. + */ + static final int UTRIE2_UTF8_2B_INDEX_2_OFFSET=UTRIE2_INDEX_2_BMP_LENGTH; + static final int UTRIE2_UTF8_2B_INDEX_2_LENGTH=0x800>>6; /* U+0800 is the first code point after 2-byte UTF-8 */ + + /** + * The index-1 table, only used for supplementary code points, at offset 2112=0x840. + * Variable length, for code points up to highStart, where the last single-value range starts. + * Maximum length 512=0x200=0x100000>>UTRIE2_SHIFT_1. + * (For 0x100000 supplementary code points U+10000..U+10ffff.) + * + * The part of the index-2 table for supplementary code points starts + * after this index-1 table. + * + * Both the index-1 table and the following part of the index-2 table + * are omitted completely if there is only BMP data. + */ + static final int UTRIE2_INDEX_1_OFFSET=UTRIE2_UTF8_2B_INDEX_2_OFFSET+UTRIE2_UTF8_2B_INDEX_2_LENGTH; + + /** + * The illegal-UTF-8 data block follows the ASCII block, at offset 128=0x80. + * Used with linear access for single bytes 0..0xbf for simple error handling. + * Length 64=0x40, not UTRIE2_DATA_BLOCK_LENGTH. + */ + static final int UTRIE2_BAD_UTF8_DATA_OFFSET=0x80; + + /** + * Implementation class for an iterator over a Trie2. + * + * Iteration over a Trie2 first returns all of the ranges that are indexed by code points, + * then returns the special alternate values for the lead surrogates + * + * @internal + */ + class Trie2Iterator implements Iterator { + + // The normal constructor that configures the iterator to cover the complete + // contents of the Trie2 + Trie2Iterator(ValueMapper vm) { + mapper = vm; + nextStart = 0; + limitCP = 0x110000; + doLeadSurrogates = true; + } + + /** + * The main next() function for Trie2 iterators + * + */ + public Range next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + if (nextStart >= limitCP) { + // Switch over from iterating normal code point values to + // doing the alternate lead-surrogate values. + doingCodePoints = false; + nextStart = 0xd800; + } + int endOfRange = 0; + int val = 0; + int mappedVal = 0; + + if (doingCodePoints) { + // Iteration over code point values. + val = get(nextStart); + mappedVal = mapper.map(val); + endOfRange = rangeEnd(nextStart, limitCP, val); + // Loop once for each range in the Trie2 with the same raw (unmapped) value. + // Loop continues so long as the mapped values are the same. + for (;;) { + if (endOfRange >= limitCP-1) { + break; + } + val = get(endOfRange+1); + if (mapper.map(val) != mappedVal) { + break; + } + endOfRange = rangeEnd(endOfRange+1, limitCP, val); + } + } else { + // Iteration over the alternate lead surrogate values. + val = getFromU16SingleLead((char)nextStart); + mappedVal = mapper.map(val); + endOfRange = rangeEndLS((char)nextStart); + // Loop once for each range in the Trie2 with the same raw (unmapped) value. + // Loop continues so long as the mapped values are the same. + for (;;) { + if (endOfRange >= 0xdbff) { + break; + } + val = getFromU16SingleLead((char)(endOfRange+1)); + if (mapper.map(val) != mappedVal) { + break; + } + endOfRange = rangeEndLS((char)(endOfRange+1)); + } + } + returnValue.startCodePoint = nextStart; + returnValue.endCodePoint = endOfRange; + returnValue.value = mappedVal; + returnValue.leadSurrogate = !doingCodePoints; + nextStart = endOfRange+1; + return returnValue; + } + + /** + * + */ + public boolean hasNext() { + return doingCodePoints && (doLeadSurrogates || nextStart < limitCP) || nextStart < 0xdc00; + } + + private int rangeEndLS(char startingLS) { + if (startingLS >= 0xdbff) { + return 0xdbff; + } + + int c; + int val = getFromU16SingleLead(startingLS); + for (c = startingLS+1; c <= 0x0dbff; c++) { + if (getFromU16SingleLead((char)c) != val) { + break; + } + } + return c-1; + } + + // + // Iteration State Variables + // + private ValueMapper mapper; + private Range returnValue = new Range(); + // The starting code point for the next range to be returned. + private int nextStart; + // The upper limit for the last normal range to be returned. Normally 0x110000, but + // may be lower when iterating over the code points for a single lead surrogate. + private int limitCP; + + // True while iterating over the Trie2 values for code points. + // False while iterating over the alternate values for lead surrogates. + private boolean doingCodePoints = true; + + // True if the iterator should iterate the special values for lead surrogates in + // addition to the normal values for code points. + private boolean doLeadSurrogates = true; + } + + /** + * Find the last character in a contiguous range of characters with the + * same Trie2 value as the input character. + * + * @param c The character to begin with. + * @return The last contiguous character with the same value. + */ + int rangeEnd(int start, int limitp, int val) { + int c; + int limit = Math.min(highStart, limitp); + + for (c = start+1; c < limit; c++) { + if (get(c) != val) { + break; + } + } + if (c >= highStart) { + c = limitp; + } + return c - 1; + } + + + // + // Hashing implementation functions. FNV hash. Respected public domain algorithm. + // + private static int initHash() { + return 0x811c9DC5; // unsigned 2166136261 + } + + private static int hashByte(int h, int b) { + h = h * 16777619; + h = h ^ b; + return h; + } + + private static int hashUChar32(int h, int c) { + h = Trie2.hashByte(h, c & 255); + h = Trie2.hashByte(h, (c>>8) & 255); + h = Trie2.hashByte(h, c>>16); + return h; + } + + private static int hashInt(int h, int i) { + h = Trie2.hashByte(h, i & 255); + h = Trie2.hashByte(h, (i>>8) & 255); + h = Trie2.hashByte(h, (i>>16) & 255); + h = Trie2.hashByte(h, (i>>24) & 255); + return h; + } + +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/Trie2_16.class b/tests/test_data/std/jdk/internal/icu/impl/Trie2_16.class new file mode 100644 index 0000000000000000000000000000000000000000..f1b86de71afff52e5152b7290ae9e5cf19f1deed GIT binary patch literal 1995 zcmbVMT~8cU7=F%vu)8pnWlO1a%7;p2*=naCP}`+o*_L*7X)zRxu`0vvfgQTc;4q7n zXcOa=-Zi~4RTE2lV|t-UlNv9K*Zu+%|BLvXneDnN-59f(J@0wX`#$g2bIz}S{PZ(` z9Nub02;mqa8lq?s(AP^h4a@eVYnv6rDpn0^W3yshcP%+8&@yS+mNz93P7g0B&$xyJ zS_Qg_t~5P4>pB|?(zVQrwJS>kW9h=WxosM@g@HU>?guZhJ6 zBNJiZH}LQGeg5t5C(wpY4JjNJh+1|@?g)h5%_;Q}4c#~@kSJSg`?rZeBYmc3Sy1&&|AdAvqA%)4JeP z-J+beRCn8ba2`vq;^Qx{;U z5Wv+2|2SU5S?bR5i|{myPMpUSB_fH>sf+OBJN+IW=&AN^(V?dfJ;0!z>exeH<}s3b ze0OZBH@c%I`)@B#DNXO#`Qwj#gA;1o83#Q}@!jPE?P$_?TWMPP>c#}Ms4HgvX=+Z-+iV`0K!e=NGH{uu+H zZ!q(eZ+efJe#KnAMi0L6bI$}2^{6^7VU_`U>NzFqxeIpcN-g*#gDV!LlB)6jkMSax z^m4Skta{(bvxf~lO9gR~7t~WqE5*~(TotEVGAEzlvD1#^A1C7*D mGPtUg)QvHk;Y4dVA-qBJ5Z*+AYl_k!zd6KtH$s?iN&E>#{hW6I literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Trie2_16.java b/tests/test_data/std/jdk/internal/icu/impl/Trie2_16.java new file mode 100644 index 00000000..06bc79ae --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/Trie2_16.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk.internal.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; + + +/** + * @author aheninger + * + * A read-only Trie2, holding 16 bit data values. + * + * A Trie2 is a highly optimized data structure for mapping from Unicode + * code points (values ranging from 0 to 0x10ffff) to a 16 or 32 bit value. + * + * See class Trie2 for descriptions of the API for accessing the contents of a trie. + * + * The fundamental data access methods are declared final in this class, with + * the intent that applications might gain a little extra performance, when compared + * with calling the same methods via the abstract UTrie2 base class. + */ +public final class Trie2_16 extends Trie2 { + + /** + * Internal constructor, not for general use. + */ + Trie2_16() { + } + + + /** + * Create a Trie2 from its serialized form. Inverse of utrie2_serialize(). + * The serialized format is identical between ICU4C and ICU4J, so this function + * will work with serialized Trie2s from either. + * + * The serialized Trie2 in the bytes may be in either little or big endian byte order. + * This allows using serialized Tries from ICU4C without needing to consider the + * byte order of the system that created them. + * + * @param bytes a byte buffer to the serialized form of a UTrie2. + * @return An unserialized Trie2_16, ready for use. + * @throws IllegalArgumentException if the buffer does not contain a serialized Trie2. + * @throws IOException if a read error occurs in the buffer. + * @throws ClassCastException if the bytes contain a serialized Trie2_32 + */ + public static Trie2_16 createFromSerialized(ByteBuffer bytes) throws IOException { + return (Trie2_16) Trie2.createFromSerialized(bytes); + } + + /** + * Get the value for a code point as stored in the Trie2. + * + * @param codePoint the code point + * @return the value + */ + @Override + public final int get(int codePoint) { + int value; + int ix; + + if (codePoint >= 0) { + if (codePoint < 0x0d800 || (codePoint > 0x0dbff && codePoint <= 0x0ffff)) { + // Ordinary BMP code point, excluding leading surrogates. + // BMP uses a single level lookup. BMP index starts at offset 0 in the Trie2 index. + // 16 bit data is stored in the index array itself. + ix = index[codePoint >> UTRIE2_SHIFT_2]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint <= 0xffff) { + // Lead Surrogate Code Point. A Separate index section is stored for + // lead surrogate code units and code points. + // The main index has the code unit data. + // For this function, we need the code point data. + // Note: this expression could be refactored for slightly improved efficiency, but + // surrogate code points will be so rare in practice that it's not worth it. + ix = index[UTRIE2_LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> UTRIE2_SHIFT_2)]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint < highStart) { + // Supplemental code point, use two-level lookup. + ix = (UTRIE2_INDEX_1_OFFSET - UTRIE2_OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> UTRIE2_SHIFT_1); + ix = index[ix]; + ix += (codePoint >> UTRIE2_SHIFT_2) & UTRIE2_INDEX_2_MASK; + ix = index[ix]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint <= 0x10ffff) { + value = index[highValueIndex]; + return value; + } + } + + // Fall through. The code point is outside of the legal range of 0..0x10ffff. + return errorValue; + } + + + /** + * Get a Trie2 value for a UTF-16 code unit. + * + * This function returns the same value as get() if the input + * character is outside of the lead surrogate range + * + * There are two values stored in a Trie2 for inputs in the lead + * surrogate range. This function returns the alternate value, + * while Trie2.get() returns the main value. + * + * @param codeUnit a 16 bit code unit or lead surrogate value. + * @return the value + */ + @Override + public int getFromU16SingleLead(char codeUnit) { + int value; + int ix; + + // Because the input is a 16 bit char, we can skip the tests for it being in + // the BMP range. It is. + ix = index[codeUnit >> UTRIE2_SHIFT_2]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codeUnit & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + + /** + * @return the number of bytes of the serialized trie + */ + public int getSerializedLength() { + return 16+(header.indexLength+dataLength)*2; + } +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/UBiDiProps$IsAcceptable.class b/tests/test_data/std/jdk/internal/icu/impl/UBiDiProps$IsAcceptable.class new file mode 100644 index 0000000000000000000000000000000000000000..c3b185f8e0fd67242eb05ac6145aa088445203e9 GIT binary patch literal 695 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 zp&expectedTrieLength) { + throw new IOException(DATA_FILE_NAME+": not enough bytes for the trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength-trieLength); + + // read mirrors[] + count=indexes[IX_MIRROR_LENGTH]; + if(count>0) { + mirrors=new int[count]; + for(i=0; i>JT_SHIFT; + } + + public final int getJoiningGroup(int c) { + int start, limit; + + start=indexes[IX_JG_START]; + limit=indexes[IX_JG_LIMIT]; + if(start<=c && c>BPT_SHIFT; + } + + public final int getPairedBracket(int c) { + int props=trie.get(c); + if((props&BPT_MASK)==0) { + return c; + } else { + return getMirror(c, props); + } + } + + // data members -------------------------------------------------------- *** + private int indexes[]; + private int mirrors[]; + private byte jgArray[]; + private byte jgArray2[]; + + private Trie2_16 trie; + + // data format constants ----------------------------------------------- *** + @SuppressWarnings("deprecation") + private static final String DATA_FILE_NAME = + "/jdk/internal/icu/impl/data/icudt" + + VersionInfo.ICU_DATA_VERSION_PATH + + "/ubidi.icu"; + + /* format "BiDi" */ + private static final int FMT=0x42694469; + + /* indexes into indexes[] */ + private static final int IX_TRIE_SIZE=2; + private static final int IX_MIRROR_LENGTH=3; + + private static final int IX_JG_START=4; + private static final int IX_JG_LIMIT=5; + private static final int IX_JG_START2=6; /* new in format version 2.2, ICU 54 */ + private static final int IX_JG_LIMIT2=7; + + private static final int IX_TOP=16; + + // definitions for 16-bit bidi/shaping properties word ----------------- *** + + /* CLASS_SHIFT=0, */ /* bidi class: 5 bits (4..0) */ + private static final int JT_SHIFT=5; /* joining type: 3 bits (7..5) */ + + private static final int BPT_SHIFT=8; /* Bidi_Paired_Bracket_Type(bpt): 2 bits (9..8) */ + + private static final int MIRROR_DELTA_SHIFT=13; /* bidi mirroring delta: 3 bits (15..13) */ + + private static final int CLASS_MASK= 0x0000001f; + private static final int JT_MASK= 0x000000e0; + private static final int BPT_MASK= 0x00000300; + + private static final int getClassFromProps(int props) { + return props&CLASS_MASK; + } + private static final boolean getFlagFromProps(int props, int shift) { + return ((props>>shift)&1)!=0; + } + private static final int getMirrorDeltaFromProps(int props) { + return (short)props>>MIRROR_DELTA_SHIFT; + } + + private static final int ESC_MIRROR_DELTA=-4; + + // definitions for 32-bit mirror table entry --------------------------- *** + + /* the source Unicode code point takes 21 bits (20..0) */ + private static final int MIRROR_INDEX_SHIFT=21; + + private static final int getMirrorCodePoint(int m) { + return m&0x1fffff; + } + private static final int getMirrorIndex(int m) { + return m>>>MIRROR_INDEX_SHIFT; + } + + + /* + * public singleton instance + */ + public static final UBiDiProps INSTANCE; + + // This static initializer block must be placed after + // other static member initialization + static { + try { + INSTANCE = new UBiDiProps(); + } catch (IOException e) { + throw new MissingResourceException(e.getMessage(),DATA_FILE_NAME,""); + } + } +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$1.class b/tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$1.class new file mode 100644 index 0000000000000000000000000000000000000000..88f457b65d9ad328e860540855ab56faf7ada3ca GIT binary patch literal 883 zcma)4T~8B16g`8byVTW|0;1vv#cB$O)i+~_iL4kmDNPe<--qpl4s3Uu-Khz0{vcoU zK@%VR0saHye=(jZh(>JEP4?coXYM`s+?o0I^UGHNJ{}Y>gG&x_9%hjjczV=3uIt#S zG?r0ahoib445RuRzb{i65^kr-P^IRix}#s}AU3~af&8|PwRtYERclVm(pc}#!Nr_| zf``lS1Xd@M+IF^ACg29G{mzS)zbmjdsndCSqd@+v9*QUlEFLP;mO53v9ZqwsOy^{% z1ah@tJ#bJK*qG4$;`mQk<|jQ?7n?d(tr5$+?5h*v5P)1#uY8#({In&n^|8SDx z|FmfEP;FK9F_leS$EwnvGX132=A8``FU=krNAJpLM0q0Q9|#oolTjL~SK4Y`zIert zj^ta(`F7(lN-`ZEp0YYv6R1slQ0&}NnR%ULM!*Z=Sfzd>vrJJ_@t-$@Rm}4_+Rs`( zNcsh?p3z$*zp?ol;=_1<(Z&$8-?2n{?KFdanUUSQjvL&+$@MJL-j%pmL5Yy1+&-gp zKf+o0ge&if&EOB|kH1LWb5a+#aGMM{+!^QJrDQOw(B2y(6;$cVWA+N})6X;J_Y1Y% B+QHesQ(WV@L7vpku2@T3=i zlyM+<055fu**Ei&_hxtI>-+5;fRB9(219K$7<)3(LPb3EWH9sOWEy&p{*Wsk5ZzVr zR4Dyy!$j6X&VhwI!%13QwH4`K4~E=@jHJF~Xw=$i9h$9r&w|ZxmR3={lGk#j@9{s{ z)q4!49}fgWsVyVXnN9jaJ@9@=Ot~EgJnV5L=k<~_^-v}Z=c&K6{=g=KdnfcT9&~B! z6G3w)Kl?tOsX*MwdE?68l{7~Di8JIoBGI>Tq8Xf46ba>rJV^u@6jx?YTAK6fin zllT(!P^6G7c{}s6Z|7xpm){?s09>?6u#mHnuV4e43}>^+vm=!eTJgY<{=$*rJa8V} zDc9Vm^iW50q0MXCQ|1pdY@SOc%>_fZ)6cp?&pRI3C@@@Qt!TSZI3^+Wix*)!H8>_@ZV(KOl8b)ow?cd(mne7I9h0*w3x?GyAx&_ zO@`!GD9A99Dcz^vZ)DO>^S_tf8Gqpng@K68Z4?_Ddkmedt}s+QrG!pB5hPb$F{ZWF zG#tUE(@!2oFP%TJBB4vES!r8$k;tipgaGmbCB-WkUNYw^6|sF)F||s+6k{ gF4EFk0ziB1P_$6TZaO!p5X3AR4Kyj*G#|kF0c#|)eEfgc5Ph4t`E=VPq)D5$dQhP%65>D5Wk2^ zp`p-2e*ixU@pdVpz$IAn&g{(2ytgy6-@c!n1L&ZYMFPn*G#ztD2|O6~58JLEJE3oR zZPy;R-O-WPe$^RRp=Hy&7Y0X87{9HXe*8-pNW}v;s&5Jy+p{Lv${~Yn8aW+#=mLeI z^~P#@mVeOR?F}6}X4Xfp@5YY>l8t6p5?#=-hyopU;EhMVfH0-Gq~nS-Ya=TG3w34Ltn@~xCo|4cP68cI)XNpXP(TtsvDdRSQ6ACy> z*A(~;?n09oBQ$>R~d~Rr}^9DAQ QT*f`h96bp>rTa+y0PN-B*Z=?k literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$IsAcceptable.class b/tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty$IsAcceptable.class new file mode 100644 index 0000000000000000000000000000000000000000..4408456746eedd032eb5d3f8ee5f864ee3bb5e14 GIT binary patch literal 728 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty.java b/tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty.java new file mode 100644 index 00000000..474b169e --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/UCharacterProperty.java @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk.internal.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.MissingResourceException; + +import jdk.internal.icu.lang.UCharacter.HangulSyllableType; +import jdk.internal.icu.lang.UCharacter.NumericType; +import jdk.internal.icu.text.UTF16; +import jdk.internal.icu.text.UnicodeSet; +import jdk.internal.icu.util.VersionInfo; + +/** +*

Internal class used for Unicode character property database.

+*

This classes store binary data read from uprops.icu. +* It does not have the capability to parse the data into more high-level +* information. It only returns bytes of information when required.

+*

Due to the form most commonly used for retrieval, array of char is used +* to store the binary data.

+*

UCharacterPropertyDB also contains information on accessing indexes to +* significant points in the binary data.

+*

Responsibility for molding the binary data into more meaning form lies on +* UCharacter.

+* @author Syn Wee Quek +* @since release 2.1, february 1st 2002 +*/ + +public final class UCharacterProperty +{ + // public data members ----------------------------------------------- + + /* + * public singleton instance + */ + public static final UCharacterProperty INSTANCE; + + /** + * Trie data + */ + public Trie2_16 m_trie_; + + /** + * Unicode version + */ + public VersionInfo m_unicodeVersion_; + + /** + * Character type mask + */ + public static final int TYPE_MASK = 0x1F; + + // uprops.h enum UPropertySource --------------------------------------- *** + + /** From uchar.c/uprops.icu main trie */ + public static final int SRC_CHAR=1; + /** From uchar.c/uprops.icu properties vectors trie */ + public static final int SRC_PROPSVEC=2; + /** From ubidi_props.c/ubidi.icu */ + public static final int SRC_BIDI=5; + /** From normalizer2impl.cpp/nfc.nrm */ + public static final int SRC_NFC=8; + /** From normalizer2impl.cpp/nfkc.nrm */ + public static final int SRC_NFKC=9; + + // public methods ---------------------------------------------------- + + /** + * Gets the main property value for code point ch. + * @param ch code point whose property value is to be retrieved + * @return property value of code point + */ + public final int getProperty(int ch) + { + return m_trie_.get(ch); + } + + /** + * Gets the unicode additional properties. + * Java version of C u_getUnicodeProperties(). + * @param codepoint codepoint whose additional properties is to be + * retrieved + * @param column The column index. + * @return unicode properties + */ + public int getAdditional(int codepoint, int column) { + assert column >= 0; + if (column >= m_additionalColumnsCount_) { + return 0; + } + return m_additionalVectors_[m_additionalTrie_.get(codepoint) + column]; + } + + /** + *

Get the "age" of the code point.

+ *

The "age" is the Unicode version when the code point was first + * designated (as a non-character or for Private Use) or assigned a + * character.

+ *

This can be useful to avoid emitting code points to receiving + * processes that do not accept newer characters.

+ *

The data is from the UCD file DerivedAge.txt.

+ *

This API does not check the validity of the codepoint.

+ * @param codepoint The code point. + * @return the Unicode version number + */ + public VersionInfo getAge(int codepoint) + { + int version = getAdditional(codepoint, 0) >> AGE_SHIFT_; + return VersionInfo.getInstance( + (version >> FIRST_NIBBLE_SHIFT_) & LAST_NIBBLE_MASK_, + version & LAST_NIBBLE_MASK_, 0, 0); + } + + // int-value and enumerated properties --------------------------------- *** + + public int getType(int c) { + return getProperty(c)&TYPE_MASK; + } + + /* + * Map some of the Grapheme Cluster Break values to Hangul Syllable Types. + * Hangul_Syllable_Type is fully redundant with a subset of Grapheme_Cluster_Break. + */ + private static final int /* UHangulSyllableType */ gcbToHst[]={ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_OTHER */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_CONTROL */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_CR */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_EXTEND */ + HangulSyllableType.LEADING_JAMO, /* U_GCB_L */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_LF */ + HangulSyllableType.LV_SYLLABLE, /* U_GCB_LV */ + HangulSyllableType.LVT_SYLLABLE, /* U_GCB_LVT */ + HangulSyllableType.TRAILING_JAMO, /* U_GCB_T */ + HangulSyllableType.VOWEL_JAMO /* U_GCB_V */ + /* + * Omit GCB values beyond what we need for hst. + * The code below checks for the array length. + */ + }; + + private class IntProperty { + int column; // SRC_PROPSVEC column, or "source" if mask==0 + int mask; + int shift; + + IntProperty(int column, int mask, int shift) { + this.column=column; + this.mask=mask; + this.shift=shift; + } + + IntProperty(int source) { + this.column=source; + this.mask=0; + } + + int getValue(int c) { + // systematic, directly stored properties + return (getAdditional(c, column)&mask)>>>shift; + } + } + + private class BiDiIntProperty extends IntProperty { + BiDiIntProperty() { + super(SRC_BIDI); + } + } + + private class CombiningClassIntProperty extends IntProperty { + CombiningClassIntProperty(int source) { + super(source); + } + } + + private class NormQuickCheckIntProperty extends IntProperty { // UCHAR_NF*_QUICK_CHECK properties + int which; + int max; + + NormQuickCheckIntProperty(int source, int which, int max) { + super(source); + this.which=which; + this.max=max; + } + } + + private IntProperty intProp = new BiDiIntProperty() { // BIDI_PAIRED_BRACKET_TYPE + int getValue(int c) { + return UBiDiProps.INSTANCE.getPairedBracketType(c); + } + }; + + public int getIntPropertyValue(int c, int which) { + if (which == BIDI_PAIRED_BRACKET_TYPE) { + return intProp.getValue(c); + } + return 0; // undefined + } + + /** + * Forms a supplementary code point from the argument character
+ * Note this is for internal use hence no checks for the validity of the + * surrogate characters are done + * @param lead lead surrogate character + * @param trail trailing surrogate character + * @return code point of the supplementary character + */ + public static int getRawSupplementary(char lead, char trail) + { + return (lead << LEAD_SURROGATE_SHIFT_) + trail + SURROGATE_OFFSET_; + } + + /** + * Gets the type mask + * @param type character type + * @return mask + */ + public static final int getMask(int type) + { + return 1 << type; + } + + /** + * Returns the digit values of characters like 'A' - 'Z', normal, + * half-width and full-width. This method assumes that the other digit + * characters are checked by the calling method. + * @param ch character to test + * @return -1 if ch is not a character of the form 'A' - 'Z', otherwise + * its corresponding digit will be returned. + */ + public static int getEuropeanDigit(int ch) { + if ((ch > 0x7a && ch < 0xff21) + || ch < 0x41 || (ch > 0x5a && ch < 0x61) + || ch > 0xff5a || (ch > 0xff3a && ch < 0xff41)) { + return -1; + } + if (ch <= 0x7a) { + // ch >= 0x41 or ch < 0x61 + return ch + 10 - ((ch <= 0x5a) ? 0x41 : 0x61); + } + // ch >= 0xff21 + if (ch <= 0xff3a) { + return ch + 10 - 0xff21; + } + // ch >= 0xff41 && ch <= 0xff5a + return ch + 10 - 0xff41; + } + + public int digit(int c) { + int value = getNumericTypeValue(getProperty(c)) - NTV_DECIMAL_START_; + if(value<=9) { + return value; + } else { + return -1; + } + } + + // protected variables ----------------------------------------------- + + /** + * Extra property trie + */ + Trie2_16 m_additionalTrie_; + /** + * Extra property vectors, 1st column for age and second for binary + * properties. + */ + int m_additionalVectors_[]; + /** + * Number of additional columns + */ + int m_additionalColumnsCount_; + /** + * Maximum values for block, bits used as in vector word + * 0 + */ + int m_maxBlockScriptValue_; + /** + * Maximum values for script, bits used as in vector word + * 0 + */ + int m_maxJTGValue_; + /** + * Script_Extensions data + */ + public char[] m_scriptExtensions_; + + // private variables ------------------------------------------------- + + /** + * Default name of the datafile + */ + @SuppressWarnings("deprecation") + private static final String DATA_FILE_NAME_ = + "/jdk/internal/icu/impl/data/icudt" + + VersionInfo.ICU_DATA_VERSION_PATH + + "/uprops.icu"; + + /** + * Shift value for lead surrogate to form a supplementary character. + */ + private static final int LEAD_SURROGATE_SHIFT_ = 10; + /** + * Offset to add to combined surrogate pair to avoid masking. + */ + private static final int SURROGATE_OFFSET_ = + UTF16.SUPPLEMENTARY_MIN_VALUE - + (UTF16.SURROGATE_MIN_VALUE << + LEAD_SURROGATE_SHIFT_) - + UTF16.TRAIL_SURROGATE_MIN_VALUE; + + + // property data constants ------------------------------------------------- + + /** + * Numeric types and values in the main properties words. + */ + private static final int NUMERIC_TYPE_VALUE_SHIFT_ = 6; + private static final int getNumericTypeValue(int props) { + return props >> NUMERIC_TYPE_VALUE_SHIFT_; + } + + /* constants for the storage form of numeric types and values */ + /** No numeric value. */ + private static final int NTV_NONE_ = 0; + /** Decimal digits: nv=0..9 */ + private static final int NTV_DECIMAL_START_ = 1; + /** Other digits: nv=0..9 */ + private static final int NTV_DIGIT_START_ = 11; + /** Small integers: nv=0..154 */ + private static final int NTV_NUMERIC_START_ = 21; + + private static final int ntvGetType(int ntv) { + return + (ntv==NTV_NONE_) ? NumericType.NONE : + (ntv> SCRIPT_HIGH_SHIFT) | + (scriptX & SCRIPT_LOW_MASK); + } + + /** + * Additional properties used in internal trie data + */ + /* + * Properties in vector word 1 + * Each bit encodes one binary property. + * The following constants represent the bit number, use 1< expectedTrieLength) { + throw new IOException("uprops.icu: not enough bytes for main trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // skip unused intervening data structures + ICUBinary.skipBytes(bytes, (additionalOffset - propertyOffset) * 4); + + if(m_additionalColumnsCount_ > 0) { + // reads the additional property block + m_additionalTrie_ = Trie2_16.createFromSerialized(bytes); + expectedTrieLength = (additionalVectorsOffset-additionalOffset)*4; + trieLength = m_additionalTrie_.getSerializedLength(); + if(trieLength > expectedTrieLength) { + throw new IOException("uprops.icu: not enough bytes for additional-properties trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // additional properties + int size = scriptExtensionsOffset - additionalVectorsOffset; + m_additionalVectors_ = new int[size]; + for (int i = 0; i < size; i ++) { + m_additionalVectors_[i] = bytes.getInt(); + } + } + + // Script_Extensions + int numChars = (reservedOffset7 - scriptExtensionsOffset) * 2; + if(numChars > 0) { + m_scriptExtensions_ = new char[numChars]; + for(int i = 0; i < numChars; ++i) { + m_scriptExtensions_[i] = bytes.getChar(); + } + } + } + + private static final class IsAcceptable implements ICUBinary.Authenticate { + // @Override when we switch to Java 6 + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 7; + } + } + + private static final int DATA_FORMAT = 0x5550726F; // "UPro" + + public void upropsvec_addPropertyStarts(UnicodeSet set) { + /* add the start code point of each same-value range of the properties vectors trie */ + if(m_additionalColumnsCount_>0) { + /* if m_additionalColumnsCount_==0 then the properties vectors trie may not be there at all */ + Iterator trieIterator = m_additionalTrie_.iterator(); + Trie2.Range range; + while(trieIterator.hasNext() && !(range=trieIterator.next()).leadSurrogate) { + set.add(range.startCodePoint); + } + } + } + + // This static initializer block must be placed after + // other static member initialization + static { + try { + INSTANCE = new UCharacterProperty(); + } + catch (IOException e) { + throw new MissingResourceException(e.getMessage(),DATA_FILE_NAME_,""); + } + } + + + // Moved from UProperty.java + /** + * Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). + * Used in UAX #9: Unicode Bidirectional Algorithm + * (http://www.unicode.org/reports/tr9/) + * Returns UCharacter.BidiPairedBracketType values. + * @stable ICU 52 + */ + public static final int BIDI_PAIRED_BRACKET_TYPE = 0x1015; + +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/UnicodeSetStringSpan$OffsetList.class b/tests/test_data/std/jdk/internal/icu/impl/UnicodeSetStringSpan$OffsetList.class new file mode 100644 index 0000000000000000000000000000000000000000..34a5d596f7e0e95f0a26434d007fc6d6c2f82800 GIT binary patch literal 2739 zcma);+fx&F6vw~6WgNZjakJ!@4w{)vVUBix=~{J!0g^CpYEI z^IRfG4!0=SDuVlxrmp2ghzbRj*haBU-MVDYF|dSqU8SH}y!Pd7EoX~2wF>I6onc$6 zme1=s+sIh?V@6(^HT4u(P5TjLs9jGgzP4*Pm&@dWh`<{_BbxkZR?s4RH*QL)U>jy^ ztYBvgcETcf-&M^l=zg>^sGBxFG5;W*LYp7$3Ob-NY+Yv>GKrm`I;H20oSrHoj@z1D zpbw<`G)Xo@ijv)kVdR!TQ*jV!fP%IN^A zYDTsKLq+jr+)52)3R2zngbd|NI_oXTjAd(vm0zcjeUY1N^>fOC;zqntq@s&{$`p(TVL4cvfo-iR9B zjAq_a3|xW=bjxt$(?t-01MsZS$@3>f`2A4b@JH$H=yngG1^D?Qxc6=`ML`L^^D%k} zpFViX28Df3QMxZk86s4#}A4;-? zIstqSA$8G)y{P5gl<0o6^B(Nw2XTNOl2}bnyrSClMW*j3CLx4J>h2fm*Rnc-Jy?Xj z9Q4bPzoT!fy^)bZwFnaiL4Du5j zh~q`#I1ahQhc^>f6Y*j6(p9wiuS85uhbc+6HTu~@P$c+3y?|RL!JUWHfLPaeE}%v} zL^n_`A}p&?-+7xlTx^Sut!JVlNSTbGl0S<&eg-Z4EL46D`}hP7^GTfG=W&K#zy&@n zvr-+fVpdabRs@SaS%*3d%KW^tA_1Dm71Xe(XvlsHxEbD{f{6xdBcOk6phsKPnZ_AX zUL)maN%_2heEq;3zd;SD}yGUm2BOP^CDYUQL`>rGe1qL=wdILXt3k-#HD(Q!@GiNCXtWQ ze>f7EJx_ZD^1MLqzv*GlsYVcjhk8^=#<3sbv@Dctol0=ugC5*q67F0L+% zz2ZWjz3u={_3#A*$ot~zZ<|~_>LWU{exjU3nB=$yAAbcE{8ehL*U-RU$4-8o2IU3~ z${XnAZ(^9gMJ@I=PVx6J!QaPuK93~-00#dMS^g2O@sDwxe}Z@Ur&7w3Gy8r+H literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/UnicodeSetStringSpan.class b/tests/test_data/std/jdk/internal/icu/impl/UnicodeSetStringSpan.class new file mode 100644 index 0000000000000000000000000000000000000000..356707ecc7482a4f64d6f8f0188693d0734f42ec GIT binary patch literal 11894 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. */ + static final short LONG_SPAN = ALL_CP_CONTAINED - 1; + + /** Set for span(). Same as parent but without strings. */ + private UnicodeSet spanSet; + + /** + * Set for span(not contained). + * Same as spanSet, plus characters that start or end strings. + */ + private UnicodeSet spanNotSet; + + /** The strings of the parent set. */ + private ArrayList strings; + + /** The lengths of span(), spanBack() etc. for each string. */ + private short[] spanLengths; + + /** Maximum lengths of relevant strings. */ + private int maxLength16; + + /** Are there strings that are not fully contained in the code point set? */ + private boolean someRelevant; + + /** Set up for all variants of span()? */ + private boolean all; + + /** Span helper */ + private OffsetList offsets; + + /** + * Constructs for all variants of span(), or only for any one variant. + * Initializes as little as possible, for single use. + */ + public UnicodeSetStringSpan(final UnicodeSet set, final ArrayList setStrings, int which) { + spanSet = new UnicodeSet(0, 0x10ffff); + // TODO: With Java 6, just take the parent set's strings as is, + // as a NavigableSet, rather than as an ArrayList copy of the set of strings. + // Then iterate via the first() and higher() methods. + // (We do not want to create multiple Iterator objects in each span().) + // See ICU ticket #7454. + strings = setStrings; + all = (which == ALL); + spanSet.retainAll(set); + if (0 != (which & NOT_CONTAINED)) { + // Default to the same sets. + // addToSpanNotSet() will create a separate set if necessary. + spanNotSet = spanSet; + } + offsets = new OffsetList(); + + // Determine if the strings even need to be taken into account at all for span() etc. + // If any string is relevant, then all strings need to be used for + // span(longest match) but only the relevant ones for span(while contained). + // TODO: Possible optimization: Distinguish CONTAINED vs. LONGEST_MATCH + // and do not store UTF-8 strings if !thisRelevant and CONTAINED. + // (Only store irrelevant UTF-8 strings for LONGEST_MATCH where they are relevant after all.) + // Also count the lengths of the UTF-8 versions of the strings for memory allocation. + int stringsLength = strings.size(); + + int i, spanLength; + someRelevant = false; + for (i = 0; i < stringsLength;) { + String string = strings.get(i); + int length16 = string.length(); + if (length16 == 0) { + // Remove the empty string. + strings.remove(i); + --stringsLength; + continue; + } + spanLength = spanSet.span(string, SpanCondition.CONTAINED); + if (spanLength < length16) { // Relevant string. + someRelevant = true; + } + if (/* (0 != (which & UTF16)) && */ length16 > maxLength16) { + maxLength16 = length16; + } + ++i; + } + if (!someRelevant && (which & WITH_COUNT) == 0) { + return; + } + + // Freeze after checking for the need to use strings at all because freezing + // a set takes some time and memory which are wasted if there are no relevant strings. + if (all) { + spanSet.freeze(); + } + + int spanBackLengthsOffset; + + // Allocate a block of meta data. + int allocSize; + if (all) { + // 2 sets of span lengths + allocSize = stringsLength * (2); + } else { + allocSize = stringsLength; // One set of span lengths. + } + spanLengths = new short[allocSize]; + + if (all) { + // Store span lengths for all span() variants. + spanBackLengthsOffset = stringsLength; + } else { + // Store span lengths for only one span() variant. + spanBackLengthsOffset = 0; + } + + // Set the meta data and spanNotSet and write the UTF-8 strings. + + for (i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + spanLength = spanSet.span(string, SpanCondition.CONTAINED); + if (spanLength < length16) { // Relevant string. + if (true /* 0 != (which & UTF16) */) { + if (0 != (which & CONTAINED)) { + if (0 != (which & FWD)) { + spanLengths[i] = makeSpanLengthByte(spanLength); + } + if (0 != (which & BACK)) { + spanLength = length16 + - spanSet.spanBack(string, length16, SpanCondition.CONTAINED); + spanLengths[spanBackLengthsOffset + i] = makeSpanLengthByte(spanLength); + } + } else /* not CONTAINED, not all, but NOT_CONTAINED */{ + spanLengths[i] = spanLengths[spanBackLengthsOffset + i] = 0; // Only store a relevant/irrelevant + // flag. + } + } + if (0 != (which & NOT_CONTAINED)) { + // Add string start and end code points to the spanNotSet so that + // a span(while not contained) stops before any string. + int c; + if (0 != (which & FWD)) { + c = string.codePointAt(0); + addToSpanNotSet(c); + } + if (0 != (which & BACK)) { + c = string.codePointBefore(length16); + addToSpanNotSet(c); + } + } + } else { // Irrelevant string. + if (all) { + spanLengths[i] = spanLengths[spanBackLengthsOffset + i] = ALL_CP_CONTAINED; + } else { + // All spanXYZLengths pointers contain the same address. + spanLengths[i] = ALL_CP_CONTAINED; + } + } + } + + // Finish. + if (all) { + spanNotSet.freeze(); + } + } + + /** + * Do the strings need to be checked in span() etc.? + * + * @return true if strings need to be checked (call span() here), + * false if not (use a BMPSet for best performance). + */ + public boolean needsStringSpanUTF16() { + return someRelevant; + } + + /** For fast UnicodeSet::contains(c). */ + public boolean contains(int c) { + return spanSet.contains(c); + } + + /** + * Adds a starting or ending string character to the spanNotSet + * so that a character span ends before any string. + */ + private void addToSpanNotSet(int c) { + if (spanNotSet == null || spanNotSet == spanSet) { + if (spanSet.contains(c)) { + return; // Nothing to do. + } + spanNotSet = spanSet.cloneAsThawed(); + } + spanNotSet.add(c); + } + + /* + * Note: In span() when spanLength==0 + * (after a string match, or at the beginning after an empty code point span) + * and in spanNot() and spanNotUTF8(), + * string matching could use a binary search because all string matches are done + * from the same start index. + * + * For UTF-8, this would require a comparison function that returns UTF-16 order. + * + * This optimization should not be necessary for normal UnicodeSets because most sets have no strings, and most sets + * with strings have very few very short strings. For cases with many strings, it might be better to use a different + * API and implementation with a DFA (state machine). + */ + + /* + * Algorithm for span(SpanCondition.CONTAINED) + * + * Theoretical algorithm: + * - Iterate through the string, and at each code point boundary: + * + If the code point there is in the set, then remember to continue after it. + * + If a set string matches at the current position, then remember to continue after it. + * + Either recursively span for each code point or string match, or recursively span + * for all but the shortest one and iteratively continue the span with the shortest local match. + * + Remember the longest recursive span (the farthest end point). + * + If there is no match at the current position, + * neither for the code point there nor for any set string, + * then stop and return the longest recursive span length. + * + * Optimized implementation: + * + * (We assume that most sets will have very few very short strings. + * A span using a string-less set is extremely fast.) + * + * Create and cache a spanSet which contains all of the single code points of the original set + * but none of its strings. + * + * - Start with spanLength=spanSet.span(SpanCondition.CONTAINED). + * - Loop: + * + Try to match each set string at the end of the spanLength. + * ~ Set strings that start with set-contained code points + * must be matched with a partial overlap + * because the recursive algorithm would have tried to match them at every position. + * ~ Set strings that entirely consist of set-contained code points + * are irrelevant for span(SpanCondition.CONTAINED) + * because the recursive algorithm would continue after them anyway and + * find the longest recursive match from their end. + * ~ Rather than recursing, note each end point of a set string match. + * + If no set string matched after spanSet.span(), + * then return with where the spanSet.span() ended. + * + If at least one set string matched after spanSet.span(), + * then pop the shortest string match end point and continue the loop, + * trying to match all set strings from there. + * + If at least one more set string matched after a previous string match, then test if the + * code point after the previous string match is also contained in the set. + * Continue the loop with the shortest end point of + * either this code point or a matching set string. + * + If no more set string matched after a previous string match, + * then try another spanLength=spanSet.span(SpanCondition.CONTAINED). + * Stop if spanLength==0, otherwise continue the loop. + * + * By noting each end point of a set string match, the function visits each string position at most once and + * finishes in linear time. + * + * The recursive algorithm may visit the same string position many times + * if multiple paths lead to it and finishes in exponential time. + */ + + /* + * Algorithm for span(SIMPLE) + * + * Theoretical algorithm: + * - Iterate through the string, and at each code point boundary: + * + If the code point there is in the set, then remember to continue after it. + * + If a set string matches at the current position, then remember to continue after it. + * + Continue from the farthest match position and ignore all others. + * + If there is no match at the current position, then stop and return the current position. + * + * Optimized implementation: + * + * (Same assumption and spanSet as above.) + * + * - Start with spanLength=spanSet.span(SpanCondition.CONTAINED). + * - Loop: + * + Try to match each set string at the end of the spanLength. + * ~ Set strings that start with set-contained code points + * must be matched with a partial overlap + * because the standard algorithm would have tried to match them earlier. + * ~ Set strings that entirely consist of set-contained code points + * must be matched with a full overlap because the longest-match algorithm + * would hide set string matches that end earlier. + * Such set strings need not be matched earlier inside the code point span + * because the standard algorithm would then have + * continued after the set string match anyway. + * ~ Remember the longest set string match (farthest end point) + * from the earliest starting point. + * + If no set string matched after spanSet.span(), + * then return with where the spanSet.span() ended. + * + If at least one set string matched, + * then continue the loop after the longest match from the earliest position. + * + If no more set string matched after a previous string match, + * then try another spanLength=spanSet.span(SpanCondition.CONTAINED). + * Stop if spanLength==0, otherwise continue the loop. + */ + /** + * Spans a string. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @return the limit (exclusive end) of the span + */ + public int span(CharSequence s, int start, SpanCondition spanCondition) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNot(s, start, null); + } + int spanLimit = spanSet.span(s, start, SpanCondition.CONTAINED); + if (spanLimit == s.length()) { + return spanLimit; + } + return spanWithStrings(s, start, spanLimit, spanCondition); + } + + /** + * Synchronized method for complicated spans using the offsets. + * Avoids synchronization for simple cases. + * + * @param spanLimit = spanSet.span(s, start, CONTAINED) + */ + private synchronized int spanWithStrings(CharSequence s, int start, int spanLimit, + SpanCondition spanCondition) { + // Consider strings; they may overlap with the span. + int initSize = 0; + if (spanCondition == SpanCondition.CONTAINED) { + // Use offset list to try all possibilities. + initSize = maxLength16; + } + offsets.setMaxLength(initSize); + int length = s.length(); + int pos = spanLimit, rest = length - spanLimit; + int spanLength = spanLimit - start; + int i, stringsLength = strings.size(); + for (;;) { + if (spanCondition == SpanCondition.CONTAINED) { + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[i]; + if (overlap == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-overlap..pos. + if (overlap >= LONG_SPAN) { + overlap = length16; + // While contained: No point matching fully inside the code point span. + overlap = string.offsetByCodePoints(overlap, -1); // Length of the string minus the last code + // point. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int inc = length16 - overlap; // Keep overlap+inc==length16. + for (;;) { + if (inc > rest) { + break; + } + // Try to match if the increment is not listed already. + if (!offsets.containsOffset(inc) && matches16CPB(s, pos - overlap, length, string, length16)) { + if (inc == rest) { + return length; // Reached the end of the string. + } + offsets.addOffset(inc); + } + if (overlap == 0) { + break; + } + --overlap; + ++inc; + } + } + } else /* SIMPLE */{ + int maxInc = 0, maxOverlap = 0; + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[i]; + // For longest match, we do need to try to match even an all-contained string + // to find the match from the earliest start. + + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-overlap..pos. + if (overlap >= LONG_SPAN) { + overlap = length16; + // Longest match: Need to match fully inside the code point span + // to find the match from the earliest start. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int inc = length16 - overlap; // Keep overlap+inc==length16. + for (;;) { + if (inc > rest || overlap < maxOverlap) { + break; + } + // Try to match if the string is longer or starts earlier. + if ((overlap > maxOverlap || /* redundant overlap==maxOverlap && */inc > maxInc) + && matches16CPB(s, pos - overlap, length, string, length16)) { + maxInc = inc; // Longest match from earliest start. + maxOverlap = overlap; + break; + } + --overlap; + ++inc; + } + } + + if (maxInc != 0 || maxOverlap != 0) { + // Longest-match algorithm, and there was a string match. + // Simply continue after it. + pos += maxInc; + rest -= maxInc; + if (rest == 0) { + return length; // Reached the end of the string. + } + spanLength = 0; // Match strings from after a string match. + continue; + } + } + // Finished trying to match all strings at pos. + + if (spanLength != 0 || pos == 0) { + // The position is after an unlimited code point span (spanLength!=0), + // not after a string match. + // The only position where spanLength==0 after a span is pos==0. + // Otherwise, an unlimited code point span is only tried again when no + // strings match, and if such a non-initial span fails we stop. + if (offsets.isEmpty()) { + return pos; // No strings matched after a span. + } + // Match strings from after the next string match. + } else { + // The position is after a string match (or a single code point). + if (offsets.isEmpty()) { + // No more strings matched after a previous string match. + // Try another code point span from after the last string match. + spanLimit = spanSet.span(s, pos, SpanCondition.CONTAINED); + spanLength = spanLimit - pos; + if (spanLength == rest || // Reached the end of the string, or + spanLength == 0 // neither strings nor span progressed. + ) { + return spanLimit; + } + pos += spanLength; + rest -= spanLength; + continue; // spanLength>0: Match strings from after a span. + } else { + // Try to match only one code point from after a string match if some + // string matched beyond it, so that we try all possible positions + // and don't overshoot. + spanLength = spanOne(spanSet, s, pos, rest); + if (spanLength > 0) { + if (spanLength == rest) { + return length; // Reached the end of the string. + } + // Match strings after this code point. + // There cannot be any increments below it because UnicodeSet strings + // contain multiple code points. + pos += spanLength; + rest -= spanLength; + offsets.shift(spanLength); + spanLength = 0; + continue; // Match strings from after a single code point. + } + // Match strings from after the next string match. + } + } + int minOffset = offsets.popMinimum(null); + pos += minOffset; + rest -= minOffset; + spanLength = 0; // Match strings from after a string match. + } + } + + /** + * Spans a string and counts the smallest number of set elements on any path across the span. + * + *

For proper counting, we cannot ignore strings that are fully contained in code point spans. + * + *

If the set does not have any fully-contained strings, then we could optimize this + * like span(), but such sets are likely rare, and this is at least still linear. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @param outCount The count + * @return the limit (exclusive end) of the span + */ + public int spanAndCount(CharSequence s, int start, SpanCondition spanCondition, + OutputInt outCount) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNot(s, start, outCount); + } + // Consider strings; they may overlap with the span, + // and they may result in a smaller count that with just code points. + if (spanCondition == SpanCondition.CONTAINED) { + return spanContainedAndCount(s, start, outCount); + } + // SIMPLE (not synchronized, does not use offsets) + int stringsLength = strings.size(); + int length = s.length(); + int pos = start; + int rest = length - start; + int count = 0; + while (rest != 0) { + // Try to match the next code point. + int cpLength = spanOne(spanSet, s, pos, rest); + int maxInc = (cpLength > 0) ? cpLength : 0; + // Try to match all of the strings. + for (int i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + if (maxInc < length16 && length16 <= rest && + matches16CPB(s, pos, length, string, length16)) { + maxInc = length16; + } + } + // We are done if there is no match beyond pos. + if (maxInc == 0) { + outCount.value = count; + return pos; + } + // Continue from the longest match. + ++count; + pos += maxInc; + rest -= maxInc; + } + outCount.value = count; + return pos; + } + + private synchronized int spanContainedAndCount(CharSequence s, int start, OutputInt outCount) { + // Use offset list to try all possibilities. + offsets.setMaxLength(maxLength16); + int stringsLength = strings.size(); + int length = s.length(); + int pos = start; + int rest = length - start; + int count = 0; + while (rest != 0) { + // Try to match the next code point. + int cpLength = spanOne(spanSet, s, pos, rest); + if (cpLength > 0) { + offsets.addOffsetAndCount(cpLength, count + 1); + } + // Try to match all of the strings. + for (int i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + // Note: If the strings were sorted by length, then we could also + // avoid trying to match if there is already a match of the same length. + if (length16 <= rest && !offsets.hasCountAtOffset(length16, count + 1) && + matches16CPB(s, pos, length, string, length16)) { + offsets.addOffsetAndCount(length16, count + 1); + } + } + // We are done if there is no match beyond pos. + if (offsets.isEmpty()) { + outCount.value = count; + return pos; + } + // Continue from the nearest match. + int minOffset = offsets.popMinimum(outCount); + count = outCount.value; + pos += minOffset; + rest -= minOffset; + } + outCount.value = count; + return pos; + } + + /** + * Span a string backwards. + * + * @param s The string to be spanned + * @param spanCondition The span condition + * @return The string index which starts the span (i.e. inclusive). + */ + public synchronized int spanBack(CharSequence s, int length, SpanCondition spanCondition) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNotBack(s, length); + } + int pos = spanSet.spanBack(s, length, SpanCondition.CONTAINED); + if (pos == 0) { + return 0; + } + int spanLength = length - pos; + + // Consider strings; they may overlap with the span. + int initSize = 0; + if (spanCondition == SpanCondition.CONTAINED) { + // Use offset list to try all possibilities. + initSize = maxLength16; + } + offsets.setMaxLength(initSize); + int i, stringsLength = strings.size(); + int spanBackLengthsOffset = 0; + if (all) { + spanBackLengthsOffset = stringsLength; + } + for (;;) { + if (spanCondition == SpanCondition.CONTAINED) { + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[spanBackLengthsOffset + i]; + if (overlap == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-(length16-overlap)..pos-length16. + if (overlap >= LONG_SPAN) { + overlap = length16; + // While contained: No point matching fully inside the code point span. + int len1 = 0; + len1 = string.offsetByCodePoints(0, 1); + overlap -= len1; // Length of the string minus the first code point. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int dec = length16 - overlap; // Keep dec+overlap==length16. + for (;;) { + if (dec > pos) { + break; + } + // Try to match if the decrement is not listed already. + if (!offsets.containsOffset(dec) && matches16CPB(s, pos - dec, length, string, length16)) { + if (dec == pos) { + return 0; // Reached the start of the string. + } + offsets.addOffset(dec); + } + if (overlap == 0) { + break; + } + --overlap; + ++dec; + } + } + } else /* SIMPLE */{ + int maxDec = 0, maxOverlap = 0; + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[spanBackLengthsOffset + i]; + // For longest match, we do need to try to match even an all-contained string + // to find the match from the latest end. + + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-(length16-overlap)..pos-length16. + if (overlap >= LONG_SPAN) { + overlap = length16; + // Longest match: Need to match fully inside the code point span + // to find the match from the latest end. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int dec = length16 - overlap; // Keep dec+overlap==length16. + for (;;) { + if (dec > pos || overlap < maxOverlap) { + break; + } + // Try to match if the string is longer or ends later. + if ((overlap > maxOverlap || /* redundant overlap==maxOverlap && */dec > maxDec) + && matches16CPB(s, pos - dec, length, string, length16)) { + maxDec = dec; // Longest match from latest end. + maxOverlap = overlap; + break; + } + --overlap; + ++dec; + } + } + + if (maxDec != 0 || maxOverlap != 0) { + // Longest-match algorithm, and there was a string match. + // Simply continue before it. + pos -= maxDec; + if (pos == 0) { + return 0; // Reached the start of the string. + } + spanLength = 0; // Match strings from before a string match. + continue; + } + } + // Finished trying to match all strings at pos. + + if (spanLength != 0 || pos == length) { + // The position is before an unlimited code point span (spanLength!=0), + // not before a string match. + // The only position where spanLength==0 before a span is pos==length. + // Otherwise, an unlimited code point span is only tried again when no + // strings match, and if such a non-initial span fails we stop. + if (offsets.isEmpty()) { + return pos; // No strings matched before a span. + } + // Match strings from before the next string match. + } else { + // The position is before a string match (or a single code point). + if (offsets.isEmpty()) { + // No more strings matched before a previous string match. + // Try another code point span from before the last string match. + int oldPos = pos; + pos = spanSet.spanBack(s, oldPos, SpanCondition.CONTAINED); + spanLength = oldPos - pos; + if (pos == 0 || // Reached the start of the string, or + spanLength == 0 // neither strings nor span progressed. + ) { + return pos; + } + continue; // spanLength>0: Match strings from before a span. + } else { + // Try to match only one code point from before a string match if some + // string matched beyond it, so that we try all possible positions + // and don't overshoot. + spanLength = spanOneBack(spanSet, s, pos); + if (spanLength > 0) { + if (spanLength == pos) { + return 0; // Reached the start of the string. + } + // Match strings before this code point. + // There cannot be any decrements below it because UnicodeSet strings + // contain multiple code points. + pos -= spanLength; + offsets.shift(spanLength); + spanLength = 0; + continue; // Match strings from before a single code point. + } + // Match strings from before the next string match. + } + } + pos -= offsets.popMinimum(null); + spanLength = 0; // Match strings from before a string match. + } + } + + /** + * Algorithm for spanNot()==span(SpanCondition.NOT_CONTAINED) + * + * Theoretical algorithm: + * - Iterate through the string, and at each code point boundary: + * + If the code point there is in the set, then return with the current position. + * + If a set string matches at the current position, then return with the current position. + * + * Optimized implementation: + * + * (Same assumption as for span() above.) + * + * Create and cache a spanNotSet which contains + * all of the single code points of the original set but none of its strings. + * For each set string add its initial code point to the spanNotSet. + * (Also add its final code point for spanNotBack().) + * + * - Loop: + * + Do spanLength=spanNotSet.span(SpanCondition.NOT_CONTAINED). + * + If the current code point is in the original set, then return the current position. + * + If any set string matches at the current position, then return the current position. + * + If there is no match at the current position, neither for the code point + * there nor for any set string, then skip this code point and continue the loop. + * This happens for set-string-initial code points that were added to spanNotSet + * when there is not actually a match for such a set string. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param outCount If not null: Receives the number of code points across the span. + * @return the limit (exclusive end) of the span + */ + private int spanNot(CharSequence s, int start, OutputInt outCount) { + int length = s.length(); + int pos = start, rest = length - start; + int stringsLength = strings.size(); + int count = 0; + do { + // Span until we find a code point from the set, + // or a code point that starts or ends some string. + int spanLimit; + if (outCount == null) { + spanLimit = spanNotSet.span(s, pos, SpanCondition.NOT_CONTAINED); + } else { + spanLimit = spanNotSet.spanAndCount(s, pos, SpanCondition.NOT_CONTAINED, outCount); + outCount.value = count = count + outCount.value; + } + if (spanLimit == length) { + return length; // Reached the end of the string. + } + pos = spanLimit; + rest = length - spanLimit; + + // Check whether the current code point is in the original set, + // without the string starts and ends. + int cpLength = spanOne(spanSet, s, pos, rest); + if (cpLength > 0) { + return pos; // There is a set element at pos. + } + + // Try to match the strings at pos. + for (int i = 0; i < stringsLength; ++i) { + if (spanLengths[i] == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + if (length16 <= rest && matches16CPB(s, pos, length, string, length16)) { + return pos; // There is a set element at pos. + } + } + + // The span(while not contained) ended on a string start/end which is + // not in the original set. Skip this code point and continue. + // cpLength<0 + pos -= cpLength; + rest += cpLength; + ++count; + } while (rest != 0); + if (outCount != null) { + outCount.value = count; + } + return length; // Reached the end of the string. + } + + private int spanNotBack(CharSequence s, int length) { + int pos = length; + int i, stringsLength = strings.size(); + do { + // Span until we find a code point from the set, + // or a code point that starts or ends some string. + pos = spanNotSet.spanBack(s, pos, SpanCondition.NOT_CONTAINED); + if (pos == 0) { + return 0; // Reached the start of the string. + } + + // Check whether the current code point is in the original set, + // without the string starts and ends. + int cpLength = spanOneBack(spanSet, s, pos); + if (cpLength > 0) { + return pos; // There is a set element at pos. + } + + // Try to match the strings at pos. + for (i = 0; i < stringsLength; ++i) { + // Use spanLengths rather than a spanLengths pointer because + // it is easier and we only need to know whether the string is irrelevant + // which is the same in either array. + if (spanLengths[i] == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + if (length16 <= pos && matches16CPB(s, pos - length16, length, string, length16)) { + return pos; // There is a set element at pos. + } + } + + // The span(while not contained) ended on a string start/end which is + // not in the original set. Skip this code point and continue. + // cpLength<0 + pos += cpLength; + } while (pos != 0); + return 0; // Reached the start of the string. + } + + static short makeSpanLengthByte(int spanLength) { + // 0xfe==UnicodeSetStringSpan::LONG_SPAN + return spanLength < LONG_SPAN ? (short) spanLength : LONG_SPAN; + } + + // Compare strings without any argument checks. Requires length>0. + private static boolean matches16(CharSequence s, int start, final String t, int length) { + int end = start + length; + while (length-- > 0) { + if (s.charAt(--end) != t.charAt(length)) { + return false; + } + } + return true; + } + + /** + * Compare 16-bit Unicode strings (which may be malformed UTF-16) + * at code point boundaries. + * That is, each edge of a match must not be in the middle of a surrogate pair. + * @param s The string to match in. + * @param start The start index of s. + * @param limit The limit of the subsequence of s being spanned. + * @param t The substring to be matched in s. + * @param tlength The length of t. + */ + static boolean matches16CPB(CharSequence s, int start, int limit, final String t, int tlength) { + return matches16(s, start, t, tlength) + && !(0 < start && Character.isHighSurrogate(s.charAt(start - 1)) && + Character.isLowSurrogate(s.charAt(start))) + && !((start + tlength) < limit && Character.isHighSurrogate(s.charAt(start + tlength - 1)) && + Character.isLowSurrogate(s.charAt(start + tlength))); + } + + /** + * Does the set contain the next code point? + * If so, return its length; otherwise return its negative length. + */ + static int spanOne(final UnicodeSet set, CharSequence s, int start, int length) { + char c = s.charAt(start); + if (c >= 0xd800 && c <= 0xdbff && length >= 2) { + char c2 = s.charAt(start + 1); + if (UTF16.isTrailSurrogate(c2)) { + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + return set.contains(supplementary) ? 2 : -2; + } + } + return set.contains(c) ? 1 : -1; + } + + static int spanOneBack(final UnicodeSet set, CharSequence s, int length) { + char c = s.charAt(length - 1); + if (c >= 0xdc00 && c <= 0xdfff && length >= 2) { + char c2 = s.charAt(length - 2); + if (UTF16.isLeadSurrogate(c2)) { + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + return set.contains(supplementary) ? 2 : -2; + } + } + return set.contains(c) ? 1 : -1; + } + + /** + * Helper class for UnicodeSetStringSpan. + * + *

List of offsets from the current position from where to try matching + * a code point or a string. + * Stores offsets rather than indexes to simplify the code and use the same list + * for both increments (in span()) and decrements (in spanBack()). + * + *

Assumption: The maximum offset is limited, and the offsets that are stored at any one time + * are relatively dense, that is, + * there are normally no gaps of hundreds or thousands of offset values. + * + *

This class optionally also tracks the minimum non-negative count for each position, + * intended to count the smallest number of elements of any path leading to that position. + * + *

The implementation uses a circular buffer of count integers, + * each indicating whether the corresponding offset is in the list, + * and its path element count. + * This avoids inserting into a sorted list of offsets (or absolute indexes) + * and physically moving part of the list. + * + *

Note: In principle, the caller should setMaxLength() to + * the maximum of the max string length and U16_LENGTH/U8_LENGTH + * to account for "long" single code points. + * + *

Note: An earlier version did not track counts and stored only byte flags. + * With boolean flags, if maxLength were guaranteed to be no more than 32 or 64, + * the list could be stored as bit flags in a single integer. + * Rather than handling a circular buffer with a start list index, + * the integer would simply be shifted when lower offsets are removed. + * UnicodeSet does not have a limit on the lengths of strings. + */ + private static final class OffsetList { + private int[] list; + private int length; + private int start; + + public OffsetList() { + list = new int[16]; // default size + } + + public void setMaxLength(int maxLength) { + if (maxLength > list.length) { + list = new int[maxLength]; + } + clear(); + } + + public void clear() { + for (int i = list.length; i-- > 0;) { + list[i] = 0; + } + start = length = 0; + } + + public boolean isEmpty() { + return (length == 0); + } + + /** + * Reduces all stored offsets by delta, used when the current position moves by delta. + * There must not be any offsets lower than delta. + * If there is an offset equal to delta, it is removed. + * + * @param delta [1..maxLength] + */ + public void shift(int delta) { + int i = start + delta; + if (i >= list.length) { + i -= list.length; + } + if (list[i] != 0) { + list[i] = 0; + --length; + } + start = i; + } + + /** + * Adds an offset. The list must not contain it yet. + * @param offset [1..maxLength] + */ + public void addOffset(int offset) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + assert list[i] == 0; + list[i] = 1; + ++length; + } + + /** + * Adds an offset and updates its count. + * The list may already contain the offset. + * @param offset [1..maxLength] + */ + public void addOffsetAndCount(int offset, int count) { + assert count > 0; + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + if (list[i] == 0) { + list[i] = count; + ++length; + } else if (count < list[i]) { + list[i] = count; + } + } + + /** + * @param offset [1..maxLength] + */ + public boolean containsOffset(int offset) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + return list[i] != 0; + } + + /** + * @param offset [1..maxLength] + */ + public boolean hasCountAtOffset(int offset, int count) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + int oldCount = list[i]; + return oldCount != 0 && oldCount <= count; + } + + /** + * Finds the lowest stored offset from a non-empty list, removes it, + * and reduces all other offsets by this minimum. + * @return min=[1..maxLength] + */ + public int popMinimum(OutputInt outCount) { + // Look for the next offset in list[start+1..list.length-1]. + int i = start, result; + while (++i < list.length) { + int count = list[i]; + if (count != 0) { + list[i] = 0; + --length; + result = i - start; + start = i; + if (outCount != null) { outCount.value = count; } + return result; + } + } + // i==list.length + + // Wrap around and look for the next offset in list[0..start]. + // Since the list is not empty, there will be one. + result = list.length - start; + i = 0; + int count; + while ((count = list[i]) == 0) { + ++i; + } + list[i] = 0; + --length; + start = i; + if (outCount != null) { outCount.value = count; } + return result + i; + } + } +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/Utility.class b/tests/test_data/std/jdk/internal/icu/impl/Utility.class new file mode 100644 index 0000000000000000000000000000000000000000..6fedabcc12b837d76986a944e9b4e9ec8dd5e362 GIT binary patch literal 4694 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 Q{(ltZvsBpjbe_U<+6aWAK literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/Utility.java b/tests/test_data/std/jdk/internal/icu/impl/Utility.java new file mode 100644 index 00000000..62c6c5a7 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/impl/Utility.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 1996-2015, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ + +package jdk.internal.icu.impl; + +import jdk.internal.icu.lang.UCharacter; +import jdk.internal.icu.text.UTF16; + +import java.io.IOException; +import java.util.Locale; + +public final class Utility { + + /** + * Convert characters outside the range U+0020 to U+007F to + * Unicode escapes, and convert backslash to a double backslash. + */ + public static final String escape(String s) { + StringBuilder buf = new StringBuilder(); + for (int i=0; i= ' ' && c <= 0x007F) { + if (c == '\\') { + buf.append("\\\\"); // That is, "\\" + } else { + buf.append((char)c); + } + } else { + boolean four = c <= 0xFFFF; + buf.append(four ? "\\u" : "\\U"); + buf.append(hex(c, four ? 4 : 8)); + } + } + return buf.toString(); + } + + /* This map must be in ASCENDING ORDER OF THE ESCAPE CODE */ + private static final char[] UNESCAPE_MAP = { + /*" 0x22, 0x22 */ + /*' 0x27, 0x27 */ + /*? 0x3F, 0x3F */ + /*\ 0x5C, 0x5C */ + /*a*/ 0x61, 0x07, + /*b*/ 0x62, 0x08, + /*e*/ 0x65, 0x1b, + /*f*/ 0x66, 0x0c, + /*n*/ 0x6E, 0x0a, + /*r*/ 0x72, 0x0d, + /*t*/ 0x74, 0x09, + /*v*/ 0x76, 0x0b + }; + + /** + * Convert an escape to a 32-bit code point value. We attempt + * to parallel the icu4c unescapeAt() function. + * @param offset16 an array containing offset to the character + * after the backslash. Upon return offset16[0] will + * be updated to point after the escape sequence. + * @return character value from 0 to 10FFFF, or -1 on error. + */ + public static int unescapeAt(String s, int[] offset16) { + int c; + int result = 0; + int n = 0; + int minDig = 0; + int maxDig = 0; + int bitsPerDigit = 4; + int dig; + int i; + boolean braces = false; + + /* Check that offset is in range */ + int offset = offset16[0]; + int length = s.length(); + if (offset < 0 || offset >= length) { + return -1; + } + + /* Fetch first UChar after '\\' */ + c = Character.codePointAt(s, offset); + offset += UTF16.getCharCount(c); + + /* Convert hexadecimal and octal escapes */ + switch (c) { + case 'u': + minDig = maxDig = 4; + break; + case 'U': + minDig = maxDig = 8; + break; + case 'x': + minDig = 1; + if (offset < length && UTF16.charAt(s, offset) == 0x7B /*{*/) { + ++offset; + braces = true; + maxDig = 8; + } else { + maxDig = 2; + } + break; + default: + dig = UCharacter.digit(c, 8); + if (dig >= 0) { + minDig = 1; + maxDig = 3; + n = 1; /* Already have first octal digit */ + bitsPerDigit = 3; + result = dig; + } + break; + } + if (minDig != 0) { + while (offset < length && n < maxDig) { + c = UTF16.charAt(s, offset); + dig = UCharacter.digit(c, (bitsPerDigit == 3) ? 8 : 16); + if (dig < 0) { + break; + } + result = (result << bitsPerDigit) | dig; + offset += UTF16.getCharCount(c); + ++n; + } + if (n < minDig) { + return -1; + } + if (braces) { + if (c != 0x7D /*}*/) { + return -1; + } + ++offset; + } + if (result < 0 || result >= 0x110000) { + return -1; + } + // If an escape sequence specifies a lead surrogate, see + // if there is a trail surrogate after it, either as an + // escape or as a literal. If so, join them up into a + // supplementary. + if (offset < length && + UTF16.isLeadSurrogate((char) result)) { + int ahead = offset+1; + c = s.charAt(offset); // [sic] get 16-bit code unit + if (c == '\\' && ahead < length) { + int o[] = new int[] { ahead }; + c = unescapeAt(s, o); + ahead = o[0]; + } + if (UTF16.isTrailSurrogate((char) c)) { + offset = ahead; + result = UCharacterProperty.getRawSupplementary( + (char) result, (char) c); + } + } + offset16[0] = offset; + return result; + } + + /* Convert C-style escapes in table */ + for (i=0; i= 0x20 && c <= 0x7E); + } + + /** + * Escape unprintable characters using uxxxx notation + * for U+0000 to U+FFFF and Uxxxxxxxx for U+10000 and + * above. If the character is printable ASCII, then do nothing + * and return false. Otherwise, append the escaped notation and + * return true. + */ + public static boolean escapeUnprintable(T result, int c) { + try { + if (isUnprintable(c)) { + result.append('\\'); + if ((c & ~0xFFFF) != 0) { + result.append('U'); + result.append(DIGITS[0xF&(c>>28)]); + result.append(DIGITS[0xF&(c>>24)]); + result.append(DIGITS[0xF&(c>>20)]); + result.append(DIGITS[0xF&(c>>16)]); + } else { + result.append('u'); + } + result.append(DIGITS[0xF&(c>>12)]); + result.append(DIGITS[0xF&(c>>8)]); + result.append(DIGITS[0xF&(c>>4)]); + result.append(DIGITS[0xF&c]); + return true; + } + return false; + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } +} diff --git a/tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/nfc.nrm b/tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/nfc.nrm new file mode 100644 index 0000000000000000000000000000000000000000..9228eebbd170eed49290c974311d494f4ea22ec0 GIT binary patch literal 35392 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 rm6eA_9zvDf2mKoAg6 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 CRn=7h literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/ubidi.icu b/tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/ubidi.icu new file mode 100644 index 0000000000000000000000000000000000000000..d5c81de1b1948d5c8a9a26b746d0d552a94b99fe GIT binary patch literal 27584 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 C6Ju=v literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/uprops.icu b/tests/test_data/std/jdk/internal/icu/impl/data/icudt74b/uprops.icu new file mode 100644 index 0000000000000000000000000000000000000000..2cfd5a784e52d8229878756ffe0ba08d325c9e52 GIT binary patch literal 141616 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/lang/UCharacter$JoiningGroup.class b/tests/test_data/std/jdk/internal/icu/lang/UCharacter$JoiningGroup.class new file mode 100644 index 0000000000000000000000000000000000000000..7c1789d8a3a66462f3980de53f3af10c6993684a GIT binary patch literal 299 zcmah@yH3ME5S&fGPE1}cT?$(8M_9r*g^hwj8y(ImoH^~GyE7k0!3XeBD4S3~mu6>Y zG@6<3pU*D<1r{j=gxhZSmK%=Rv$DBq``jwt=bPeHdDV)1vvP(F?@RCc_Y@a|MW;U0 zudR9MbQ?vgo9(Kp>Z&fc<+|BC5~w0f3&$ZUj?c>WdMLFZWKXX5t-d!_6Xt(KcgI-5 zsMaAqxDZoJ3CnZy2$PCg`@*UabP)P~Zz4Nz>?K^|5{Y0cY=Dv6A;zaa!_^5VmVEwr??RqNl*g-avP&`eQDEF@aok2p~f2LpqNujaxB@S%)%a3MPv zlbdhuWX^ZKzCS(z2pqZCBAn$9&wi$jsPJ5jPqLCJU!O+Ji>k78^Zu$_ z^a=A^zRBNL@qMmRL+D3w6c8vROhu_{Bel7cMWcG01cJK?M7UmFTO`6@6<&rL3oPJ9 z$vU_Rg~cB4M4UwJj-$NWvZ+#akrj$C`*S+C3WQ;#YI9ZA#>GD21 z)r4`Un#20A4g(zXajdl!#E^N^VUKy-;R*A!!`sZW4$o~b?6iOFVy~SG9PsowgRsD% GGx`A$F-=1N literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/lang/UCharacter.class b/tests/test_data/std/jdk/internal/icu/lang/UCharacter.class new file mode 100644 index 0000000000000000000000000000000000000000..56bd9814265b79a3d659916deed922b41a510d9b GIT binary patch literal 2897 zcma)7-BS}+6#v~oNH#7S5w$|9s7M2Tq-bkD5NlWhtR@>u0!90gF3B1emrc6aDA+Ii z`Ot^HJMB~LOkaGcj-yUH(>}G+>EF|*j#GQiCO}AVG&6Ab+sYdE%U#msy)<{B$*Y&JVFd^&`7_yg#W5kOF&uf^5U?P6?JS=1dp zPZ0$C1+!?n0_{g zWQ4I(AgF4YY+O?k0z=7XjXA<%{QR$5#%`7qAdc*6*^sao&jqlLqxWpJ$(qVBbKGQs z6@f!fVqNzkw!MhRc%F%ZM5I`HrNWa3Wc2Z*M3X7gaY_!)9+GjGXL;Y#y6G5&G0Nx_ z!wumG1_F3NMiher2V1u59hO#dmUYX#Za60ewo?pkVqCQ=u5RZIfg{nuR>93UQhWqQ zWgKG}J6UmQdBLiR)(r;TCuu^YF{o9 zgTP4{r|^=%4zrRp^g^ae87S&5spN{e#4e|0yuvPFvyydm(^~i8!+TA}>lhK(MG9y1 zYnf`fY#Gaj?dlGdjX$a=gK7YybVf`1RXyg_r)pV7QMckwvC5u_mAp}QNp=u#2t?|u zeU&vSefhO=rUN^JxQsC<0v%^48}3>y$WTfT%wlh zD^=<5a^FI!Y8NP22vagtoTp$UKVGC=574fkDRm(vWu&0hwyxUlTC>dQR+R$zqpH_& z(|9w08P=Sk6mAGjFDw~(YRtCi;2c$7O4V|6@#JhmK&S$pO35o1*NfIh*8?4dl#0)< zIfb>fmdi}X6;+$erQ$Oe2sg%l9aL}$O-ZIRYb!h(5ZI%nQ)8;evyC`jr3%}nOvPt% zN<5pGOwU}*Dd|})%S-!7%ZxfXmCa?-xnyF(n-l`wnb;A=HuB9CWn1!`ZbFt7qEb0h~O2y`Px$wt_6W@no)6624|@fz{dioTCS9)nEg|9$ycq+s%3d; zBt-#yDsb$nKspS=G4p)M2Jo4{@uworQzodNCY@5XO!-l5+i<-5$Dr+ZwF=?=Y>*J5 zF#v|?`I_c>!#-p&OC>!=mJe@{J>OuDlYJ4F*4N)A`<({+U9#V6uybU;-(c%xFEqr< zlU-=A4akt_3Dt<_Z79u?l(KZ_S9zpt$MkBpHAQ1Tp?Y`T- z+vM4XBK_|{2leG3wuvEx#Zh#NK6e>492mU#O~_=C;(Z#UsfUT!6RF`M}xqM!JOn(;R`;cI6j zp^Oje_yaWZFF^UfhvPrfr)Wt3Ejla*BX#FI9X22Gekz#Zn+W$l#LG7!_0ah0?O$=` zV%OORIQKhw)QV?2jSzRRUEHO@x#vmQQ;UEKT=Jt>sM42!<)K735z=#2C!D7MtS{2@ z9no}+|Ap72zZ!NPsaFn@w8IyYh=m@uI?E{Gd0P@k?7fc* z%}M;HLAkVE;1aHS1@7aAuO2E!BMbHqJwW;neKgkcqXtEOT*C^jw_(-ux{eQN43hm3 cKEVxqPF9a+wd0EpiRRkzC5<;|{HjCxALyBDSpWb4 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/lang/UCharacter.java b/tests/test_data/std/jdk/internal/icu/lang/UCharacter.java new file mode 100644 index 00000000..cd87db30 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/lang/UCharacter.java @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 1996-2014, International Business Machines Corporation and +* others. All Rights Reserved. +******************************************************************************* +*/ + +package jdk.internal.icu.lang; + +import jdk.internal.icu.impl.UBiDiProps; +import jdk.internal.icu.impl.UCharacterProperty; +import jdk.internal.icu.text.Normalizer2; +import jdk.internal.icu.text.UTF16; +import jdk.internal.icu.util.VersionInfo; + +/** + *

The UCharacter class provides extensions to the + * + * java.lang.Character class. These extensions provide support for + * more Unicode properties and together with the UTF16 + * class, provide support for supplementary characters (those with code + * points above U+FFFF). + * Each ICU release supports the latest version of Unicode available at that time. + * + *

Code points are represented in these API using ints. While it would be + * more convenient in Java to have a separate primitive datatype for them, + * ints suffice in the meantime. + * + *

To use this class please add the jar file name icu4j.jar to the + * class path, since it contains data files which supply the information used + * by this file.
+ * E.g. In Windows
+ * set CLASSPATH=%CLASSPATH%;$JAR_FILE_PATH/ucharacter.jar.
+ * Otherwise, another method would be to copy the files uprops.dat and + * unames.icu from the icu4j source subdirectory + * $ICU4J_SRC/src/com.ibm.icu.impl.data to your class directory + * $ICU4J_CLASS/com.ibm.icu.impl.data. + * + *

Aside from the additions for UTF-16 support, and the updated Unicode + * properties, the main differences between UCharacter and Character are: + *

    + *
  • UCharacter is not designed to be a char wrapper and does not have + * APIs to which involves management of that single char.
    + * These include: + *
      + *
    • char charValue(), + *
    • int compareTo(java.lang.Character, java.lang.Character), etc. + *
    + *
  • UCharacter does not include Character APIs that are deprecated, nor + * does it include the Java-specific character information, such as + * boolean isJavaIdentifierPart(char ch). + *
  • Character maps characters 'A' - 'Z' and 'a' - 'z' to the numeric + * values '10' - '35'. UCharacter also does this in digit and + * getNumericValue, to adhere to the java semantics of these + * methods. New methods unicodeDigit, and + * getUnicodeNumericValue do not treat the above code points + * as having numeric values. This is a semantic change from ICU4J 1.3.1. + *
+ *

+ * Further detail on differences can be determined using the program + * + * com.ibm.icu.dev.test.lang.UCharacterCompare + *

+ *

+ * In addition to Java compatibility functions, which calculate derived properties, + * this API provides low-level access to the Unicode Character Database. + *

+ *

+ * Unicode assigns each code point (not just assigned character) values for + * many properties. + * Most of them are simple boolean flags, or constants from a small enumerated list. + * For some properties, values are strings or other relatively more complex types. + *

+ *

+ * For more information see + * "About the Unicode Character Database" + * (http://www.unicode.org/ucd/) + * and the ICU + * User Guide chapter on Properties + * (https://unicode-org.github.io/icu/userguide/strings/properties). + *

+ *

+ * There are also functions that provide easy migration from C/POSIX functions + * like isblank(). Their use is generally discouraged because the C/POSIX + * standards do not define their semantics beyond the ASCII range, which means + * that different implementations exhibit very different behavior. + * Instead, Unicode properties should be used directly. + *

+ *

+ * There are also only a few, broad C/POSIX character classes, and they tend + * to be used for conflicting purposes. For example, the "isalpha()" class + * is sometimes used to determine word boundaries, while a more sophisticated + * approach would at least distinguish initial letters from continuation + * characters (the latter including combining marks). + * (In ICU, BreakIterator is the most sophisticated API for word boundaries.) + * Another example: There is no "istitle()" class for titlecase characters. + *

+ *

+ * ICU 3.4 and later provides API access for all twelve C/POSIX character classes. + * ICU implements them according to the Standard Recommendations in + * Annex C: Compatibility Properties of UTS #18 Unicode Regular Expressions + * (http://www.unicode.org/reports/tr18/#Compatibility_Properties). + *

+ *

+ * API access for C/POSIX character classes is as follows: + *

{@code
+ * - alpha:     isUAlphabetic(c) or hasBinaryProperty(c, UProperty.ALPHABETIC)
+ * - lower:     isULowercase(c) or hasBinaryProperty(c, UProperty.LOWERCASE)
+ * - upper:     isUUppercase(c) or hasBinaryProperty(c, UProperty.UPPERCASE)
+ * - punct:     ((1<
+ * 

+ *

+ * The C/POSIX character classes are also available in UnicodeSet patterns, + * using patterns like [:graph:] or \p{graph}. + *

+ * + * There are several ICU (and Java) whitespace functions. + * Comparison:
    + *
  • isUWhiteSpace=UCHAR_WHITE_SPACE: Unicode White_Space property; + * most of general categories "Z" (separators) + most whitespace ISO controls + * (including no-break spaces, but excluding IS1..IS4 and ZWSP) + *
  • isWhitespace: Java isWhitespace; Z + whitespace ISO controls but excluding no-break spaces + *
  • isSpaceChar: just Z (including no-break spaces)
+ *

+ *

+ * This class is not subclassable. + *

+ * @author Syn Wee Quek + * @stable ICU 2.1 + * @see com.ibm.icu.lang.UCharacterEnums + */ + +public final class UCharacter +{ + + /** + * Joining Group constants. + * @see UProperty#JOINING_GROUP + * @stable ICU 2.4 + */ + public static interface JoiningGroup + { + /** + * @stable ICU 2.4 + */ + public static final int NO_JOINING_GROUP = 0; + } + + /** + * Numeric Type constants. + * @see UProperty#NUMERIC_TYPE + * @stable ICU 2.4 + */ + public static interface NumericType + { + /** + * @stable ICU 2.4 + */ + public static final int NONE = 0; + /** + * @stable ICU 2.4 + */ + public static final int DECIMAL = 1; + /** + * @stable ICU 2.4 + */ + public static final int DIGIT = 2; + /** + * @stable ICU 2.4 + */ + public static final int NUMERIC = 3; + /** + * @stable ICU 2.4 + */ + public static final int COUNT = 4; + } + + /** + * Hangul Syllable Type constants. + * + * @see UProperty#HANGUL_SYLLABLE_TYPE + * @stable ICU 2.6 + */ + public static interface HangulSyllableType + { + /** + * @stable ICU 2.6 + */ + public static final int NOT_APPLICABLE = 0; /*[NA]*/ /*See note !!*/ + /** + * @stable ICU 2.6 + */ + public static final int LEADING_JAMO = 1; /*[L]*/ + /** + * @stable ICU 2.6 + */ + public static final int VOWEL_JAMO = 2; /*[V]*/ + /** + * @stable ICU 2.6 + */ + public static final int TRAILING_JAMO = 3; /*[T]*/ + /** + * @stable ICU 2.6 + */ + public static final int LV_SYLLABLE = 4; /*[LV]*/ + /** + * @stable ICU 2.6 + */ + public static final int LVT_SYLLABLE = 5; /*[LVT]*/ + /** + * @stable ICU 2.6 + */ + public static final int COUNT = 6; + } + + // public data members ----------------------------------------------- + + /** + * The lowest Unicode code point value. + * @stable ICU 2.1 + */ + public static final int MIN_VALUE = UTF16.CODEPOINT_MIN_VALUE; + + /** + * The highest Unicode code point value (scalar value) according to the + * Unicode Standard. + * This is a 21-bit value (21 bits, rounded up).
+ * Up-to-date Unicode implementation of java.lang.Character.MAX_VALUE + * @stable ICU 2.1 + */ + public static final int MAX_VALUE = UTF16.CODEPOINT_MAX_VALUE; + + // public methods ---------------------------------------------------- + + /** + * Returns the numeric value of a decimal digit code point. + *
This method observes the semantics of + * java.lang.Character.digit(). Note that this + * will return positive values for code points for which isDigit + * returns false, just like java.lang.Character. + *
Semantic Change: In release 1.3.1 and + * prior, this did not treat the European letters as having a + * digit value, and also treated numeric letters and other numbers as + * digits. + * This has been changed to conform to the java semantics. + *
A code point is a valid digit if and only if: + *
    + *
  • ch is a decimal digit or one of the european letters, and + *
  • the value of ch is less than the specified radix. + *
+ * @param ch the code point to query + * @param radix the radix + * @return the numeric value represented by the code point in the + * specified radix, or -1 if the code point is not a decimal digit + * or if its value is too large for the radix + * @stable ICU 2.1 + */ + public static int digit(int ch, int radix) + { + if (2 <= radix && radix <= 36) { + int value = digit(ch); + if (value < 0) { + // ch is not a decimal digit, try latin letters + value = UCharacterProperty.getEuropeanDigit(ch); + } + return (value < radix) ? value : -1; + } else { + return -1; // invalid radix + } + } + + /** + * Returns the numeric value of a decimal digit code point. + *
This is a convenience overload of digit(int, int) + * that provides a decimal radix. + *
Semantic Change: In release 1.3.1 and prior, this + * treated numeric letters and other numbers as digits. This has + * been changed to conform to the java semantics. + * @param ch the code point to query + * @return the numeric value represented by the code point, + * or -1 if the code point is not a decimal digit or if its + * value is too large for a decimal radix + * @stable ICU 2.1 + */ + public static int digit(int ch) + { + return UCharacterProperty.INSTANCE.digit(ch); + } + + /** + * Returns a value indicating a code point's Unicode category. + * Up-to-date Unicode implementation of java.lang.Character.getType() + * except for the above mentioned code points that had their category + * changed.
+ * Return results are constants from the interface + * UCharacterCategory
+ * NOTE: the UCharacterCategory values are not compatible with + * those returned by java.lang.Character.getType. UCharacterCategory values + * match the ones used in ICU4C, while java.lang.Character type + * values, though similar, skip the value 17.

+ * @param ch code point whose type is to be determined + * @return category which is a value of UCharacterCategory + * @stable ICU 2.1 + */ + public static int getType(int ch) + { + return UCharacterProperty.INSTANCE.getType(ch); + } + + /** + * Returns the Bidirection property of a code point. + * For example, 0x0041 (letter A) has the LEFT_TO_RIGHT directional + * property.
+ * Result returned belongs to the interface + * UCharacterDirection + * @param ch the code point to be determined its direction + * @return direction constant from UCharacterDirection. + * @stable ICU 2.1 + */ + public static int getDirection(int ch) + { + return UBiDiProps.INSTANCE.getClass(ch); + } + + /** + * Maps the specified code point to a "mirror-image" code point. + * For code points with the "mirrored" property, implementations sometimes + * need a "poor man's" mapping to another code point such that the default + * glyph may serve as the mirror-image of the default glyph of the + * specified code point.
+ * This is useful for text conversion to and from codepages with visual + * order, and for displays without glyph selection capabilities. + * @param ch code point whose mirror is to be retrieved + * @return another code point that may serve as a mirror-image substitute, + * or ch itself if there is no such mapping or ch does not have the + * "mirrored" property + * @stable ICU 2.1 + */ + public static int getMirror(int ch) + { + return UBiDiProps.INSTANCE.getMirror(ch); + } + + /** + * Maps the specified character to its paired bracket character. + * For Bidi_Paired_Bracket_Type!=None, this is the same as getMirror(int). + * Otherwise c itself is returned. + * See http://www.unicode.org/reports/tr9/ + * + * @param c the code point to be mapped + * @return the paired bracket code point, + * or c itself if there is no such mapping + * (Bidi_Paired_Bracket_Type=None) + * + * @see UProperty#BIDI_PAIRED_BRACKET + * @see UProperty#BIDI_PAIRED_BRACKET_TYPE + * @see #getMirror(int) + * @stable ICU 52 + */ + public static int getBidiPairedBracket(int c) { + return UBiDiProps.INSTANCE.getPairedBracket(c); + } + + /** + * Returns the combining class of the argument codepoint + * @param ch code point whose combining is to be retrieved + * @return the combining class of the codepoint + * @stable ICU 2.1 + */ + public static int getCombiningClass(int ch) + { + return Normalizer2.getNFDInstance().getCombiningClass(ch); + } + + /** + * Returns the version of Unicode data used. + * @return the unicode version number used + * @stable ICU 2.1 + */ + public static VersionInfo getUnicodeVersion() + { + return UCharacterProperty.INSTANCE.m_unicodeVersion_; + } + + /** + * Returns a code point corresponding to the two UTF16 characters. + * @param lead the lead char + * @param trail the trail char + * @return code point if surrogate characters are valid. + * @exception IllegalArgumentException thrown when argument characters do + * not form a valid codepoint + * @stable ICU 2.1 + */ + public static int getCodePoint(char lead, char trail) + { + if (UTF16.isLeadSurrogate(lead) && UTF16.isTrailSurrogate(trail)) { + return UCharacterProperty.getRawSupplementary(lead, trail); + } + throw new IllegalArgumentException("Illegal surrogate characters"); + } + + /** + * Returns the "age" of the code point.

+ *

The "age" is the Unicode version when the code point was first + * designated (as a non-character or for Private Use) or assigned a + * character. + *

This can be useful to avoid emitting code points to receiving + * processes that do not accept newer characters.

+ *

The data is from the UCD file DerivedAge.txt.

+ * @param ch The code point. + * @return the Unicode version number + * @stable ICU 2.6 + */ + public static VersionInfo getAge(int ch) + { + if (ch < MIN_VALUE || ch > MAX_VALUE) { + throw new IllegalArgumentException("Codepoint out of bounds"); + } + return UCharacterProperty.INSTANCE.getAge(ch); + } + + /** + * Returns the property value for an Unicode property type of a code point. + * Also returns binary and mask property values.

+ *

Unicode, especially in version 3.2, defines many more properties than + * the original set in UnicodeData.txt.

+ *

The properties APIs are intended to reflect Unicode properties as + * defined in the Unicode Character Database (UCD) and Unicode Technical + * Reports (UTR). For details about the properties see + * http://www.unicode.org/.

+ *

For names of Unicode properties see the UCD file PropertyAliases.txt. + *

+ *
+     * Sample usage:
+     * int ea = UCharacter.getIntPropertyValue(c, UProperty.EAST_ASIAN_WIDTH);
+     * int ideo = UCharacter.getIntPropertyValue(c, UProperty.IDEOGRAPHIC);
+     * boolean b = (ideo == 1) ? true : false;
+     * 
+ * @param ch code point to test. + * @param type UProperty selector constant, identifies which binary + * property to check. Must be + * UProperty.BINARY_START <= type < UProperty.BINARY_LIMIT or + * UProperty.INT_START <= type < UProperty.INT_LIMIT or + * UProperty.MASK_START <= type < UProperty.MASK_LIMIT. + * @return numeric value that is directly the property value or, + * for enumerated properties, corresponds to the numeric value of + * the enumerated constant of the respective property value + * enumeration type (cast to enum type if necessary). + * Returns 0 or 1 (for false / true) for binary Unicode properties. + * Returns a bit-mask for mask properties. + * Returns 0 if 'type' is out of bounds or if the Unicode version + * does not have data for the property at all, or not for this code + * point. + * @see UProperty + * @see #hasBinaryProperty + * @see #getIntPropertyMinValue + * @see #getIntPropertyMaxValue + * @see #getUnicodeVersion + * @stable ICU 2.4 + */ + // for BiDiBase.java + public static int getIntPropertyValue(int ch, int type) { + return UCharacterProperty.INSTANCE.getIntPropertyValue(ch, type); + } + + // private constructor ----------------------------------------------- + + /** + * Private constructor to prevent instantiation + */ + private UCharacter() { } + + /* + * Copied from UCharacterEnums.java + */ + + /** + * Character type Mn + * @stable ICU 2.1 + */ + public static final byte NON_SPACING_MARK = 6; + /** + * Character type Me + * @stable ICU 2.1 + */ + public static final byte ENCLOSING_MARK = 7; + /** + * Character type Mc + * @stable ICU 2.1 + */ + public static final byte COMBINING_SPACING_MARK = 8; + /** + * Character type count + * @stable ICU 2.1 + */ + public static final byte CHAR_CATEGORY_COUNT = 30; + + /** + * Directional type R + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT = 1; + /** + * Directional type AL + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_ARABIC = 13; +} diff --git a/tests/test_data/std/jdk/internal/icu/lang/UCharacterDirection.class b/tests/test_data/std/jdk/internal/icu/lang/UCharacterDirection.class new file mode 100644 index 0000000000000000000000000000000000000000..38101b415b553fa50cd0cde71eb31472fd588772 GIT binary patch literal 1352 zcmah|Yi|=r6g`uKc;klGkU$76Y|ATw21DtKLZM(1DZ)trlOV*S8t+c+N$gp7yiNsb z)e6+A6;)ADEAbonG<-thLw^8&2?_N$4#5VbtaSG7+&gpby=U({fBEb`0D0uI=s|A= zeS_G5et|8EYFXu~%9e9;r9~a30{y3qHR)-A-m&q80D-{9g8nX@NRx@nrd&w_Wa(P@ zZ24NT0D}UXCz~#*Yh}aPX04=MfK38B-*ARST~|(}3By|iM&Ary(XM7}J1&{#tWzZu ztuYP>?8qmzTJkDMC*O8~Z5K&icB)?K42%eDE$VVj+qBa?Dv-TeF{y6URip#FFR*DY zt!Nj{>SpRxwGm)96LxhUPO`T+Hntof6xiM!oLkn;nV4iB2@G{<6t-Ilu#c48kq*iO zr0fp9rW|AJVp0#!8^<4I6054=RN`ui`XA!2oK5URk*%<{a7MYM03XwPE@|3Wx!bRr z3UGvd&s)`Kn6lMz21f&6%j#9*OyUg?dJGujS0(6M+-!ZJ)HwT4Uej z+s6g^@=2^YEd^tBdr+>ZQk5QANFr5TP|md0tIoc(Vj2R63+rWEEAXU1kS4{{Q3iqG zvFY)`>ltsmxurKYPC!g^#EPkkmS$9aHDk7zG+m^pOsl4mcPMbAMJF&gZLN0sDs|M2 z49*JdU$4d$RXC*Y&;`ekk+*Q@&dl890ePoWf`P z8f?yxi#JW-qsTxy{RAFL!vk)5~36e&FREFF*8hub2D1Jm}@P zmxsNa@I2p(R!<8U=6eb^FpY0<0VT{pV-6Ku!V-$Gn8)|HiWJxI18cv7oA`-4e_{Ri z5aBoO{)0XI34;eb@sNG|i=;!JNBD}Gftmp$7UCharacter + *

+ * This class is not subclassable + *

+ * @author Syn Wee Quek + * @stable ICU 2.1 + */ + +@SuppressWarnings("deprecation") +public final class UCharacterDirection implements UCharacterEnums.ECharacterDirection { + + // private constructor ========================================= + // CLOVER:OFF + /** + * Private constructor to prevent initialization + */ + private UCharacterDirection() + { + } + // CLOVER:ON + + /** + * Gets the name of the argument direction + * @param dir direction type to retrieve name + * @return directional name + * @stable ICU 2.1 + */ + public static String toString(int dir) { + switch(dir) + { + case LEFT_TO_RIGHT : + return "Left-to-Right"; + case RIGHT_TO_LEFT : + return "Right-to-Left"; + case EUROPEAN_NUMBER : + return "European Number"; + case EUROPEAN_NUMBER_SEPARATOR : + return "European Number Separator"; + case EUROPEAN_NUMBER_TERMINATOR : + return "European Number Terminator"; + case ARABIC_NUMBER : + return "Arabic Number"; + case COMMON_NUMBER_SEPARATOR : + return "Common Number Separator"; + case BLOCK_SEPARATOR : + return "Paragraph Separator"; + case SEGMENT_SEPARATOR : + return "Segment Separator"; + case WHITE_SPACE_NEUTRAL : + return "Whitespace"; + case OTHER_NEUTRAL : + return "Other Neutrals"; + case LEFT_TO_RIGHT_EMBEDDING : + return "Left-to-Right Embedding"; + case LEFT_TO_RIGHT_OVERRIDE : + return "Left-to-Right Override"; + case RIGHT_TO_LEFT_ARABIC : + return "Right-to-Left Arabic"; + case RIGHT_TO_LEFT_EMBEDDING : + return "Right-to-Left Embedding"; + case RIGHT_TO_LEFT_OVERRIDE : + return "Right-to-Left Override"; + case POP_DIRECTIONAL_FORMAT : + return "Pop Directional Format"; + case DIR_NON_SPACING_MARK : + return "Non-Spacing Mark"; + case BOUNDARY_NEUTRAL : + return "Boundary Neutral"; + } + return "Unassigned"; + } +} diff --git a/tests/test_data/std/jdk/internal/icu/lang/UCharacterEnums$ECharacterCategory.class b/tests/test_data/std/jdk/internal/icu/lang/UCharacterEnums$ECharacterCategory.class new file mode 100644 index 0000000000000000000000000000000000000000..97b1e3665ee774207a7b0e8541b35887d47626f6 GIT binary patch literal 1731 zcma)-*>W326oyaR*z&$FQ8pkX>_qGY!q#rJMomWDlUYppYHFfP1sP>TNh7LwH7-Rs1NKx3J1woI_pa0w%6lFdxvSDk`pSFfs@uHQe zpR#e*hpda~%gKFx$to-J7o+iS4SGe;&UyB0HuG@L&hvgLXf3faii~GbFjajm}wuBJY*)$5IGS*9bGJH~{To$yYt@2&O)rO!W<$5Q^ zR%+d6MbJT8E7L<$ZR43ZwMp+}*1{^LFw4rswabF$hU=)k3arye2QrkgyBNU+>hX=O zshb#MW#ol2=>FGXOHe~O8;8!X`q>t=+;L$~#ue=dS`R{VDr21{k*=g&L90;`hR%an z3454KTSnb9NUVwz85?ISeP7US6w5HK9~_`^ZQFJEP|zU?v09;(`r#3R%~n#&a*PU5 zESfs&oy=Oef%pm)Vl8J(Zt`W%t#4k=cCOvRxUjm|U_rHfw*@u-J$jlr%!L`?O1JZ0 z#(5tX|2Yi9X;BVd=BI*3Ge!`$aF+Uyv6HSHZi$FqZLlJ2Xn z3{!=DcrH9kl}qf!_U@vdXfz%7^Uh$Hfh>cgr8K`S<&l-<#!Y>*T5;D5bx49yfp zK32nQGRe`;-qmN1ry;1i3HPW;OSBAXfEH*4yjtTm#_KrWV7v+5V!RFBVZ008W4sSO zV0;KZVtfp~!MF*&$@mudHsd?syNq82zsC4=@IA(FfbTPY0DhD4Ti~}DzXN`k@q6I+ z8GitN$hZamknu<0j~Rag{*>`&;LjO<0e-~zOYm2WAA`SU{0;b9#@~UzXDq=d;KhIT zEAcO*`n2&^ZC&HHNgd|lfxFDZyVk=nj~@_YiJstlf&6Q%dlx5`0{pHaryxsDmskG= D+{7Jj literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/lang/UCharacterEnums$ECharacterDirection.class b/tests/test_data/std/jdk/internal/icu/lang/UCharacterEnums$ECharacterDirection.class new file mode 100644 index 0000000000000000000000000000000000000000..0da72b14919999b3baa4c560b046f1771b03bee4 GIT binary patch literal 2642 zcma*n>2lLB5C`y83r$-ny*OHqmZL4@3^$b9v6aL$u``ZShEE<-JdhF`CUJN;KJWlM z6!2G=;7hC3s zuov#4TgHP={WbZgZMA#RZqn|?1v(^XZZG^2{wD6*Jq!q%smZb*_-^3Ym8vgD*yuC6 zaX$&;WGCzlqH)Ymg3emDCr#gW9iwLZZ-Trl37WQ|&zLSuqIZIpy+NF`KSew3e*0}F zGUB+KglZ*yK__eJLQ?YtGY?mxmZQ?EnZ@YLnHWK{vgNrAX*hw?s+Xjv6iT&{TW>B3 z3(WNdP1!I!!*_=n#szKuJwqBV=yX1pFTJ|$>?cF%ulyrf3Qz?sqhy{>cfSVd+Eg_r1a0J|KOh>_EY)0dJL?OAF6O+dRK+tI)ihGjd{b8H((%(iHT$HX z^Eo{dCus3?)%Io3Y#62t9NF?cqo(u}K2%N*BZq+~mFrif$HBCqb2*TSX`)t{vl~d9 z8q2bsikk1pXsr&2R>zp%oxt6Zo@ZN9r8z2SJ+}&du%P3a^BnyCt}4fjpi8+Nx=`#V z+nw3ZvC;h;5RLt0NBDkbNB5%-MwW)#2-v!Vvg_52;bop1&7u!RRgfWYaG=$P#p zqUM3eB^RU$v`Nc!m?qFFpfyI5Xiw2J#`fDs(2paEe-$-@-(@<+#4Or#Ow5u_%rmh7 zvB<=NRvc&I1jI=uPH4p`CYB(UnOM?_(@dN}{8=W>XvH}uRv=cHSka2}Ok9At$ixM$ zxWvR7#5xmeTCu^zWr$5CE^EaVCaywUW8$h-Txa42#7!n{Xho5UTM)OIxTO_$n79jZ zkBPflai56?5D%GnpcRjp*n)V>#Fkb(Vd5#oGbWyD#d9WJK)ht)g;p3$lpstdN?Ktt kAtB04R5XHc&#Sn-V`OVaUkyjLsgB=i+;c(O@v*R5jmAU^CMFdVAMA%Rfx$90?bO82a%JMe5AdUm zcSI#IF0e`Ox%bRHbMDN%y}!Hy@UT{Zg^Yu22|3sdl@Wj7ZphWZz3h!dpc(8VsiZz; z$ZYR)9n3Loj{0}5R9eJ}hpr6LiQv{7@|Xuiw^ce$7_wf}7Yt=zD$z;DJrUpVUPw&U zj{+Wcc`Qx+MP~I-l4#4HY4<~h!gZ9!fjE<9%la?(J#!H1X^Hz-1YC3m zCX#$ll!`RhGE!vQ@TVuAYRIM75sAJKX8Odz62rkv^KG<$Zlfh>0%PM~nPLCGa*u`| zMDZg->0Buhdm&E}K_l1xu%Nr0vfoOq!=Yz3A0woPCd^ai5;DTv?lagEB^C-4%`$L` vBE{0AfpDIx92O{AD5F9MEYfeftAw@B+(I1but not in value
with those defined in + * java.lang.Character. + * @see UCharacterCategory + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static interface ECharacterCategory { + /** + * Unassigned character type + * @stable ICU 2.1 + */ + public static final int UNASSIGNED = 0; + + /** + * Character type Cn + * Not Assigned (no characters in [UnicodeData.txt] have this property) + * @stable ICU 2.6 + */ + public static final int GENERAL_OTHER_TYPES = 0; + + /** + * Character type Lu + * @stable ICU 2.1 + */ + public static final int UPPERCASE_LETTER = 1; + + /** + * Character type Ll + * @stable ICU 2.1 + */ + public static final int LOWERCASE_LETTER = 2; + + /** + * Character type Lt + * @stable ICU 2.1 + */ + + public static final int TITLECASE_LETTER = 3; + + /** + * Character type Lm + * @stable ICU 2.1 + */ + public static final int MODIFIER_LETTER = 4; + + /** + * Character type Lo + * @stable ICU 2.1 + */ + public static final int OTHER_LETTER = 5; + + /** + * Character type Mn + * @stable ICU 2.1 + */ + public static final int NON_SPACING_MARK = 6; + + /** + * Character type Me + * @stable ICU 2.1 + */ + public static final int ENCLOSING_MARK = 7; + + /** + * Character type Mc + * @stable ICU 2.1 + */ + public static final int COMBINING_SPACING_MARK = 8; + + /** + * Character type Nd + * @stable ICU 2.1 + */ + public static final int DECIMAL_DIGIT_NUMBER = 9; + + /** + * Character type Nl + * @stable ICU 2.1 + */ + public static final int LETTER_NUMBER = 10; + + /** + * Character type No + * @stable ICU 2.1 + */ + public static final int OTHER_NUMBER = 11; + + /** + * Character type Zs + * @stable ICU 2.1 + */ + public static final int SPACE_SEPARATOR = 12; + + /** + * Character type Zl + * @stable ICU 2.1 + */ + public static final int LINE_SEPARATOR = 13; + + /** + * Character type Zp + * @stable ICU 2.1 + */ + public static final int PARAGRAPH_SEPARATOR = 14; + + /** + * Character type Cc + * @stable ICU 2.1 + */ + public static final int CONTROL = 15; + + /** + * Character type Cf + * @stable ICU 2.1 + */ + public static final int FORMAT = 16; + + /** + * Character type Co + * @stable ICU 2.1 + */ + public static final int PRIVATE_USE = 17; + + /** + * Character type Cs + * @stable ICU 2.1 + */ + public static final int SURROGATE = 18; + + /** + * Character type Pd + * @stable ICU 2.1 + */ + public static final int DASH_PUNCTUATION = 19; + + /** + * Character type Ps + * @stable ICU 2.1 + */ + public static final int START_PUNCTUATION = 20; + + /** + * Character type Pe + * @stable ICU 2.1 + */ + public static final int END_PUNCTUATION = 21; + + /** + * Character type Pc + * @stable ICU 2.1 + */ + public static final int CONNECTOR_PUNCTUATION = 22; + + /** + * Character type Po + * @stable ICU 2.1 + */ + public static final int OTHER_PUNCTUATION = 23; + + /** + * Character type Sm + * @stable ICU 2.1 + */ + public static final int MATH_SYMBOL = 24; + + /** + * Character type Sc + * @stable ICU 2.1 + */ + public static final int CURRENCY_SYMBOL = 25; + + /** + * Character type Sk + * @stable ICU 2.1 + */ + public static final int MODIFIER_SYMBOL = 26; + + /** + * Character type So + * @stable ICU 2.1 + */ + public static final int OTHER_SYMBOL = 27; + + /** + * Character type Pi + * @see #INITIAL_QUOTE_PUNCTUATION + * @stable ICU 2.1 + */ + public static final int INITIAL_PUNCTUATION = 28; + + /** + * Character type Pi + * This name is compatible with java.lang.Character's name for this type. + * @see #INITIAL_PUNCTUATION + * @draft ICU 2.8 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final int INITIAL_QUOTE_PUNCTUATION = 28; + + /** + * Character type Pf + * @see #FINAL_QUOTE_PUNCTUATION + * @stable ICU 2.1 + */ + public static final int FINAL_PUNCTUATION = 29; + + /** + * Character type Pf + * This name is compatible with java.lang.Character's name for this type. + * @see #FINAL_PUNCTUATION + * @draft ICU 2.8 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final int FINAL_QUOTE_PUNCTUATION = 29; + + /** + * Character type count + * @stable ICU 2.1 + */ + public static final int CHAR_CATEGORY_COUNT = 30; + } + + /** + * 'Enum' for the CharacterDirection constants. There are two sets + * of names, those used in ICU, and those used in the JDK. The + * JDK constants are compatible in name but not in value + * with those defined in java.lang.Character. + * @see UCharacterDirection + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + + @Deprecated + public static interface ECharacterDirection { + /** + * Directional type L + * @stable ICU 2.1 + */ + public static final int LEFT_TO_RIGHT = 0; + + /** + * JDK-compatible synonum for LEFT_TO_RIGHT. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = (byte)LEFT_TO_RIGHT; + + /** + * Directional type R + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT = 1; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = (byte)RIGHT_TO_LEFT; + + /** + * Directional type EN + * @stable ICU 2.1 + */ + public static final int EUROPEAN_NUMBER = 2; + + /** + * JDK-compatible synonum for EUROPEAN_NUMBER. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = (byte)EUROPEAN_NUMBER; + + /** + * Directional type ES + * @stable ICU 2.1 + */ + public static final int EUROPEAN_NUMBER_SEPARATOR = 3; + + /** + * JDK-compatible synonum for EUROPEAN_NUMBER_SEPARATOR. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = (byte)EUROPEAN_NUMBER_SEPARATOR; + + /** + * Directional type ET + * @stable ICU 2.1 + */ + public static final int EUROPEAN_NUMBER_TERMINATOR = 4; + + /** + * JDK-compatible synonum for EUROPEAN_NUMBER_TERMINATOR. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = (byte)EUROPEAN_NUMBER_TERMINATOR; + + /** + * Directional type AN + * @stable ICU 2.1 + */ + public static final int ARABIC_NUMBER = 5; + + /** + * JDK-compatible synonum for ARABIC_NUMBER. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_ARABIC_NUMBER = (byte)ARABIC_NUMBER; + + /** + * Directional type CS + * @stable ICU 2.1 + */ + public static final int COMMON_NUMBER_SEPARATOR = 6; + + /** + * JDK-compatible synonum for COMMON_NUMBER_SEPARATOR. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = (byte)COMMON_NUMBER_SEPARATOR; + + /** + * Directional type B + * @stable ICU 2.1 + */ + public static final int BLOCK_SEPARATOR = 7; + + /** + * JDK-compatible synonum for BLOCK_SEPARATOR. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = (byte)BLOCK_SEPARATOR; + + /** + * Directional type S + * @stable ICU 2.1 + */ + public static final int SEGMENT_SEPARATOR = 8; + + /** + * JDK-compatible synonum for SEGMENT_SEPARATOR. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = (byte)SEGMENT_SEPARATOR; + + /** + * Directional type WS + * @stable ICU 2.1 + */ + public static final int WHITE_SPACE_NEUTRAL = 9; + + /** + * JDK-compatible synonum for WHITE_SPACE_NEUTRAL. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_WHITESPACE = (byte)WHITE_SPACE_NEUTRAL; + + /** + * Directional type ON + * @stable ICU 2.1 + */ + public static final int OTHER_NEUTRAL = 10; + + /** + * JDK-compatible synonum for OTHER_NEUTRAL. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_OTHER_NEUTRALS = (byte)OTHER_NEUTRAL; + + /** + * Directional type LRE + * @stable ICU 2.1 + */ + public static final int LEFT_TO_RIGHT_EMBEDDING = 11; + + /** + * JDK-compatible synonum for LEFT_TO_RIGHT_EMBEDDING. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = (byte)LEFT_TO_RIGHT_EMBEDDING; + + /** + * Directional type LRO + * @stable ICU 2.1 + */ + public static final int LEFT_TO_RIGHT_OVERRIDE = 12; + + /** + * JDK-compatible synonum for LEFT_TO_RIGHT_OVERRIDE. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = (byte)LEFT_TO_RIGHT_OVERRIDE; + + /** + * Directional type AL + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_ARABIC = 13; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT_ARABIC. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = (byte)RIGHT_TO_LEFT_ARABIC; + + /** + * Directional type RLE + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_EMBEDDING = 14; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT_EMBEDDING. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = (byte)RIGHT_TO_LEFT_EMBEDDING; + + /** + * Directional type RLO + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_OVERRIDE = 15; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT_OVERRIDE. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = (byte)RIGHT_TO_LEFT_OVERRIDE; + + /** + * Directional type PDF + * @stable ICU 2.1 + */ + public static final int POP_DIRECTIONAL_FORMAT = 16; + + /** + * JDK-compatible synonum for POP_DIRECTIONAL_FORMAT. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = (byte)POP_DIRECTIONAL_FORMAT; + + /** + * Directional type NSM + * @stable ICU 2.1 + */ + public static final int DIR_NON_SPACING_MARK = 17; + + /** + * JDK-compatible synonum for DIR_NON_SPACING_MARK. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_NON_SPACING_MARK = (byte)DIR_NON_SPACING_MARK; + + /** + * Directional type BN + * @stable ICU 2.1 + */ + public static final int BOUNDARY_NEUTRAL = 18; + + /** + * JDK-compatible synonum for BOUNDARY_NEUTRAL. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = (byte)BOUNDARY_NEUTRAL; + + /** + * Number of directional types + * @stable ICU 2.1 + */ + public static final int CHAR_DIRECTION_COUNT = 19; + + /** + * Undefined bidirectional character type. Undefined char + * values have undefined directionality in the Unicode specification. + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_UNDEFINED = -1; + } +} diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiBase$BidiPairedBracketType.class b/tests/test_data/std/jdk/internal/icu/text/BidiBase$BidiPairedBracketType.class new file mode 100644 index 0000000000000000000000000000000000000000..4b772fb56be731dcda506c8cfc638ec1f389ca38 GIT binary patch literal 385 zcmaKn&q~8U5Ql$b^QVoi)@lVWo;;h2PmmC?AW5Os`C{d;lLx+${(> zh^Lv4VdnSE*Z0RKfE4E;4hT1OwTq=P+$qt-vg~8SZzfJ;B@?0f$~9{tJFb#Wlsh)t z_ZJS~5$3gc6>%ffb6h;tTpEIx7kNgY6=9aPN*kffqiA{_*+kfRvCeYW6TwgKi%sUh zTKH-4kZ&D~2+^kPyOM8Z!}iXv$+e3kjC0oJuGJ>QDdF;ed%|?36nAMOv}R3M{`pQ| xmEpoYT);KTb>L!vV1t;spZ*#kK6+|-tW$FvabuA*&5lKgawwtW*(> zfsiWE58$J!Ue5%HRcB!z`}n?m?tT3G`wxH)J_Yay%frECq_mZp7D=SyQDo&W8@1Iy zwS|#&_?QSV86rTH&>V_u5hX&ON5}o4j4feuPibZM36;&Q(*SkC#{WaE9bZYU^mz>- z8Udz5%%DkVm3Xx?5noFCRail&rbP@x*gET#c#iY!2ACtPml$_V`fa3LZ7)K+#4AFe za*9)JmZmDacM0{vsV59eL|s-+nWNFqzRb+Ym5h~0nEpZVJLy0YW_n7?;{ChmC(O+C z(pV&?B2(@@CVhLMxQ^|zA3xK|)pC-KvRED{7q{`$+0U+(tmKh2_Aqs2hFz^?)=7jh zlCuP3-3U|9;&H=^Phy2N@_CZn;tui-EZ}vHEL@Inu*gWfczhU__|%1$GYhSIR9emY z18R4eYBg^jFnfpjTQ>3VmiK8?__zb#`+|nIhj+|{g)5fvo^KT{!dZX7#~cZ(jEl_I R*lvweI{S6TS;h@i{{d1Vx()yU literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiBase$ImpTabPair.class b/tests/test_data/std/jdk/internal/icu/text/BidiBase$ImpTabPair.class new file mode 100644 index 0000000000000000000000000000000000000000..9fa76905304a4c6ce5652bef30fc78b6602773a1 GIT binary patch literal 631 zcma)3+iuf96r8o4IyMdsp{0~dTY8C_7O<%L2I3)+5S5~W7hkl+LO7cO6bI-64QhLF7H%p9GaGkg5)_vfzwI%tM);QH_)RIngWAIo<#&Sd^3 zel-}Yp%GYkrgLqc3%I+jo{uU)nzjRkxaK2@P{VbB)_C+b*11tdF0)tm71YjHX>_MUne}9$E&o&W%&9H~_PhUW@hKh9V5Xj2fddYuA#$6@ z!elxthU$g3V{2E>d~CNTP(4zd_rLPV&8p4zUr}X<0CsAtS~m< z0l{~8!4E72Kd}@1!fnfg604K literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiBase$InsertPoints.class b/tests/test_data/std/jdk/internal/icu/text/BidiBase$InsertPoints.class new file mode 100644 index 0000000000000000000000000000000000000000..fa15f367e602c41e7f9be2ee0c45e5c6e1c97477 GIT binary patch literal 598 zcmah`O;5r=5PjPg3Rnd38x@QpQ8C&dfbjr{k%XX$hKr}Ath!jXrd^EjUwJSlCi(;X zQO0S-=t&N{GxK)d%+8yS&)0VVEmU(bVA`-8q>yGP4*5NIeXg$E)BaF+njw8CmDEQJ z=FV=e|gJQ#%(hbZ_EXhp~qeB}dTOzMP*)fu@zkt=vH`vd} xJ`rGGp6;ZWQH5n}VS!@jI~j{uqR7N@lDUG_#Fnv6wnSVTWo#fr{4y%Yd;!)QjV%BG literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiBase$IsoRun.class b/tests/test_data/std/jdk/internal/icu/text/BidiBase$IsoRun.class new file mode 100644 index 0000000000000000000000000000000000000000..be07ef43dcc931940a1b30f27f0c4d0559b7e69b GIT binary patch literal 544 zcma)3$xZ@65Pi)yI1Ylii`zltlIVPZ#se552|*)cO~iEGk>kVm#>jaDOuauOtZzd|?CFceyPNL;lemFUKkfiO>e5E4`G=zxcP zZe$W?WWhd5>VDk$*UXpHtEXcVh+CORR(^K6NbW*2bwy6n>5~f9q zM1qDW%@2bEICOQ81s33v1s36@Sjlh+)ikbUxSU}`I_T7NBAKc9Tdo8bet;h( z-o&~U7jw^J?p)5D&#(6n0A1_{@K6!(LsYRuXiVj^j8bXtqrrHp5=U6N)JD52LZy8& z5~vZ5r<2D>8>ez3(?}=t$f*|>b@W7cq*X_;%~I(UL0BhqH|P^6=0T-8C)AiY70;g7 z9}=piB>3HI!jIN^+Nl0~Hdgta9H;Cwds!mWk<4|W7pCtXv?a8A{|j?L2!`1_Pt=Vr zX4Zexo)sH&roOW7HnUD(hj8%sP(m0Rqw;PltyP>tELO%L1b-;t^I1l~6aSiVp>&(NS1~jq3s)9|f9=5PuVhg*B0rv>Bu!q_= D(uiog literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiBase$LevState.class b/tests/test_data/std/jdk/internal/icu/text/BidiBase$LevState.class new file mode 100644 index 0000000000000000000000000000000000000000..03ebfac159482212920ad8342537aee4c1bfa529 GIT binary patch literal 581 zcma)3$xZ@65Pi)yFoGcN8!jtj#Nfy#eGM56UT^m= zimp_mIT`nbrl)=Kl-E;$GwVHM$I%u zXr6-5SU6&+{H@B6Zzv^nodyjBwUJ%!49BqOOMon$9BjIQ735GwhI^pC@1!d&H91kFySN7-NN6qg2YV IP{9f8U+n&Sga7~l literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiBase$NumericShapings.class b/tests/test_data/std/jdk/internal/icu/text/BidiBase$NumericShapings.class new file mode 100644 index 0000000000000000000000000000000000000000..89acd543885c88b73cb2f9bded022ab87e0d5536 GIT binary patch literal 1182 zcma)5TTc@~6#k~&vP)SkZc#xlf`YU~yQp|ciYCxVEYxaJ0*O2g+X1$eU9vk>evA(q zAB@Hq^g;B&M<4uA#xq-#QZ@QA=Q4A?^PS6l`~LY0fFkZB5kp*uW+H(uhQ2y~%IyaC zw(Lh6b>T>ct~u9pnW@kOQr0pfqsS|b(!bSWPX!U=G(}MAc?a$r(?jxAkH(Sj&X_& z9#SRxrXN)JE@ipfo~0@Ss0w4pktU}tOLH{%SFHG)$Z>*Vo$oh zm&7P8=om9Gj*ATAe`*AEIS{p~Z~`HTVE>koOPw8M$YzK``_%s0e419#uTg=ivg--z z&V~q9_(p>~R@rxWW0eQ4vX7ja+;%DN%t`ovE=7S>ESguKaE}|&+CRG0)J`$P){APg zk_Tk466p@Li1gm77)p?u(nQpZh( z(GyMijWvT=@;nhl!xU6zs%>4=ZextTMvOic!+`o6q{YdmUqzlvWZ5Jc$wclW*a0aq zOwg&WVLitr>1OKzE@O%;LoGddRB(fUG?MA}(7z%@XKs3UJ&*>Z_s7E zg=M{qAakuSWRRtI1b`f-qcmw;!PSUy8hO&<#84qIi!#srqWxI8RG^jC*dflWy@s}Y zh>;J_526c$svV+7s+bmo7ci`sFs)Y+1Jx6StRuFp(@T1Kjm#LX<3=QBaf@Vjdp7CI=t1;DRw^wMh_ELjmBgu-vm?co zYOVkEcgYua%`6J!tx9SZe;#m=41v3E%h=wT*gDuH9R6LD;5D_DQ6m&_EV&COodS;F z@QlIp1(xBm1y)jeDT`QL=p~ey#EXA}xyGK)Tqx(SpcfW0sIX18kvYLS``&i~Hn7Q2 W7F&y~ZR{*q#U9h;90yhGqwodUoo;^s literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiBase$Point.class b/tests/test_data/std/jdk/internal/icu/text/BidiBase$Point.class new file mode 100644 index 0000000000000000000000000000000000000000..e8c52f6a2e49139f50adbe8ba4acbb8448b917ed GIT binary patch literal 432 zcma)2%TB{E5S&fgCWMxjQXb-fI8=yoz#jnO&`5|%Q9%Or?xv+dsQMd&5+Ns3gOrMR3YDz=2ysW#f45!}Pk z%!5xDCX0Kaja9jksnBsLta`R$tQUGL3pKpT_>ujOSwWx)p>dnaB}14k6rmewqo(D< zT;(@%p0d)9vRI}wnd>V45gYbSbN)f}pWjXh!F5*Vu{zgP#m;Xt$JIatf2s<5krmd% zCSmXIl7#le7?p>qEDFUvH0z1550AHn`m7*e2CUXd%y@s`OlE?yR*qglFDy9d@LfH_ g*~J?3_O}6D^f+>{Uc36(sBwTT#(+H@2H1xG1;=t-$^ZZW literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiBase$TextAttributeConstants$1.class b/tests/test_data/std/jdk/internal/icu/text/BidiBase$TextAttributeConstants$1.class new file mode 100644 index 0000000000000000000000000000000000000000..f6bd2e9e2468e305048fc9ab02f8f0a274c7b096 GIT binary patch literal 796 zcmbVK$w~u35PcQLjK*j*YTPx42rl5@LBs{Y42nYZqImDjG)c#?2c|pXZ}=&m1P^|I zA0^f#8VHJr4NX|HrB;FVfpte3HfuaW#UJ|7-?KA5mx_nCxqeNS_!4T zW_oKz87?1T`iMWDA=6>z_8Cp_?8fFZ=!v-ua;co!6(2Fee5q@JJVsecbz>;7-oZFa j8BCza)WIaCG221ru)uU41FT)dGH05^99B58%Q(LeQ99hG literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiBase$TextAttributeConstants.class b/tests/test_data/std/jdk/internal/icu/text/BidiBase$TextAttributeConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..b9d4e401ff712ed4aef6cfbf473c48007ce06d87 GIT binary patch literal 1863 zcmb7E-E$LF6#v~O?QX)RDVKt=R0Isr6wTTS7EM9(*`}l^Bx$R@bZ$4>vL)=|W`lk5 z^F^N=$3KE6W`I6eb;j|{8U857bGK`nlrU2>vpM(PbMHC7^E)3eUjFeHfIL2nVhAAx zVGY9=VHn#HkA&V5_O`yVxnmk0!^pg4Tiz{(&{S$I0u>PjQ4J@cF zbj#@Ip1JGkIjd>qMB7X@XqWXo*V^oOX5O*ep0K?(LwHAQ35F|`zW2f~%ywH}A_&>_ zM#-_gtbdYGFv>93clWryk~2}nFebx0$#8nAau{HpaM|0L)Y=K0!nlId8qVMihD&{p zUI&UHv2A(-17x^7$WM>!18ymQDb z3I00_=Z~1LI$p`?*v;auVLtRM$ByC>E-SdAVG1dR3xn9LQ@CccZW^vB%VV6FT{>C? z45=x?&|7e?%S}ebRfbq?wYpI#*NXW@d8Hbq%6(5m8ah?^(abRv2QU#teEig8WP8kL zxQbbZnFGH5$7>bWC|%Xn5HU@06y~uE?CzFAa7|YS4KE^gGjhggc(2$cR z!+EDkH50E`wpr~w*fiaS*lf`WuQ-NitqIqX``|F_-Loi_bNv}RZrf(ao$Z$>?*SWh zETy*Y3FH2-EpR1O%4rma4`M4o%(7QGeo*t>Q0r0FK99)yL%z*XlHfmMg#Us#|Fy^VB$jZS?p6G|EKV^k zcM(1boGkE(Fx$uE`eTG|?<2Vfg-`F}-95a|Kk(&sKIhAid^nNk$UMdvt$8*8Grx!Y zGas=^WL*q!%}UyM2P%IAjqifKT z@4XKaQK8vplN8kBl-g4V)h}(SYg$^}FsQy}`Jk4%l`Vq`>TBx@s+;SAB*;`0AWM)_ zTi-Ojsc~7eAUUrfgc3(lkV1mo30}#>hU!JA->0B&F*j6-!W0n{PAD!Z=hnJ7Sy2iX ztAyerZkML0%f1C=T+mffH%dpp%c`5I8AU-kC5IlsXq&nVI^vY-71e_ps+TSrRNT-| zx2U?IqNTc}u4rXV-LjVY#-$<3pe#k%)I*RprhaLC%Q!(spT4tf$`N$bey#JH7A;>= zx3nb=z^0=Fb?c~C(b81EbWy?b`i9!NrVt%TSq}9A>{-4hYVv(&oCRmg$XHZ_Oc^;Q^beXcnD-an~o5f*lTl%znW1!~nIq zG|#3J6`e#UV?6s|!`Kd*Sx`Tr-e1Q~acMI9`Ps%t66x~Z>j@RxI(t|r(Md?9F&qQzXdYe(IZedhWUMW<4Oprj?$tMVHf z8f&mhD1aP}J1a*yPZekgF4`>l^B7 zd4W~?nTBRCEztjJ4O%pkP%CdNV8MOfQ0vNDww&pG@)p zQ*MD^8$XEDHqS<#(5&?TlMsAyjQM=ln_0-PGn|tEmHQwRYa6XgA%1`7Umr zP`9vpc?0+wWbzdBTyA@xqWc+Iq^Yj435p6TYg%KiR{9SrdWeg{V7`|8rs@UtHPah) zhmR=wGnb@vG%C|dRF^)c=r3GqHRv_Oy*#1lN!?3hQ~jcPm>J&k;-aS&Jwwj|BQ`qN zFenVs-{|i)J*Vh-dO=X;elkp(Co?N24#`6&HH)j8^3l-gGq13?xVUdIH-AylOY|}X zD(1To75ph=F@$nK|5WrUm#1?1^5&MtCG}_2)oK>y;(sZ6o!-FsiksQQC~REX($v_% zfS7W{eKqCYQuH>DN!9qp%qHCWT}AJ)6%nafTvv1I^cV+m(Fbe}g?QK>Df*cCE>%;V zD=liOUbeWoq_UigKUMT^p3>x6Z`!zmp1L4?PXDp#3q@aY=eY+aPRw@eSmDlKYN+ zRP+=548DbgYvT1(!MVRE+N*Q5P6v%ZP$2}&(#WK`miVxFhMDpOXd_G|0!*Ah12Z${ z*h)B@6XLl5A3=O@c1Q`AvmNGO&zAj8gq4Wsx||8g)wpyK*G*O;g((^X0amv~8szX{ zMp*{a4T}Z@6;UO+if-tx(aQrx`yQ5}etT%v&qan3-I*zp>zhlLFIfO-RI#kC2Kp2% zA+nUnW(1vS`4v;EiYv;PSVt(4BaQ^trHy5fUQPA2EX-kj7dYZ*Ab)6K6~i+mQZYv& zRrFTk7~RLR#%3t;#-*IuSBYHC3@oW`saec9HvdWHKLc49{mhsQR$_=4iUql_er4(4 z8bL!L)(*L`NMz2@#l;0$yoqC#7|zpUPb`~RI-#nBhdx4ykqLR_+}|iAMvE~}&Dwyr7diI!4O=fcLShp9~NDyp|n<7 zNzhLL05(R3#b&ly*{QRx1!R_14rjy~l~^WD!{9oD^VG}#2GO6VW+ht0a#+=! zAr?R*)mAsb#P}cAVu8OFPgi0kQ@D$7j`0LcgAq~hnbSg?p~P>PGW#sTlJerJ@)Fjx z;w&Xr^DM-e(qE?2C+O01c$**MdTZDdz?xC4RpNKtX~dh>X$3_SCKQ)Wa>V(uWtroM z3qiivZgv3=vpJ`_CC3)9ZF?SO{ph_{NL<8PX@jnllW@PflN}#C5s?+iF3vUR-aB8So&H!E?A_#>1Cl&KGmwL=Ay z{5BwtdaKTViQh zw!Ebo3J7|i7c*9>1*yiY1Q7QqaW8`nYOp0ki%J>B{YpF_9t3*TwY8e8z9fX9J3~CI z#3Q;1l={N@rX_W?4CqlM9^+hXm3jgR;>Qt>!+e2U)lRIO;=-9Z(1zG$)i2Fi=4pnQ z#I2}1jeR|N4D2Z-o@QVU1_tspwS>fay(JfaRpM{r?`$(^+Os&v=KgRRtvFtJbWl7m zUa-YKlz36R1Vi93v)$3so7NVdZ*!iW@aM%VO8is2>XkszXik9nB*edzcwN9!b$ki> zt4t1mf`H;%;!az~dlB|a7Z z##-Hf4t|X&jxB-F70`~n`4OKh@gMFzSqq1P(yEx)=fW?Q_==ZBa8Xm^@?|{VocoOu z-!ko7ebWvIvQ{G*3xVFl&Llt&u;0Cr}znnw*!^(gbe-ESD21G$V4ErKHVep2b&C z#j92Zl?+Lj*QaM5qZm7%f_a{DkzpkxGKpyrTa`SbzS>zUQXb8qNHMh!QB(otK zpdaIIS0Ac}syssG*z!mvkCL!c58;9?sb30{)<*ZNbg=(EoXQ=oIYstTvbQE4mbSJl z7~4Kd_GPb~iA?NOCrS8E_tH)LHh{M$H!<>qlpM^~p2K!rRsI6z776$0MuJG4B#(vj zQ|v+$VRCYWk|X7DsLh*swo>3nI~0l-1u$fgqm>-P7NOVAw0gKDC&_V29?xj|uE28m zi&oTyWWFr0WucN2B)l{UZdH$_VD6SiwjX>47Ed^~(LzpAa zjf?7Qsv9aBJw{3$>rjoPtme}v6VtEZ4>s&OOy*{j~6U)luNchCrr-QSVJcnBz zb@-M%@oSX)t-v;e1#L+=uc4TcA%Cajc@l%F$%{0TRo9*Z zpUw#to>js_xkSnTV-5~#$y;8PU*gKk_6lvtW4({6Vp8 zT`|mx>Xt@W009^x&8&a>^eqg^tK`+Tyhh1u<#mFFA4bDh!Y>hr4VMy>CC&h#f68Z; z`twv=hV9!BPh=hrm!5H0qj@armAqcw;K}KDiJ&510RIor5*0zr$t+>7rgTX1g2u*% zy6UA&fXzy7;n637EsM&F3#%$7=TC>Z&Sl$_yitPcDV;`Gh0PxpXo6z!!Ho{d4f19s zZ;>!ct-8~oYe1e(XG}gmedqF!Z&UJi3HK_?i=w5q#Y=1J;MT{?6m#iaN^a*;cKH_6 z!Re^W4WjmT#_et;+ZgXiLGgs*s-oB~!hvdVyd_>7V%SQzbJPb#`#{;okQ?a;u85BRp8feBV1awBC+VscF z-c66s|DxpM%;!;0r~{SyT6UC`HL`L>!{hF~@Q6havZx1{?K4*0_;l=-glK<5J(v&V9792H^v}T# zQ9GWI0qirm@`AcmjZ1NAx415cIW@;S#mEU6$wrE8q$(rL=+f!PEv_c8w(6TFgUA)j zvG-hry$~D9g?;C8+pfy!#tkEwjmFdCHMl548QqOc;8TN>7rhN;R%Zi@k1IsJk&XGF zmmT8>$R=-u4ZPvj8wFqv)tTyLH|kUNSUwDEpCFp+P_vhy2|UII7+)A+_0pU(>Y5rg z84{cJ%kdg?P{S+bhHU%c>{7@N9ixvR3K_XZKilY!t%Wf_9Kb~yU+yRHrUN>3_^(=0 z`)(T$Rbap}f65pP;&%#6@DD1Dp~f)VI93_MIgBBxLtE)`Zwpacy#xaCNXm1Jk)ZHA zY+6QvEC^LlISU|sG+8+Zj^&^~SWb>Z^PDEET272-Y2V0__DBPP34M%0j=v~O)SI4J z9t+fPj3S6J%}t|n<_%s6ZDLGP#$?`#!Em2kx6-Tc7*n9Xat5z-4D38n^8o8($2Ygtnb+ zU87kUEeTBy*xf!&Rw(22gr0|T&#RPiMnc{&&O1{XXEEr3`(krw3mihCq-a)AoJ~A~ zD;zU9wWNT^q}BUXgd>d$&W1dhmOnf0TdC6Exa2IzFAsJZHY4T56N(H->T|%x)AF$q zDm!6vQMt})2P4DI<2I1@h7VXkz)vflT{MC7;R{KdT2wT>svsY`n!>Va1;wQ>9I+H9 zlvPbDE-x=D*U7F3P$?>}tSTv=R^<rHL!Ey++?hx@}jcx2}SXh0*;U6#CXoucWGtQE3vh}iqVAB`#@+$Ki4NAOvp|E)UVL0XschNc*WTQSLlk@qEg)t{8xC@+?WoQDV&^- z+1EQ`CQBg>8Znr3%|g@jkw2lTpgg~DYEfkshs6L`GT^3G6i=Iui%=s}UXoD23BSO`Ic`aQCHDb1lv-L=SyfR~G!;~@ z0{zQ)J#_1wp%(!ofhjyd3CIH;FDWb2FqmsV5AXnxugou)US2kxkuRA!trWAEl$cwt z=aur5UsV7SdhN6*NC21IDOM zPpH^<(&wpj0k36oeKV5v-sUh2)2QZDIHi05aANcMKS*DLy34SM!n`f1Ug?FWK&;^% z#=7<&q7v|kChS||u~wteLqqif4y;K{DEG8F7wTxA&V~NA4!ofYeIo@O#)IBa#OF$- zb#=AuqcvcAVahwx0Y|_7P`V^^tbvWm9fz)i74?gjR<|r~0`8?Sy!JJ#5^{Wu5^~~j z4j8t@_*Ji{E8$>F(AZ1pgCLAp8<6O}v7y!@rp?;}Sr6+?)(=62Nz~TOHJ` z*T!+@IHhQPb7F=cq6JDeX~!sUJfYV(ItLh}_=h0c{?#*$ip!enR@65xZ$`SM&d=mS zsG3tb4hBXb_TJiYAQynh{SUF1b)w4QilMJ+FESv z{S0>*cZib|FcePz4%d-ak!O(m&_qTbOmP2DA6+`j;s^YPv#ERfHAmYVp_0_-MW_IA z9p-_Y8ZU67BgZ){4qW-weHTj-0u_1AI_lbf4rcLG*qdCvxE9VBJ|xo1*Qn>D4yW^h z#E#{?&?E-{d^!cd5q!iIj?G*wUr!oj4;BR}Sge|5^@a+X>hEE6IlJur=k9!y;HWqHk*NgMP9=IKd^+vDJ-)zEE^8->7Ah#FTtAfq3U-7 zJ8Vc19Qt_k($q2(6sY%t9$}z?W!Z-Xp#_QP0ShN&FpCS!p;!er^mq9{pEvE6UO~Vp zh%Hh~bcXyodTp49dIUPIu2@!ETfm_haG9MB&BT%XODfSbPdQ%Weg(i=(Q)Dw^4`6Q zzO3;=bklfIRCYc-11!#+5OZFjZ?C< zRgD@!rjb8eCNEV?6pJ<##R5C^4mj?V-QTT@^B^o5^i*B40$dr4_W`w?AdP)rB#Q*D ztK$W=Ao(?}YqXLzi!pVWq6Df~+T#e0FdJ5|2sK)G9?U*-86}0-#OfwJAMCPi@zsYO z&aZO$dC33z`Uh|k0+|I6@~}$x1qROH5|+xK9(ajS!uyL)m{eH)mDx`@KwBF!B4AhhOkcR4imh`wn>wM2#^p^l zbrTVBkG0RNzzi^u2LUunVId-voFgi2^F~1<4kNC4YT^qvwsCIm2@$7?moBYq(uNU7 zxFFeap938gB*xoXF=cPZHEEPF>l7Qv(R&aXTB%?}pbe0r|-+}a<3F*6#-ky-&fi&XB;`4Vm(uweQ zBE2i2d^ghfB&6>}`o4rT&)@wC=?9R0Fd_XA(hn!3A3^%h3F$|Xek>vV7o;CgNI!w} zlL_gkkbXKL{S4C2Cd|)M;IF?Xr2mHb`g=l}>G7QLe0=;o-WL+mccK1266!NQyqJ(? z{(C7Q&HV6kLi!K55Q&&+tj%GE|cgd?uY0nE;;BYE~w}yZZ+^z zAh?d796ZENzS5$fxN*Wy4vNxgT*J{%T>sNgT=(NA$M)zn?(pd}!g_QXm-6_@QE~c- z_+ozY>6CsVUWK20-%dYqg#*uYj&tQF-&WO6TuaqY+(Omm2wv7tL_PD9!wK;0&JoD^ ziKsOFM2J2=IdBWlbPo8^`3Q{GPlUE|zVRxaF?o6s(yt|?dH(;EkmmV+Jt58O`Hh4$ zuZK4i(pWDX2*>>yZzaebmK$#;q*-pflaOY)@oqwz`*|-R&2r=Ygfz>I4-(Rla~x`? z`~5HhAC?y%C8Qxw_&`I~!{LQ~;-G?`9G#=nIEv6|gyiTnjve$9rwTeBaX31S!vp=q z*?`VR$c#?o2tYsK;@9~Ic+qLN_w^G#d;NqXUO(Y{=O>5K=qKV=bUqyLI*mveJkyPj z6UK2D*8L|5=`~bA4qu1H%zld614&|K!A)&;UwIpz()c(2TAXK|Z+wP#<&_(sd#k|s zkMV`y_9V15P@_xk-DG49+f8=n>g&ihTgfySmXQGKVhtNOq9LQ{>>#(hxq9Hfs9u$Ts>3&LP&b{UwfAqIbfETEAFw^* zzV~mRdZ6~#9H>2COz_(u59}HLQ1^9YLlK(hz68290Yb?5hDQ)1hBF?-5IJ#RgZ(+P zx+kB#`tp5Aaa{r+%O^#MgO_|%2KlW67{`8%A53T*h&AT>d4A&we&eL>$*Wf<6AJ2M?0I$^ss>rNg}Mo@36%0FeMjk8@-X-`zT}1F3NmpJLbn@*$A_# z`5Zas^OS7B6EAc$I0#2?_eEuXH8+g zLILwt3Yo8wYra9<%s1%>^KIQ}R}Y@QUILV9dIUBPVKpqdS~vW+|&Vh$>Ntmc*(}gP8za{hVMs)_kr05 zG{XE?W0dQ`j<4X6dfhT>kL1`?jqgZ~R|P3~Et@1m{Rshu;z18TF%V;Bsc~`cE*hC@ z-tV;0XzwvDH#u~FsEzXZiR=lv#sf5|jf!(kJmvp_7a z*5`0cMjoY_^QpU8O-Gq^lxx=081pwYDd19BK+y?-BkANoPg)S@MT-KxsWH%pS_1uO zWnciE6&Ogr3k;!)0>d=fJi&KyoNN~x{{@MdY!@5fGubq;(#UG3GBPl!0%dkLGa2;b zi_NG2X)UrqPX~=o?7y3u^Q>qfYHgxG|GT2*Iy#0^TRC+ft%^_gZ!o$2@J~w) z%+d%F_PZ@Wno$n1kf{d;Uf$79h)V+16bvlTeRzvJ6z?OXA;Y1<7svM>##MkgZr@>y z>j3W!VA9)vFpT2VNgb1M zJr;TgbZ-==f!CU-Tc9~%6zOq7rN<{D-Jgu4gvmfC{DDTX43lv~M?c;uPRA%#9%dBy zeuNM2cz<&3T=PIPdlnYT>I7hR9AP^?v-rTo0fFsD-!%aC+rt3ErzQ>vY`g2trhTl8!1Wr8w;}`n043ik_Zo|?di4^`MdPjGvhjDqgIl2w z^-G?KM}7&vPs_~?EcS#xzp&JArKC{-mQSgzyXdTk`Wal=h?=|Umj3)c!F%5hUG!`rc&cIMep z`#MTT>Rx9fDSjqH(tDhbvVYd9E=g6R(eNk)txl;^iqWcsz4A z{WZ_b&RLg6w$ysIzH-}n>-W&X{%XlFiNd-WYi68qRePg@>yFc z#e>_$hid`nJk{DhH5xECQYaco4sW74`vNjOKm#s$;Nq;K8(F*4FN(|A0hTj{v9Nx}n^%0N)5EF%(4in^6tZ4;$2c;qH`sSIEc zd;bVbTla25Vb@JGLL-uXz!620*6%&bD+w{gVR`P_r1sXm^=N8u+PlD;AWDy#Jk%6) z^Hk=s$)QbTweBrKDj)wqyUenvgZYjskd!%Mf|qSp;;FeKlAFog5e>G{n;y))7L#GC zIlqmz!ZLh^8K!$jQ*aG9h8d?dagtC$vkn-q^_RyO@of}JJ}WN?!^T)(qwwr?={#-V zyM(c|zZOG^5n+yfd<*sRkOA$tw(4c!4~$F8JhTroLdHAHN_c`Xtc`YfJiT=bWojHa zKNB0*_nBkY3enpB9kch%#A~zy^5$`pfhWigJWZj% zGn5wi8x0OT4;k|U?4p0rC-z#Sq-l+ot~E|(SoyMtRUms=g|fdjK@PPh z%j2wKSz%3)v#hCdfmI@xSkvSxt5mMBX2|oca`}H&rM$|TDK}cPkMOpwc04N&Nk**=Nj{^HO48{c}9zMzHuI&msl4Xo2-kB+pSBq zKDZ4Ig!2$8$9`-VigCEvK?#H?aegm#y*0Rc)kTtBs&C(n6CF^oZv96%5)*mRxx{7kGt7!n%an&+iAN`x$os zUt#b19d@VRSLno0Wd9I<+vC0E8at`IO&DG(@vkm{+Me4cEc^?$2^DKBlKLfw9uTQ* zqDwyv_+IF}eXNBxksg;=-cHWCodVV!lxp2cS=L?D+uBaYTG%vOf1(=eZfdaF=sate zUIE_LKN&X8=luK}yBGc*g+Hs;fF3-nMIH2D z68HnpI^dwQ4mRKp+g*E4totyU`zgtKfHJHHX_WO4O|Tx;*n6{B6vw{E!=4e*J}G!> z_?r|yk{2UFKGsvz&w84MThGuK>sgv%{gqCz{-(#l zb}8_Rk7IUx9J9>~@Fla_Y?DtZn8>ruOuU(pSkufbGn)chG6YHP;V&M3$DE4qVfcgo z4ufV>cX52sr2~>f;IRRB)1ExDA8dfn*apx{tcg-O;0cPxYWrM0ucCCofT%eabO2)y z;0YZtV8A{zIKb#cgrN{OWW7Kk>qSboUc!=m8B6jNEXjY;KvdXS zy+MntH#ISi_3(`oV{x1qi~UIr(aCz?Y?_ywJ>dNJOml>*|3c$I0%lHp@WUrToiB1S zy}`o9=osv@{+bvaESJj81nWIu{XTWEKA`T_hY75f8OJKq$Epi#cAf-gHGKHS>r!Bg z!orAdjL~uEC^N$Z#rxeYx;(g=HfaRd7Leo9LxEvJY6*yjxgpqM!Gc)F%381Takl zGE7YT9&`Scm{Hzm^`OD{@@8zGRZ3|f!l&Th&nVscoO)PaQZMT(8f<+FN%}Q-_!~^$ zcQnoV9#Z88I@$V>nyjB_rS&tdw)W5k)-QC0wU@4iw`-eCnt%(T^LkN4@2PBp^G)x< z9P~WMJVJEC3K&mezZ8Uv6Z*#Z^xr6QabC%5;YM)`R)v8Tuuc=-q&ZY#=9owNYoQOB z?HG>j$t!3%eB;YDkJ3A|JqZ2&fz%%AY2$-alD`*~Flq3E(KQ{D7RWN^^Hz<8z@9C1 zHWNH*4;^J?Sa*v)>sdF|W%GM~t*5H=d#}x$KP_rfau&;x-i8@iUQnzo> z8$2T#)EStTKDl58F5f8z=~tBCb*&BUcUFgZ(LPLUE?wK9?skxlwnNm5%wOKn9?RASy^jm+$)-wFo_UEw7Tfi_`W^G<58q#ey!x7B<8A@o@ z#miY6YKJ}+eOlXJW{&n-fTR2SEj*6yg|h^3Yd6iE8z>0rgGOsZV87?0!46An4duXj z-2)7GG^N=+DckNvIred2y3sVn9t&n0Pp8=VV6*}l5EH;?ljstAGF@g*q4oAu+GuqFLe*0Fgut9tT{LJlZgYB*DrM%CNKn;rVSL8XZ zWEoh}SkxP7Ow>+Ej_wvk<|Y~(byAMbWgketl)*fZsk}BFyl;Zp+z(}(he0~}*?AE8 z{vbd#_~bJ12yUcQrr}0%HA&&^(jyFdQ4_~bAykK>rYD<`WlRs)jHr#j zs#EQ)Q8NJ7)c}wSlOfbPI?BikVC?DZ{JxUARkA@91K(r<8Y(jMutvtIY>ib-uN;6L zVpS(aO=lCOa|4ILClvJudMWU(0a7qF#q5MMvM@BruP8UtIK#unqtPC=LQJSAgLmZ0 zJV(zdG$QlT7V4X&r^{xEvyH7rtseCpJKh|#>UuG*x?mtxKysW4wq8o9b|YojEp(*4 zoQB#fDBnJvCfKW})INh|+P|UM_L=yM^lGZM&!$E8In-dE3yHFZ&a{6=zqQY!3+?mi za{B_>U|$GnaslnMFQz}+m(nZtW%N(LeAE5|y=PyAFO^_^3? z_G98(`*E?yenJZSNg1@CkxBNmGS&X8>}LN>X4!w2J?-aZKl>#)#C}A7m`Tb$8c)kBZ!vw6DjJUz6vr$>)w8MCcnW0|a zjF0M+=iwObl*e7!2ddb;M>{OCeL<>UaH&-E;ZqGM=8I}iHPD$D0|3!5Eb%*ci1O9z zhN({S`N%`Xc8FDCn0cyjKgV#n3ua#oXlD(0Ob=k8H0Nvb!I{m zMtNrrH_${rDu5D#ZencnA(mQfZF4$QNWHz67rHZE$7$&A`t_<%!<&CIUUuHG-# z1|WTQd5|%-1=!@DgYn_~{BvxV>P9)a8O~0zFrmLI{>T1K^!o!IM&_`wS;?u|-akGI z-g_FFY0gK%qg!YY9_+Y>@aCg}r%>Q~@!>1aaI$xbQ(EEI%5XAwilrL&Z5sDefqQmd zAUn^7x=TL${@^IkBE&~GdCJHO$Ho!K&4^$e89^ia%30n?lRnycbc^wSG0gr5J|F|8 zGT0aQQn4a0^3t5A^UIKre~It(cP}lm@;F~)`2XJWJp3I8KA?KkuFOhyH&QSwS#82? z)j(iAVu)}Sh4VhvAU(|a<~e*cW%1EYUesMjL!!`p{WGD;t-Ju5>BdQ$$c5rL2XzCm zJu`w)=%FiTwaWX@MDE0=Ia}pj2kt-WZh#phuZSvGuWMC%t2{p%+9203jNvJK_IWxw zgEg!(0KZi(^dN<>B-n0w|D1F5*%pt7amE1;{<7WCV)ZlC3!IWSgX5rt+K^R`hiHyXzBV4}nc0PN>ua)AIkU)3t^ z&=Z>+tYkAvZ2EO*f;=f}-S$}1RxFeae=$~VrItim6&!p@wPouaWpRtM8QWI>NRl(ojm^A2 zyh?!L^{e~ymYqLFUeS9_Ll%V4Z(%N{#j4;aSf5Ox=+I|UF-aL0%W^5LN3>)=lFk5f zoIwq@U)YBP9gPr4PxHFzcI|Ve+DWo!I0-fL#(R^njEy8mN>NGo( zX@xU|e&>|ZrA`_B!I@5*oEdbZQ%<)!m9*2DNe?-*=n3Zpdd`_muQ+q)O=m8>@64l* zoD=DD=Op^xIawq*RU*}yFS49kakO)S=<7@ugPcWTsIx>2cb1BgPNNv@G>d#^xtQRr z5R;tK#S~|ynC7e!vz#-;iOz4t0%x^Y(RJCDg9oxd0%=Lw^m^Q6(;dCJIko;G?r&lvrkXN|$m-;H6;bH?$`^TrhCMWft# z$(ZT9V$614HR_z#jMJRgjkBD$j5W^N#_ybWjo&-(8&^3W7+akWjhmd0j9Z+Kjk}#s zjC-9=jR%~68xK358BaN17|%Oj8gDpX8DBYH8{awKAS~=#({TQ4ra0f5S0oL|go&R%nl({9d3eA}r(%WMwX=D9(~TpM)F%Y(|iAs8`l2_~7_ zgURNfgQ@0o!7k>D@G-p}>}tLjOgF!C&M|)uW(BNZcA#tUh(K;ICom#-bYN_-7pr=F z7e0$d!tcg$fEIrAW`O@zMm=>zpiRe6nK=NZ0lGO}?@gMjZ8}LiX_epNAzJ3QxQ5pI zEiR>P=0Kc2IO1FE-v<#+)1*N~{@bVVydSB`%M&Y&-};c*vhdI30^_vxi6GR#NNqP7 zII|sK4hB3^;Dk?m&jVtl>6k;1XN%EhKzrF8eB`Lz9Euq1pqOCn(Wh=9G0FJR9EK6O zVv6x!^H{v$3+Ki+=5V})#Vq4fjdMiXrkBz1c94jpLfFJ4+Jmo8r176U_*6tH%(I_J zwo{Jw4){hWAE;1TJ1lp08R$&hKjX}Hcwsy8*bBgUSzaDnvFt2EUTzR>R`{Fa&0|#) z@>uKZ<~X^EW7kf3loV@)zHMV#9B4bPXy`J|*{AGC)efIqyp-`sXnC{^$3>{4c%R1E zp`4$ou0`q^dEf^dLiZe)p!g7{?f!`~_#fbw_NzbH;v+*CaF!#2e$&>HBw` zw13whB(&zP`G!P@Kd!!C*Y^HhdxuxAgqyQ%VS z@qZ8U_HCWs)Kv00^+j#s{}80c;eRN;JZf&{g`=zL!`4b{_Hfk2)o>8ymw4fR12Wsh zAK1Bgji2qq7*N44@F`u6b4sDZY!jjZLobjMdXZ8?FHyJ9%XD<;6*?yLDh&(0Mq@(% zqA8)*X>RCEstUbDwV}7ECG-xR8+uohicej~P!Ds2_&o~-S`+h7&>Ddc=!dIL}{SsRnZv5?&eI;x)=;j6SOYo z1DpxI#xy8jFBqQnaoTTg>8*V~!m*x(WzkOQ+6%$zfftDiL$L*7S$f@oAo%XOM-b;| zNM8hR8i-5Rzrcriw9^xFtwmc`piaJB#PY(2B!@9LiY|G%?n7DO#9u6V6&d_8V zv2oGhb;hb_Q14~Qs0YG~K3|TTjDIumZw~&QhJP2Ls2u;!!9QHW6HtC~0RD}`KeUrO zfXlFcQPn2yXf^oUOCX=4hz&K?}ZN?+sM}TcRRP#y)xjj2Las6 z>*fC*#Qw0O=|fm<-1H7TtbTBC*8=-i@qL!HiKd{Q5mm#SO>{h75x%;S@|X^C6Gb}e zKEqk-DYb({$$Obb-T+(0tzHwcRnNulR^{`;=T=OK4LPc?alQ|(-p&IASwwHt*&jlyhyc0mQI{tkZ+FD#-owWu z8rs6aIE+&?{_Dh7EXCKe_J$1Uo? zM?-8d@Zi6S=LFDRAIWG$;BN6sz+Lm1AyD^HMnH3RXB_&+VQh=F@;cP5Ugw)rY2q)t z#1jv(<06>NY&U{oc~r^9>yw))D_fHWwg%3c63Ov-Zg$kvizqI{ppQ<$;jTp%&b^eY zD9H^|)QwONH;ImMlWB;XLSx-DDsa2dC2m)`!tF*^x!q}6J4syaP7|BmGI6InUEJ-?5cjy{;t{t(Jm$_8Z@4Fl z58RW*=Wdnw(ybQXy9*?_HPUhy%CNggCcCG|boW$wq`OS^bx)H6-6lE2T_H=|m9oNJ zCFiN z+$-g)cz?^iT7K?cBfoL4mH&0u%RTP(hU?y7WVjoQW896#aqecL$lYR0b#FB0xHlOK z+*YH`y~Q{U^-g#1FwSxBG%j=RGS<7>jaIzh?(Q;nyZ0K8y7w7>b?-M`avw0>avwB4 z#`8b!BgXgcV_Jdifnyuthgva&=)u^V2;-Mq`5tCS6wwT=BEoV6!sq#nKP-3A@m{HX zfR6L?_Rw#<6~cQQBo_B5dPemnf1mEY`;QFH|n9%O^8%{Q^G0VQpf&etq_C@f^oG zY&TaAZ4>Kac`tY5Z9;Ew?DHis;oQ{|6f&|uRh z=CK0Bwr{9L>JB)4eegJwRc7}5EBOKhPPWk+o6~K%8CG^CJc=J@<^?l33@K}?xCDPU z(?pK@NQDo2Vk18nt1*U<$JG@Cq9w8jZrH9ju{5 zhvjvNc0n9{w2Qu%(S_S5MY~*?mlBQUrE&mo6jsS|(G)JQoV>Ih;)`h7aA*xTFSJ8^ zjhK~acz9k?G-M;CZ?laq$$MWRZZflFZQu@Q)k zA8$wzdcikU@ofcAFRH!uARxkXoK~9RMd=jAN`ffCyNv)WXn(&_uf)=5kOPM}v?t=J z!ab}CIUZ|o3r_*&Bt8Xp;uP5NDFB5zmO>l$dJ3A@xqvgFQ#_8qo@QR0b)Mjzl*dN* ziMPP^d$IZP*(&O`367TVSdLkATbuYOo)N`aKdg_0;yc>Jo9vnZ9n37mJAB-sgU{d( zaJWxV(ES^9@ZX_>|4GNWuha4F8&u@NVduU@v)s4o6!#rk?S4oXx*tLReoQyJpU_VC zQ+mSvH}vi2^qTu0=-e;pWA{t?%Ke(Yb-$sX+;5?K|0^u_2a)9dD5CDqqPx3C9OM2X zhPZph2)A8~$4;{pKe0IjKSqQPM2p!fAgYxm7AspUQI2R*L9t4?;%tTAVN+poiAoli zsTBOyS*qBe(nPE3f*MuvCfpUTxBqyuE_ywAwvP=!bZ^;aoC#yVJuSUovYNTAI zM&TDoM$2>57`axBmFKJD*3SZ%`BEAJruMh{I%guPT<0sww#3|5SWWzeIka zrpb0yYJ^pp(L+tghskFc<5i_GMa^WLsvW5}<0sScBUX@yJMm?C{B{*&_J43ZuisE( zwAO)X2w_Uso40_N2^VMq>cPUNo@OC5RTptB4KpVIN)&#sGtDC8rO9+`RwtrfM7%@0 z%t?3)iJxeLIT>#XyP^AhD4)@7(2zg#!K^Vgu3e|bwuQ#j*tXD^Y8Im&YuBmf6ug=8 zQM$mx3a7ILS|3{?C=0xUe|iJIKcmMcELmhu1%5&LR-WLG@;D>aEJ5g0GW6^5<}|=d zfyNzUmZDy&*0_JAquO!vFAa)Bt2?M&ENTBgR(}RxcDVk)6|{b2mD{N~%Lx9@FO~b1 z>I%9v!YVGYG3Ry^@4;Dn79aO_@zL|Gf_N2FZHKXOC6g(yw6vf+vi9jHdU{h?@Kf)HKft@kAa z(SV<6JR;NiH*tK=$Xw7Cj6^#i1#ukK4vlq7?%h(3!F~Qs_{SH&jJ2YjZ*AFg#(Fid zP2mHwZa7v)E}CeEYo>vH(cdBS#%6j4h^_69WNv7`ClSKfEKe(T@v3oMbN(>2d-dQT zS7z;yxOLgSvlHkAaq&r0-~}SJfLv8e$*PXJs6{kDEv9j*o+hhPX_h*T=Bg(A(0nsB zsuns&EvL)X3j9>~>9k(0q^)Wd-J#B)?aK2P@;4WH!<^=CrAS&tQ~bAN+U%cYfL`7L z)n1scWHS@u^AN+Zu)}+(uju|GygX9k2d+Fi)3Jbr2_`Eyw~eBVyXU9W_o3Aq3MlW^ zvFG!%{N;~%K8u0Fzf=cXla`_Vv=pc~UvTqL;=^ngmD(=2LXksAb#mPr!{2O8( z+~Ap5FPRV$yV%ixZ@&lgGNKvl5F64jOYD?RF7ChFyB*X2a9(;e-7_KKVt*L!lQw#o zo$C(=&cPdBZx|bE1C@;nw|4GMsf-MpJ(rInBA*!-(I|nPGI^AVvM!~$(R2oaVjPFx zEz@D*;mY&9S>_tRLbxvw$jsd>dl-CkSN6;c>tGIqWJbeVXgRWui6S6V=0@FGm^hJu zjw_!Y&+pH6kQc!V?^I;|7CIK;lmqj+;x9+Wbjyu)jdrWuDF>Q31%MN+>oEN3HVm5| zTw&Fbyif84To-L&Y_?w%P1=BN;WtQ{zf%rjl+Z90_!nc0@)%=i1tKW*TP&|9kDC*1 z@)!_H_C(V*{0(zpDFfI-J-GqK@r2hj8sraq7>2P+4y!=#SbWhitS8i8FJ8jXlji4j zj|LH+?RAOax3XOuqlNdz;m|S{REZaW81eVv=4#lWOs{+%l14e&eW+i)Q|1kbs)2cM zs{m;Cq0wlYgiO)zpigvIw9A^y+vM<8F+SR519gomSguT8V414z;Ivp0`FW`lR&xrw z@1m(2>FM|kMAPOUY6`B&9S}_!811@KjyfzRK5{<(7LA9PD>UxT*8>lQ=h^{{kL@0=lFfh|Hy3hg&eHDl*825uv5R0W7M~@NPP!8^?O;Ve!%Y){wU|E zpXEZeM>eQmuw&$egT~S7 zXJbHE8AHQiqcEIg%m^nNCxugtW$Ha+MYyYRZaBj@FWlX@B%Enn5zaEM4QCr0!aa;_ z;UkRO!a2tF@X^N3a8GT^woos64c01Kp&@#a^354|Q}ikI)1MCNN?+5_W;yb@(L+>Y zR^TlnQ}D$d{)}Bzj)DEj0R<_t2u2h8Zc^oBSh_RumL|Wa{t~}MNy&0OEKaXQ13ltF zmdk0k2U%8$6b}PgiI3=b@Mep2AKp9>_27wj#8n=C;w7=!!$o`{&NpYFk1oax+D7C>y-Zfvqj6$tW`C;snB=CB_tUo&npKRvX8eC!%eD z78)~5K6kWe1}^^chb3%UYYa0_Mq7t&F(O*M{T%hpl~wS%bF>)_n3R4u#Fc6(IPf%vxY|p#PA~uBk&-^6bP@q>Rk?!qpI0^Iz*X7&+_&nG!&mhhNjA`9BiawyeZi`OSM5Bmp2=O0 z4&W+&mY4;@d<13sgx#ly7~(uoJ%(etv8(P-wf!c#b~||GfOWYNaMyq0rv0G9*Y%oV z7j-3v2LD>n@Wk~$aAl2wo<*i4qXZ5*1id>GaTFL6KfCK&c&o4+*fW#a?+Ivk)O_uPpuC}zQ!hH3f<@*hPMte2~!0{QDL+<`7d{`+2}itNcb_)v$e z+zv+_lH7EsJb|C1x%ZuNj?RNd#Rc9Te));~9LH#(!pXpxzX3DAPgnB@;Fa7!N8|C@ ziTdFmQ=R{Vp{?iQXdba_g%iqq@&@Z( z?V=;PTGzy81ke8Xmxq7j@ox(L&BVVd{5vyuhlG3d*;cB-+amoo2XCk7x3c@>k~wLz zahE&|AAplhI&&1dc$iO6!^m2$vyQ>rO8th@(T>93=&TS5SK|!?;#0t_=2n8q%iGWu zI8yALtIc{HpT1k3d!;6!S&Oh5PVJOyTZO=JzAonwbTQT#1`i-UwX;RvOhP606yl>P zTp!kL04M!64*$&!`ip@Gb1-X%v9C2%e^N(-WxpgGkO=<`;IlYD2A)Bljj@Pok6Ihs z|BWmJws!ayt=9HeVimn}z5uY`Ge2&u(PgA!LCXh0%|eLLI*kWDD(6IlJUTYH(XYAI z6#msKoZSUBOOLp%c{Y27hiVEsi?gmoj0)b0yxrpgZ0aaMVaKa&a@335<)Iy^$H%qCZ5##9$f*5k0|Y zpwR%I+~T7#QFaaNkQaj;06wU1jqP0PV7Ji>So$+cyuu`huDl7OxwKWs;p#LW(qj`- zs@E5I(X&3^rIoma_Y_&-rzsMCmQurirLN)UsYmz)>KXnA^$O!Qd-$I;DEulFgkPgc z;eSzC_;sobzeDrF@6v+sdvr?peQFGUK&OX4q_e~Srpv;g)79Z`=!WpObaVJSx;^|o zwS|A6d&57{L*bw3(eTgoSa>fz6$#Mu5sO~MVagkkAbk)~^hqQ_UqzDW$4Ig;BWWTS zfg353F47|zqFhbjr0}ukzCOb86>Wc3=vx+L&Z&zW5w-} z;o`2y2(c?NQrsIEE&dW2C!UQQFa93M7ypbDh<76s#3zx7;7GR zM^2QzA}7gVk(1>pypNAm%fiS)IVG}4mPZ!LIgxr<8#z@rM4IHXNV9B-w8--#E9BLY zm2zF=OnFaawR}8suKassjr><+t^6o*f&4adp=^&_Y}k?C8%dGNjUJJ!jDeA>jp31N zjd79dje^KFqb72z(HObSI3seq@!QB9#s!f(jf*3985<+pjXy?q7=McV$=Dsa+juC_ zW;_$wX*?gf$M|RDUgKYp`;Ctx4;Y`K-j{&!-^imzd*m@QDe|~^MC3{H=*UxAzwCs? zSq+PmJ)1#!CEnQE>BwdDH*HCpvJh#uOapQXeXCC-Em@8aCoF{avE@1hu6ivR=mif7 zJ~cj8`$z5nSJ|~dX;ED1`*+v>>VM|%>Yf+l3}NIkAWVE9prU{aO2h{U41+_!!%H-* zh>xJ45jg=PqN|dGjcZU5Fht{n%%3xW0gNGw(M=9Zd~C8g3FojYo6X9}i6=2=Q1-jG zy8G|{pMQAFnZLTa`u43`w{G34zEyS0-U2rbJT}hS&tioNk4%+)FKo3pGd_DY-DU9E zi|7d%4Q9BX3P+r3pt{A3II$Ny=vAUG$NnQ|BY_KScQFb@TxT)3}Wae{yGvZ z_2a4()fnXZKJkjo?Y|rUiV|6`Cvw34g z-x)w!2(suNoomePr%{c$ZfhsoaYPReuERHNLt_RzurqZIR@5vE)|BSMw7RNxWc6dv zEB2c$jqpf?t>?VqA&oWbLmRWrjVX+(iUX;yQwvr_eM~GEx%@Gz%YQ;G`M=Yk{BatV z|C~mFf0wxyjdN|9>?&$^lQhds(HtzLUFc?Lv74paT!)ssIlAAiqBU+cJ?gr&-qp0h z_2_xGhF)-MX}jA%JKR3>n%hWw+$Q>|+f2W3zd-M~{iI>>{_G)WPK#xbwgwX(ykMXT zYIVH&M|CSccTg9hsMGsuiMkB}aT&Zim^adNKrO`{MH{xwH`MJGnhr|Vt?qz3&LoY4 zlYu)iq)1_><62phm!@`j3FXF-p;>5RccJNIX%4NBhUJL4@J7NMHI}ila9WRZ@JyNy zn8;r)?I%dbw@;AH7J95yVc;;4Ka21)-&~);?Sj>v=<_K#pHdb35d4GsYB2g8i&ntH zq!fE!J5pwYb+Lfe9VvV==FQLs3wX5*(<5jcd;)TS>mt4ft}ObfpYceHEu}G&t~-g8 zd$pi5Cf#hn*aY2Uy;2zo?Jq~t2_&;BA>kvJdqL7wj^s`tF%CV;Dfvxg`dtjhuyGlN zI=J%fw%)|vxdwP2(9W2cm07+B+;33UeF#3N){^f&EX1{#cO%iMwf_Qbijzd(R^%vR z#^MYc^>KnLiG+1P-5n7BBm^god|ScBw=sCYf=qk}z!D{6KLsP`#G&wx!mf6ATEE;L z@z_v;Ed*{iRl7UrEO(bs!pkdxEuy4V-J_OEMYXCG_+sbkZ&mjqjZ53A?n4@X5VcBA zz{^fsrDp-H*82&V?8QqKzJbh}FpTGT#lybmq~Z^*e@UvpNvLI7n|507GXKqzSa!-u zF6MOI1K`!KsNQ{tTHJSqQX^z>O25WDlSYBus_-UGD~G}q3Z@6*R%^tK_C3v?N}27j zUH_W7V)8RwIRdWy59QoHppO0+6P{Yb70Cg@3*!W4&@a=45sdI=@u9gwTf?tTE$-vdA*V^Y5f4)M4<0WjK+7#)Vd^hY}jZABXJUzbr`zqFnh*h z^o>~Gk^QP{(!@89SnuIc1y9oA60$DK{vfj4rNQxu^jmv@4ILzWpzuyTo3wvr{#Uv{@23&^=X9}ti!RmwM&tAWnxOxkCh1?%6#XuB z>i1~AexGjE|3P=@U(<5^8~U35Pg<>iOY8LSX+2=RqYu;5`oCzK{%`uBHp}Jlor})E z^iXN69SLLDrPd&gn|_z#^EbHZcM+dBl0r{*SCHEj7)VWS@KB?^!TpyspDVc68e;Z+7sp7H zOv0Opoyek%@PH3JSkPHTFo6w^>OVohn@|r$&VMICc9>Rf;Q#j&c2{>>f5HcuV#`EP zp%}^gOH6*_jT%#Le2zoHIvSz92E}Hy^}zQL&$;nb06sM?G`c)=78P3~cgp?8~Spxksl|9mds6&_G=GcB-Y-}Cd+q4;$ zswTKpwvILJ&P~P^CZsff5zC6K!OfT>YkN?)tZ064-u1kp=fnqJ+-d#Yz%=md06eeO zPCT%7iah=!Ojy>`;?Qv{uLki(Q`)02EC#+5a%CoouN~-S>F%l0ydos9*iuC zu=p?V=8*DkM2Y56tv8<%j!kPh8-Pm0=#6!pjOlsuS5y?a5?{iMB>7t@=dGpz-WuVfp=@|W z+3-@zd~VQ>N0hw@qp{B5SvC(^uT0ATV^tRAMZ);2nrbX0GGt?7YdW(}03#zqBhVAAc zi7f0r$8mU1JBD%U3ANtzYKeO5gWRC!F?@hYh`#Ih1 zy+v!iw`raC3wp}?C2hpB&E7#_8gFWwM%PO-;mX_^osqRw28^txw#tCf0$(<%Z$eZJ z`!t~|s7;JMj%_y=d7lDLR((r-JK*9zzQ?;qn1k7&dl9ykFz*W`%p1Cw4T<5#K)WyA zY1@mi^qm&G!{>?^hPRczQwQT}RomV=wXpAI8dj25f4pb5Ald^FZHv`P9gYjZMzJPr z4g=rmg~sGgyLB{7s8~flI^EV6OD`ndcz;rxsiCcJU1n}$n)lS4JAAs>`-%%4$*8jr zDd!!f5#FC^oc9sk;(bi_cz>g3z2o#emSMf>eNNqQX1fQAdfvq6!a?7nL%4q6o9<~g zIQKRt7`Vqr!=)p^*b6bWfmH>ksee}A5hZm*J;`+!xF5WQC@CH#PH^do|AIwX+VAjCrrP?UdZ#?ycD53JtLLcK>HKszbe$#wf@>mp~ zgFKCpuCWJi#|MFZPT5%0A5Y4kKso1^Ir{wcNK zt^wD9IL>HOIF9HuTRu#wVUrEB`1(TPLNq77j?(=QDJ1Sr?sl*y2k|MLil0p>P)^cx z&Lrx*Np(#smQOIKc1^0!uVNUVUZoo(?86~@7Fs0;R%w1=l@{Oq1-R0~ovxN7#=A=J ztb*e<#0!aO#m5Ef5kU~V9|zV3c)lDo0DnGs@k7bLpwTsgSp1k264(NbTP+k7tR$B7 z=`26TdO-Y|@a_rCUSD*IQzhUR@azPh&Cnihx)L)GU#%N=XThruFsh?7ne6CH>2yaY zaCdZOQXQQ-rLzcu31J3_I*Z5J;UK3SgjEt&>ng!-U1acI}NdhW`eA7%;M!SGcX%C?!=!}q;<%ilqDL@oQ ztC-ws?IX&80!mRrPwI0aD9mL27GxGBQn9>&@lms9@2k|UF)DGy;IS#7y z0EE?gIKsRhiO{uyJZX^Yvje)%2ssL>a~xDau7ErhLvBcKWzrF(^$;fge7qZyjs%d- zVOBzinUUilU`vd0MxHK54i5Ilma7Ff*J)OB+z5iOJYY+V=Sd*Xlp`0uNQIu1=hrfF zfax3u71)vjauiu=RG4n~f?}pvSWm&1>lnQVbxy)CgBbOaK@Z-Y96V;mCvPJn+N=hT!5uOkK>Uy!s^jlF2?PEjaY>gW))w+D!w?PERhS}RA80lk}qeKM{7=1<9W`* z=ul{4W;cfcvpo7HZt@;&z(w?^cFXgKwF;>Zqo#Y&q@u)gqE*BChzV_m>l=UE2gKTS zu~iIVPHE86tG<(`InjN+W#IM5U|__gm_(V5#z<7GFOUwX*AhUXpa_1C9ME!lQ>)Wa zoQ$qTnAIG2r0dE_7#0Dqhn*SsH@YUsAZmCFojRkIR|Aw~LR+3o?U@wAFv=8z;a34NCOV81rApzK)-^0T2x3we6CK^32^hfyAV@=sGWZoMIb<6u zR-Ftj#H?V?GG(4sTIQQeq=XS6htnyvZV6z+LW6(|C!)XMFwL?Z6#JC0FgO?vaG}@V63qg!vzaLrFj>z3WMgvs~@EiK@3X=*vg9I|PHP7Vp21$(Zk`8i$o+?cd4?osn7t0+ojR6&Hx z6eWOIiJq>a6wp&E%HFWX6r~6glgbg1wW6Yw+E2&oy#g>qz^KXyxL_|R;RTSNUfq`i zid1nB6V{;i%Ry1lScS%_z8o+j7jI}OT3GWXx{?)Ukq-jPQWA*&$&re(Tx5h~L6^NK zCM0+2bWA6PXdud`--!UYqMj>bOl6!g#z^0w&*zFqYY_FxtpY!293-3WJkFd_;E0h1 zI923M1imf;Htx?zW72)%(()BDa;WMgF=>5!U8NUhw*~x0kCNd%#?Wl!!+m_+{`+-79rVj+zcJ^ z8#yXHp#)siu~5>J;}JL*-2=G+XUZdj7nu!kWt? zKC&Q&d^`mxx4VFepi{EPHKj*IM3%3AAuffH~a=c+jHtsiB$Vh=CEf zG#(B_TL|8i!H()I*l6%^xrMFGSQRmH%E*^5N(L!jrc-e+wtQgS7Mqh`P{_c@S+JKI zL0{Ts-`Qm^>#~=Npf5A27=^^ee`UPuwV4m|!3RiaFT<%=U(^G#vhYVpbvxGuf|rttTbvgAIVdQZqH>@Q;S zhj0RAM&X=BOgZ<#9B3P6_{OVm;mo&<)QLHohp?C6d$95sFuV2+c1<3_dW}!iiLJd>`IIvu-|S3u2RqZS@@S5( zcjkHhohAMtXN7;MbAQb;XI;%dIgiwAaUQGv(0Qu9&DmBz-T8j~-Oda3k2){cZ+5mf zJnX!NH8IbDZcA+j9qb{q%6i?}ptiz0(!s=}#3A^a{VNW=nVMLqzK7?FvFdgzCabq$ z{_H5O-^UdPKdBes>la7ks26d?dKC48R5q~=*OzerU0h#=Ew0{|NV6kq`dBidi algorithm for ICU + * + * This is an implementation of the Unicode Bidirectional Algorithm. The + * algorithm is defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm. + *

+ * + * Note: Libraries that perform a bidirectional algorithm and reorder strings + * accordingly are sometimes called "Storage Layout Engines". ICU's Bidi and + * shaping (ArabicShaping) classes can be used at the core of such "Storage + * Layout Engines". + * + *

General remarks about the API:

+ * + * The "limit" of a sequence of characters is the position just after + * their last character, i.e., one more than that position. + *

+ * + * Some of the API methods provide access to "runs". Such a + * "run" is defined as a sequence of characters that are at the same + * embedding level after performing the Bidi algorithm. + * + *

Basic concept: paragraph

+ * A piece of text can be divided into several paragraphs by characters + * with the Bidi class Block Separator. For handling of + * paragraphs, see: + *
    + *
  • {@link #countParagraphs} + *
  • {@link #getParaLevel} + *
  • {@link #getParagraph} + *
  • {@link #getParagraphByIndex} + *
+ * + *

Basic concept: text direction

+ * The direction of a piece of text may be: + *
    + *
  • {@link #LTR} + *
  • {@link #RTL} + *
  • {@link #MIXED} + *
  • {@link #NEUTRAL} + *
+ * + *

Basic concept: levels

+ * + * Levels in this API represent embedding levels according to the Unicode + * Bidirectional Algorithm. + * Their low-order bit (even/odd value) indicates the visual direction.

+ * + * Levels can be abstract values when used for the + * paraLevel and embeddingLevels + * arguments of setPara(); there: + *

    + *
  • the high-order bit of an embeddingLevels[] + * value indicates whether the using application is + * specifying the level of a character to override whatever the + * Bidi implementation would resolve it to.
  • + *
  • paraLevel can be set to the + * pseudo-level values LEVEL_DEFAULT_LTR + * and LEVEL_DEFAULT_RTL.
  • + *
+ * + *

The related constants are not real, valid level values. + * DEFAULT_XXX can be used to specify + * a default for the paragraph level for + * when the setPara() method + * shall determine it but there is no + * strongly typed character in the input.

+ * + * Note that the value for LEVEL_DEFAULT_LTR is even + * and the one for LEVEL_DEFAULT_RTL is odd, + * just like with normal LTR and RTL level values - + * these special values are designed that way. Also, the implementation + * assumes that MAX_EXPLICIT_LEVEL is odd. + * + *

See Also: + *

    + *
  • {@link #LEVEL_DEFAULT_LTR} + *
  • {@link #LEVEL_DEFAULT_RTL} + *
  • {@link #LEVEL_OVERRIDE} + *
  • {@link #MAX_EXPLICIT_LEVEL} + *
  • {@link #setPara} + *
+ * + *

Basic concept: Reordering Mode

+ * Reordering mode values indicate which variant of the Bidi algorithm to + * use. + * + *

See Also: + *

    + *
  • {@link #setReorderingMode} + *
  • {@link #REORDER_DEFAULT} + *
  • {@link #REORDER_NUMBERS_SPECIAL} + *
  • {@link #REORDER_GROUP_NUMBERS_WITH_R} + *
  • {@link #REORDER_RUNS_ONLY} + *
  • {@link #REORDER_INVERSE_NUMBERS_AS_L} + *
  • {@link #REORDER_INVERSE_LIKE_DIRECT} + *
  • {@link #REORDER_INVERSE_FOR_NUMBERS_SPECIAL} + *
+ * + *

Basic concept: Reordering Options

+ * Reordering options can be applied during Bidi text transformations. + * + *

See Also: + *

    + *
  • {@link #setReorderingOptions} + *
  • {@link #OPTION_DEFAULT} + *
  • {@link #OPTION_INSERT_MARKS} + *
  • {@link #OPTION_REMOVE_CONTROLS} + *
  • {@link #OPTION_STREAMING} + *
+ * + * + * @author Simon Montagu, Matitiahu Allouche (ported from C code written by Markus W. Scherer) + * @stable ICU 3.8 + * + * + *

Sample code for the ICU Bidi API

+ * + *
Rendering a paragraph with the ICU Bidi API
+ * + * This is (hypothetical) sample code that illustrates how the ICU Bidi API + * could be used to render a paragraph of text. Rendering code depends highly on + * the graphics system, therefore this sample code must make a lot of + * assumptions, which may or may not match any existing graphics system's + * properties. + * + *

+ * The basic assumptions are: + *

+ *
    + *
  • Rendering is done from left to right on a horizontal line.
  • + *
  • A run of single-style, unidirectional text can be rendered at once. + *
  • + *
  • Such a run of text is passed to the graphics system with characters + * (code units) in logical order.
  • + *
  • The line-breaking algorithm is very complicated and Locale-dependent - + * and therefore its implementation omitted from this sample code.
  • + *
+ * + *
{@code
+ *
+ *  package com.ibm.icu.dev.test.bidi;
+ *
+ *  import com.ibm.icu.text.Bidi;
+ *  import com.ibm.icu.text.BidiRun;
+ *
+ *  public class Sample {
+ *
+ *      static final int styleNormal = 0;
+ *      static final int styleSelected = 1;
+ *      static final int styleBold = 2;
+ *      static final int styleItalics = 4;
+ *      static final int styleSuper=8;
+ *      static final int styleSub = 16;
+ *
+ *      static class StyleRun {
+ *          int limit;
+ *          int style;
+ *
+ *          public StyleRun(int limit, int style) {
+ *              this.limit = limit;
+ *              this.style = style;
+ *          }
+ *      }
+ *
+ *      static class Bounds {
+ *          int start;
+ *          int limit;
+ *
+ *          public Bounds(int start, int limit) {
+ *              this.start = start;
+ *              this.limit = limit;
+ *          }
+ *      }
+ *
+ *      static int getTextWidth(String text, int start, int limit,
+ *                              StyleRun[] styleRuns, int styleRunCount) {
+ *          // simplistic way to compute the width
+ *          return limit - start;
+ *      }
+ *
+ *      // set limit and StyleRun limit for a line
+ *      // from text[start] and from styleRuns[styleRunStart]
+ *      // using Bidi.getLogicalRun(...)
+ *      // returns line width
+ *      static int getLineBreak(String text, Bounds line, Bidi para,
+ *                              StyleRun styleRuns[], Bounds styleRun) {
+ *          // dummy return
+ *          return 0;
+ *      }
+ *
+ *      // render runs on a line sequentially, always from left to right
+ *
+ *      // prepare rendering a new line
+ *      static void startLine(byte textDirection, int lineWidth) {
+ *          System.out.println();
+ *      }
+ *
+ *      // render a run of text and advance to the right by the run width
+ *      // the text[start..limit-1] is always in logical order
+ *      static void renderRun(String text, int start, int limit,
+ *                            byte textDirection, int style) {
+ *      }
+ *
+ *      // We could compute a cross-product
+ *      // from the style runs with the directional runs
+ *      // and then reorder it.
+ *      // Instead, here we iterate over each run type
+ *      // and render the intersections -
+ *      // with shortcuts in simple (and common) cases.
+ *      // renderParagraph() is the main function.
+ *
+ *      // render a directional run with
+ *      // (possibly) multiple style runs intersecting with it
+ *      static void renderDirectionalRun(String text, int start, int limit,
+ *                                       byte direction, StyleRun styleRuns[],
+ *                                       int styleRunCount) {
+ *          int i;
+ *
+ *          // iterate over style runs
+ *          if (direction == Bidi.LTR) {
+ *              int styleLimit;
+ *              for (i = 0; i < styleRunCount; ++i) {
+ *                  styleLimit = styleRuns[i].limit;
+ *                  if (start < styleLimit) {
+ *                      if (styleLimit > limit) {
+ *                          styleLimit = limit;
+ *                      }
+ *                      renderRun(text, start, styleLimit,
+ *                                direction, styleRuns[i].style);
+ *                      if (styleLimit == limit) {
+ *                          break;
+ *                      }
+ *                      start = styleLimit;
+ *                  }
+ *              }
+ *          } else {
+ *              int styleStart;
+ *
+ *              for (i = styleRunCount-1; i >= 0; --i) {
+ *                  if (i > 0) {
+ *                      styleStart = styleRuns[i-1].limit;
+ *                  } else {
+ *                      styleStart = 0;
+ *                  }
+ *                  if (limit >= styleStart) {
+ *                      if (styleStart < start) {
+ *                          styleStart = start;
+ *                      }
+ *                      renderRun(text, styleStart, limit, direction,
+ *                                styleRuns[i].style);
+ *                      if (styleStart == start) {
+ *                          break;
+ *                      }
+ *                      limit = styleStart;
+ *                  }
+ *              }
+ *          }
+ *      }
+ *
+ *      // the line object represents text[start..limit-1]
+ *      static void renderLine(Bidi line, String text, int start, int limit,
+ *                             StyleRun styleRuns[], int styleRunCount) {
+ *          byte direction = line.getDirection();
+ *          if (direction != Bidi.MIXED) {
+ *              // unidirectional
+ *              if (styleRunCount <= 1) {
+ *                  renderRun(text, start, limit, direction, styleRuns[0].style);
+ *              } else {
+ *                  renderDirectionalRun(text, start, limit, direction,
+ *                                       styleRuns, styleRunCount);
+ *              }
+ *          } else {
+ *              // mixed-directional
+ *              int count, i;
+ *              BidiRun run;
+ *
+ *              try {
+ *                  count = line.countRuns();
+ *              } catch (IllegalStateException e) {
+ *                  e.printStackTrace();
+ *                  return;
+ *              }
+ *              if (styleRunCount <= 1) {
+ *                  int style = styleRuns[0].style;
+ *
+ *                  // iterate over directional runs
+ *                  for (i = 0; i < count; ++i) {
+ *                      run = line.getVisualRun(i);
+ *                      renderRun(text, run.getStart(), run.getLimit(),
+ *                                run.getDirection(), style);
+ *                  }
+ *              } else {
+ *                  // iterate over both directional and style runs
+ *                  for (i = 0; i < count; ++i) {
+ *                      run = line.getVisualRun(i);
+ *                      renderDirectionalRun(text, run.getStart(),
+ *                                           run.getLimit(), run.getDirection(),
+ *                                           styleRuns, styleRunCount);
+ *                  }
+ *              }
+ *          }
+ *      }
+ *
+ *      static void renderParagraph(String text, byte textDirection,
+ *                                  StyleRun styleRuns[], int styleRunCount,
+ *                                  int lineWidth) {
+ *          int length = text.length();
+ *          Bidi para = new Bidi();
+ *          try {
+ *              para.setPara(text,
+ *                           textDirection != 0 ? Bidi.LEVEL_DEFAULT_RTL
+ *                                              : Bidi.LEVEL_DEFAULT_LTR,
+ *                           null);
+ *          } catch (Exception e) {
+ *              e.printStackTrace();
+ *              return;
+ *          }
+ *          byte paraLevel = (byte)(1 & para.getParaLevel());
+ *          StyleRun styleRun = new StyleRun(length, styleNormal);
+ *
+ *          if (styleRuns == null || styleRunCount <= 0) {
+ *              styleRuns = new StyleRun[1];
+ *              styleRunCount = 1;
+ *              styleRuns[0] = styleRun;
+ *          }
+ *          // assume styleRuns[styleRunCount-1].limit>=length
+ *
+ *          int width = getTextWidth(text, 0, length, styleRuns, styleRunCount);
+ *          if (width <= lineWidth) {
+ *              // everything fits onto one line
+ *
+ *              // prepare rendering a new line from either left or right
+ *              startLine(paraLevel, width);
+ *
+ *              renderLine(para, text, 0, length, styleRuns, styleRunCount);
+ *          } else {
+ *              // we need to render several lines
+ *              Bidi line = new Bidi(length, 0);
+ *              int start = 0, limit;
+ *              int styleRunStart = 0, styleRunLimit;
+ *
+ *              for (;;) {
+ *                  limit = length;
+ *                  styleRunLimit = styleRunCount;
+ *                  width = getLineBreak(text, new Bounds(start, limit),
+ *                                       para, styleRuns,
+ *                                       new Bounds(styleRunStart, styleRunLimit));
+ *                  try {
+ *                      line = para.setLine(start, limit);
+ *                  } catch (Exception e) {
+ *                      e.printStackTrace();
+ *                      return;
+ *                  }
+ *                  // prepare rendering a new line
+ *                  // from either left or right
+ *                  startLine(paraLevel, width);
+ *
+ *                  if (styleRunStart > 0) {
+ *                      int newRunCount = styleRuns.length - styleRunStart;
+ *                      StyleRun[] newRuns = new StyleRun[newRunCount];
+ *                      System.arraycopy(styleRuns, styleRunStart, newRuns, 0,
+ *                                       newRunCount);
+ *                      renderLine(line, text, start, limit, newRuns,
+ *                                 styleRunLimit - styleRunStart);
+ *                  } else {
+ *                      renderLine(line, text, start, limit, styleRuns,
+ *                                 styleRunLimit - styleRunStart);
+ *                  }
+ *                  if (limit == length) {
+ *                      break;
+ *                  }
+ *                  start = limit;
+ *                  styleRunStart = styleRunLimit - 1;
+ *                  if (start >= styleRuns[styleRunStart].limit) {
+ *                      ++styleRunStart;
+ *                  }
+ *              }
+ *          }
+ *      }
+ *
+ *      public static void main(String[] args)
+ *      {
+ *          renderParagraph("Some Latin text...", Bidi.LTR, null, 0, 80);
+ *          renderParagraph("Some Hebrew text...", Bidi.RTL, null, 0, 60);
+ *      }
+ *  }
+ *
+ * }
+ */ + +/* + * General implementation notes: + * + * Throughout the implementation, there are comments like (W2) that refer to + * rules of the BiDi algorithm, in this example to the second rule of the + * resolution of weak types. + * + * For handling surrogate pairs, where two UChar's form one "abstract" (or UTF-32) + * character according to UTF-16, the second UChar gets the directional property of + * the entire character assigned, while the first one gets a BN, a boundary + * neutral, type, which is ignored by most of the algorithm according to + * rule (X9) and the implementation suggestions of the BiDi algorithm. + * + * Later, adjustWSLevels() will set the level for each BN to that of the + * following character (UChar), which results in surrogate pairs getting the + * same level on each of their surrogates. + * + * In a UTF-8 implementation, the same thing could be done: the last byte of + * a multi-byte sequence would get the "real" property, while all previous + * bytes of that sequence would get BN. + * + * It is not possible to assign all those parts of a character the same real + * property because this would fail in the resolution of weak types with rules + * that look at immediately surrounding types. + * + * As a related topic, this implementation does not remove Boundary Neutral + * types from the input, but ignores them wherever this is relevant. + * For example, the loop for the resolution of the weak types reads + * types until it finds a non-BN. + * Also, explicit embedding codes are neither changed into BN nor removed. + * They are only treated the same way real BNs are. + * As stated before, adjustWSLevels() takes care of them at the end. + * For the purpose of conformance, the levels of all these codes + * do not matter. + * + * Note that this implementation modifies the dirProps + * after the initial setup, when applying X5c (replace FSI by LRI or RLI), + * X6, N0 (replace paired brackets by L or R). + * + * In this implementation, the resolution of weak types (W1 to W6), + * neutrals (N1 and N2), and the assignment of the resolved level (In) + * are all done in one single loop, in resolveImplicitLevels(). + * Changes of dirProp values are done on the fly, without writing + * them back to the dirProps array. + * + * + * This implementation contains code that allows to bypass steps of the + * algorithm that are not needed on the specific paragraph + * in order to speed up the most common cases considerably, + * like text that is entirely LTR, or RTL text without numbers. + * + * Most of this is done by setting a bit for each directional property + * in a flags variable and later checking for whether there are + * any LTR characters or any RTL characters, or both, whether + * there are any explicit embedding codes, etc. + * + * If the (Xn) steps are performed, then the flags are re-evaluated, + * because they will then not contain the embedding codes any more + * and will be adjusted for override codes, so that subsequently + * more bypassing may be possible than what the initial flags suggested. + * + * If the text is not mixed-directional, then the + * algorithm steps for the weak type resolution are not performed, + * and all levels are set to the paragraph level. + * + * If there are no explicit embedding codes, then the (Xn) steps + * are not performed. + * + * If embedding levels are supplied as a parameter, then all + * explicit embedding codes are ignored, and the (Xn) steps + * are not performed. + * + * White Space types could get the level of the run they belong to, + * and are checked with a test of (flags&MASK_EMBEDDING) to + * consider if the paragraph direction should be considered in + * the flags variable. + * + * If there are no White Space types in the paragraph, then + * (L1) is not necessary in adjustWSLevels(). + */ + +// Original filename in ICU4J: Bidi.java +public class BidiBase { + + static class Point { + int pos; /* position in text */ + int flag; /* flag for LRM/RLM, before/after */ + } + + static class InsertPoints { + int size; + int confirmed; + Point[] points = new Point[0]; + } + + static class Opening { + int position; /* position of opening bracket */ + int match; /* matching char or -position of closing bracket */ + int contextPos; /* position of last strong char found before opening */ + short flags; /* bits for L or R/AL found within the pair */ + byte contextDir; /* L or R according to last strong char before opening */ + } + + static class IsoRun { + int contextPos; /* position of char determining context */ + short start; /* index of first opening entry for this run */ + short limit; /* index after last opening entry for this run */ + byte level; /* level of this run */ + byte lastStrong; /* bidi class of last strong char found in this run */ + byte lastBase; /* bidi class of last base char found in this run */ + byte contextDir; /* L or R to use as context for following openings */ + } + + static class BracketData { + Opening[] openings = new Opening[SIMPLE_PARAS_COUNT]; + int isoRunLast; /* index of last used entry */ + /* array of nested isolated sequence entries; can never excess UBIDI_MAX_EXPLICIT_LEVEL + + 1 for index 0, + 1 for before the first isolated sequence */ + IsoRun[] isoRuns = new IsoRun[MAX_EXPLICIT_LEVEL+2]; + boolean isNumbersSpecial; /*reordering mode for NUMBERS_SPECIAL */ + } + + static class Isolate { + int startON; + int start1; + short stateImp; + short state; + } + + /** Paragraph level setting

+ * + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, + * then set the paragraph level to 0 (left-to-right).

+ * + * If this value is used in conjunction with reordering modes + * REORDER_INVERSE_LIKE_DIRECT or + * REORDER_INVERSE_FOR_NUMBERS_SPECIAL, the text to reorder + * is assumed to be visual LTR, and the text after reordering is required + * to be the corresponding logical string with appropriate contextual + * direction. The direction of the result string will be RTL if either + * the rightmost or leftmost strong character of the source text is RTL + * or Arabic Letter, the direction will be LTR otherwise.

+ * + * If reordering option OPTION_INSERT_MARKS is set, an RLM may + * be added at the beginning of the result string to ensure round trip + * (that the result string, when reordered back to visual, will produce + * the original source text). + * @see #REORDER_INVERSE_LIKE_DIRECT + * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * @stable ICU 3.8 + */ + public static final byte LEVEL_DEFAULT_LTR = (byte)0x7e; + + /** Paragraph level setting

+ * + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, + * then set the paragraph level to 1 (right-to-left).

+ * + * If this value is used in conjunction with reordering modes + * REORDER_INVERSE_LIKE_DIRECT or + * REORDER_INVERSE_FOR_NUMBERS_SPECIAL, the text to reorder + * is assumed to be visual LTR, and the text after reordering is required + * to be the corresponding logical string with appropriate contextual + * direction. The direction of the result string will be RTL if either + * the rightmost or leftmost strong character of the source text is RTL + * or Arabic Letter, or if the text contains no strong character; + * the direction will be LTR otherwise.

+ * + * If reordering option OPTION_INSERT_MARKS is set, an RLM may + * be added at the beginning of the result string to ensure round trip + * (that the result string, when reordered back to visual, will produce + * the original source text). + * @see #REORDER_INVERSE_LIKE_DIRECT + * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * @stable ICU 3.8 + */ + public static final byte LEVEL_DEFAULT_RTL = (byte)0x7f; + + /** + * Maximum explicit embedding level. + * (The maximum resolved level can be up to MAX_EXPLICIT_LEVEL+1). + * @stable ICU 3.8 + */ + public static final byte MAX_EXPLICIT_LEVEL = 125; + + /** + * Bit flag for level input. + * Overrides directional properties. + * @stable ICU 3.8 + */ + public static final byte LEVEL_OVERRIDE = (byte)0x80; + + /** + * Special value which can be returned by the mapping methods when a + * logical index has no corresponding visual index or vice-versa. This may + * happen for the logical-to-visual mapping of a Bidi control when option + * OPTION_REMOVE_CONTROLS is + * specified. This can also happen for the visual-to-logical mapping of a + * Bidi mark (LRM or RLM) inserted by option + * OPTION_INSERT_MARKS. + * @see #getVisualIndex + * @see #getVisualMap + * @see #getLogicalIndex + * @see #getLogicalMap + * @see #OPTION_INSERT_MARKS + * @see #OPTION_REMOVE_CONTROLS + * @stable ICU 3.8 + */ + public static final int MAP_NOWHERE = -1; + + /** + * Left-to-right text. + *

    + *
  • As return value for getDirection(), it means + * that the source string contains no right-to-left characters, or + * that the source string is empty and the paragraph level is even. + *
  • As return value for getBaseDirection(), it + * means that the first strong character of the source string has + * a left-to-right direction. + *
+ * @stable ICU 3.8 + */ + public static final byte LTR = 0; + + /** + * Right-to-left text. + *
    + *
  • As return value for getDirection(), it means + * that the source string contains no left-to-right characters, or + * that the source string is empty and the paragraph level is odd. + *
  • As return value for getBaseDirection(), it + * means that the first strong character of the source string has + * a right-to-left direction. + *
+ * @stable ICU 3.8 + */ + public static final byte RTL = 1; + + /** + * Mixed-directional text. + *

As return value for getDirection(), it means + * that the source string contains both left-to-right and + * right-to-left characters. + * @stable ICU 3.8 + */ + public static final byte MIXED = 2; + + /** + * option bit for writeReordered(): + * keep combining characters after their base characters in RTL runs + * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short KEEP_BASE_COMBINING = 1; + + /** + * option bit for writeReordered(): + * replace characters with the "mirrored" property in RTL runs + * by their mirror-image mappings + * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short DO_MIRRORING = 2; + + /** + * option bit for writeReordered(): + * surround the run with LRMs if necessary; + * this is part of the approximate "inverse Bidi" algorithm + * + *

This option does not imply corresponding adjustment of the index + * mappings.

+ * + * @see #setInverse + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short INSERT_LRM_FOR_NUMERIC = 4; + + /** + * option bit for writeReordered(): + * remove Bidi control characters + * (this does not affect INSERT_LRM_FOR_NUMERIC) + * + *

This option does not imply corresponding adjustment of the index + * mappings.

+ * + * @see #writeReordered + * @see #INSERT_LRM_FOR_NUMERIC + * @stable ICU 3.8 + */ + public static final short REMOVE_BIDI_CONTROLS = 8; + + /** + * option bit for writeReordered(): + * write the output in reverse order + * + *

This has the same effect as calling writeReordered() + * first without this option, and then calling + * writeReverse() without mirroring. + * Doing this in the same step is faster and avoids a temporary buffer. + * An example for using this option is output to a character terminal that + * is designed for RTL scripts and stores text in reverse order.

+ * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short OUTPUT_REVERSE = 16; + + /** Reordering mode: Regular Logical to Visual Bidi algorithm according to Unicode. + * @see #setReorderingMode + * @stable ICU 3.8 + */ + private static final short REORDER_DEFAULT = 0; + + /** Reordering mode: Logical to Visual algorithm which handles numbers in + * a way which mimicks the behavior of Windows XP. + * @see #setReorderingMode + * @stable ICU 3.8 + */ + private static final short REORDER_NUMBERS_SPECIAL = 1; + + /** Reordering mode: Logical to Visual algorithm grouping numbers with + * adjacent R characters (reversible algorithm). + * @see #setReorderingMode + * @stable ICU 3.8 + */ + private static final short REORDER_GROUP_NUMBERS_WITH_R = 2; + + /** Reordering mode: Reorder runs only to transform a Logical LTR string + * to the logical RTL string with the same display, or vice-versa.
+ * If this mode is set together with option + * OPTION_INSERT_MARKS, some Bidi controls in the source + * text may be removed and other controls may be added to produce the + * minimum combination which has the required display. + * @see #OPTION_INSERT_MARKS + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_RUNS_ONLY = 3; + + /** Reordering mode: Visual to Logical algorithm which handles numbers + * like L (same algorithm as selected by setInverse(true). + * @see #setInverse + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_INVERSE_NUMBERS_AS_L = 4; + + /** Reordering mode: Visual to Logical algorithm equivalent to the regular + * Logical to Visual algorithm. + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_INVERSE_LIKE_DIRECT = 5; + + /** Reordering mode: Inverse Bidi (Visual to Logical) algorithm for the + * REORDER_NUMBERS_SPECIAL Bidi algorithm. + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6; + + /* Reordering mode values must be ordered so that all the regular logical to + * visual modes come first, and all inverse Bidi modes come last. + */ + private static final short REORDER_LAST_LOGICAL_TO_VISUAL = + REORDER_NUMBERS_SPECIAL; + + /** + * Option bit for setReorderingOptions: + * insert Bidi marks (LRM or RLM) when needed to ensure correct result of + * a reordering to a Logical order + * + *

This option must be set or reset before calling + * setPara.

+ * + *

This option is significant only with reordering modes which generate + * a result with Logical order, specifically.

+ *
    + *
  • REORDER_RUNS_ONLY
  • + *
  • REORDER_INVERSE_NUMBERS_AS_L
  • + *
  • REORDER_INVERSE_LIKE_DIRECT
  • + *
  • REORDER_INVERSE_FOR_NUMBERS_SPECIAL
  • + *
+ * + *

If this option is set in conjunction with reordering mode + * REORDER_INVERSE_NUMBERS_AS_L or with calling + * setInverse(true), it implies option + * INSERT_LRM_FOR_NUMERIC in calls to method + * writeReordered().

+ * + *

For other reordering modes, a minimum number of LRM or RLM characters + * will be added to the source text after reordering it so as to ensure + * round trip, i.e. when applying the inverse reordering mode on the + * resulting logical text with removal of Bidi marks + * (option OPTION_REMOVE_CONTROLS set before calling + * setPara() or option + * REMOVE_BIDI_CONTROLS in + * writeReordered), the result will be identical to the + * source text in the first transformation. + * + *

This option will be ignored if specified together with option + * OPTION_REMOVE_CONTROLS. It inhibits option + * REMOVE_BIDI_CONTROLS in calls to method + * writeReordered() and it implies option + * INSERT_LRM_FOR_NUMERIC in calls to method + * writeReordered() if the reordering mode is + * REORDER_INVERSE_NUMBERS_AS_L.

+ * + * @see #setReorderingMode + * @see #setReorderingOptions + * @see #INSERT_LRM_FOR_NUMERIC + * @see #REMOVE_BIDI_CONTROLS + * @see #OPTION_REMOVE_CONTROLS + * @see #REORDER_RUNS_ONLY + * @see #REORDER_INVERSE_NUMBERS_AS_L + * @see #REORDER_INVERSE_LIKE_DIRECT + * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * @stable ICU 3.8 + */ + static final int OPTION_INSERT_MARKS = 1; + + /** + * Option bit for setReorderingOptions: + * remove Bidi control characters + * + *

This option must be set or reset before calling + * setPara.

+ * + *

This option nullifies option + * OPTION_INSERT_MARKS. It inhibits option + * INSERT_LRM_FOR_NUMERIC in calls to method + * writeReordered() and it implies option + * REMOVE_BIDI_CONTROLS in calls to that method.

+ * + * @see #setReorderingMode + * @see #setReorderingOptions + * @see #OPTION_INSERT_MARKS + * @see #INSERT_LRM_FOR_NUMERIC + * @see #REMOVE_BIDI_CONTROLS + * @stable ICU 3.8 + */ + static final int OPTION_REMOVE_CONTROLS = 2; + + /** + * Option bit for setReorderingOptions: + * process the output as part of a stream to be continued + * + *

This option must be set or reset before calling + * setPara.

+ * + *

This option specifies that the caller is interested in processing + * large text object in parts. The results of the successive calls are + * expected to be concatenated by the caller. Only the call for the last + * part will have this option bit off.

+ * + *

When this option bit is on, setPara() may process + * less than the full source text in order to truncate the text at a + * meaningful boundary. The caller should call + * getProcessedLength() immediately after calling + * setPara() in order to determine how much of the source + * text has been processed. Source text beyond that length should be + * resubmitted in following calls to setPara. The + * processed length may be less than the length of the source text if a + * character preceding the last character of the source text constitutes a + * reasonable boundary (like a block separator) for text to be continued.
+ * If the last character of the source text constitutes a reasonable + * boundary, the whole text will be processed at once.
+ * If nowhere in the source text there exists + * such a reasonable boundary, the processed length will be zero.
+ * The caller should check for such an occurrence and do one of the following: + *

  • submit a larger amount of text with a better chance to include + * a reasonable boundary.
  • + *
  • resubmit the same text after turning off option + * OPTION_STREAMING.
+ * In all cases, this option should be turned off before processing the last + * part of the text.

+ * + *

When the OPTION_STREAMING option is used, it is + * recommended to call orderParagraphsLTR(true) before calling + * setPara() so that later paragraphs may be concatenated to + * previous paragraphs on the right. + *

+ * + * @see #setReorderingMode + * @see #setReorderingOptions + * @see #getProcessedLength + * @stable ICU 3.8 + */ + private static final int OPTION_STREAMING = 4; + + /* + * Comparing the description of the Bidi algorithm with this implementation + * is easier with the same names for the Bidi types in the code as there. + * See UCharacterDirection + */ + /* private */ static final byte L = 0; + private static final byte R = 1; + private static final byte EN = 2; + private static final byte ES = 3; + private static final byte ET = 4; + private static final byte AN = 5; + private static final byte CS = 6; + static final byte B = 7; + private static final byte S = 8; + private static final byte WS = 9; + private static final byte ON = 10; + private static final byte LRE = 11; + private static final byte LRO = 12; + private static final byte AL = 13; + private static final byte RLE = 14; + private static final byte RLO = 15; + private static final byte PDF = 16; + private static final byte NSM = 17; + private static final byte BN = 18; + private static final byte FSI = 19; + private static final byte LRI = 20; + private static final byte RLI = 21; + private static final byte PDI = 22; + private static final byte ENL = PDI + 1; /* EN after W7 */ + private static final byte ENR = ENL + 1; /* EN not subject to W7 */ + + // Number of directional types + private static final int CHAR_DIRECTION_COUNT = 23; + + /** + * Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). + * Used in + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm. + * Returns UCharacter.BidiPairedBracketType values. + * @stable ICU 52 + */ + public static final int BIDI_PAIRED_BRACKET_TYPE = 0x1015; + + /** + * Bidi Paired Bracket Type constants. + * + * @see UProperty#BIDI_PAIRED_BRACKET_TYPE + * @stable ICU 52 + */ + public static interface BidiPairedBracketType { + /** + * Not a paired bracket. + * @stable ICU 52 + */ + public static final int NONE = 0; + /** + * Open paired bracket. + * @stable ICU 52 + */ + public static final int OPEN = 1; + /** + * Close paired bracket. + * @stable ICU 52 + */ + public static final int CLOSE = 2; + /** + * @stable ICU 52 + */ + public static final int COUNT = 3; + } + + /* number of paras entries allocated initially */ + static final int SIMPLE_PARAS_COUNT = 10; + + private static final char CR = '\r'; + private static final char LF = '\n'; + + static final int LRM_BEFORE = 1; + static final int LRM_AFTER = 2; + static final int RLM_BEFORE = 4; + static final int RLM_AFTER = 8; + + /* flags for Opening.flags */ + static final byte FOUND_L = (byte)DirPropFlag(L); + static final byte FOUND_R = (byte)DirPropFlag(R); + + /* + * The following bit is used for the directional isolate status. + * Stack entries corresponding to isolate sequences are greater than ISOLATE. + */ + static final int ISOLATE = 0x0100; + + /* + * reference to parent paragraph object (reference to self if this object is + * a paragraph object); set to null in a newly opened object; set to a + * real value after a successful execution of setPara or setLine + */ + BidiBase paraBidi; + + final UBiDiProps bdp; + + /* character array representing the current text */ + char[] text; + + /* length of the current text */ + int originalLength; + + /* if the option OPTION_STREAMING is set, this is the length of + * text actually processed by setPara, which may be shorter + * than the original length. Otherwise, it is identical to the original + * length. + */ + public int length; + + /* if option OPTION_REMOVE_CONTROLS is set, and/or Bidi + * marks are allowed to be inserted in one of the reordering modes, the + * length of the result string may be different from the processed length. + */ + int resultLength; + + /* indicators for whether memory may be allocated after construction */ + boolean mayAllocateText; + boolean mayAllocateRuns; + + /* arrays with one value per text-character */ + byte[] dirPropsMemory = new byte[1]; + byte[] levelsMemory = new byte[1]; + byte[] dirProps; + byte[] levels; + + /* are we performing an approximation of the "inverse Bidi" algorithm? */ + boolean isInverse; + + /* are we using the basic algorithm or its variation? */ + int reorderingMode; + + /* bitmask for reordering options */ + int reorderingOptions; + + /* must block separators receive level 0? */ + boolean orderParagraphsLTR; + + /* the paragraph level */ + byte paraLevel; + + /* original paraLevel when contextual */ + /* must be one of DEFAULT_xxx or 0 if not contextual */ + byte defaultParaLevel; + + /* the following is set in setPara, used in processPropertySeq */ + + ImpTabPair impTabPair; /* reference to levels state table pair */ + + /* the overall paragraph or line directionality*/ + byte direction; + + /* flags is a bit set for which directional properties are in the text */ + int flags; + + /* lastArabicPos is index to the last AL in the text, -1 if none */ + int lastArabicPos; + + /* characters after trailingWSStart are WS and are */ + /* implicitly at the paraLevel (rule (L1)) - levels may not reflect that */ + int trailingWSStart; + + /* fields for paragraph handling, set in getDirProps() */ + int paraCount; + int[] paras_limit = new int[SIMPLE_PARAS_COUNT]; + byte[] paras_level = new byte[SIMPLE_PARAS_COUNT]; + + /* fields for line reordering */ + int runCount; /* ==-1: runs not set up yet */ + BidiRun[] runsMemory = new BidiRun[0]; + BidiRun[] runs; + + /* for non-mixed text, we only need a tiny array of runs (no allocation) */ + BidiRun[] simpleRuns = {new BidiRun()}; + + /* fields for managing isolate sequences */ + Isolate[] isolates; + + /* maximum or current nesting depth of isolate sequences */ + /* Within resolveExplicitLevels() and checkExplicitLevels(), this is the maximal + nesting encountered. + Within resolveImplicitLevels(), this is the index of the current isolates + stack entry. */ + int isolateCount; + + /* mapping of runs in logical order to visual order */ + int[] logicalToVisualRunsMap; + /* flag to indicate that the map has been updated */ + boolean isGoodLogicalToVisualRunsMap; + + /* for inverse Bidi with insertion of directional marks */ + InsertPoints insertPoints = new InsertPoints(); + + /* for option OPTION_REMOVE_CONTROLS */ + int controlCount; + + /* + * Sometimes, bit values are more appropriate + * to deal with directionality properties. + * Abbreviations in these method names refer to names + * used in the Bidi algorithm. + */ + static int DirPropFlag(byte dir) { + return (1 << dir); + } + + boolean testDirPropFlagAt(int flag, int index) { + return ((DirPropFlag(dirProps[index]) & flag) != 0); + } + + static final int DirPropFlagMultiRuns = DirPropFlag((byte)31); + + /* to avoid some conditional statements, use tiny constant arrays */ + static final int DirPropFlagLR[] = { DirPropFlag(L), DirPropFlag(R) }; + static final int DirPropFlagE[] = { DirPropFlag(LRE), DirPropFlag(RLE) }; + static final int DirPropFlagO[] = { DirPropFlag(LRO), DirPropFlag(RLO) }; + + static final int DirPropFlagLR(byte level) { return DirPropFlagLR[level & 1]; } + static final int DirPropFlagE(byte level) { return DirPropFlagE[level & 1]; } + static final int DirPropFlagO(byte level) { return DirPropFlagO[level & 1]; } + static final byte DirFromStrong(byte strong) { return strong == L ? L : R; } + static final byte NoOverride(byte level) { return (byte)(level & ~LEVEL_OVERRIDE); } + + /* are there any characters that are LTR or RTL? */ + static final int MASK_LTR = + DirPropFlag(L)|DirPropFlag(EN)|DirPropFlag(ENL)|DirPropFlag(ENR)|DirPropFlag(AN)|DirPropFlag(LRE)|DirPropFlag(LRO)|DirPropFlag(LRI); + static final int MASK_RTL = DirPropFlag(R)|DirPropFlag(AL)|DirPropFlag(RLE)|DirPropFlag(RLO)|DirPropFlag(RLI); + + static final int MASK_R_AL = DirPropFlag(R)|DirPropFlag(AL); + + /* explicit embedding codes */ + private static final int MASK_EXPLICIT = DirPropFlag(LRE)|DirPropFlag(LRO)|DirPropFlag(RLE)|DirPropFlag(RLO)|DirPropFlag(PDF); + private static final int MASK_BN_EXPLICIT = DirPropFlag(BN)|MASK_EXPLICIT; + + /* explicit isolate codes */ + private static final int MASK_ISO = DirPropFlag(LRI)|DirPropFlag(RLI)|DirPropFlag(FSI)|DirPropFlag(PDI); + + /* paragraph and segment separators */ + private static final int MASK_B_S = DirPropFlag(B)|DirPropFlag(S); + + /* all types that are counted as White Space or Neutral in some steps */ + static final int MASK_WS = MASK_B_S|DirPropFlag(WS)|MASK_BN_EXPLICIT|MASK_ISO; + + /* types that are neutrals or could becomes neutrals in (Wn) */ + private static final int MASK_POSSIBLE_N = DirPropFlag(ON)|DirPropFlag(CS)|DirPropFlag(ES)|DirPropFlag(ET)|MASK_WS; + + /* + * These types may be changed to "e", + * the embedding type (L or R) of the run, + * in the Bidi algorithm (N2) + */ + private static final int MASK_EMBEDDING = DirPropFlag(NSM)|MASK_POSSIBLE_N; + + /* + * the dirProp's L and R are defined to 0 and 1 values in UCharacterDirection.java + */ + private static byte GetLRFromLevel(byte level) + { + return (byte)(level & 1); + } + + private static boolean IsDefaultLevel(byte level) + { + return ((level & LEVEL_DEFAULT_LTR) == LEVEL_DEFAULT_LTR); + } + + static boolean IsBidiControlChar(int c) + { + /* check for range 0x200c to 0x200f (ZWNJ, ZWJ, LRM, RLM) or + 0x202a to 0x202e (LRE, RLE, PDF, LRO, RLO) */ + return (((c & 0xfffffffc) == 0x200c) || ((c >= 0x202a) && (c <= 0x202e)) + || ((c >= 0x2066) && (c <= 0x2069))); + } + + void verifyValidPara() + { + if (!(this == this.paraBidi)) { + throw new IllegalStateException(); + } + } + + void verifyValidParaOrLine() + { + BidiBase para = this.paraBidi; + /* verify Para */ + if (this == para) { + return; + } + /* verify Line */ + if ((para == null) || (para != para.paraBidi)) { + throw new IllegalStateException(); + } + } + + void verifyRange(int index, int start, int limit) + { + if (index < start || index >= limit) { + throw new IllegalArgumentException("Value " + index + + " is out of range " + start + " to " + limit); + } + } + + /** + * Allocate a Bidi object with preallocated memory + * for internal structures. + * This method provides a Bidi object like the default constructor + * but it also preallocates memory for internal structures + * according to the sizings supplied by the caller.

+ * The preallocation can be limited to some of the internal memory + * by setting some values to 0 here. That means that if, e.g., + * maxRunCount cannot be reasonably predetermined and should not + * be set to maxLength (the only failproof value) to avoid + * wasting memory, then maxRunCount could be set to 0 here + * and the internal structures that are associated with it will be allocated + * on demand, just like with the default constructor. + * + * @param maxLength is the maximum text or line length that internal memory + * will be preallocated for. An attempt to associate this object with a + * longer text will fail, unless this value is 0, which leaves the allocation + * up to the implementation. + * + * @param maxRunCount is the maximum anticipated number of same-level runs + * that internal memory will be preallocated for. An attempt to access + * visual runs on an object that was not preallocated for as many runs + * as the text was actually resolved to will fail, + * unless this value is 0, which leaves the allocation up to the implementation.

+ * The number of runs depends on the actual text and maybe anywhere between + * 1 and maxLength. It is typically small. + * + * @throws IllegalArgumentException if maxLength or maxRunCount is less than 0 + * @stable ICU 3.8 + */ + public BidiBase(int maxLength, int maxRunCount) + { + /* check the argument values */ + if (maxLength < 0 || maxRunCount < 0) { + throw new IllegalArgumentException(); + } + + /* reset the object, all reference variables null, all flags false, + all sizes 0. + In fact, we don't need to do anything, since class members are + initialized as zero when an instance is created. + */ + /* + mayAllocateText = false; + mayAllocateRuns = false; + orderParagraphsLTR = false; + paraCount = 0; + runCount = 0; + trailingWSStart = 0; + flags = 0; + paraLevel = 0; + defaultParaLevel = 0; + direction = 0; + */ + /* get Bidi properties */ + bdp = UBiDiProps.INSTANCE; + + /* allocate memory for arrays as requested */ + if (maxLength > 0) { + getInitialDirPropsMemory(maxLength); + getInitialLevelsMemory(maxLength); + } else { + mayAllocateText = true; + } + + if (maxRunCount > 0) { + // if maxRunCount == 1, use simpleRuns[] + if (maxRunCount > 1) { + getInitialRunsMemory(maxRunCount); + } + } else { + mayAllocateRuns = true; + } + } + + /* + * We are allowed to allocate memory if object==null or + * mayAllocate==true for each array that we need. + * + * Assume sizeNeeded>0. + * If object != null, then assume size > 0. + */ + private Object getMemory(String label, Object array, Class arrayClass, + boolean mayAllocate, int sizeNeeded) + { + int len = Array.getLength(array); + + /* we have at least enough memory and must not allocate */ + if (sizeNeeded == len) { + return array; + } + if (!mayAllocate) { + /* we must not allocate */ + if (sizeNeeded <= len) { + return array; + } + throw new OutOfMemoryError("Failed to allocate memory for " + + label); + } + /* we may try to grow or shrink */ + /* FOOD FOR THOUGHT: when shrinking it should be possible to avoid + the allocation altogether and rely on this.length */ + try { + return Array.newInstance(arrayClass, sizeNeeded); + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for " + + label); + } + } + + /* helper methods for each allocated array */ + private void getDirPropsMemory(boolean mayAllocate, int len) + { + Object array = getMemory("DirProps", dirPropsMemory, Byte.TYPE, mayAllocate, len); + dirPropsMemory = (byte[]) array; + } + + void getDirPropsMemory(int len) + { + getDirPropsMemory(mayAllocateText, len); + } + + private void getLevelsMemory(boolean mayAllocate, int len) + { + Object array = getMemory("Levels", levelsMemory, Byte.TYPE, mayAllocate, len); + levelsMemory = (byte[]) array; + } + + void getLevelsMemory(int len) + { + getLevelsMemory(mayAllocateText, len); + } + + private void getRunsMemory(boolean mayAllocate, int len) + { + Object array = getMemory("Runs", runsMemory, BidiRun.class, mayAllocate, len); + runsMemory = (BidiRun[]) array; + } + + void getRunsMemory(int len) + { + getRunsMemory(mayAllocateRuns, len); + } + + /* additional methods used by constructor - always allow allocation */ + private void getInitialDirPropsMemory(int len) + { + getDirPropsMemory(true, len); + } + + private void getInitialLevelsMemory(int len) + { + getLevelsMemory(true, len); + } + + private void getInitialRunsMemory(int len) + { + getRunsMemory(true, len); + } + + /** + * Is this Bidi object set to perform the inverse Bidi + * algorithm? + *

Note: calling this method after setting the reordering mode with + * setReorderingMode will return true if the + * reordering mode was set to + * REORDER_INVERSE_NUMBERS_AS_L, false + * for all other values.

+ * + * @return true if the Bidi object is set to + * perform the inverse Bidi algorithm by handling numbers as L. + * + * @see #setInverse + * @see #setReorderingMode + * @see #REORDER_INVERSE_NUMBERS_AS_L + * @stable ICU 3.8 + */ + public boolean isInverse() { + return isInverse; + } + + /* perform (P2)..(P3) ------------------------------------------------------- */ + + /* + * Check that there are enough entries in the arrays paras_limit and paras_level + */ + private void checkParaCount() { + int[] saveLimits; + byte[] saveLevels; + int count = paraCount; + if (count <= paras_level.length) + return; + int oldLength = paras_level.length; + saveLimits = paras_limit; + saveLevels = paras_level; + try { + paras_limit = new int[count * 2]; + paras_level = new byte[count * 2]; + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for paras"); + } + System.arraycopy(saveLimits, 0, paras_limit, 0, oldLength); + System.arraycopy(saveLevels, 0, paras_level, 0, oldLength); + } + + /* + * Get the directional properties for the text, calculate the flags bit-set, and + * determine the paragraph level if necessary (in paras_level[i]). + * FSI initiators are also resolved and their dirProp replaced with LRI or RLI. + * When encountering an FSI, it is initially replaced with an LRI, which is the + * default. Only if a strong R or AL is found within its scope will the LRI be + * replaced by an RLI. + */ + static final int NOT_SEEKING_STRONG = 0; /* 0: not contextual paraLevel, not after FSI */ + static final int SEEKING_STRONG_FOR_PARA = 1; /* 1: looking for first strong char in para */ + static final int SEEKING_STRONG_FOR_FSI = 2; /* 2: looking for first strong after FSI */ + static final int LOOKING_FOR_PDI = 3; /* 3: found strong after FSI, looking for PDI */ + + private void getDirProps() + { + int i = 0, i0, i1; + flags = 0; /* collect all directionalities in the text */ + int uchar; + byte dirProp; + byte defaultParaLevel = 0; /* initialize to avoid compiler warnings */ + boolean isDefaultLevel = IsDefaultLevel(paraLevel); + /* for inverse Bidi, the default para level is set to RTL if there is a + strong R or AL character at either end of the text */ + boolean isDefaultLevelInverse=isDefaultLevel && + (reorderingMode == REORDER_INVERSE_LIKE_DIRECT || + reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL); + lastArabicPos = -1; + int controlCount = 0; + boolean removeBidiControls = (reorderingOptions & OPTION_REMOVE_CONTROLS) != 0; + + byte state; + byte lastStrong = ON; /* for default level & inverse Bidi */ + /* The following stacks are used to manage isolate sequences. Those + sequences may be nested, but obviously never more deeply than the + maximum explicit embedding level. + lastStack is the index of the last used entry in the stack. A value of -1 + means that there is no open isolate sequence. + lastStack is reset to -1 on paragraph boundaries. */ + /* The following stack contains the position of the initiator of + each open isolate sequence */ + int[] isolateStartStack= new int[MAX_EXPLICIT_LEVEL+1]; + /* The following stack contains the last known state before + encountering the initiator of an isolate sequence */ + byte[] previousStateStack = new byte[MAX_EXPLICIT_LEVEL+1]; + int stackLast=-1; + + if ((reorderingOptions & OPTION_STREAMING) != 0) + length = 0; + defaultParaLevel = (byte)(paraLevel & 1); + + if (isDefaultLevel) { + paras_level[0] = defaultParaLevel; + lastStrong = defaultParaLevel; + state = SEEKING_STRONG_FOR_PARA; + } else { + paras_level[0] = paraLevel; + state = NOT_SEEKING_STRONG; + } + /* count paragraphs and determine the paragraph level (P2..P3) */ + /* + * see comment on constant fields: + * the LEVEL_DEFAULT_XXX values are designed so that + * their low-order bit alone yields the intended default + */ + + for (i = 0; i < originalLength; /* i is incremented in the loop */) { + i0 = i; /* index of first code unit */ + uchar = UTF16.charAt(text, 0, originalLength, i); + i += UTF16.getCharCount(uchar); + i1 = i - 1; /* index of last code unit, gets the directional property */ + + dirProp = (byte)getCustomizedClass(uchar); + flags |= DirPropFlag(dirProp); + dirProps[i1] = dirProp; + if (i1 > i0) { /* set previous code units' properties to BN */ + flags |= DirPropFlag(BN); + do { + dirProps[--i1] = BN; + } while (i1 > i0); + } + if (removeBidiControls && IsBidiControlChar(uchar)) { + controlCount++; + } + if (dirProp == L) { + if (state == SEEKING_STRONG_FOR_PARA) { + paras_level[paraCount - 1] = 0; + state = NOT_SEEKING_STRONG; + } + else if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + } + state = LOOKING_FOR_PDI; + } + lastStrong = L; + continue; + } + if (dirProp == R || dirProp == AL) { + if (state == SEEKING_STRONG_FOR_PARA) { + paras_level[paraCount - 1] = 1; + state = NOT_SEEKING_STRONG; + } + else if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + dirProps[isolateStartStack[stackLast]] = RLI; + flags |= DirPropFlag(RLI); + } + state = LOOKING_FOR_PDI; + } + lastStrong = R; + if (dirProp == AL) + lastArabicPos = i - 1; + continue; + } + if (dirProp >= FSI && dirProp <= RLI) { /* FSI, LRI or RLI */ + stackLast++; + if (stackLast <= MAX_EXPLICIT_LEVEL) { + isolateStartStack[stackLast] = i - 1; + previousStateStack[stackLast] = state; + } + if (dirProp == FSI) { + dirProps[i-1] = LRI; /* default if no strong char */ + state = SEEKING_STRONG_FOR_FSI; + } + else + state = LOOKING_FOR_PDI; + continue; + } + if (dirProp == PDI) { + if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + } + } + if (stackLast >= 0) { + if (stackLast <= MAX_EXPLICIT_LEVEL) + state = previousStateStack[stackLast]; + stackLast--; + } + continue; + } + if (dirProp == B) { + if (i < originalLength && uchar == CR && text[i] == LF) /* do nothing on the CR */ + continue; + paras_limit[paraCount - 1] = i; + if (isDefaultLevelInverse && lastStrong == R) + paras_level[paraCount - 1] = 1; + if ((reorderingOptions & OPTION_STREAMING) != 0) { + /* When streaming, we only process whole paragraphs + thus some updates are only done on paragraph boundaries */ + length = i; /* i is index to next character */ + this.controlCount = controlCount; + } + if (i < originalLength) { /* B not last char in text */ + paraCount++; + checkParaCount(); /* check that there is enough memory for a new para entry */ + if (isDefaultLevel) { + paras_level[paraCount - 1] = defaultParaLevel; + state = SEEKING_STRONG_FOR_PARA; + lastStrong = defaultParaLevel; + } else { + paras_level[paraCount - 1] = paraLevel; + state = NOT_SEEKING_STRONG; + } + stackLast = -1; + } + continue; + } + } + /* +Ignore still open isolate sequences with overflow */ + if (stackLast > MAX_EXPLICIT_LEVEL) { + stackLast = MAX_EXPLICIT_LEVEL; + state=SEEKING_STRONG_FOR_FSI; /* to be on the safe side */ + } + /* Resolve direction of still unresolved open FSI sequences */ + while (stackLast >= 0) { + if (state == SEEKING_STRONG_FOR_FSI) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + break; + } + state = previousStateStack[stackLast]; + stackLast--; + } + /* When streaming, ignore text after the last paragraph separator */ + if ((reorderingOptions & OPTION_STREAMING) != 0) { + if (length < originalLength) + paraCount--; + } else { + paras_limit[paraCount - 1] = originalLength; + this.controlCount = controlCount; + } + /* For inverse bidi, default para direction is RTL if there is + a strong R or AL at either end of the paragraph */ + if (isDefaultLevelInverse && lastStrong == R) { + paras_level[paraCount - 1] = 1; + } + if (isDefaultLevel) { + paraLevel = paras_level[0]; + } + /* The following is needed to resolve the text direction for default level + paragraphs containing no strong character */ + for (i = 0; i < paraCount; i++) + flags |= DirPropFlagLR(paras_level[i]); + + if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) { + flags |= DirPropFlag(L); + } + } + + /* determine the paragraph level at position index */ + byte GetParaLevelAt(int pindex) + { + if (defaultParaLevel == 0 || pindex < paras_limit[0]) + return paraLevel; + int i; + for (i = 1; i < paraCount; i++) + if (pindex < paras_limit[i]) + break; + if (i >= paraCount) + i = paraCount - 1; + return paras_level[i]; + } + + /* Functions for handling paired brackets ----------------------------------- */ + + /* In the isoRuns array, the first entry is used for text outside of any + isolate sequence. Higher entries are used for each more deeply nested + isolate sequence. isoRunLast is the index of the last used entry. The + openings array is used to note the data of opening brackets not yet + matched by a closing bracket, or matched but still susceptible to change + level. + Each isoRun entry contains the index of the first and + one-after-last openings entries for pending opening brackets it + contains. The next openings entry to use is the one-after-last of the + most deeply nested isoRun entry. + isoRun entries also contain their current embedding level and the last + encountered strong character, since these will be needed to resolve + the level of paired brackets. */ + + private void bracketInit(BracketData bd) { + bd.isoRunLast = 0; + bd.isoRuns[0] = new IsoRun(); + bd.isoRuns[0].start = 0; + bd.isoRuns[0].limit = 0; + bd.isoRuns[0].level = GetParaLevelAt(0); + bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte)(GetParaLevelAt(0) & 1); + bd.isoRuns[0].contextPos = 0; + bd.openings = new Opening[SIMPLE_PARAS_COUNT]; + bd.isNumbersSpecial = reorderingMode == REORDER_NUMBERS_SPECIAL || + reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL; + } + + /* paragraph boundary */ + private void bracketProcessB(BracketData bd, byte level) { + bd.isoRunLast = 0; + bd.isoRuns[0].limit = 0; + bd.isoRuns[0].level = level; + bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte)(level & 1); + bd.isoRuns[0].contextPos = 0; + } + + /* LRE, LRO, RLE, RLO, PDF */ + private void bracketProcessBoundary(BracketData bd, int lastCcPos, + byte contextLevel, byte embeddingLevel) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + if ((DirPropFlag(dirProps[lastCcPos]) & MASK_ISO) != 0) /* after an isolate */ + return; + if (NoOverride(embeddingLevel) > NoOverride(contextLevel)) /* not a PDF */ + contextLevel = embeddingLevel; + pLastIsoRun.limit = pLastIsoRun.start; + pLastIsoRun.level = embeddingLevel; + pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte)(contextLevel & 1); + pLastIsoRun.contextPos = lastCcPos; + } + + /* LRI or RLI */ + private void bracketProcessLRI_RLI(BracketData bd, byte level) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + short lastLimit; + pLastIsoRun.lastBase = ON; + lastLimit = pLastIsoRun.limit; + bd.isoRunLast++; + pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + if (pLastIsoRun == null) + pLastIsoRun = bd.isoRuns[bd.isoRunLast] = new IsoRun(); + pLastIsoRun.start = pLastIsoRun.limit = lastLimit; + pLastIsoRun.level = level; + pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte)(level & 1); + pLastIsoRun.contextPos = 0; + } + + /* PDI */ + private void bracketProcessPDI(BracketData bd) { + IsoRun pLastIsoRun; + bd.isoRunLast--; + pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + pLastIsoRun.lastBase = ON; + } + + /* newly found opening bracket: create an openings entry */ + private void bracketAddOpening(BracketData bd, char match, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening pOpening; + if (pLastIsoRun.limit >= bd.openings.length) { /* no available new entry */ + Opening[] saveOpenings = bd.openings; + int count; + try { + count = bd.openings.length; + bd.openings = new Opening[count * 2]; + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for openings"); + } + System.arraycopy(saveOpenings, 0, bd.openings, 0, count); + } + pOpening = bd.openings[pLastIsoRun.limit]; + if (pOpening == null) + pOpening = bd.openings[pLastIsoRun.limit]= new Opening(); + pOpening.position = position; + pOpening.match = match; + pOpening.contextDir = pLastIsoRun.contextDir; + pOpening.contextPos = pLastIsoRun.contextPos; + pOpening.flags = 0; + pLastIsoRun.limit++; + } + + /* change N0c1 to N0c2 when a preceding bracket is assigned the embedding level */ + private void fixN0c(BracketData bd, int openingIndex, int newPropPosition, byte newProp) { + /* This function calls itself recursively */ + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening qOpening; + int k, openingPosition, closingPosition; + for (k = openingIndex+1; k < pLastIsoRun.limit; k++) { + qOpening = bd.openings[k]; + if (qOpening.match >= 0) /* not an N0c match */ + continue; + if (newPropPosition < qOpening.contextPos) + break; + if (newPropPosition >= qOpening.position) + continue; + if (newProp == qOpening.contextDir) + break; + openingPosition = qOpening.position; + dirProps[openingPosition] = newProp; + closingPosition = -(qOpening.match); + dirProps[closingPosition] = newProp; + qOpening.match = 0; /* prevent further changes */ + fixN0c(bd, k, openingPosition, newProp); + fixN0c(bd, k, closingPosition, newProp); + } + } + + /* process closing bracket; return L or R if N0b or N0c, ON if N0d */ + private byte bracketProcessClosing(BracketData bd, int openIdx, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening pOpening, qOpening; + byte direction; + boolean stable; + byte newProp; + pOpening = bd.openings[openIdx]; + direction = (byte)(pLastIsoRun.level & 1); + stable = true; /* assume stable until proved otherwise */ + + /* The stable flag is set when brackets are paired and their + level is resolved and cannot be changed by what will be + found later in the source string. + An unstable match can occur only when applying N0c, where + the resolved level depends on the preceding context, and + this context may be affected by text occurring later. + Example: RTL paragraph containing: abc[(latin) HEBREW] + When the closing parenthesis is encountered, it appears + that N0c1 must be applied since 'abc' sets an opposite + direction context and both parentheses receive level 2. + However, when the closing square bracket is processed, + N0b applies because of 'HEBREW' being included within the + brackets, thus the square brackets are treated like R and + receive level 1. However, this changes the preceding + context of the opening parenthesis, and it now appears + that N0c2 must be applied to the parentheses rather than + N0c1. */ + + if ((direction == 0 && (pOpening.flags & FOUND_L) > 0) || + (direction == 1 && (pOpening.flags & FOUND_R) > 0)) { /* N0b */ + newProp = direction; + } + else if ((pOpening.flags & (FOUND_L | FOUND_R)) != 0) { /* N0c */ + /* it is stable if there is no preceding text or in + conditions too complicated and not worth checking */ + stable = (openIdx == pLastIsoRun.start); + if (direction != pOpening.contextDir) + newProp = pOpening.contextDir; /* N0c1 */ + else + newProp = direction; /* N0c2 */ + } else { + /* forget this and any brackets nested within this pair */ + pLastIsoRun.limit = (short)openIdx; + return ON; /* N0d */ + } + dirProps[pOpening.position] = newProp; + dirProps[position] = newProp; + /* Update nested N0c pairs that may be affected */ + fixN0c(bd, openIdx, pOpening.position, newProp); + if (stable) { + pLastIsoRun.limit = (short)openIdx; /* forget any brackets nested within this pair */ + /* remove lower located synonyms if any */ + while (pLastIsoRun.limit > pLastIsoRun.start && + bd.openings[pLastIsoRun.limit - 1].position == pOpening.position) + pLastIsoRun.limit--; + } else { + int k; + pOpening.match = -position; + /* neutralize lower located synonyms if any */ + k = openIdx - 1; + while (k >= pLastIsoRun.start && + bd.openings[k].position == pOpening.position) + bd.openings[k--].match = 0; + /* neutralize any unmatched opening between the current pair; + this will also neutralize higher located synonyms if any */ + for (k = openIdx + 1; k < pLastIsoRun.limit; k++) { + qOpening =bd.openings[k]; + if (qOpening.position >= position) + break; + if (qOpening.match > 0) + qOpening.match = 0; + } + } + return newProp; + } + + /* handle strong characters, digits and candidates for closing brackets */ + private void bracketProcessChar(BracketData bd, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + byte dirProp, newProp; + byte level; + dirProp = dirProps[position]; + if (dirProp == ON) { + char c, match; + int idx; + /* First see if it is a matching closing bracket. Hopefully, this is + more efficient than checking if it is a closing bracket at all */ + c = text[position]; + for (idx = pLastIsoRun.limit - 1; idx >= pLastIsoRun.start; idx--) { + if (bd.openings[idx].match != c) + continue; + /* We have a match */ + newProp = bracketProcessClosing(bd, idx, position); + if(newProp == ON) { /* N0d */ + c = 0; /* prevent handling as an opening */ + break; + } + pLastIsoRun.lastBase = ON; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + level = levels[position]; + if ((level & LEVEL_OVERRIDE) != 0) { /* X4, X5 */ + short flag; + int i; + newProp = (byte)(level & 1); + pLastIsoRun.lastStrong = newProp; + flag = (short)DirPropFlag(newProp); + for (i = pLastIsoRun.start; i < idx; i++) + bd.openings[i].flags |= flag; + /* matching brackets are not overridden by LRO/RLO */ + levels[position] &= ~LEVEL_OVERRIDE; + } + /* matching brackets are not overridden by LRO/RLO */ + levels[bd.openings[idx].position] &= ~LEVEL_OVERRIDE; + return; + } + /* We get here only if the ON character is not a matching closing + bracket or it is a case of N0d */ + /* Now see if it is an opening bracket */ + if (c != 0) { + match = (char)UCharacter.getBidiPairedBracket(c); /* get the matching char */ + } else { + match = 0; + } + if (match != c && /* has a matching char */ + UCharacter.getIntPropertyValue(c, BIDI_PAIRED_BRACKET_TYPE) == + /* opening bracket */ BidiPairedBracketType.OPEN) { + /* special case: process synonyms + create an opening entry for each synonym */ + if (match == 0x232A) { /* RIGHT-POINTING ANGLE BRACKET */ + bracketAddOpening(bd, (char)0x3009, position); + } + else if (match == 0x3009) { /* RIGHT ANGLE BRACKET */ + bracketAddOpening(bd, (char)0x232A, position); + } + bracketAddOpening(bd, match, position); + } + } + level = levels[position]; + if ((level & LEVEL_OVERRIDE) != 0) { /* X4, X5 */ + newProp = (byte)(level & 1); + if (dirProp != S && dirProp != WS && dirProp != ON) + dirProps[position] = newProp; + pLastIsoRun.lastBase = newProp; + pLastIsoRun.lastStrong = newProp; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + } + else if (dirProp <= R || dirProp == AL) { + newProp = DirFromStrong(dirProp); + pLastIsoRun.lastBase = dirProp; + pLastIsoRun.lastStrong = dirProp; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + } + else if(dirProp == EN) { + pLastIsoRun.lastBase = EN; + if (pLastIsoRun.lastStrong == L) { + newProp = L; /* W7 */ + if (!bd.isNumbersSpecial) + dirProps[position] = ENL; + pLastIsoRun.contextDir = L; + pLastIsoRun.contextPos = position; + } + else { + newProp = R; /* N0 */ + if (pLastIsoRun.lastStrong == AL) + dirProps[position] = AN; /* W2 */ + else + dirProps[position] = ENR; + pLastIsoRun.contextDir = R; + pLastIsoRun.contextPos = position; + } + } + else if (dirProp == AN) { + newProp = R; /* N0 */ + pLastIsoRun.lastBase = AN; + pLastIsoRun.contextDir = R; + pLastIsoRun.contextPos = position; + } + else if (dirProp == NSM) { + /* if the last real char was ON, change NSM to ON so that it + will stay ON even if the last real char is a bracket which + may be changed to L or R */ + newProp = pLastIsoRun.lastBase; + if (newProp == ON) + dirProps[position] = newProp; + } + else { + newProp = dirProp; + pLastIsoRun.lastBase = dirProp; + } + if (newProp <= R || newProp == AL) { + int i; + short flag = (short)DirPropFlag(DirFromStrong(newProp)); + for (i = pLastIsoRun.start; i < pLastIsoRun.limit; i++) + if (position > bd.openings[i].position) + bd.openings[i].flags |= flag; + } + } + + /* perform (X1)..(X9) ------------------------------------------------------- */ + + /* determine if the text is mixed-directional or single-directional */ + private byte directionFromFlags() { + + /* if the text contains AN and neutrals, then some neutrals may become RTL */ + if (!((flags & MASK_RTL) != 0 || + ((flags & DirPropFlag(AN)) != 0 && + (flags & MASK_POSSIBLE_N) != 0))) { + return LTR; + } else if ((flags & MASK_LTR) == 0) { + return RTL; + } else { + return MIXED; + } + } + + /* + * Resolve the explicit levels as specified by explicit embedding codes. + * Recalculate the flags to have them reflect the real properties + * after taking the explicit embeddings into account. + * + * The BiDi algorithm is designed to result in the same behavior whether embedding + * levels are externally specified (from "styled text", supposedly the preferred + * method) or set by explicit embedding codes (LRx, RLx, PDF, FSI, PDI) in the plain text. + * That is why (X9) instructs to remove all not-isolate explicit codes (and BN). + * However, in a real implementation, the removal of these codes and their index + * positions in the plain text is undesirable since it would result in + * reallocated, reindexed text. + * Instead, this implementation leaves the codes in there and just ignores them + * in the subsequent processing. + * In order to get the same reordering behavior, positions with a BN or a not-isolate + * explicit embedding code just get the same level assigned as the last "real" + * character. + * + * Some implementations, not this one, then overwrite some of these + * directionality properties at "real" same-level-run boundaries by + * L or R codes so that the resolution of weak types can be performed on the + * entire paragraph at once instead of having to parse it once more and + * perform that resolution on same-level-runs. + * This limits the scope of the implicit rules in effectively + * the same way as the run limits. + * + * Instead, this implementation does not modify these codes, except for + * paired brackets whose properties (ON) may be replaced by L or R. + * On one hand, the paragraph has to be scanned for same-level-runs, but + * on the other hand, this saves another loop to reset these codes, + * or saves making and modifying a copy of dirProps[]. + * + * + * Note that (Pn) and (Xn) changed significantly from version 4 of the BiDi algorithm. + * + * + * Handling the stack of explicit levels (Xn): + * + * With the BiDi stack of explicit levels, as pushed with each + * LRE, RLE, LRO, RLO, LRI, RLI and FSI and popped with each PDF and PDI, + * the explicit level must never exceed MAX_EXPLICIT_LEVEL. + * + * In order to have a correct push-pop semantics even in the case of overflows, + * overflow counters and a valid isolate counter are used as described in UAX#9 + * section 3.3.2 "Explicit Levels and Directions". + * + * This implementation assumes that MAX_EXPLICIT_LEVEL is odd. + * + * Returns the direction + * + */ + private byte resolveExplicitLevels() { + int i = 0; + byte dirProp; + byte level = GetParaLevelAt(0); + byte dirct; + isolateCount = 0; + + /* determine if the text is mixed-directional or single-directional */ + dirct = directionFromFlags(); + + /* we may not need to resolve any explicit levels */ + if (dirct != MIXED) { + /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */ + return dirct; + } + + if (reorderingMode > REORDER_LAST_LOGICAL_TO_VISUAL) { + /* inverse BiDi: mixed, but all characters are at the same embedding level */ + /* set all levels to the paragraph level */ + int paraIndex, start, limit; + for (paraIndex = 0; paraIndex < paraCount; paraIndex++) { + if (paraIndex == 0) + start = 0; + else + start = paras_limit[paraIndex - 1]; + limit = paras_limit[paraIndex]; + level = paras_level[paraIndex]; + for (i = start; i < limit; i++) + levels[i] =level; + } + return dirct; /* no bracket matching for inverse BiDi */ + } + if ((flags & (MASK_EXPLICIT | MASK_ISO)) == 0) { + /* no embeddings, set all levels to the paragraph level */ + /* we still have to perform bracket matching */ + int paraIndex, start, limit; + BracketData bracketData = new BracketData(); + bracketInit(bracketData); + for (paraIndex = 0; paraIndex < paraCount; paraIndex++) { + if (paraIndex == 0) + start = 0; + else + start = paras_limit[paraIndex-1]; + limit = paras_limit[paraIndex]; + level = paras_level[paraIndex]; + for (i = start; i < limit; i++) { + levels[i] = level; + dirProp = dirProps[i]; + if (dirProp == BN) + continue; + if (dirProp == B) { + if ((i + 1) < length) { + if (text[i] == CR && text[i + 1] == LF) + continue; /* skip CR when followed by LF */ + bracketProcessB(bracketData, level); + } + continue; + } + bracketProcessChar(bracketData, i); + } + } + return dirct; + } + /* continue to perform (Xn) */ + + /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */ + /* both variables may carry the LEVEL_OVERRIDE flag to indicate the override status */ + byte embeddingLevel = level, newLevel; + byte previousLevel = level; /* previous level for regular (not CC) characters */ + int lastCcPos = 0; /* index of last effective LRx,RLx, PDx */ + + /* The following stack remembers the embedding level and the ISOLATE flag of level runs. + stackLast points to its current entry. */ + short[] stack = new short[MAX_EXPLICIT_LEVEL + 2]; /* we never push anything >= MAX_EXPLICIT_LEVEL + but we need one more entry as base */ + int stackLast = 0; + int overflowIsolateCount = 0; + int overflowEmbeddingCount = 0; + int validIsolateCount = 0; + BracketData bracketData = new BracketData(); + bracketInit(bracketData); + stack[0] = level; /* initialize base entry to para level, no override, no isolate */ + + /* recalculate the flags */ + flags = 0; + + for (i = 0; i < length; i++) { + dirProp = dirProps[i]; + switch (dirProp) { + case LRE: + case RLE: + case LRO: + case RLO: + /* (X2, X3, X4, X5) */ + flags |= DirPropFlag(BN); + levels[i] = previousLevel; + if (dirProp == LRE || dirProp == LRO) { + /* least greater even level */ + newLevel = (byte)((embeddingLevel+2) & ~(LEVEL_OVERRIDE | 1)); + } else { + /* least greater odd level */ + newLevel = (byte)((NoOverride(embeddingLevel) + 1) | 1); + } + if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 && + overflowEmbeddingCount == 0) { + lastCcPos = i; + embeddingLevel = newLevel; + if (dirProp == LRO || dirProp == RLO) + embeddingLevel |= LEVEL_OVERRIDE; + stackLast++; + stack[stackLast] = embeddingLevel; + /* we don't need to set LEVEL_OVERRIDE off for LRE and RLE + since this has already been done for newLevel which is + the source for embeddingLevel. + */ + } else { + if (overflowIsolateCount == 0) + overflowEmbeddingCount++; + } + break; + case PDF: + /* (X7) */ + flags |= DirPropFlag(BN); + levels[i] = previousLevel; + /* handle all the overflow cases first */ + if (overflowIsolateCount > 0) { + break; + } + if (overflowEmbeddingCount > 0) { + overflowEmbeddingCount--; + break; + } + if (stackLast > 0 && stack[stackLast] < ISOLATE) { /* not an isolate entry */ + lastCcPos = i; + stackLast--; + embeddingLevel = (byte)stack[stackLast]; + } + break; + case LRI: + case RLI: + flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel); + levels[i] = NoOverride(embeddingLevel); + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, + previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + } + previousLevel = embeddingLevel; + /* (X5a, X5b) */ + if (dirProp == LRI) + /* least greater even level */ + newLevel=(byte)((embeddingLevel+2)&~(LEVEL_OVERRIDE|1)); + else + /* least greater odd level */ + newLevel=(byte)((NoOverride(embeddingLevel)+1)|1); + if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 + && overflowEmbeddingCount == 0) { + flags |= DirPropFlag(dirProp); + lastCcPos = i; + validIsolateCount++; + if (validIsolateCount > isolateCount) + isolateCount = validIsolateCount; + embeddingLevel = newLevel; + /* we can increment stackLast without checking because newLevel + will exceed UBIDI_MAX_EXPLICIT_LEVEL before stackLast overflows */ + stackLast++; + stack[stackLast] = (short)(embeddingLevel + ISOLATE); + bracketProcessLRI_RLI(bracketData, embeddingLevel); + } else { + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + overflowIsolateCount++; + } + break; + case PDI: + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, + previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + } + /* (X6a) */ + if (overflowIsolateCount > 0) { + overflowIsolateCount--; + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + } + else if (validIsolateCount > 0) { + flags |= DirPropFlag(PDI); + lastCcPos = i; + overflowEmbeddingCount = 0; + while (stack[stackLast] < ISOLATE) /* pop embedding entries */ + stackLast--; /* until the last isolate entry */ + stackLast--; /* pop also the last isolate entry */ + validIsolateCount--; + bracketProcessPDI(bracketData); + } else + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + embeddingLevel = (byte)(stack[stackLast] & ~ISOLATE); + flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel); + previousLevel = embeddingLevel; + levels[i] = NoOverride(embeddingLevel); + break; + case B: + flags |= DirPropFlag(B); + levels[i] = GetParaLevelAt(i); + if ((i + 1) < length) { + if (text[i] == CR && text[i + 1] == LF) + break; /* skip CR when followed by LF */ + overflowEmbeddingCount = overflowIsolateCount = 0; + validIsolateCount = 0; + stackLast = 0; + previousLevel = embeddingLevel = GetParaLevelAt(i + 1); + stack[0] = embeddingLevel; /* initialize base entry to para level, no override, no isolate */ + bracketProcessB(bracketData, embeddingLevel); + } + break; + case BN: + /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */ + /* they will get their levels set correctly in adjustWSLevels() */ + levels[i] = previousLevel; + flags |= DirPropFlag(BN); + break; + default: + /* all other types are normal characters and get the "real" level */ + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, + previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + if ((embeddingLevel & LEVEL_OVERRIDE) != 0) + flags |= DirPropFlagO(embeddingLevel); + else + flags |= DirPropFlagE(embeddingLevel); + } + previousLevel = embeddingLevel; + levels[i] = embeddingLevel; + bracketProcessChar(bracketData, i); + /* the dirProp may have been changed in bracketProcessChar() */ + flags |= DirPropFlag(dirProps[i]); + break; + } + } + if ((flags & MASK_EMBEDDING) != 0) { + flags |= DirPropFlagLR(paraLevel); + } + if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) { + flags |= DirPropFlag(L); + } + /* again, determine if the text is mixed-directional or single-directional */ + dirct = directionFromFlags(); + + return dirct; + } + + /* + * Use a pre-specified embedding levels array: + * + * Adjust the directional properties for overrides (->LEVEL_OVERRIDE), + * ignore all explicit codes (X9), + * and check all the preset levels. + * + * Recalculate the flags to have them reflect the real properties + * after taking the explicit embeddings into account. + */ + private byte checkExplicitLevels() { + byte dirProp; + int i; + int isolateCount = 0; + + this.flags = 0; /* collect all directionalities in the text */ + byte level; + this.isolateCount = 0; + + for (i = 0; i < length; ++i) { + if (levels[i] == 0) { + levels[i] = paraLevel; + } + + // for backward compatibility + if (MAX_EXPLICIT_LEVEL < (levels[i]&0x7f)) { + if ((levels[i] & LEVEL_OVERRIDE) != 0) { + levels[i] = (byte)(paraLevel|LEVEL_OVERRIDE); + } else { + levels[i] = paraLevel; + } + } + + level = levels[i]; + dirProp = dirProps[i]; + if (dirProp == LRI || dirProp == RLI) { + isolateCount++; + if (isolateCount > this.isolateCount) + this.isolateCount = isolateCount; + } + else if (dirProp == PDI) { + isolateCount--; + } else if (dirProp == B) { + isolateCount = 0; + } + if ((level & LEVEL_OVERRIDE) != 0) { + /* keep the override flag in levels[i] but adjust the flags */ + level &= ~LEVEL_OVERRIDE; /* make the range check below simpler */ + flags |= DirPropFlagO(level); + } else { + /* set the flags */ + flags |= DirPropFlagE(level) | DirPropFlag(dirProp); + } + if ((level < GetParaLevelAt(i) && + !((0 == level) && (dirProp == B))) || + (MAX_EXPLICIT_LEVEL < level)) { + /* level out of bounds */ + throw new IllegalArgumentException("level " + level + + " out of bounds at " + i); + } + } + if ((flags & MASK_EMBEDDING) != 0) { + flags |= DirPropFlagLR(paraLevel); + } + /* determine if the text is mixed-directional or single-directional */ + return directionFromFlags(); + } + + /* *******************************************************************/ + /* The Properties state machine table */ + /* *******************************************************************/ + /* */ + /* All table cells are 8 bits: */ + /* bits 0..4: next state */ + /* bits 5..7: action to perform (if > 0) */ + /* */ + /* Cells may be of format "n" where n represents the next state */ + /* (except for the rightmost column). */ + /* Cells may also be of format "_(x,y)" where x represents an action */ + /* to perform and y represents the next state. */ + /* */ + /* *******************************************************************/ + /* Definitions and type for properties state tables */ + /* *******************************************************************/ + private static final int IMPTABPROPS_COLUMNS = 16; + private static final int IMPTABPROPS_RES = IMPTABPROPS_COLUMNS - 1; + private static short GetStateProps(short cell) { + return (short)(cell & 0x1f); + } + private static short GetActionProps(short cell) { + return (short)(cell >> 5); + } + + private static final short groupProp[] = /* dirProp regrouped */ + { + /* L R EN ES ET AN CS B S WS ON LRE LRO AL RLE RLO PDF NSM BN FSI LRI RLI PDI ENL ENR */ + 0, 1, 2, 7, 8, 3, 9, 6, 5, 4, 4, 10, 10, 12, 10, 10, 10, 11, 10, 4, 4, 4, 4, 13, 14 + }; + private static final short _L = 0; + private static final short _R = 1; + private static final short _EN = 2; + private static final short _AN = 3; + private static final short _ON = 4; + private static final short _S = 5; + private static final short _B = 6; /* reduced dirProp */ + + /* *******************************************************************/ + /* */ + /* PROPERTIES STATE TABLE */ + /* */ + /* In table impTabProps, */ + /* - the ON column regroups ON and WS, FSI, RLI, LRI and PDI */ + /* - the BN column regroups BN, LRE, RLE, LRO, RLO, PDF */ + /* - the Res column is the reduced property assigned to a run */ + /* */ + /* Action 1: process current run1, init new run1 */ + /* 2: init new run2 */ + /* 3: process run1, process run2, init new run1 */ + /* 4: process run1, set run1=run2, init new run2 */ + /* */ + /* Notes: */ + /* 1) This table is used in resolveImplicitLevels(). */ + /* 2) This table triggers actions when there is a change in the Bidi*/ + /* property of incoming characters (action 1). */ + /* 3) Most such property sequences are processed immediately (in */ + /* fact, passed to processPropertySeq(). */ + /* 4) However, numbers are assembled as one sequence. This means */ + /* that undefined situations (like CS following digits, until */ + /* it is known if the next char will be a digit) are held until */ + /* following chars define them. */ + /* Example: digits followed by CS, then comes another CS or ON; */ + /* the digits will be processed, then the CS assigned */ + /* as the start of an ON sequence (action 3). */ + /* 5) There are cases where more than one sequence must be */ + /* processed, for instance digits followed by CS followed by L: */ + /* the digits must be processed as one sequence, and the CS */ + /* must be processed as an ON sequence, all this before starting */ + /* assembling chars for the opening L sequence. */ + /* */ + /* */ + private static final short impTabProps[][] = + { +/* L, R, EN, AN, ON, S, B, ES, ET, CS, BN, NSM, AL, ENL, ENR, Res */ +/* 0 Init */ { 1, 2, 4, 5, 7, 15, 17, 7, 9, 7, 0, 7, 3, 18, 21, _ON }, +/* 1 L */ { 1, 32+2, 32+4, 32+5, 32+7, 32+15, 32+17, 32+7, 32+9, 32+7, 1, 1, 32+3, 32+18, 32+21, _L }, +/* 2 R */ { 32+1, 2, 32+4, 32+5, 32+7, 32+15, 32+17, 32+7, 32+9, 32+7, 2, 2, 32+3, 32+18, 32+21, _R }, +/* 3 AL */ { 32+1, 32+2, 32+6, 32+6, 32+8, 32+16, 32+17, 32+8, 32+8, 32+8, 3, 3, 3, 32+18, 32+21, _R }, +/* 4 EN */ { 32+1, 32+2, 4, 32+5, 32+7, 32+15, 32+17, 64+10, 11, 64+10, 4, 4, 32+3, 18, 21, _EN }, +/* 5 AN */ { 32+1, 32+2, 32+4, 5, 32+7, 32+15, 32+17, 32+7, 32+9, 64+12, 5, 5, 32+3, 32+18, 32+21, _AN }, +/* 6 AL:EN/AN */ { 32+1, 32+2, 6, 6, 32+8, 32+16, 32+17, 32+8, 32+8, 64+13, 6, 6, 32+3, 18, 21, _AN }, +/* 7 ON */ { 32+1, 32+2, 32+4, 32+5, 7, 32+15, 32+17, 7, 64+14, 7, 7, 7, 32+3, 32+18, 32+21, _ON }, +/* 8 AL:ON */ { 32+1, 32+2, 32+6, 32+6, 8, 32+16, 32+17, 8, 8, 8, 8, 8, 32+3, 32+18, 32+21, _ON }, +/* 9 ET */ { 32+1, 32+2, 4, 32+5, 7, 32+15, 32+17, 7, 9, 7, 9, 9, 32+3, 18, 21, _ON }, +/*10 EN+ES/CS */ { 96+1, 96+2, 4, 96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 10, 128+7, 96+3, 18, 21, _EN }, +/*11 EN+ET */ { 32+1, 32+2, 4, 32+5, 32+7, 32+15, 32+17, 32+7, 11, 32+7, 11, 11, 32+3, 18, 21, _EN }, +/*12 AN+CS */ { 96+1, 96+2, 96+4, 5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 12, 128+7, 96+3, 96+18, 96+21, _AN }, +/*13 AL:EN/AN+CS */ { 96+1, 96+2, 6, 6, 128+8, 96+16, 96+17, 128+8, 128+8, 128+8, 13, 128+8, 96+3, 18, 21, _AN }, +/*14 ON+ET */ { 32+1, 32+2, 128+4, 32+5, 7, 32+15, 32+17, 7, 14, 7, 14, 14, 32+3,128+18,128+21, _ON }, +/*15 S */ { 32+1, 32+2, 32+4, 32+5, 32+7, 15, 32+17, 32+7, 32+9, 32+7, 15, 32+7, 32+3, 32+18, 32+21, _S }, +/*16 AL:S */ { 32+1, 32+2, 32+6, 32+6, 32+8, 16, 32+17, 32+8, 32+8, 32+8, 16, 32+8, 32+3, 32+18, 32+21, _S }, +/*17 B */ { 32+1, 32+2, 32+4, 32+5, 32+7, 32+15, 17, 32+7, 32+9, 32+7, 17, 32+7, 32+3, 32+18, 32+21, _B }, +/*18 ENL */ { 32+1, 32+2, 18, 32+5, 32+7, 32+15, 32+17, 64+19, 20, 64+19, 18, 18, 32+3, 18, 21, _L }, +/*19 ENL+ES/CS */ { 96+1, 96+2, 18, 96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 19, 128+7, 96+3, 18, 21, _L }, +/*20 ENL+ET */ { 32+1, 32+2, 18, 32+5, 32+7, 32+15, 32+17, 32+7, 20, 32+7, 20, 20, 32+3, 18, 21, _L }, +/*21 ENR */ { 32+1, 32+2, 21, 32+5, 32+7, 32+15, 32+17, 64+22, 23, 64+22, 21, 21, 32+3, 18, 21, _AN }, +/*22 ENR+ES/CS */ { 96+1, 96+2, 21, 96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7, 22, 128+7, 96+3, 18, 21, _AN }, +/*23 ENR+ET */ { 32+1, 32+2, 21, 32+5, 32+7, 32+15, 32+17, 32+7, 23, 32+7, 23, 23, 32+3, 18, 21, _AN } + }; + + /* *******************************************************************/ + /* The levels state machine tables */ + /* *******************************************************************/ + /* */ + /* All table cells are 8 bits: */ + /* bits 0..3: next state */ + /* bits 4..7: action to perform (if > 0) */ + /* */ + /* Cells may be of format "n" where n represents the next state */ + /* (except for the rightmost column). */ + /* Cells may also be of format "_(x,y)" where x represents an action */ + /* to perform and y represents the next state. */ + /* */ + /* This format limits each table to 16 states each and to 15 actions.*/ + /* */ + /* *******************************************************************/ + /* Definitions and type for levels state tables */ + /* *******************************************************************/ + private static final int IMPTABLEVELS_COLUMNS = _B + 2; + private static final int IMPTABLEVELS_RES = IMPTABLEVELS_COLUMNS - 1; + private static short GetState(byte cell) { return (short)(cell & 0x0f); } + private static short GetAction(byte cell) { return (short)(cell >> 4); } + + private static class ImpTabPair { + byte[][][] imptab; + short[][] impact; + + ImpTabPair(byte[][] table1, byte[][] table2, + short[] act1, short[] act2) { + imptab = new byte[][][] {table1, table2}; + impact = new short[][] {act1, act2}; + } + } + + /* *******************************************************************/ + /* */ + /* LEVELS STATE TABLES */ + /* */ + /* In all levels state tables, */ + /* - state 0 is the initial state */ + /* - the Res column is the increment to add to the text level */ + /* for this property sequence. */ + /* */ + /* The impact arrays for each table of a pair map the local action */ + /* numbers of the table to the total list of actions. For instance, */ + /* action 2 in a given table corresponds to the action number which */ + /* appears in entry [2] of the impact array for that table. */ + /* The first entry of all impact arrays must be 0. */ + /* */ + /* Action 1: init conditional sequence */ + /* 2: prepend conditional sequence to current sequence */ + /* 3: set ON sequence to new level - 1 */ + /* 4: init EN/AN/ON sequence */ + /* 5: fix EN/AN/ON sequence followed by R */ + /* 6: set previous level sequence to level 2 */ + /* */ + /* Notes: */ + /* 1) These tables are used in processPropertySeq(). The input */ + /* is property sequences as determined by resolveImplicitLevels. */ + /* 2) Most such property sequences are processed immediately */ + /* (levels are assigned). */ + /* 3) However, some sequences cannot be assigned a final level till */ + /* one or more following sequences are received. For instance, */ + /* ON following an R sequence within an even-level paragraph. */ + /* If the following sequence is R, the ON sequence will be */ + /* assigned basic run level+1, and so will the R sequence. */ + /* 4) S is generally handled like ON, since its level will be fixed */ + /* to paragraph level in adjustWSLevels(). */ + /* */ + + private static final byte impTabL_DEFAULT[][] = /* Even paragraph level */ + /* In this table, conditional sequences receive the lower possible level + until proven otherwise. + */ + { + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 1, 0, 2, 0, 0, 0, 0 }, + /* 1 : R */ { 0, 1, 3, 3, 0x14, 0x14, 0, 1 }, + /* 2 : AN */ { 0, 1, 0, 2, 0x15, 0x15, 0, 2 }, + /* 3 : R+EN/AN */ { 0, 1, 3, 3, 0x14, 0x14, 0, 2 }, + /* 4 : R+ON */ { 0, 0x21, 0x33, 0x33, 4, 4, 0, 0 }, + /* 5 : AN+ON */ { 0, 0x21, 0, 0x32, 5, 5, 0, 0 } + }; + + private static final byte impTabR_DEFAULT[][] = /* Odd paragraph level */ + /* In this table, conditional sequences receive the lower possible level + until proven otherwise. + */ + { + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 1, 0, 2, 2, 0, 0, 0, 0 }, + /* 1 : L */ { 1, 0, 1, 3, 0x14, 0x14, 0, 1 }, + /* 2 : EN/AN */ { 1, 0, 2, 2, 0, 0, 0, 1 }, + /* 3 : L+AN */ { 1, 0, 1, 3, 5, 5, 0, 1 }, + /* 4 : L+ON */ { 0x21, 0, 0x21, 3, 4, 4, 0, 0 }, + /* 5 : L+AN+ON */ { 1, 0, 1, 3, 5, 5, 0, 0 } + }; + + private static final short[] impAct0 = {0,1,2,3,4}; + + private static final ImpTabPair impTab_DEFAULT = new ImpTabPair( + impTabL_DEFAULT, impTabR_DEFAULT, impAct0, impAct0); + + private static final byte impTabL_NUMBERS_SPECIAL[][] = { /* Even paragraph level */ + /* In this table, conditional sequences receive the lower possible + level until proven otherwise. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 2, 0x11, 0x11, 0, 0, 0, 0 }, + /* 1 : L+EN/AN */ { 0, 0x42, 1, 1, 0, 0, 0, 0 }, + /* 2 : R */ { 0, 2, 4, 4, 0x13, 0x13, 0, 1 }, + /* 3 : R+ON */ { 0, 0x22, 0x34, 0x34, 3, 3, 0, 0 }, + /* 4 : R+EN/AN */ { 0, 2, 4, 4, 0x13, 0x13, 0, 2 } + }; + private static final ImpTabPair impTab_NUMBERS_SPECIAL = new ImpTabPair( + impTabL_NUMBERS_SPECIAL, impTabR_DEFAULT, impAct0, impAct0); + + private static final byte impTabL_GROUP_NUMBERS_WITH_R[][] = { + /* In this table, EN/AN+ON sequences receive levels as if associated with R + until proven that there is L or sor/eor on both sides. AN is handled like EN. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 init */ { 0, 3, 0x11, 0x11, 0, 0, 0, 0 }, + /* 1 EN/AN */ { 0x20, 3, 1, 1, 2, 0x20, 0x20, 2 }, + /* 2 EN/AN+ON */ { 0x20, 3, 1, 1, 2, 0x20, 0x20, 1 }, + /* 3 R */ { 0, 3, 5, 5, 0x14, 0, 0, 1 }, + /* 4 R+ON */ { 0x20, 3, 5, 5, 4, 0x20, 0x20, 1 }, + /* 5 R+EN/AN */ { 0, 3, 5, 5, 0x14, 0, 0, 2 } + }; + private static final byte impTabR_GROUP_NUMBERS_WITH_R[][] = { + /* In this table, EN/AN+ON sequences receive levels as if associated with R + until proven that there is L on both sides. AN is handled like EN. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 init */ { 2, 0, 1, 1, 0, 0, 0, 0 }, + /* 1 EN/AN */ { 2, 0, 1, 1, 0, 0, 0, 1 }, + /* 2 L */ { 2, 0, 0x14, 0x14, 0x13, 0, 0, 1 }, + /* 3 L+ON */ { 0x22, 0, 4, 4, 3, 0, 0, 0 }, + /* 4 L+EN/AN */ { 0x22, 0, 4, 4, 3, 0, 0, 1 } + }; + private static final ImpTabPair impTab_GROUP_NUMBERS_WITH_R = new + ImpTabPair(impTabL_GROUP_NUMBERS_WITH_R, + impTabR_GROUP_NUMBERS_WITH_R, impAct0, impAct0); + + private static final byte impTabL_INVERSE_NUMBERS_AS_L[][] = { + /* This table is identical to the Default LTR table except that EN and AN + are handled like L. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 1, 0, 0, 0, 0, 0, 0 }, + /* 1 : R */ { 0, 1, 0, 0, 0x14, 0x14, 0, 1 }, + /* 2 : AN */ { 0, 1, 0, 0, 0x15, 0x15, 0, 2 }, + /* 3 : R+EN/AN */ { 0, 1, 0, 0, 0x14, 0x14, 0, 2 }, + /* 4 : R+ON */ { 0x20, 1, 0x20, 0x20, 4, 4, 0x20, 1 }, + /* 5 : AN+ON */ { 0x20, 1, 0x20, 0x20, 5, 5, 0x20, 1 } + }; + private static final byte impTabR_INVERSE_NUMBERS_AS_L[][] = { + /* This table is identical to the Default RTL table except that EN and AN + are handled like L. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 1, 0, 1, 1, 0, 0, 0, 0 }, + /* 1 : L */ { 1, 0, 1, 1, 0x14, 0x14, 0, 1 }, + /* 2 : EN/AN */ { 1, 0, 1, 1, 0, 0, 0, 1 }, + /* 3 : L+AN */ { 1, 0, 1, 1, 5, 5, 0, 1 }, + /* 4 : L+ON */ { 0x21, 0, 0x21, 0x21, 4, 4, 0, 0 }, + /* 5 : L+AN+ON */ { 1, 0, 1, 1, 5, 5, 0, 0 } + }; + private static final ImpTabPair impTab_INVERSE_NUMBERS_AS_L = new ImpTabPair + (impTabL_INVERSE_NUMBERS_AS_L, impTabR_INVERSE_NUMBERS_AS_L, + impAct0, impAct0); + + private static final byte impTabR_INVERSE_LIKE_DIRECT[][] = { /* Odd paragraph level */ + /* In this table, conditional sequences receive the lower possible level + until proven otherwise. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 1, 0, 2, 2, 0, 0, 0, 0 }, + /* 1 : L */ { 1, 0, 1, 2, 0x13, 0x13, 0, 1 }, + /* 2 : EN/AN */ { 1, 0, 2, 2, 0, 0, 0, 1 }, + /* 3 : L+ON */ { 0x21, 0x30, 6, 4, 3, 3, 0x30, 0 }, + /* 4 : L+ON+AN */ { 0x21, 0x30, 6, 4, 5, 5, 0x30, 3 }, + /* 5 : L+AN+ON */ { 0x21, 0x30, 6, 4, 5, 5, 0x30, 2 }, + /* 6 : L+ON+EN */ { 0x21, 0x30, 6, 4, 3, 3, 0x30, 1 } + }; + private static final short[] impAct1 = {0,1,13,14}; + private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT = new ImpTabPair( + impTabL_DEFAULT, impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1); + + private static final byte impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS[][] = { + /* The case handled in this table is (visually): R EN L + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 0x63, 0, 1, 0, 0, 0, 0 }, + /* 1 : L+AN */ { 0, 0x63, 0, 1, 0x12, 0x30, 0, 4 }, + /* 2 : L+AN+ON */ { 0x20, 0x63, 0x20, 1, 2, 0x30, 0x20, 3 }, + /* 3 : R */ { 0, 0x63, 0x55, 0x56, 0x14, 0x30, 0, 3 }, + /* 4 : R+ON */ { 0x30, 0x43, 0x55, 0x56, 4, 0x30, 0x30, 3 }, + /* 5 : R+EN */ { 0x30, 0x43, 5, 0x56, 0x14, 0x30, 0x30, 4 }, + /* 6 : R+AN */ { 0x30, 0x43, 0x55, 6, 0x14, 0x30, 0x30, 4 } + }; + private static final byte impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS[][] = { + /* The cases handled in this table are (visually): R EN L + R L AN L + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0x13, 0, 1, 1, 0, 0, 0, 0 }, + /* 1 : R+EN/AN */ { 0x23, 0, 1, 1, 2, 0x40, 0, 1 }, + /* 2 : R+EN/AN+ON */ { 0x23, 0, 1, 1, 2, 0x40, 0, 0 }, + /* 3 : L */ { 3, 0, 3, 0x36, 0x14, 0x40, 0, 1 }, + /* 4 : L+ON */ { 0x53, 0x40, 5, 0x36, 4, 0x40, 0x40, 0 }, + /* 5 : L+ON+EN */ { 0x53, 0x40, 5, 0x36, 4, 0x40, 0x40, 1 }, + /* 6 : L+AN */ { 0x53, 0x40, 6, 6, 4, 0x40, 0x40, 3 } + }; + private static final short[] impAct2 = {0,1,2,5,6,7,8}; + private static final short[] impAct3 = {0,1,9,10,11,12}; + private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT_WITH_MARKS = + new ImpTabPair(impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS, + impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3); + + private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL = new ImpTabPair( + impTabL_NUMBERS_SPECIAL, impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1); + + private static final byte impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS[][] = { + /* The case handled in this table is (visually): R EN L + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 0x62, 1, 1, 0, 0, 0, 0 }, + /* 1 : L+EN/AN */ { 0, 0x62, 1, 1, 0, 0x30, 0, 4 }, + /* 2 : R */ { 0, 0x62, 0x54, 0x54, 0x13, 0x30, 0, 3 }, + /* 3 : R+ON */ { 0x30, 0x42, 0x54, 0x54, 3, 0x30, 0x30, 3 }, + /* 4 : R+EN/AN */ { 0x30, 0x42, 4, 4, 0x13, 0x30, 0x30, 4 } + }; + private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS = new + ImpTabPair(impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS, + impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3); + + private static class LevState { + byte[][] impTab; /* level table pointer */ + short[] impAct; /* action map array */ + int startON; /* start of ON sequence */ + int startL2EN; /* start of level 2 sequence */ + int lastStrongRTL; /* index of last found R or AL */ + int runStart; /* start position of the run */ + short state; /* current state */ + byte runLevel; /* run level before implicit solving */ + } + + /*------------------------------------------------------------------------*/ + + static final int FIRSTALLOC = 10; + /* + * param pos: position where to insert + * param flag: one of LRM_BEFORE, LRM_AFTER, RLM_BEFORE, RLM_AFTER + */ + private void addPoint(int pos, int flag) + { + Point point = new Point(); + + int len = insertPoints.points.length; + if (len == 0) { + insertPoints.points = new Point[FIRSTALLOC]; + len = FIRSTALLOC; + } + if (insertPoints.size >= len) { /* no room for new point */ + Point[] savePoints = insertPoints.points; + insertPoints.points = new Point[len * 2]; + System.arraycopy(savePoints, 0, insertPoints.points, 0, len); + } + point.pos = pos; + point.flag = flag; + insertPoints.points[insertPoints.size] = point; + insertPoints.size++; + } + + private void setLevelsOutsideIsolates(int start, int limit, byte level) + { + byte dirProp; + int isolateCount = 0, k; + for (k = start; k < limit; k++) { + dirProp = dirProps[k]; + if (dirProp == PDI) + isolateCount--; + if (isolateCount == 0) { + levels[k] = level; + } + if (dirProp == LRI || dirProp == RLI) + isolateCount++; + } + } + + /* perform rules (Wn), (Nn), and (In) on a run of the text ------------------ */ + + /* + * This implementation of the (Wn) rules applies all rules in one pass. + * In order to do so, it needs a look-ahead of typically 1 character + * (except for W5: sequences of ET) and keeps track of changes + * in a rule Wp that affect a later Wq (p= 0) { + addPoint(levState.startL2EN, LRM_BEFORE); + } + levState.startL2EN = -1; /* not within previous if since could also be -2 */ + /* check if we had any relevant EN/AN after R/AL */ + if ((insertPoints.points.length == 0) || + (insertPoints.size <= insertPoints.confirmed)) { + /* nothing, just clean up */ + levState.lastStrongRTL = -1; + /* check if we have a pending conditional segment */ + level = impTab[oldStateSeq][IMPTABLEVELS_RES]; + if ((level & 1) != 0 && levState.startON > 0) { /* after ON */ + start = levState.startON; /* reset to basic run level */ + } + if (_prop == _S) { /* add LRM before S */ + addPoint(start0, LRM_BEFORE); + insertPoints.confirmed = insertPoints.size; + } + break; + } + /* reset previous RTL cont to level for LTR text */ + for (k = levState.lastStrongRTL + 1; k < start0; k++) { + /* reset odd level, leave runLevel+2 as is */ + levels[k] = (byte)((levels[k] - 2) & ~1); + } + /* mark insert points as confirmed */ + insertPoints.confirmed = insertPoints.size; + levState.lastStrongRTL = -1; + if (_prop == _S) { /* add LRM before S */ + addPoint(start0, LRM_BEFORE); + insertPoints.confirmed = insertPoints.size; + } + break; + + case 6: /* R/AL after possible relevant EN/AN */ + /* just clean up */ + if (insertPoints.points.length > 0) + /* remove all non confirmed insert points */ + insertPoints.size = insertPoints.confirmed; + levState.startON = -1; + levState.startL2EN = -1; + levState.lastStrongRTL = limit - 1; + break; + + case 7: /* EN/AN after R/AL + possible cont */ + /* check for real AN */ + + if ((_prop == _AN) && (dirProps[start0] == AN) && + (reorderingMode != REORDER_INVERSE_FOR_NUMBERS_SPECIAL)) + { + /* real AN */ + if (levState.startL2EN == -1) { /* if no relevant EN already found */ + /* just note the rightmost digit as a strong RTL */ + levState.lastStrongRTL = limit - 1; + break; + } + if (levState.startL2EN >= 0) { /* after EN, no AN */ + addPoint(levState.startL2EN, LRM_BEFORE); + levState.startL2EN = -2; + } + /* note AN */ + addPoint(start0, LRM_BEFORE); + break; + } + /* if first EN/AN after R/AL */ + if (levState.startL2EN == -1) { + levState.startL2EN = start0; + } + break; + + case 8: /* note location of latest R/AL */ + levState.lastStrongRTL = limit - 1; + levState.startON = -1; + break; + + case 9: /* L after R+ON/EN/AN */ + /* include possible adjacent number on the left */ + for (k = start0-1; k >= 0 && ((levels[k] & 1) == 0); k--) { + } + if (k >= 0) { + addPoint(k, RLM_BEFORE); /* add RLM before */ + insertPoints.confirmed = insertPoints.size; /* confirm it */ + } + levState.startON = start0; + break; + + case 10: /* AN after L */ + /* AN numbers between L text on both sides may be trouble. */ + /* tentatively bracket with LRMs; will be confirmed if followed by L */ + addPoint(start0, LRM_BEFORE); /* add LRM before */ + addPoint(start0, LRM_AFTER); /* add LRM after */ + break; + + case 11: /* R after L+ON/EN/AN */ + /* false alert, infirm LRMs around previous AN */ + insertPoints.size=insertPoints.confirmed; + if (_prop == _S) { /* add RLM before S */ + addPoint(start0, RLM_BEFORE); + insertPoints.confirmed = insertPoints.size; + } + break; + + case 12: /* L after L+ON/AN */ + level = (byte)(levState.runLevel + addLevel); + for (k=levState.startON; k < start0; k++) { + if (levels[k] < level) { + levels[k] = level; + } + } + insertPoints.confirmed = insertPoints.size; /* confirm inserts */ + levState.startON = start0; + break; + + case 13: /* L after L+ON+EN/AN/ON */ + level = levState.runLevel; + for (k = start0-1; k >= levState.startON; k--) { + if (levels[k] == level+3) { + while (levels[k] == level+3) { + levels[k--] -= 2; + } + while (levels[k] == level) { + k--; + } + } + if (levels[k] == level+2) { + levels[k] = level; + continue; + } + levels[k] = (byte)(level+1); + } + break; + + case 14: /* R after L+ON+EN/AN/ON */ + level = (byte)(levState.runLevel+1); + for (k = start0-1; k >= levState.startON; k--) { + if (levels[k] > level) { + levels[k] -= 2; + } + } + break; + + default: /* we should never get here */ + throw new IllegalStateException("Internal ICU error in processPropertySeq"); + } + } + if ((addLevel) != 0 || (start < start0)) { + level = (byte)(levState.runLevel + addLevel); + if (start >= levState.runStart) { + for (k = start; k < limit; k++) { + levels[k] = level; + } + } else { + setLevelsOutsideIsolates(start, limit, level); + } + } + } + + private void resolveImplicitLevels(int start, int limit, short sor, short eor) + { + byte dirProp; + LevState levState = new LevState(); + int i, start1, start2; + short oldStateImp, stateImp, actionImp; + short gprop, resProp, cell; + boolean inverseRTL; + short nextStrongProp = R; + int nextStrongPos = -1; + + /* check for RTL inverse Bidi mode */ + /* FOOD FOR THOUGHT: in case of RTL inverse Bidi, it would make sense to + * loop on the text characters from end to start. + * This would need a different properties state table (at least different + * actions) and different levels state tables (maybe very similar to the + * LTR corresponding ones. + */ + inverseRTL=((start0) && + (reorderingMode == REORDER_INVERSE_LIKE_DIRECT || + reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL)); + /* initialize for property and levels state table */ + levState.startL2EN = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */ + levState.lastStrongRTL = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */ + levState.runStart = start; + levState.runLevel = levels[start]; + levState.impTab = impTabPair.imptab[levState.runLevel & 1]; + levState.impAct = impTabPair.impact[levState.runLevel & 1]; + + /* The isolates[] entries contain enough information to + resume the bidi algorithm in the same state as it was + when it was interrupted by an isolate sequence. */ + if (dirProps[start] == PDI) { + levState.startON = isolates[isolateCount].startON; + start1 = isolates[isolateCount].start1; + stateImp = isolates[isolateCount].stateImp; + levState.state = isolates[isolateCount].state; + isolateCount--; + } else { + levState.startON = -1; + start1 = start; + if (dirProps[start] == NSM) + stateImp = (short)(1 + sor); + else + stateImp = 0; + levState.state = 0; + processPropertySeq(levState, sor, start, start); + } + start2 = start; /* to make the Java compiler happy */ + + for (i = start; i <= limit; i++) { + if (i >= limit) { + int k; + for (k = limit - 1; + k > start && + (DirPropFlag(dirProps[k]) & MASK_BN_EXPLICIT) != 0; + k--); + dirProp = dirProps[k]; + if (dirProp == LRI || dirProp == RLI) + break; /* no forced closing for sequence ending with LRI/RLI */ + gprop = eor; + } else { + byte prop, prop1; + prop = dirProps[i]; + if (prop == B) + isolateCount = -1; /* current isolates stack entry == none */ + if (inverseRTL) { + if (prop == AL) { + /* AL before EN does not make it AN */ + prop = R; + } else if (prop == EN) { + if (nextStrongPos <= i) { + /* look for next strong char (L/R/AL) */ + int j; + nextStrongProp = R; /* set default */ + nextStrongPos = limit; + for (j = i+1; j < limit; j++) { + prop1 = dirProps[j]; + if (prop1 == L || prop1 == R || prop1 == AL) { + nextStrongProp = prop1; + nextStrongPos = j; + break; + } + } + } + if (nextStrongProp == AL) { + prop = AN; + } + } + } + gprop = groupProp[prop]; + } + oldStateImp = stateImp; + cell = impTabProps[oldStateImp][gprop]; + stateImp = GetStateProps(cell); /* isolate the new state */ + actionImp = GetActionProps(cell); /* isolate the action */ + if ((i == limit) && (actionImp == 0)) { + /* there is an unprocessed sequence if its property == eor */ + actionImp = 1; /* process the last sequence */ + } + if (actionImp != 0) { + resProp = impTabProps[oldStateImp][IMPTABPROPS_RES]; + switch (actionImp) { + case 1: /* process current seq1, init new seq1 */ + processPropertySeq(levState, resProp, start1, i); + start1 = i; + break; + case 2: /* init new seq2 */ + start2 = i; + break; + case 3: /* process seq1, process seq2, init new seq1 */ + processPropertySeq(levState, resProp, start1, start2); + processPropertySeq(levState, _ON, start2, i); + start1 = i; + break; + case 4: /* process seq1, set seq1=seq2, init new seq2 */ + processPropertySeq(levState, resProp, start1, start2); + start1 = start2; + start2 = i; + break; + default: /* we should never get here */ + throw new IllegalStateException("Internal ICU error in resolveImplicitLevels"); + } + } + } + + /* look for the last char not a BN or LRE/RLE/LRO/RLO/PDF */ + for (i = limit - 1; + i > start && + (DirPropFlag(dirProps[i]) & MASK_BN_EXPLICIT) != 0; + i--); + dirProp = dirProps[i]; + if ((dirProp == LRI || dirProp == RLI) && limit < length) { + isolateCount++; + if (isolates[isolateCount] == null) + isolates[isolateCount] = new Isolate(); + isolates[isolateCount].stateImp = stateImp; + isolates[isolateCount].state = levState.state; + isolates[isolateCount].start1 = start1; + isolates[isolateCount].startON = levState.startON; + } + else + processPropertySeq(levState, eor, limit, limit); + } + + /* perform (L1) and (X9) ---------------------------------------------------- */ + + /* + * Reset the embedding levels for some non-graphic characters (L1). + * This method also sets appropriate levels for BN, and + * explicit embedding types that are supposed to have been removed + * from the paragraph in (X9). + */ + private void adjustWSLevels() { + int i; + + if ((flags & MASK_WS) != 0) { + int flag; + i = trailingWSStart; + while (i > 0) { + /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */ + while (i > 0 && ((flag = DirPropFlag(dirProps[--i])) & MASK_WS) != 0) { + if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) { + levels[i] = 0; + } else { + levels[i] = GetParaLevelAt(i); + } + } + + /* reset BN to the next character's paraLevel until B/S, which restarts above loop */ + /* here, i+1 is guaranteed to be 0) { + flag = DirPropFlag(dirProps[--i]); + if ((flag & MASK_BN_EXPLICIT) != 0) { + levels[i] = levels[i + 1]; + } else if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) { + levels[i] = 0; + break; + } else if ((flag & MASK_B_S) != 0){ + levels[i] = GetParaLevelAt(i); + break; + } + } + } + } + } + + private void setParaSuccess() { + paraBidi = this; /* mark successful setPara */ + } + + private int Bidi_Min(int x, int y) { + return x < y ? x : y; + } + + private int Bidi_Abs(int x) { + return x >= 0 ? x : -x; + } + + void setParaRunsOnly(char[] parmText, byte parmParaLevel) { + int[] visualMap; + String visualText; + int saveLength, saveTrailingWSStart; + byte[] saveLevels; + byte saveDirection; + int i, j, visualStart, logicalStart, + oldRunCount, runLength, addedRuns, insertRemove, + start, limit, step, indexOddBit, logicalPos, + index, index1; + int saveOptions; + + reorderingMode = REORDER_DEFAULT; + int parmLength = parmText.length; + if (parmLength == 0) { + setPara(parmText, parmParaLevel, null); + reorderingMode = REORDER_RUNS_ONLY; + return; + } + /* obtain memory for mapping table and visual text */ + saveOptions = reorderingOptions; + if ((saveOptions & OPTION_INSERT_MARKS) > 0) { + reorderingOptions &= ~OPTION_INSERT_MARKS; + reorderingOptions |= OPTION_REMOVE_CONTROLS; + } + parmParaLevel &= 1; /* accept only 0 or 1 */ + setPara(parmText, parmParaLevel, null); + /* we cannot access directly levels since it is not yet set if + * direction is not MIXED + */ + saveLevels = new byte[this.length]; + System.arraycopy(getLevels(), 0, saveLevels, 0, this.length); + saveTrailingWSStart = trailingWSStart; + + /* FOOD FOR THOUGHT: instead of writing the visual text, we could use + * the visual map and the dirProps array to drive the second call + * to setPara (but must make provision for possible removal of + * Bidi controls. Alternatively, only use the dirProps array via + * customized classifier callback. + */ + visualText = writeReordered(DO_MIRRORING); + visualMap = getVisualMap(); + this.reorderingOptions = saveOptions; + saveLength = this.length; + saveDirection=this.direction; + + this.reorderingMode = REORDER_INVERSE_LIKE_DIRECT; + parmParaLevel ^= 1; + setPara(visualText, parmParaLevel, null); + BidiLine.getRuns(this); + /* check if some runs must be split, count how many splits */ + addedRuns = 0; + oldRunCount = this.runCount; + visualStart = 0; + for (i = 0; i < oldRunCount; i++, visualStart += runLength) { + runLength = runs[i].limit - visualStart; + if (runLength < 2) { + continue; + } + logicalStart = runs[i].start; + for (j = logicalStart+1; j < logicalStart+runLength; j++) { + index = visualMap[j]; + index1 = visualMap[j-1]; + if ((Bidi_Abs(index-index1)!=1) || (saveLevels[index]!=saveLevels[index1])) { + addedRuns++; + } + } + } + if (addedRuns > 0) { + getRunsMemory(oldRunCount + addedRuns); + if (runCount == 1) { + /* because we switch from UBiDi.simpleRuns to UBiDi.runs */ + runsMemory[0] = runs[0]; + } else { + System.arraycopy(runs, 0, runsMemory, 0, runCount); + } + runs = runsMemory; + runCount += addedRuns; + for (i = oldRunCount; i < runCount; i++) { + if (runs[i] == null) { + runs[i] = new BidiRun(0, 0, (byte)0); + } + } + } + /* split runs which are not consecutive in source text */ + int newI; + for (i = oldRunCount-1; i >= 0; i--) { + newI = i + addedRuns; + runLength = i==0 ? runs[0].limit : + runs[i].limit - runs[i-1].limit; + logicalStart = runs[i].start; + indexOddBit = runs[i].level & 1; + if (runLength < 2) { + if (addedRuns > 0) { + runs[newI].copyFrom(runs[i]); + } + logicalPos = visualMap[logicalStart]; + runs[newI].start = logicalPos; + runs[newI].level = (byte)(saveLevels[logicalPos] ^ indexOddBit); + continue; + } + if (indexOddBit > 0) { + start = logicalStart; + limit = logicalStart + runLength - 1; + step = 1; + } else { + start = logicalStart + runLength - 1; + limit = logicalStart; + step = -1; + } + for (j = start; j != limit; j += step) { + index = visualMap[j]; + index1 = visualMap[j+step]; + if ((Bidi_Abs(index-index1)!=1) || (saveLevels[index]!=saveLevels[index1])) { + logicalPos = Bidi_Min(visualMap[start], index); + runs[newI].start = logicalPos; + runs[newI].level = (byte)(saveLevels[logicalPos] ^ indexOddBit); + runs[newI].limit = runs[i].limit; + runs[i].limit -= Bidi_Abs(j - start) + 1; + insertRemove = runs[i].insertRemove & (LRM_AFTER|RLM_AFTER); + runs[newI].insertRemove = insertRemove; + runs[i].insertRemove &= ~insertRemove; + start = j + step; + addedRuns--; + newI--; + } + } + if (addedRuns > 0) { + runs[newI].copyFrom(runs[i]); + } + logicalPos = Bidi_Min(visualMap[start], visualMap[limit]); + runs[newI].start = logicalPos; + runs[newI].level = (byte)(saveLevels[logicalPos] ^ indexOddBit); + } + + cleanup1: + /* restore initial paraLevel */ + this.paraLevel ^= 1; + cleanup2: + /* restore real text */ + this.text = parmText; + this.length = saveLength; + this.originalLength = parmLength; + this.direction=saveDirection; + this.levels = saveLevels; + this.trailingWSStart = saveTrailingWSStart; + if (runCount > 1) { + this.direction = MIXED; + } + cleanup3: + this.reorderingMode = REORDER_RUNS_ONLY; + } + + /** + * Perform the Unicode Bidi algorithm. It is defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, + * also described in The Unicode Standard, Version 4.0 .

+ * + * This method takes a piece of plain text containing one or more paragraphs, + * with or without externally specified embedding levels from styled + * text and computes the left-right-directionality of each character.

+ * + * If the entire text is all of the same directionality, then + * the method may not perform all the steps described by the algorithm, + * i.e., some levels may not be the same as if all steps were performed. + * This is not relevant for unidirectional text.
+ * For example, in pure LTR text with numbers the numbers would get + * a resolved level of 2 higher than the surrounding text according to + * the algorithm. This implementation may set all resolved levels to + * the same value in such a case.

+ * + * The text can be composed of multiple paragraphs. Occurrence of a block + * separator in the text terminates a paragraph, and whatever comes next starts + * a new paragraph. The exception to this rule is when a Carriage Return (CR) + * is followed by a Line Feed (LF). Both CR and LF are block separators, but + * in that case, the pair of characters is considered as terminating the + * preceding paragraph, and a new paragraph will be started by a character + * coming after the LF. + * + * Although the text is passed here as a String, it is + * stored internally as an array of characters. Therefore the + * documentation will refer to indexes of the characters in the text. + * + * @param text contains the text that the Bidi algorithm will be performed + * on. This text can be retrieved with getText() or + * getTextAsString.
+ * + * @param paraLevel specifies the default level for the text; + * it is typically 0 (LTR) or 1 (RTL). + * If the method shall determine the paragraph level from the text, + * then paraLevel can be set to + * either LEVEL_DEFAULT_LTR + * or LEVEL_DEFAULT_RTL; if the text contains multiple + * paragraphs, the paragraph level shall be determined separately for + * each paragraph; if a paragraph does not include any strongly typed + * character, then the desired default is used (0 for LTR or 1 for RTL). + * Any other value between 0 and MAX_EXPLICIT_LEVEL + * is also valid, with odd levels indicating RTL. + * + * @param embeddingLevels (in) may be used to preset the embedding and override levels, + * ignoring characters like LRE and PDF in the text. + * A level overrides the directional property of its corresponding + * (same index) character if the level has the + * LEVEL_OVERRIDE bit set.

+ * Except for that bit, it must be + * paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL, + * with one exception: a level of zero may be specified for a + * paragraph separator even if paraLevel>0 when multiple + * paragraphs are submitted in the same call to setPara().

+ * Caution: A reference to this array, not a copy + * of the levels, will be stored in the Bidi object; + * the embeddingLevels + * should not be modified to avoid unexpected results on subsequent + * Bidi operations. However, the setPara() and + * setLine() methods may modify some or all of the + * levels.

+ * Note: the embeddingLevels array must + * have one entry for each character in text. + * + * @throws IllegalArgumentException if the values in embeddingLevels are + * not within the allowed range + * + * @see #LEVEL_DEFAULT_LTR + * @see #LEVEL_DEFAULT_RTL + * @see #LEVEL_OVERRIDE + * @see #MAX_EXPLICIT_LEVEL + * @stable ICU 3.8 + */ + void setPara(String text, byte paraLevel, byte[] embeddingLevels) + { + if (text == null) { + setPara(new char[0], paraLevel, embeddingLevels); + } else { + setPara(text.toCharArray(), paraLevel, embeddingLevels); + } + } + + /** + * Perform the Unicode Bidi algorithm. It is defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, + * also described in The Unicode Standard, Version 4.0 .

+ * + * This method takes a piece of plain text containing one or more paragraphs, + * with or without externally specified embedding levels from styled + * text and computes the left-right-directionality of each character.

+ * + * If the entire text is all of the same directionality, then + * the method may not perform all the steps described by the algorithm, + * i.e., some levels may not be the same as if all steps were performed. + * This is not relevant for unidirectional text.
+ * For example, in pure LTR text with numbers the numbers would get + * a resolved level of 2 higher than the surrounding text according to + * the algorithm. This implementation may set all resolved levels to + * the same value in such a case. + * + * The text can be composed of multiple paragraphs. Occurrence of a block + * separator in the text terminates a paragraph, and whatever comes next starts + * a new paragraph. The exception to this rule is when a Carriage Return (CR) + * is followed by a Line Feed (LF). Both CR and LF are block separators, but + * in that case, the pair of characters is considered as terminating the + * preceding paragraph, and a new paragraph will be started by a character + * coming after the LF. + * + * The text is stored internally as an array of characters. Therefore the + * documentation will refer to indexes of the characters in the text. + * + * @param chars contains the text that the Bidi algorithm will be performed + * on. This text can be retrieved with getText() or + * getTextAsString.
+ * + * @param paraLevel specifies the default level for the text; + * it is typically 0 (LTR) or 1 (RTL). + * If the method shall determine the paragraph level from the text, + * then paraLevel can be set to + * either LEVEL_DEFAULT_LTR + * or LEVEL_DEFAULT_RTL; if the text contains multiple + * paragraphs, the paragraph level shall be determined separately for + * each paragraph; if a paragraph does not include any strongly typed + * character, then the desired default is used (0 for LTR or 1 for RTL). + * Any other value between 0 and MAX_EXPLICIT_LEVEL + * is also valid, with odd levels indicating RTL. + * + * @param embeddingLevels (in) may be used to preset the embedding and + * override levels, ignoring characters like LRE and PDF in the text. + * A level overrides the directional property of its corresponding + * (same index) character if the level has the + * LEVEL_OVERRIDE bit set.

+ * Except for that bit, it must be + * paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL, + * with one exception: a level of zero may be specified for a + * paragraph separator even if paraLevel>0 when multiple + * paragraphs are submitted in the same call to setPara().

+ * Caution: A reference to this array, not a copy + * of the levels, will be stored in the Bidi object; + * the embeddingLevels + * should not be modified to avoid unexpected results on subsequent + * Bidi operations. However, the setPara() and + * setLine() methods may modify some or all of the + * levels.

+ * Note: the embeddingLevels array must + * have one entry for each character in text. + * + * @throws IllegalArgumentException if the values in embeddingLevels are + * not within the allowed range + * + * @see #LEVEL_DEFAULT_LTR + * @see #LEVEL_DEFAULT_RTL + * @see #LEVEL_OVERRIDE + * @see #MAX_EXPLICIT_LEVEL + * @stable ICU 3.8 + */ + void setPara(char[] chars, byte paraLevel, byte[] embeddingLevels) + { + /* check the argument values */ + if (paraLevel < LEVEL_DEFAULT_LTR) { + verifyRange(paraLevel, 0, MAX_EXPLICIT_LEVEL + 1); + } + if (chars == null) { + chars = new char[0]; + } + + /* special treatment for RUNS_ONLY mode */ + if (reorderingMode == REORDER_RUNS_ONLY) { + setParaRunsOnly(chars, paraLevel); + return; + } + + /* initialize the Bidi object */ + this.paraBidi = null; /* mark unfinished setPara */ + this.text = chars; + this.length = this.originalLength = this.resultLength = text.length; + this.paraLevel = paraLevel; + this.direction = (byte)(paraLevel & 1); + this.paraCount = 1; + + /* Allocate zero-length arrays instead of setting to null here; then + * checks for null in various places can be eliminated. + */ + dirProps = new byte[0]; + levels = new byte[0]; + runs = new BidiRun[0]; + isGoodLogicalToVisualRunsMap = false; + insertPoints.size = 0; /* clean up from last call */ + insertPoints.confirmed = 0; /* clean up from last call */ + + /* + * Save the original paraLevel if contextual; otherwise, set to 0. + */ + defaultParaLevel = IsDefaultLevel(paraLevel) ? paraLevel : 0; + + if (length == 0) { + /* + * For an empty paragraph, create a Bidi object with the paraLevel and + * the flags and the direction set but without allocating zero-length arrays. + * There is nothing more to do. + */ + if (IsDefaultLevel(paraLevel)) { + this.paraLevel &= 1; + defaultParaLevel = 0; + } + flags = DirPropFlagLR(paraLevel); + runCount = 0; + paraCount = 0; + setParaSuccess(); + return; + } + + runCount = -1; + + /* + * Get the directional properties, + * the flags bit-set, and + * determine the paragraph level if necessary. + */ + getDirPropsMemory(length); + dirProps = dirPropsMemory; + getDirProps(); + /* the processed length may have changed if OPTION_STREAMING is set */ + trailingWSStart = length; /* the levels[] will reflect the WS run */ + + /* are explicit levels specified? */ + if (embeddingLevels == null) { + /* no: determine explicit levels according to the (Xn) rules */ + getLevelsMemory(length); + levels = levelsMemory; + direction = resolveExplicitLevels(); + } else { + /* set BN for all explicit codes, check that all levels are 0 or paraLevel..MAX_EXPLICIT_LEVEL */ + levels = embeddingLevels; + direction = checkExplicitLevels(); + } + + /* allocate isolate memory */ + if (isolateCount > 0) { + if (isolates == null || isolates.length < isolateCount) + isolates = new Isolate[isolateCount + 3]; /* keep some reserve */ + } + isolateCount = -1; /* current isolates stack entry == none */ + + /* + * The steps after (X9) in the Bidi algorithm are performed only if + * the paragraph text has mixed directionality! + */ + switch (direction) { + case LTR: + /* all levels are implicitly at paraLevel (important for getLevels()) */ + trailingWSStart = 0; + break; + case RTL: + /* all levels are implicitly at paraLevel (important for getLevels()) */ + trailingWSStart = 0; + break; + default: + /* + * Choose the right implicit state table + */ + switch(reorderingMode) { + case REORDER_DEFAULT: + this.impTabPair = impTab_DEFAULT; + break; + case REORDER_NUMBERS_SPECIAL: + this.impTabPair = impTab_NUMBERS_SPECIAL; + break; + case REORDER_GROUP_NUMBERS_WITH_R: + this.impTabPair = impTab_GROUP_NUMBERS_WITH_R; + break; + case REORDER_RUNS_ONLY: + /* we should never get here */ + throw new InternalError("Internal ICU error in setPara"); + /* break; */ + case REORDER_INVERSE_NUMBERS_AS_L: + this.impTabPair = impTab_INVERSE_NUMBERS_AS_L; + break; + case REORDER_INVERSE_LIKE_DIRECT: + if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) { + this.impTabPair = impTab_INVERSE_LIKE_DIRECT_WITH_MARKS; + } else { + this.impTabPair = impTab_INVERSE_LIKE_DIRECT; + } + break; + case REORDER_INVERSE_FOR_NUMBERS_SPECIAL: + if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) { + this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS; + } else { + this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL; + } + break; + } + /* + * If there are no external levels specified and there + * are no significant explicit level codes in the text, + * then we can treat the entire paragraph as one run. + * Otherwise, we need to perform the following rules on runs of + * the text with the same embedding levels. (X10) + * "Significant" explicit level codes are ones that actually + * affect non-BN characters. + * Examples for "insignificant" ones are empty embeddings + * LRE-PDF, LRE-RLE-PDF-PDF, etc. + */ + if (embeddingLevels == null && paraCount <= 1 && + (flags & DirPropFlagMultiRuns) == 0) { + resolveImplicitLevels(0, length, + GetLRFromLevel(GetParaLevelAt(0)), + GetLRFromLevel(GetParaLevelAt(length - 1))); + } else { + /* sor, eor: start and end types of same-level-run */ + int start, limit = 0; + byte level, nextLevel; + short sor, eor; + + /* determine the first sor and set eor to it because of the loop body (sor=eor there) */ + level = GetParaLevelAt(0); + nextLevel = levels[0]; + if (level < nextLevel) { + eor = GetLRFromLevel(nextLevel); + } else { + eor = GetLRFromLevel(level); + } + + do { + /* determine start and limit of the run (end points just behind the run) */ + + /* the values for this run's start are the same as for the previous run's end */ + start = limit; + level = nextLevel; + if ((start > 0) && (dirProps[start - 1] == B)) { + /* except if this is a new paragraph, then set sor = para level */ + sor = GetLRFromLevel(GetParaLevelAt(start)); + } else { + sor = eor; + } + + /* search for the limit of this run */ + while ((++limit < length) && + ((levels[limit] == level) || + ((DirPropFlag(dirProps[limit]) & MASK_BN_EXPLICIT) != 0))) {} + + /* get the correct level of the next run */ + if (limit < length) { + nextLevel = levels[limit]; + } else { + nextLevel = GetParaLevelAt(length - 1); + } + + /* determine eor from max(level, nextLevel); sor is last run's eor */ + if (NoOverride(level) < NoOverride(nextLevel)) { + eor = GetLRFromLevel(nextLevel); + } else { + eor = GetLRFromLevel(level); + } + + /* if the run consists of overridden directional types, then there + are no implicit types to be resolved */ + if ((level & LEVEL_OVERRIDE) == 0) { + resolveImplicitLevels(start, limit, sor, eor); + } else { + /* remove the LEVEL_OVERRIDE flags */ + do { + levels[start++] &= ~LEVEL_OVERRIDE; + } while (start < limit); + } + } while (limit < length); + } + + /* reset the embedding levels for some non-graphic characters (L1), (X9) */ + adjustWSLevels(); + + break; + } + + /* add RLM for inverse Bidi with contextual orientation resolving + * to RTL which would not round-trip otherwise + */ + if ((defaultParaLevel > 0) && + ((reorderingOptions & OPTION_INSERT_MARKS) != 0) && + ((reorderingMode == REORDER_INVERSE_LIKE_DIRECT) || + (reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL))) { + int start, last; + byte level; + byte dirProp; + for (int i = 0; i < paraCount; i++) { + last = paras_limit[i] - 1; + level = paras_level[i]; + if (level == 0) + continue; /* LTR paragraph */ + start = i == 0 ? 0 : paras_limit[i - 1]; + for (int j = last; j >= start; j--) { + dirProp = dirProps[j]; + if (dirProp == L) { + if (j < last) { + while (dirProps[last] == B) { + last--; + } + } + addPoint(last, RLM_BEFORE); + break; + } + if ((DirPropFlag(dirProp) & MASK_R_AL) != 0) { + break; + } + } + } + } + + if ((reorderingOptions & OPTION_REMOVE_CONTROLS) != 0) { + resultLength -= controlCount; + } else { + resultLength += insertPoints.size; + } + setParaSuccess(); + } + + /** + * Perform the Unicode Bidi algorithm on a given paragraph, as defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, + * also described in The Unicode Standard, Version 4.0 .

+ * + * This method takes a paragraph of text and computes the + * left-right-directionality of each character. The text should not + * contain any Unicode block separators.

+ * + * The RUN_DIRECTION attribute in the text, if present, determines the base + * direction (left-to-right or right-to-left). If not present, the base + * direction is computed using the Unicode Bidirectional Algorithm, + * defaulting to left-to-right if there are no strong directional characters + * in the text. This attribute, if present, must be applied to all the text + * in the paragraph.

+ * + * The BIDI_EMBEDDING attribute in the text, if present, represents + * embedding level information. Negative values from -1 to -62 indicate + * overrides at the absolute value of the level. Positive values from 1 to + * 62 indicate embeddings. Where values are zero or not defined, the base + * embedding level as determined by the base direction is assumed.

+ * + * The NUMERIC_SHAPING attribute in the text, if present, converts European + * digits to other decimal digits before running the bidi algorithm. This + * attribute, if present, must be applied to all the text in the paragraph. + * + * If the entire text is all of the same directionality, then + * the method may not perform all the steps described by the algorithm, + * i.e., some levels may not be the same as if all steps were performed. + * This is not relevant for unidirectional text.
+ * For example, in pure LTR text with numbers the numbers would get + * a resolved level of 2 higher than the surrounding text according to + * the algorithm. This implementation may set all resolved levels to + * the same value in such a case.

+ * + * @param paragraph a paragraph of text with optional character and + * paragraph attribute information + * @stable ICU 3.8 + */ + public void setPara(AttributedCharacterIterator paragraph) + { + byte paraLvl; + char ch = paragraph.first(); + Boolean runDirection = + (Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION); + Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING); + + if (runDirection == null) { + paraLvl = LEVEL_DEFAULT_LTR; + } else { + paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ? + LTR : RTL; + } + + byte[] lvls = null; + int len = paragraph.getEndIndex() - paragraph.getBeginIndex(); + byte[] embeddingLevels = new byte[len]; + char[] txt = new char[len]; + int i = 0; + while (ch != AttributedCharacterIterator.DONE) { + txt[i] = ch; + Integer embedding = + (Integer) paragraph.getAttribute(TextAttributeConstants.BIDI_EMBEDDING); + if (embedding != null) { + byte level = embedding.byteValue(); + if (level == 0) { + /* no-op */ + } else if (level < 0) { + lvls = embeddingLevels; + embeddingLevels[i] = (byte)((0 - level) | LEVEL_OVERRIDE); + } else { + lvls = embeddingLevels; + embeddingLevels[i] = level; + } + } + ch = paragraph.next(); + ++i; + } + + if (shaper != null) { + NumericShapings.shape(shaper, txt, 0, len); + } + setPara(txt, paraLvl, lvls); + } + + /** + * Specify whether block separators must be allocated level zero, + * so that successive paragraphs will progress from left to right. + * This method must be called before setPara(). + * Paragraph separators (B) may appear in the text. Setting them to level zero + * means that all paragraph separators (including one possibly appearing + * in the last text position) are kept in the reordered text after the text + * that they follow in the source text. + * When this feature is not enabled, a paragraph separator at the last + * position of the text before reordering will go to the first position + * of the reordered text when the paragraph level is odd. + * + * @param ordarParaLTR specifies whether paragraph separators (B) must + * receive level 0, so that successive paragraphs progress from left to right. + * + * @see #setPara + * @stable ICU 3.8 + */ + public void orderParagraphsLTR(boolean ordarParaLTR) { + orderParagraphsLTR = ordarParaLTR; + } + + /** + * Get the directionality of the text. + * + * @return a value of LTR, RTL or MIXED + * that indicates if the entire text + * represented by this object is unidirectional, + * and which direction, or if it is mixed-directional. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * + * @see #LTR + * @see #RTL + * @see #MIXED + * @stable ICU 3.8 + */ + public byte getDirection() + { + verifyValidParaOrLine(); + return direction; + } + + /** + * Get the length of the text. + * + * @return The length of the text that the Bidi object was + * created for. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * @stable ICU 3.8 + */ + public int getLength() + { + verifyValidParaOrLine(); + return originalLength; + } + + /* paragraphs API methods ------------------------------------------------- */ + + /** + * Get the paragraph level of the text. + * + * @return The paragraph level. If there are multiple paragraphs, their + * level may vary if the required paraLevel is LEVEL_DEFAULT_LTR or + * LEVEL_DEFAULT_RTL. In that case, the level of the first paragraph + * is returned. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * + * @see #LEVEL_DEFAULT_LTR + * @see #LEVEL_DEFAULT_RTL + * @see #getParagraph + * @see #getParagraphByIndex + * @stable ICU 3.8 + */ + public byte getParaLevel() + { + verifyValidParaOrLine(); + return paraLevel; + } + + /** + * Retrieves the Bidi class for a given code point. + *

If a BidiClassifier is defined and returns a value + * other than CLASS_DEFAULT, that value is used; otherwise + * the default class determination mechanism is invoked.

+ * + * @param c The code point to get a Bidi class for. + * + * @return The Bidi class for the character c that is in effect + * for this Bidi instance. + * + * @stable ICU 3.8 + */ + public int getCustomizedClass(int c) { + int dir; + + dir = bdp.getClass(c); + if (dir >= CHAR_DIRECTION_COUNT) + dir = ON; + return dir; + } + + /** + * setLine() returns a Bidi object to + * contain the reordering information, especially the resolved levels, + * for all the characters in a line of text. This line of text is + * specified by referring to a Bidi object representing + * this information for a piece of text containing one or more paragraphs, + * and by specifying a range of indexes in this text.

+ * In the new line object, the indexes will range from 0 to limit-start-1.

+ * + * This is used after calling setPara() + * for a piece of text, and after line-breaking on that text. + * It is not necessary if each paragraph is treated as a single line.

+ * + * After line-breaking, rules (L1) and (L2) for the treatment of + * trailing WS and for reordering are performed on + * a Bidi object that represents a line.

+ * + * Important: the line Bidi object may + * reference data within the global text Bidi object. + * You should not alter the content of the global text object until + * you are finished using the line object. + * + * @param start is the line's first index into the text. + * + * @param limit is just behind the line's last index into the text + * (its last index +1). + * + * @return a Bidi object that will now represent a line of the text. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @throws IllegalArgumentException if start and limit are not in the range + * 0<=start<limit<=getProcessedLength(), + * or if the specified line crosses a paragraph boundary + * + * @see #setPara + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public Bidi setLine(Bidi bidi, BidiBase bidiBase, Bidi newBidi, BidiBase newBidiBase, int start, int limit) + { + verifyValidPara(); + verifyRange(start, 0, limit); + verifyRange(limit, 0, length+1); + + return BidiLine.setLine(this, newBidi, newBidiBase, start, limit); + } + + /** + * Get the level for one character. + * + * @param charIndex the index of a character. + * + * @return The level for the character at charIndex. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * @throws IllegalArgumentException if charIndex is not in the range + * 0<=charIndex<getProcessedLength() + * + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public byte getLevelAt(int charIndex) + { + // for backward compatibility + if (charIndex < 0 || charIndex >= length) { + return (byte)getBaseLevel(); + } + + verifyValidParaOrLine(); + verifyRange(charIndex, 0, length); + return BidiLine.getLevelAt(this, charIndex); + } + + /** + * Get an array of levels for each character.

+ * + * Note that this method may allocate memory under some + * circumstances, unlike getLevelAt(). + * + * @return The levels array for the text, + * or null if an error occurs. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * @stable ICU 3.8 + */ + byte[] getLevels() + { + verifyValidParaOrLine(); + if (length <= 0) { + return new byte[0]; + } + return BidiLine.getLevels(this); + } + + /** + * Get the number of runs. + * This method may invoke the actual reordering on the + * Bidi object, after setPara() + * may have resolved only the levels of the text. Therefore, + * countRuns() may have to allocate memory, + * and may throw an exception if it fails to do so. + * + * @return The number of runs. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * @stable ICU 3.8 + */ + public int countRuns() + { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + return runCount; + } + + /** + * + * Get a BidiRun object according to its index. BidiRun methods + * may be used to retrieve the run's logical start, length and level, + * which can be even for an LTR run or odd for an RTL run. + * In an RTL run, the character at the logical start is + * visually on the right of the displayed run. + * The length is the number of characters in the run.

+ * countRuns() is normally called + * before the runs are retrieved. + * + *

+ * Example: + *

+     *  Bidi bidi = new Bidi();
+     *  String text = "abc 123 DEFG xyz";
+     *  bidi.setPara(text, Bidi.RTL, null);
+     *  int i, count=bidi.countRuns(), logicalStart, visualIndex=0, length;
+     *  BidiRun run;
+     *  for (i = 0; i < count; ++i) {
+     *      run = bidi.getVisualRun(i);
+     *      logicalStart = run.getStart();
+     *      length = run.getLength();
+     *      if (Bidi.LTR == run.getEmbeddingLevel()) {
+     *          do { // LTR
+     *              show_char(text.charAt(logicalStart++), visualIndex++);
+     *          } while (--length > 0);
+     *      } else {
+     *          logicalStart += length;  // logicalLimit
+     *          do { // RTL
+     *              show_char(text.charAt(--logicalStart), visualIndex++);
+     *          } while (--length > 0);
+     *      }
+     *  }
+     * 
+ *

+ * Note that in right-to-left runs, code like this places + * second surrogates before first ones (which is generally a bad idea) + * and combining characters before base characters. + *

+ * Use of {@link #writeReordered}, optionally with the + * {@link #KEEP_BASE_COMBINING} option, can be considered in + * order to avoid these issues. + * + * @param runIndex is the number of the run in visual order, in the + * range [0..countRuns()-1]. + * + * @return a BidiRun object containing the details of the run. The + * directionality of the run is + * LTR==0 or RTL==1, + * never MIXED. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * @throws IllegalArgumentException if runIndex is not in + * the range 0<=runIndex<countRuns() + * + * @see #countRuns() + * @see com.ibm.icu.text.BidiRun + * @see com.ibm.icu.text.BidiRun#getStart() + * @see com.ibm.icu.text.BidiRun#getLength() + * @see com.ibm.icu.text.BidiRun#getEmbeddingLevel() + * @stable ICU 3.8 + */ + BidiRun getVisualRun(int runIndex) + { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + verifyRange(runIndex, 0, runCount); + return BidiLine.getVisualRun(this, runIndex); + } + + /** + * Get a visual-to-logical index map (array) for the characters in the + * Bidi (paragraph or line) object. + *

+ * Some values in the map may be MAP_NOWHERE if the + * corresponding text characters are Bidi marks inserted in the visual + * output by the option OPTION_INSERT_MARKS. + *

+ * When the visual output is altered by using options of + * writeReordered() such as INSERT_LRM_FOR_NUMERIC, + * KEEP_BASE_COMBINING, OUTPUT_REVERSE, + * REMOVE_BIDI_CONTROLS, the logical positions returned may not + * be correct. It is advised to use, when possible, reordering options + * such as {@link #OPTION_INSERT_MARKS} and {@link #OPTION_REMOVE_CONTROLS}. + * + * @return an array of getResultLength() + * indexes which will reflect the reordering of the characters.

+ * The index map will result in + * indexMap[visualIndex]==logicalIndex, where + * indexMap represents the returned array. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * + * @see #getLogicalMap + * @see #getLogicalIndex + * @see #getResultLength + * @see #MAP_NOWHERE + * @see #OPTION_INSERT_MARKS + * @see #writeReordered + * @stable ICU 3.8 + */ + private int[] getVisualMap() + { + /* countRuns() checks successful call to setPara/setLine */ + countRuns(); + if (resultLength <= 0) { + return new int[0]; + } + return BidiLine.getVisualMap(this); + } + + /** + * This is a convenience method that does not use a Bidi object. + * It is intended to be used for when an application has determined the levels + * of objects (character sequences) and just needs to have them reordered (L2). + * This is equivalent to using getVisualMap() on a + * Bidi object. + * + * @param levels is an array of levels that have been determined by + * the application. + * + * @return an array of levels.length + * indexes which will reflect the reordering of the characters.

+ * The index map will result in + * indexMap[visualIndex]==logicalIndex, where + * indexMap represents the returned array. + * + * @stable ICU 3.8 + */ + private static int[] reorderVisual(byte[] levels) + { + return BidiLine.reorderVisual(levels); + } + + /** + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, the base + * direction is right-to-left. + * @stable ICU 3.8 + */ + public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = LEVEL_DEFAULT_RTL; + + /** + * Create Bidi from the given text, embedding, and direction information. + * The embeddings array may be null. If present, the values represent + * embedding level information. Negative values from -1 to -61 indicate + * overrides at the absolute value of the level. Positive values from 1 to + * 61 indicate embeddings. Where values are zero, the base embedding level + * as determined by the base direction is assumed.

+ * + * Note: this constructor calls setPara() internally. + * + * @param text an array containing the paragraph of text to process. + * @param textStart the index into the text array of the start of the + * paragraph. + * @param embeddings an array containing embedding values for each character + * in the paragraph. This can be null, in which case it is assumed + * that there is no external embedding information. + * @param embStart the index into the embedding array of the start of the + * paragraph. + * @param paragraphLength the length of the paragraph in the text and + * embeddings arrays. + * @param flags a collection of flags that control the algorithm. The + * algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, + * DIRECTION_RIGHT_TO_LEFT, DIRECTION_DEFAULT_LEFT_TO_RIGHT, and + * DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are reserved. + * + * @throws IllegalArgumentException if the values in embeddings are + * not within the allowed range + * + * @see #DIRECTION_LEFT_TO_RIGHT + * @see #DIRECTION_RIGHT_TO_LEFT + * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT + * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT + * @stable ICU 3.8 + */ + public BidiBase(char[] text, + int textStart, + byte[] embeddings, + int embStart, + int paragraphLength, + int flags) + { + this(0, 0); + byte paraLvl; + switch (flags) { + case Bidi.DIRECTION_LEFT_TO_RIGHT: + default: + paraLvl = LTR; + break; + case Bidi.DIRECTION_RIGHT_TO_LEFT: + paraLvl = RTL; + break; + case Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT: + paraLvl = LEVEL_DEFAULT_LTR; + break; + case Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT: + paraLvl = LEVEL_DEFAULT_RTL; + break; + } + byte[] paraEmbeddings; + if (embeddings == null) { + paraEmbeddings = null; + } else { + paraEmbeddings = new byte[paragraphLength]; + byte lev; + for (int i = 0; i < paragraphLength; i++) { + lev = embeddings[i + embStart]; + if (lev < 0) { + lev = (byte)((- lev) | LEVEL_OVERRIDE); + } else if (lev == 0) { + lev = paraLvl; + if (paraLvl > MAX_EXPLICIT_LEVEL) { + lev &= 1; + } + } + paraEmbeddings[i] = lev; + } + } + + char[] paraText = new char[paragraphLength]; + System.arraycopy(text, textStart, paraText, 0, paragraphLength); + setPara(paraText, paraLvl, paraEmbeddings); + } + + /** + * Return true if the line is not left-to-right or right-to-left. This means + * it either has mixed runs of left-to-right and right-to-left text, or the + * base direction differs from the direction of the only run of text. + * + * @return true if the line is not left-to-right or right-to-left. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @stable ICU 3.8 + */ + public boolean isMixed() + { + return (!isLeftToRight() && !isRightToLeft()); + } + + /** + * Return true if the line is all left-to-right text and the base direction + * is left-to-right. + * + * @return true if the line is all left-to-right text and the base direction + * is left-to-right. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @stable ICU 3.8 + */ + public boolean isLeftToRight() + { + return (getDirection() == LTR && (paraLevel & 1) == 0); + } + + /** + * Return true if the line is all right-to-left text, and the base direction + * is right-to-left + * + * @return true if the line is all right-to-left text, and the base + * direction is right-to-left + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @stable ICU 3.8 + */ + public boolean isRightToLeft() + { + return (getDirection() == RTL && (paraLevel & 1) == 1); + } + + /** + * Return true if the base direction is left-to-right + * + * @return true if the base direction is left-to-right + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * + * @stable ICU 3.8 + */ + public boolean baseIsLeftToRight() + { + return (getParaLevel() == LTR); + } + + /** + * Return the base level (0 if left-to-right, 1 if right-to-left). + * + * @return the base level + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * + * @stable ICU 3.8 + */ + public int getBaseLevel() + { + return getParaLevel(); + } + + /** + * Compute the logical to visual run mapping + */ + void getLogicalToVisualRunsMap() + { + if (isGoodLogicalToVisualRunsMap) { + return; + } + int count = countRuns(); + if ((logicalToVisualRunsMap == null) || + (logicalToVisualRunsMap.length < count)) { + logicalToVisualRunsMap = new int[count]; + } + int i; + long[] keys = new long[count]; + for (i = 0; i < count; i++) { + keys[i] = ((long)(runs[i].start)<<32) + i; + } + Arrays.sort(keys); + for (i = 0; i < count; i++) { + logicalToVisualRunsMap[i] = (int)(keys[i] & 0x00000000FFFFFFFF); + } + isGoodLogicalToVisualRunsMap = true; + } + + /** + * Return the level of the nth logical run in this line. + * + * @param run the index of the run, between 0 and countRuns()-1 + * + * @return the level of the run + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * @throws IllegalArgumentException if run is not in + * the range 0<=run<countRuns() + * @stable ICU 3.8 + */ + public int getRunLevel(int run) + { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + + // for backward compatibility + if (run < 0 || run >= runCount) { + return getParaLevel(); + } + + getLogicalToVisualRunsMap(); + return runs[logicalToVisualRunsMap[run]].level; + } + + /** + * Return the index of the character at the start of the nth logical run in + * this line, as an offset from the start of the line. + * + * @param run the index of the run, between 0 and countRuns() + * + * @return the start of the run + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * @throws IllegalArgumentException if run is not in + * the range 0<=run<countRuns() + * @stable ICU 3.8 + */ + public int getRunStart(int run) + { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + + // for backward compatibility + if (runCount == 1) { + return 0; + } else if (run == runCount) { + return length; + } + + getLogicalToVisualRunsMap(); + return runs[logicalToVisualRunsMap[run]].start; + } + + /** + * Return the index of the character past the end of the nth logical run in + * this line, as an offset from the start of the line. For example, this + * will return the length of the line for the last run on the line. + * + * @param run the index of the run, between 0 and countRuns() + * + * @return the limit of the run + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * @throws IllegalArgumentException if run is not in + * the range 0<=run<countRuns() + * @stable ICU 3.8 + */ + public int getRunLimit(int run) + { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + + // for backward compatibility + if (runCount == 1) { + return length; + } + + getLogicalToVisualRunsMap(); + int idx = logicalToVisualRunsMap[run]; + int len = idx == 0 ? runs[idx].limit : + runs[idx].limit - runs[idx-1].limit; + return runs[idx].start + len; + } + + /** + * Return true if the specified text requires bidi analysis. If this returns + * false, the text will display left-to-right. Clients can then avoid + * constructing a Bidi object. Text in the Arabic Presentation Forms area of + * Unicode is presumed to already be shaped and ordered for display, and so + * will not cause this method to return true. + * + * @param text the text containing the characters to test + * @param start the start of the range of characters to test + * @param limit the limit of the range of characters to test + * + * @return true if the range of characters requires bidi analysis + * + * @stable ICU 3.8 + */ + public static boolean requiresBidi(char[] text, + int start, + int limit) + { + final int RTLMask = (1 << R | + 1 << AL | + 1 << RLE | + 1 << RLO | + 1 << AN); + + if (0 > start || start > limit || limit > text.length) { + throw new IllegalArgumentException("Value start " + start + + " is out of range 0 to " + limit + ", or limit " + limit + + " is beyond the text length " + text.length); + } + + for (int i = start; i < limit; ++i) { + if (Character.isHighSurrogate(text[i]) && i < (limit-1) && + Character.isLowSurrogate(text[i+1])) { + if (((1 << UCharacter.getDirection(Character.codePointAt(text, i))) & RTLMask) != 0) { + return true; + } + } else if (((1 << UCharacter.getDirection(text[i])) & RTLMask) != 0) { + return true; + } + } + + return false; + } + + /** + * Reorder the objects in the array into visual order based on their levels. + * This is a utility method to use when you have a collection of objects + * representing runs of text in logical order, each run containing text at a + * single level. The elements at index from + * objectStart up to objectStart + count in the + * objects array will be reordered into visual order assuming + * each run of text has the level indicated by the corresponding element in + * the levels array (at index - objectStart + levelStart). + * + * @param levels an array representing the bidi level of each object + * @param levelStart the start position in the levels array + * @param objects the array of objects to be reordered into visual order + * @param objectStart the start position in the objects array + * @param count the number of objects to reorder + * @stable ICU 3.8 + */ + public static void reorderVisually(byte[] levels, + int levelStart, + Object[] objects, + int objectStart, + int count) + { + // for backward compatibility + if (0 > levelStart || levels.length <= levelStart) { + throw new IllegalArgumentException("Value levelStart " + + levelStart + " is out of range 0 to " + + (levels.length-1)); + } + if (0 > objectStart || objects.length <= objectStart) { + throw new IllegalArgumentException("Value objectStart " + + objectStart + " is out of range 0 to " + + (objects.length-1)); + } + if (0 > count || objects.length - count < objectStart) { + throw new IllegalArgumentException("Value count " + + count + " is less than zero, or objectStart + count" + + " is beyond objects length " + objects.length); + } + + byte[] reorderLevels = new byte[count]; + System.arraycopy(levels, levelStart, reorderLevels, 0, count); + int[] indexMap = reorderVisual(reorderLevels); + Object[] temp = new Object[count]; + System.arraycopy(objects, objectStart, temp, 0, count); + for (int i = 0; i < count; ++i) { + objects[objectStart + i] = temp[indexMap[i]]; + } + } + + /** + * Take a Bidi object containing the reordering + * information for a piece of text (one or more paragraphs) set by + * setPara() or for a line of text set by setLine() + * and return a string containing the reordered text. + * + *

The text may have been aliased (only a reference was stored + * without copying the contents), thus it must not have been modified + * since the setPara() call.

+ * + * This method preserves the integrity of characters with multiple + * code units and (optionally) combining characters. + * Characters in RTL runs can be replaced by mirror-image characters + * in the returned string. Note that "real" mirroring has to be done in a + * rendering engine by glyph selection and that for many "mirrored" + * characters there are no Unicode characters as mirror-image equivalents. + * There are also options to insert or remove Bidi control + * characters; see the descriptions of the return value and the + * options parameter, and of the option bit flags. + * + * @param options A bit set of options for the reordering that control + * how the reordered text is written. + * The options include mirroring the characters on a code + * point basis and inserting LRM characters, which is used + * especially for transforming visually stored text + * to logically stored text (although this is still an + * imperfect implementation of an "inverse Bidi" algorithm + * because it uses the "forward Bidi" algorithm at its core). + * The available options are: + * DO_MIRRORING, + * INSERT_LRM_FOR_NUMERIC, + * KEEP_BASE_COMBINING, + * OUTPUT_REVERSE, + * REMOVE_BIDI_CONTROLS, + * STREAMING + * + * @return The reordered text. + * If the INSERT_LRM_FOR_NUMERIC option is set, then + * the length of the returned string could be as large as + * getLength()+2*countRuns().
+ * If the REMOVE_BIDI_CONTROLS option is set, then the + * length of the returned string may be less than + * getLength().
+ * If none of these options is set, then the length of the returned + * string will be exactly getProcessedLength(). + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or setLine + * + * @see #DO_MIRRORING + * @see #INSERT_LRM_FOR_NUMERIC + * @see #KEEP_BASE_COMBINING + * @see #OUTPUT_REVERSE + * @see #REMOVE_BIDI_CONTROLS + * @see #OPTION_STREAMING + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public String writeReordered(int options) + { + verifyValidParaOrLine(); + if (length == 0) { + /* nothing to do */ + return ""; + } + return BidiWriter.writeReordered(this, options); + } + + /** + * Display the bidi internal state, used in debugging. + */ + public String toString() { + StringBuilder buf = new StringBuilder(getClass().getName()); + + buf.append("[dir: "); + buf.append(direction); + buf.append(" baselevel: "); + buf.append(paraLevel); + buf.append(" length: "); + buf.append(length); + buf.append(" runs: "); + if (levels == null) { + buf.append("none"); + } else { + buf.append('['); + buf.append(levels[0]); + for (int i = 1; i < levels.length; i++) { + buf.append(' '); + buf.append(levels[i]); + } + buf.append(']'); + } + buf.append(" text: [0x"); + buf.append(Integer.toHexString(text[0])); + for (int i = 1; i < text.length; i++) { + buf.append(" 0x"); + buf.append(Integer.toHexString(text[i])); + } + buf.append("]]"); + + return buf.toString(); + } + + /** + * A class that provides access to constants defined by + * java.awt.font.TextAttribute without creating a static dependency. + */ + private static class TextAttributeConstants { + // Make sure to load the AWT's TextAttribute class before using the constants, if any. + static { + try { + Class.forName("java.awt.font.TextAttribute", true, null); + } catch (ClassNotFoundException e) {} + } + static final JavaAWTFontAccess jafa = SharedSecrets.getJavaAWTFontAccess(); + + /** + * TextAttribute instances (or a fake Attribute type if + * java.awt.font.TextAttribute is not present) + */ + static final AttributedCharacterIterator.Attribute RUN_DIRECTION = + getTextAttribute("RUN_DIRECTION"); + static final AttributedCharacterIterator.Attribute NUMERIC_SHAPING = + getTextAttribute("NUMERIC_SHAPING"); + static final AttributedCharacterIterator.Attribute BIDI_EMBEDDING = + getTextAttribute("BIDI_EMBEDDING"); + + /** + * TextAttribute.RUN_DIRECTION_LTR + */ + static final Boolean RUN_DIRECTION_LTR = (jafa == null) ? + Boolean.FALSE : (Boolean)jafa.getTextAttributeConstant("RUN_DIRECTION_LTR"); + + @SuppressWarnings("serial") + private static AttributedCharacterIterator.Attribute + getTextAttribute(String name) + { + if (jafa == null) { + // fake attribute + return new AttributedCharacterIterator.Attribute(name) { }; + } else { + return (AttributedCharacterIterator.Attribute)jafa.getTextAttributeConstant(name); + } + } + } + + /** + * A class that provides access to java.awt.font.NumericShaper without + * creating a static dependency. + */ + private static class NumericShapings { + // Make sure to load the AWT's NumericShaper class before calling shape, if any. + static { + try { + Class.forName("java.awt.font.NumericShaper", true, null); + } catch (ClassNotFoundException e) {} + } + static final JavaAWTFontAccess jafa = SharedSecrets.getJavaAWTFontAccess(); + + /** + * Invokes NumericShaping shape(text,start,count) method. + */ + static void shape(Object shaper, char[] text, int start, int count) { + if (jafa != null) { + jafa.shape(shaper, text, start, count); + } + } + } + +} diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiLine.class b/tests/test_data/std/jdk/internal/icu/text/BidiLine.class new file mode 100644 index 0000000000000000000000000000000000000000..423ee209f86a475b15d79eadc41ab9d031749e4f GIT binary patch literal 9731 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 Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, + * also described in The Unicode Standard, Version 4.0.1 . + * + * This means that there is a Bidi object with a levels + * and a dirProps array. + * paraLevel and direction are also set. + * Only if the length of the text is zero, then levels==dirProps==NULL. + * + * The overall directionality of the paragraph + * or line is used to bypass the reordering steps if possible. + * Even purely RTL text does not need reordering there because + * the getLogical/VisualIndex() methods can compute the + * index on the fly in such a case. + * + * The implementation of the access to same-level-runs and of the reordering + * do attempt to provide better performance and less memory usage compared to + * a direct implementation of especially rule (L2) with an array of + * one (32-bit) integer per text character. + * + * Here, the levels array is scanned as soon as necessary, and a vector of + * same-level-runs is created. Reordering then is done on this vector. + * For each run of text positions that were resolved to the same level, + * only 8 bytes are stored: the first text position of the run and the visual + * position behind the run after reordering. + * One sign bit is used to hold the directionality of the run. + * This is inefficient if there are many very short runs. If the average run + * length is <2, then this uses more memory. + * + * In a further attempt to save memory, the levels array is never changed + * after all the resolution rules (Xn, Wn, Nn, In). + * Many methods have to consider the field trailingWSStart: + * if it is less than length, then there is an implicit trailing run + * at the paraLevel, + * which is not reflected in the levels array. + * This allows a line Bidi object to use the same levels array as + * its paragraph parent object. + * + * When a Bidi object is created for a line of a paragraph, then the + * paragraph's levels and dirProps arrays are reused by way of setting + * a pointer into them, not by copying. This again saves memory and forbids to + * change the now shared levels for (L1). + */ + + /* handle trailing WS (L1) -------------------------------------------------- */ + + /* + * setTrailingWSStart() sets the start index for a trailing + * run of WS in the line. This is necessary because we do not modify + * the paragraph's levels array that we just point into. + * Using trailingWSStart is another form of performing (L1). + * + * To make subsequent operations easier, we also include the run + * before the WS if it is at the paraLevel - we merge the two here. + * + * This method is called only from setLine(), so paraLevel is + * set correctly for the line even when contextual multiple paragraphs. + */ + + static void setTrailingWSStart(BidiBase bidiBase) + { + byte[] dirProps = bidiBase.dirProps; + byte[] levels = bidiBase.levels; + int start = bidiBase.length; + byte paraLevel = bidiBase.paraLevel; + + /* If the line is terminated by a block separator, all preceding WS etc... + are already set to paragraph level. + Setting trailingWSStart to pBidi->length will avoid changing the + level of B chars from 0 to paraLevel in getLevels when + orderParagraphsLTR==true + */ + if (dirProps[start - 1] == BidiBase.B) { + bidiBase.trailingWSStart = start; /* currently == bidiBase.length */ + return; + } + /* go backwards across all WS, BN, explicit codes */ + while (start > 0 && + (BidiBase.DirPropFlag(dirProps[start - 1]) & BidiBase.MASK_WS) != 0) { + --start; + } + + /* if the WS run can be merged with the previous run then do so here */ + while (start > 0 && levels[start - 1] == paraLevel) { + --start; + } + + bidiBase.trailingWSStart=start; + } + + static Bidi setLine(BidiBase paraBidi, + Bidi newBidi, BidiBase lineBidi, + int start, int limit) { + int length; + + /* set the values in lineBidi from its paraBidi parent */ + /* class members are already initialized to 0 */ + // lineBidi.paraBidi = null; /* mark unfinished setLine */ + // lineBidi.flags = 0; + // lineBidi.controlCount = 0; + + length = lineBidi.length = lineBidi.originalLength = + lineBidi.resultLength = limit - start; + + lineBidi.text = new char[length]; + System.arraycopy(paraBidi.text, start, lineBidi.text, 0, length); + lineBidi.paraLevel = paraBidi.GetParaLevelAt(start); + lineBidi.paraCount = paraBidi.paraCount; + lineBidi.runs = new BidiRun[0]; + lineBidi.reorderingMode = paraBidi.reorderingMode; + lineBidi.reorderingOptions = paraBidi.reorderingOptions; + if (paraBidi.controlCount > 0) { + int j; + for (j = start; j < limit; j++) { + if (BidiBase.IsBidiControlChar(paraBidi.text[j])) { + lineBidi.controlCount++; + } + } + lineBidi.resultLength -= lineBidi.controlCount; + } + /* copy proper subset of DirProps */ + lineBidi.getDirPropsMemory(length); + lineBidi.dirProps = lineBidi.dirPropsMemory; + System.arraycopy(paraBidi.dirProps, start, lineBidi.dirProps, 0, + length); + /* copy proper subset of Levels */ + lineBidi.getLevelsMemory(length); + lineBidi.levels = lineBidi.levelsMemory; + System.arraycopy(paraBidi.levels, start, lineBidi.levels, 0, + length); + lineBidi.runCount = -1; + + if (paraBidi.direction != BidiBase.MIXED) { + /* the parent is already trivial */ + lineBidi.direction = paraBidi.direction; + + /* + * The parent's levels are all either + * implicitly or explicitly ==paraLevel; + * do the same here. + */ + if (paraBidi.trailingWSStart <= start) { + lineBidi.trailingWSStart = 0; + } else if (paraBidi.trailingWSStart < limit) { + lineBidi.trailingWSStart = paraBidi.trailingWSStart - start; + } else { + lineBidi.trailingWSStart = length; + } + } else { + byte[] levels = lineBidi.levels; + int i, trailingWSStart; + byte level; + + setTrailingWSStart(lineBidi); + trailingWSStart = lineBidi.trailingWSStart; + + /* recalculate lineBidiBase.direction */ + if (trailingWSStart == 0) { + /* all levels are at paraLevel */ + lineBidi.direction = (byte)(lineBidi.paraLevel & 1); + } else { + /* get the level of the first character */ + level = (byte)(levels[0] & 1); + + /* if there is anything of a different level, then the line + is mixed */ + if (trailingWSStart < length && + (lineBidi.paraLevel & 1) != level) { + /* the trailing WS is at paraLevel, which differs from + levels[0] */ + lineBidi.direction = BidiBase.MIXED; + } else { + /* see if levels[1..trailingWSStart-1] have the same + direction as levels[0] and paraLevel */ + for (i = 1; ; i++) { + if (i == trailingWSStart) { + /* the direction values match those in level */ + lineBidi.direction = level; + break; + } else if ((levels[i] & 1) != level) { + lineBidi.direction = BidiBase.MIXED; + break; + } + } + } + } + + switch(lineBidi.direction) { + case Bidi.DIRECTION_LEFT_TO_RIGHT: + /* make sure paraLevel is even */ + lineBidi.paraLevel = (byte) + ((lineBidi.paraLevel + 1) & ~1); + + /* all levels are implicitly at paraLevel (important for + getLevels()) */ + lineBidi.trailingWSStart = 0; + break; + case Bidi.DIRECTION_RIGHT_TO_LEFT: + /* make sure paraLevel is odd */ + lineBidi.paraLevel |= 1; + + /* all levels are implicitly at paraLevel (important for + getLevels()) */ + lineBidi.trailingWSStart = 0; + break; + default: + break; + } + } + + lineBidi.paraBidi = paraBidi; /* mark successful setLine */ + + return newBidi; + } + + static byte getLevelAt(BidiBase bidiBase, int charIndex) + { + /* return paraLevel if in the trailing WS run, otherwise the real level */ + if (bidiBase.direction != BidiBase.MIXED || charIndex >= bidiBase.trailingWSStart) { + return bidiBase.GetParaLevelAt(charIndex); + } else { + return bidiBase.levels[charIndex]; + } + } + + static byte[] getLevels(BidiBase bidiBase) + { + int start = bidiBase.trailingWSStart; + int length = bidiBase.length; + + if (start != length) { + /* the current levels array does not reflect the WS run */ + /* + * After the previous if(), we know that the levels array + * has an implicit trailing WS run and therefore does not fully + * reflect itself all the levels. + * This must be a Bidi object for a line, and + * we need to create a new levels array. + */ + /* bidiBase.paraLevel is ok even if contextual multiple paragraphs, + since bidiBase is a line object */ + Arrays.fill(bidiBase.levels, start, length, bidiBase.paraLevel); + + /* this new levels array is set for the line and reflects the WS run */ + bidiBase.trailingWSStart = length; + } + if (length < bidiBase.levels.length) { + byte[] levels = new byte[length]; + System.arraycopy(bidiBase.levels, 0, levels, 0, length); + return levels; + } + return bidiBase.levels; + } + + static BidiRun getVisualRun(BidiBase bidiBase, int runIndex) { + int start = bidiBase.runs[runIndex].start; + int limit; + byte level = bidiBase.runs[runIndex].level; + + if (runIndex > 0) { + limit = start + + bidiBase.runs[runIndex].limit - + bidiBase.runs[runIndex - 1].limit; + } else { + limit = start + bidiBase.runs[0].limit; + } + return new BidiRun(start, limit, level); + } + + /* in trivial cases there is only one trivial run; called by getRuns() */ + private static void getSingleRun(BidiBase bidiBase, byte level) { + /* simple, single-run case */ + bidiBase.runs = bidiBase.simpleRuns; + bidiBase.runCount = 1; + + /* fill and reorder the single run */ + bidiBase.runs[0] = new BidiRun(0, bidiBase.length, level); + } + + /* reorder the runs array (L2) ---------------------------------------------- */ + + /* + * Reorder the same-level runs in the runs array. + * Here, runCount>1 and maxLevel>=minLevel>=paraLevel. + * All the visualStart fields=logical start before reordering. + * The "odd" bits are not set yet. + * + * Reordering with this data structure lends itself to some handy shortcuts: + * + * Since each run is moved but not modified, and since at the initial maxLevel + * each sequence of same-level runs consists of only one run each, we + * don't need to do anything there and can predecrement maxLevel. + * In many simple cases, the reordering is thus done entirely in the + * index mapping. + * Also, reordering occurs only down to the lowest odd level that occurs, + * which is minLevel|1. However, if the lowest level itself is odd, then + * in the last reordering the sequence of the runs at this level or higher + * will be all runs, and we don't need the elaborate loop to search for them. + * This is covered by ++minLevel instead of minLevel|=1 followed + * by an extra reorder-all after the reorder-some loop. + * About a trailing WS run: + * Such a run would need special treatment because its level is not + * reflected in levels[] if this is not a paragraph object. + * Instead, all characters from trailingWSStart on are implicitly at + * paraLevel. + * However, for all maxLevel>paraLevel, this run will never be reordered + * and does not need to be taken into account. maxLevel==paraLevel is only reordered + * if minLevel==paraLevel is odd, which is done in the extra segment. + * This means that for the main reordering loop we don't need to consider + * this run and can --runCount. If it is later part of the all-runs + * reordering, then runCount is adjusted accordingly. + */ + private static void reorderLine(BidiBase bidiBase, byte minLevel, byte maxLevel) { + + /* nothing to do? */ + if (maxLevel<=(minLevel|1)) { + return; + } + + BidiRun[] runs; + BidiRun tempRun; + byte[] levels; + int firstRun, endRun, limitRun, runCount; + + /* + * Reorder only down to the lowest odd level + * and reorder at an odd minLevel in a separate, simpler loop. + * See comments above for why minLevel is always incremented. + */ + ++minLevel; + + runs = bidiBase.runs; + levels = bidiBase.levels; + runCount = bidiBase.runCount; + + /* do not include the WS run at paraLevel<=old minLevel except in the simple loop */ + if (bidiBase.trailingWSStart < bidiBase.length) { + --runCount; + } + + while (--maxLevel >= minLevel) { + firstRun = 0; + + /* loop for all sequences of runs */ + for ( ; ; ) { + /* look for a sequence of runs that are all at >=maxLevel */ + /* look for the first run of such a sequence */ + while (firstRun < runCount && levels[runs[firstRun].start] < maxLevel) { + ++firstRun; + } + if (firstRun >= runCount) { + break; /* no more such runs */ + } + + /* look for the limit run of such a sequence (the run behind it) */ + for (limitRun = firstRun; ++limitRun < runCount && + levels[runs[limitRun].start]>=maxLevel; ) {} + + /* Swap the entire sequence of runs from firstRun to limitRun-1. */ + endRun = limitRun - 1; + while (firstRun < endRun) { + tempRun = runs[firstRun]; + runs[firstRun] = runs[endRun]; + runs[endRun] = tempRun; + ++firstRun; + --endRun; + } + + if (limitRun == runCount) { + break; /* no more such runs */ + } else { + firstRun = limitRun + 1; + } + } + } + + /* now do maxLevel==old minLevel (==odd!), see above */ + if ((minLevel & 1) == 0) { + firstRun = 0; + + /* include the trailing WS run in this complete reordering */ + if (bidiBase.trailingWSStart == bidiBase.length) { + --runCount; + } + + /* Swap the entire sequence of all runs. (endRun==runCount) */ + while (firstRun < runCount) { + tempRun = runs[firstRun]; + runs[firstRun] = runs[runCount]; + runs[runCount] = tempRun; + ++firstRun; + --runCount; + } + } + } + + /* compute the runs array --------------------------------------------------- */ + + static int getRunFromLogicalIndex(BidiBase bidiBase, int logicalIndex) { + BidiRun[] runs = bidiBase.runs; + int runCount = bidiBase.runCount, visualStart = 0, i, length, logicalStart; + + for (i = 0; i < runCount; i++) { + length = runs[i].limit - visualStart; + logicalStart = runs[i].start; + if ((logicalIndex >= logicalStart) && (logicalIndex < (logicalStart+length))) { + return i; + } + visualStart += length; + } + /* we should never get here */ + throw new IllegalStateException("Internal ICU error in getRunFromLogicalIndex"); + } + + /* + * Compute the runs array from the levels array. + * After getRuns() returns true, runCount is guaranteed to be >0 + * and the runs are reordered. + * Odd-level runs have visualStart on their visual right edge and + * they progress visually to the left. + * If option OPTION_INSERT_MARKS is set, insertRemove will contain the + * sum of appropriate LRM/RLM_BEFORE/AFTER flags. + * If option OPTION_REMOVE_CONTROLS is set, insertRemove will contain the + * negative number of BiDi control characters within this run. + */ + static void getRuns(BidiBase bidiBase) { + /* + * This method returns immediately if the runs are already set. This + * includes the case of length==0 (handled in setPara).. + */ + if (bidiBase.runCount >= 0) { + return; + } + if (bidiBase.direction != BidiBase.MIXED) { + /* simple, single-run case - this covers length==0 */ + /* bidiBase.paraLevel is ok even for contextual multiple paragraphs */ + getSingleRun(bidiBase, bidiBase.paraLevel); + } else /* BidiBase.MIXED, length>0 */ { + /* mixed directionality */ + int length = bidiBase.length, limit; + byte[] levels = bidiBase.levels; + int i, runCount; + byte level = -1; /* initialize with no valid level */ + /* + * If there are WS characters at the end of the line + * and the run preceding them has a level different from + * paraLevel, then they will form their own run at paraLevel (L1). + * Count them separately. + * We need some special treatment for this in order to not + * modify the levels array which a line Bidi object shares + * with its paragraph parent and its other line siblings. + * In other words, for the trailing WS, it may be + * levels[]!=paraLevel but we have to treat it like it were so. + */ + limit = bidiBase.trailingWSStart; + /* count the runs, there is at least one non-WS run, and limit>0 */ + runCount = 0; + for (i = 0; i < limit; ++i) { + /* increment runCount at the start of each run */ + if (levels[i] != level) { + ++runCount; + level = levels[i]; + } + } + + /* + * We don't need to see if the last run can be merged with a trailing + * WS run because setTrailingWSStart() would have done that. + */ + if (runCount == 1 && limit == length) { + /* There is only one non-WS run and no trailing WS-run. */ + getSingleRun(bidiBase, levels[0]); + } else /* runCount>1 || limit 1 */ + bidiBase.getRunsMemory(runCount); + runs = bidiBase.runsMemory; + + /* set the runs */ + /* FOOD FOR THOUGHT: this could be optimized, e.g.: + * 464->444, 484->444, 575->555, 595->555 + * However, that would take longer. Check also how it would + * interact with BiDi control removal and inserting Marks. + */ + runIndex = 0; + + /* search for the run limits and initialize visualLimit values with the run lengths */ + i = 0; + do { + /* prepare this run */ + start = i; + level = levels[i]; + if (level < minLevel) { + minLevel = level; + } + if (level > maxLevel) { + maxLevel = level; + } + + /* look for the run limit */ + while (++i < limit && levels[i] == level) {} + + /* i is another run limit */ + runs[runIndex] = new BidiRun(start, i - start, level); + ++runIndex; + } while (i < limit); + + if (limit < length) { + /* there is a separate WS run */ + runs[runIndex] = new BidiRun(limit, length - limit, bidiBase.paraLevel); + /* For the trailing WS run, bidiBase.paraLevel is ok even + if contextual multiple paragraphs. */ + if (bidiBase.paraLevel < minLevel) { + minLevel = bidiBase.paraLevel; + } + } + + /* set the object fields */ + bidiBase.runs = runs; + bidiBase.runCount = runCount; + + reorderLine(bidiBase, minLevel, maxLevel); + + /* now add the direction flags and adjust the visualLimit's to be just that */ + /* this loop will also handle the trailing WS run */ + limit = 0; + for (i = 0; i < runCount; ++i) { + runs[i].level = levels[runs[i].start]; + limit = (runs[i].limit += limit); + } + + /* Set the embedding level for the trailing WS run. */ + /* For a RTL paragraph, it will be the *first* run in visual order. */ + /* For the trailing WS run, bidiBase.paraLevel is ok even if + contextual multiple paragraphs. */ + if (runIndex < runCount) { + int trailingRun = ((bidiBase.paraLevel & 1) != 0)? 0 : runIndex; + runs[trailingRun].level = bidiBase.paraLevel; + } + } + } + + /* handle insert LRM/RLM BEFORE/AFTER run */ + if (bidiBase.insertPoints.size > 0) { + BidiBase.Point point; + int runIndex, ip; + for (ip = 0; ip < bidiBase.insertPoints.size; ip++) { + point = bidiBase.insertPoints.points[ip]; + runIndex = getRunFromLogicalIndex(bidiBase, point.pos); + bidiBase.runs[runIndex].insertRemove |= point.flag; + } + } + + /* handle remove BiDi control characters */ + if (bidiBase.controlCount > 0) { + int runIndex, ic; + char c; + for (ic = 0; ic < bidiBase.length; ic++) { + c = bidiBase.text[ic]; + if (BidiBase.IsBidiControlChar(c)) { + runIndex = getRunFromLogicalIndex(bidiBase, ic); + bidiBase.runs[runIndex].insertRemove--; + } + } + } + } + + static int[] prepareReorder(byte[] levels, byte[] pMinLevel, byte[] pMaxLevel) + { + int start; + byte level, minLevel, maxLevel; + + if (levels == null || levels.length <= 0) { + return null; + } + + /* determine minLevel and maxLevel */ + minLevel = BidiBase.MAX_EXPLICIT_LEVEL + 1; + maxLevel = 0; + for (start = levels.length; start>0; ) { + level = levels[--start]; + if (level < 0 || level > (BidiBase.MAX_EXPLICIT_LEVEL + 1)) { + return null; + } + if (level < minLevel) { + minLevel = level; + } + if (level > maxLevel) { + maxLevel = level; + } + } + pMinLevel[0] = minLevel; + pMaxLevel[0] = maxLevel; + + /* initialize the index map */ + int[] indexMap = new int[levels.length]; + for (start = levels.length; start > 0; ) { + --start; + indexMap[start] = start; + } + + return indexMap; + } + + static int[] reorderVisual(byte[] levels) + { + byte[] aMinLevel = new byte[1]; + byte[] aMaxLevel = new byte[1]; + int start, end, limit, temp; + byte minLevel, maxLevel; + + int[] indexMap = prepareReorder(levels, aMinLevel, aMaxLevel); + if (indexMap == null) { + return null; + } + + minLevel = aMinLevel[0]; + maxLevel = aMaxLevel[0]; + + /* nothing to do? */ + if (minLevel == maxLevel && (minLevel & 1) == 0) { + return indexMap; + } + + /* reorder only down to the lowest odd level */ + minLevel |= 1; + + /* loop maxLevel..minLevel */ + do { + start = 0; + + /* loop for all sequences of levels to reorder at the current maxLevel */ + for ( ; ; ) { + /* look for a sequence of levels that are all at >=maxLevel */ + /* look for the first index of such a sequence */ + while (start < levels.length && levels[start] < maxLevel) { + ++start; + } + if (start >= levels.length) { + break; /* no more such runs */ + } + + /* look for the limit of such a sequence (the index behind it) */ + for (limit = start; ++limit < levels.length && levels[limit] >= maxLevel; ) {} + + /* + * Swap the entire interval of indexes from start to limit-1. + * We don't need to swap the levels for the purpose of this + * algorithm: the sequence of levels that we look at does not + * move anyway. + */ + end = limit - 1; + while (start < end) { + temp = indexMap[start]; + indexMap[start] = indexMap[end]; + indexMap[end] = temp; + + ++start; + --end; + } + + if (limit == levels.length) { + break; /* no more such sequences */ + } else { + start = limit + 1; + } + } + } while (--maxLevel >= minLevel); + + return indexMap; + } + + static int[] getVisualMap(BidiBase bidiBase) + { + /* fill a visual-to-logical index map using the runs[] */ + BidiRun[] runs = bidiBase.runs; + int logicalStart, visualStart, visualLimit; + int allocLength = bidiBase.length > bidiBase.resultLength ? bidiBase.length + : bidiBase.resultLength; + int[] indexMap = new int[allocLength]; + + visualStart = 0; + int idx = 0; + for (int j = 0; j < bidiBase.runCount; ++j) { + logicalStart = runs[j].start; + visualLimit = runs[j].limit; + if (runs[j].isEvenRun()) { + do { /* LTR */ + indexMap[idx++] = logicalStart++; + } while (++visualStart < visualLimit); + } else { + logicalStart += visualLimit - visualStart; /* logicalLimit */ + do { /* RTL */ + indexMap[idx++] = --logicalStart; + } while (++visualStart < visualLimit); + } + /* visualStart==visualLimit; */ + } + + if (bidiBase.insertPoints.size > 0) { + int markFound = 0, runCount = bidiBase.runCount; + int insertRemove, i, j, k; + runs = bidiBase.runs; + /* count all inserted marks */ + for (i = 0; i < runCount; i++) { + insertRemove = runs[i].insertRemove; + if ((insertRemove & (BidiBase.LRM_BEFORE|BidiBase.RLM_BEFORE)) > 0) { + markFound++; + } + if ((insertRemove & (BidiBase.LRM_AFTER|BidiBase.RLM_AFTER)) > 0) { + markFound++; + } + } + /* move back indexes by number of preceding marks */ + k = bidiBase.resultLength; + for (i = runCount - 1; i >= 0 && markFound > 0; i--) { + insertRemove = runs[i].insertRemove; + if ((insertRemove & (BidiBase.LRM_AFTER|BidiBase.RLM_AFTER)) > 0) { + indexMap[--k] = BidiBase.MAP_NOWHERE; + markFound--; + } + visualStart = i > 0 ? runs[i-1].limit : 0; + for (j = runs[i].limit - 1; j >= visualStart && markFound > 0; j--) { + indexMap[--k] = indexMap[j]; + } + if ((insertRemove & (BidiBase.LRM_BEFORE|BidiBase.RLM_BEFORE)) > 0) { + indexMap[--k] = BidiBase.MAP_NOWHERE; + markFound--; + } + } + } + else if (bidiBase.controlCount > 0) { + int runCount = bidiBase.runCount, logicalEnd; + int insertRemove, length, i, j, k, m; + char uchar; + boolean evenRun; + runs = bidiBase.runs; + visualStart = 0; + /* move forward indexes by number of preceding controls */ + k = 0; + for (i = 0; i < runCount; i++, visualStart += length) { + length = runs[i].limit - visualStart; + insertRemove = runs[i].insertRemove; + /* if no control found yet, nothing to do in this run */ + if ((insertRemove == 0) && (k == visualStart)) { + k += length; + continue; + } + /* if no control in this run */ + if (insertRemove == 0) { + visualLimit = runs[i].limit; + for (j = visualStart; j < visualLimit; j++) { + indexMap[k++] = indexMap[j]; + } + continue; + } + logicalStart = runs[i].start; + evenRun = runs[i].isEvenRun(); + logicalEnd = logicalStart + length - 1; + for (j = 0; j < length; j++) { + m = evenRun ? logicalStart + j : logicalEnd - j; + uchar = bidiBase.text[m]; + if (!BidiBase.IsBidiControlChar(uchar)) { + indexMap[k++] = m; + } + } + } + } + if (allocLength == bidiBase.resultLength) { + return indexMap; + } + int[] newMap = new int[bidiBase.resultLength]; + System.arraycopy(indexMap, 0, newMap, 0, bidiBase.resultLength); + return newMap; + } + +} diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiRun.class b/tests/test_data/std/jdk/internal/icu/text/BidiRun.class new file mode 100644 index 0000000000000000000000000000000000000000..221efc2cf9370af9d2ff4f30ad47c6674e5c9642 GIT binary patch literal 946 zcmah{%Wl(95Ir}x^QzONO-KuEXj5K^k?@WU2%(f#suVyB0=3cL%vOFR zL*Mai@<0}HCku!5_&+&)$>;6c( zk$~1{_Hsm0FtLiFfH8@jkm}-yt7|6KerzdKP6P_w$Z^kJ zI_HVjd^ebet~^w{jhXoWi0#EL`H`isr_)20(g`*(j$~3C$wG=o{H#FW7G;lVLQu?F znxNC|R{R%75{y zG4mVhJV6d`N##3~@jk}37V}H&O1uN>s>EBck_vW6zed?E>It(XW`0+<9)5?(#1u=+ zO|eY$95?3JxGrNrW=WLr0h<^S;At$Qx&T|ssAG?oWf^yHH=(pCa>cNS;VUHzx7Z6H zxZ;$tgt>?N$?yy6=Ds2i>z_U&qkn;}F^m?QzJR&70#i(29#D^gRN*<(H|UZ=^AA?5 Bm6!kk literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiRun.java b/tests/test_data/std/jdk/internal/icu/text/BidiRun.java new file mode 100644 index 00000000..4764e718 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/text/BidiRun.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ +/* Written by Simon Montagu, Matitiahu Allouche + * (ported from C code written by Markus W. Scherer) + */ + +package jdk.internal.icu.text; + +/** + * A BidiRun represents a sequence of characters at the same embedding level. + * The Bidi algorithm decomposes a piece of text into sequences of characters + * at the same embedding level, each such sequence is called a "run". + * + *

A BidiRun represents such a run by storing its essential properties, + * but does not duplicate the characters which form the run. + * + *

The "limit" of the run is the position just after the + * last character, i.e., one more than that position. + * + *

This class has no public constructor, and its members cannot be + * modified by users. + * + * @see com.ibm.icu.text.Bidi + */ +class BidiRun { + + int start; /* first logical position of the run */ + int limit; /* last visual position of the run +1 */ + int insertRemove; /* if >0, flags for inserting LRM/RLM before/after run, + if <0, count of bidi controls within run */ + byte level; + + /* + * Default constructor + * + * Note that members start and limit of a run instance have different + * meanings depending whether the run is part of the runs array of a Bidi + * object, or if it is a reference returned by getVisualRun() or + * getLogicalRun(). + * For a member of the runs array of a Bidi object, + * - start is the first logical position of the run in the source text. + * - limit is one after the last visual position of the run. + * For a reference returned by getLogicalRun() or getVisualRun(), + * - start is the first logical position of the run in the source text. + * - limit is one after the last logical position of the run. + */ + BidiRun() + { + this(0, 0, (byte)0); + } + + /* + * Constructor + */ + BidiRun(int start, int limit, byte embeddingLevel) + { + this.start = start; + this.limit = limit; + this.level = embeddingLevel; + } + + /* + * Copy the content of a BidiRun instance + */ + void copyFrom(BidiRun run) + { + this.start = run.start; + this.limit = run.limit; + this.level = run.level; + this.insertRemove = run.insertRemove; + } + + /** + * Get level of run + */ + byte getEmbeddingLevel() + { + return level; + } + + /** + * Check if run level is even + * @return true if the embedding level of this run is even, i.e. it is a + * left-to-right run. + */ + boolean isEvenRun() + { + return (level & 1) == 0; + } + +} diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiWriter.class b/tests/test_data/std/jdk/internal/icu/text/BidiWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..8fb05d7bb9065b74f8405e6c616afa7020c9f1d1 GIT binary patch literal 5478 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 A?EnA( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/BidiWriter.java b/tests/test_data/std/jdk/internal/icu/text/BidiWriter.java new file mode 100644 index 00000000..3b4c5dd4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/text/BidiWriter.java @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 2001-2010, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ +/* Written by Simon Montagu, Matitiahu Allouche + * (ported from C code written by Markus W. Scherer) + */ + +package jdk.internal.icu.text; + +import jdk.internal.icu.lang.UCharacter; + +final class BidiWriter { + + /** Bidi control code points */ + static final char LRM_CHAR = 0x200e; + static final char RLM_CHAR = 0x200f; + static final int MASK_R_AL = (1 << UCharacter.RIGHT_TO_LEFT | + 1 << UCharacter.RIGHT_TO_LEFT_ARABIC); + + private static boolean IsCombining(int type) { + return ((1< 0); + break; + + case BidiBase.KEEP_BASE_COMBINING: + /* + * Here, too, the destination + * run will have the same length as the source run, + * and there is no mirroring. + * We do need to keep combining characters with their base + * characters. + */ + srcLength = src.length(); + + /* preserve character integrity */ + do { + /* i is always after the last code unit known to need to be kept + * in this segment */ + int c; + int i = srcLength; + + /* collect code units and modifier letters for one base + * character */ + do { + c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + } while(srcLength > 0 && IsCombining(UCharacter.getType(c))); + + /* copy this "user character" */ + dest.append(src.substring(srcLength, i)); + } while(srcLength > 0); + break; + + default: + /* + * With several "complicated" options set, this is the most + * general and the slowest copying of an RTL run. + * We will do mirroring, remove Bidi controls, and + * keep combining characters with their base characters + * as requested. + */ + srcLength = src.length(); + + /* preserve character integrity */ + do { + /* i is always after the last code unit known to need to be kept + * in this segment */ + int i = srcLength; + + /* collect code units for one base character */ + int c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + if ((options & BidiBase.KEEP_BASE_COMBINING) != 0) { + /* collect modifier letters for this base character */ + while(srcLength > 0 && IsCombining(UCharacter.getType(c))) { + c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + } + } + + if ((options & BidiBase.REMOVE_BIDI_CONTROLS) != 0 && + BidiBase.IsBidiControlChar(c)) { + /* do not copy this Bidi control character */ + continue; + } + + /* copy this "user character" */ + int j = srcLength; + if((options & BidiBase.DO_MIRRORING) != 0) { + /* mirror only the base character */ + c = UCharacter.getMirror(c); + UTF16.append(dest, c); + j += UTF16.getCharCount(c); + } + dest.append(src.substring(j, i)); + } while(srcLength > 0); + break; + } /* end of switch */ + + return dest.toString(); + } + + static String doWriteReverse(char[] text, int start, int limit, int options) { + return writeReverse(new String(text, start, limit - start), options); + } + + static String writeReordered(BidiBase bidi, int options) { + int run, runCount; + StringBuilder dest; + char[] text = bidi.text; + runCount = bidi.countRuns(); + + /* + * Option "insert marks" implies BidiBase.INSERT_LRM_FOR_NUMERIC if the + * reordering mode (checked below) is appropriate. + */ + if ((bidi.reorderingOptions & BidiBase.OPTION_INSERT_MARKS) != 0) { + options |= BidiBase.INSERT_LRM_FOR_NUMERIC; + options &= ~BidiBase.REMOVE_BIDI_CONTROLS; + } + /* + * Option "remove controls" implies BidiBase.REMOVE_BIDI_CONTROLS + * and cancels BidiBase.INSERT_LRM_FOR_NUMERIC. + */ + if ((bidi.reorderingOptions & BidiBase.OPTION_REMOVE_CONTROLS) != 0) { + options |= BidiBase.REMOVE_BIDI_CONTROLS; + options &= ~BidiBase.INSERT_LRM_FOR_NUMERIC; + } + /* + * If we do not perform the "inverse Bidi" algorithm, then we + * don't need to insert any LRMs, and don't need to test for it. + */ + if ((bidi.reorderingMode != BidiBase.REORDER_INVERSE_NUMBERS_AS_L) && + (bidi.reorderingMode != BidiBase.REORDER_INVERSE_LIKE_DIRECT) && + (bidi.reorderingMode != BidiBase.REORDER_INVERSE_FOR_NUMBERS_SPECIAL) && + (bidi.reorderingMode != BidiBase.REORDER_RUNS_ONLY)) { + options &= ~BidiBase.INSERT_LRM_FOR_NUMERIC; + } + dest = new StringBuilder((options & BidiBase.INSERT_LRM_FOR_NUMERIC) != 0 ? + bidi.length * 2 : bidi.length); + /* + * Iterate through all visual runs and copy the run text segments to + * the destination, according to the options. + * + * The tests for where to insert LRMs ignore the fact that there may be + * BN codes or non-BMP code points at the beginning and end of a run; + * they may insert LRMs unnecessarily but the tests are faster this way + * (this would have to be improved for UTF-8). + */ + if ((options & BidiBase.OUTPUT_REVERSE) == 0) { + /* forward output */ + if ((options & BidiBase.INSERT_LRM_FOR_NUMERIC) == 0) { + /* do not insert Bidi controls */ + for (run = 0; run < runCount; ++run) { + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + dest.append(doWriteForward(text, bidiRun.start, + bidiRun.limit, + options & ~BidiBase.DO_MIRRORING)); + } else { + dest.append(doWriteReverse(text, bidiRun.start, + bidiRun.limit, options)); + } + } + } else { + /* insert Bidi controls for "inverse Bidi" */ + byte[] dirProps = bidi.dirProps; + char uc; + int markFlag; + + for (run = 0; run < runCount; ++run) { + BidiRun bidiRun = bidi.getVisualRun(run); + markFlag=0; + /* check if something relevant in insertPoints */ + markFlag = bidi.runs[run].insertRemove; + if (markFlag < 0) { /* bidi controls count */ + markFlag = 0; + } + if (bidiRun.isEvenRun()) { + if (bidi.isInverse() && + dirProps[bidiRun.start] != BidiBase.L) { + markFlag |= BidiBase.LRM_BEFORE; + } + if ((markFlag & BidiBase.LRM_BEFORE) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_BEFORE) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + dest.append(doWriteForward(text, + bidiRun.start, bidiRun.limit, + options & ~BidiBase.DO_MIRRORING)); + + if (bidi.isInverse() && + dirProps[bidiRun.limit - 1] != BidiBase.L) { + markFlag |= BidiBase.LRM_AFTER; + } + if ((markFlag & BidiBase.LRM_AFTER) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_AFTER) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + } else { /* RTL run */ + if (bidi.isInverse() && + !bidi.testDirPropFlagAt(MASK_R_AL, + bidiRun.limit - 1)) { + markFlag |= BidiBase.RLM_BEFORE; + } + if ((markFlag & BidiBase.LRM_BEFORE) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_BEFORE) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + dest.append(doWriteReverse(text, bidiRun.start, + bidiRun.limit, options)); + + if(bidi.isInverse() && + (MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.start])) == 0) { + markFlag |= BidiBase.RLM_AFTER; + } + if ((markFlag & BidiBase.LRM_AFTER) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_AFTER) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + } + } + } + } else { + /* reverse output */ + if((options & BidiBase.INSERT_LRM_FOR_NUMERIC) == 0) { + /* do not insert Bidi controls */ + for(run = runCount; --run >= 0; ) { + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + dest.append(doWriteReverse(text, + bidiRun.start, bidiRun.limit, + options & ~BidiBase.DO_MIRRORING)); + } else { + dest.append(doWriteForward(text, bidiRun.start, + bidiRun.limit, options)); + } + } + } else { + /* insert Bidi controls for "inverse Bidi" */ + + byte[] dirProps = bidi.dirProps; + + for (run = runCount; --run >= 0; ) { + /* reverse output */ + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + if (dirProps[bidiRun.limit - 1] != BidiBase.L) { + dest.append(LRM_CHAR); + } + + dest.append(doWriteReverse(text, bidiRun.start, + bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + + if (dirProps[bidiRun.start] != BidiBase.L) { + dest.append(LRM_CHAR); + } + } else { + if ((MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.start])) == 0) { + dest.append(RLM_CHAR); + } + + dest.append(doWriteForward(text, bidiRun.start, + bidiRun.limit, options)); + + if ((MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.limit - 1])) == 0) { + dest.append(RLM_CHAR); + } + } + } + } + } + + return dest.toString(); + } +} diff --git a/tests/test_data/std/jdk/internal/icu/text/FilteredNormalizer2.class b/tests/test_data/std/jdk/internal/icu/text/FilteredNormalizer2.class new file mode 100644 index 0000000000000000000000000000000000000000..417369b889ce05a59b71a8b4da218f1952d20785 GIT binary patch literal 4898 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/Normalizer2.java b/tests/test_data/std/jdk/internal/icu/text/Normalizer2.java new file mode 100644 index 00000000..db0d1fc2 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/text/Normalizer2.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk.internal.icu.text; + +import jdk.internal.icu.impl.Norm2AllModes; + +/** + * Unicode normalization functionality for standard Unicode normalization or + * for using custom mapping tables. + * All instances of this class are unmodifiable/immutable. + * The Normalizer2 class is not intended for public subclassing. + *

+ * The primary functions are to produce a normalized string and to detect whether + * a string is already normalized. + * The most commonly used normalization forms are those defined in + * Unicode Standard Annex #15: + * Unicode Normalization Forms. + * However, this API supports additional normalization forms for specialized purposes. + * For example, NFKC_Casefold is provided via getInstance("nfkc_cf", COMPOSE) + * and can be used in implementations of UTS #46. + *

+ * Not only are the standard compose and decompose modes supplied, + * but additional modes are provided as documented in the Mode enum. + *

+ * Some of the functions in this class identify normalization boundaries. + * At a normalization boundary, the portions of the string + * before it and starting from it do not interact and can be handled independently. + *

+ * The spanQuickCheckYes() stops at a normalization boundary. + * When the goal is a normalized string, then the text before the boundary + * can be copied, and the remainder can be processed with normalizeSecondAndAppend(). + *

+ * The hasBoundaryBefore(), hasBoundaryAfter() and isInert() functions test whether + * a character is guaranteed to be at a normalization boundary, + * regardless of context. + * This is used for moving from one normalization boundary to the next + * or preceding boundary, and for performing iterative normalization. + *

+ * Iterative normalization is useful when only a small portion of a + * longer string needs to be processed. + * For example, in ICU, iterative normalization is used by the NormalizationTransliterator + * (to avoid replacing already-normalized text) and ucol_nextSortKeyPart() + * (to process only the substring for which sort key bytes are computed). + *

+ * The set of normalization boundaries returned by these functions may not be + * complete: There may be more boundaries that could be returned. + * Different functions may return different boundaries. + * @stable ICU 4.4 + * @author Markus W. Scherer + */ +public abstract class Normalizer2 { + + /** + * Returns a Normalizer2 instance for Unicode NFC normalization. + * Same as getInstance(null, "nfc", Mode.COMPOSE). + * Returns an unmodifiable singleton instance. + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFCInstance() { + return Norm2AllModes.getNFCInstance().comp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFD normalization. + * Same as getInstance(null, "nfc", Mode.DECOMPOSE). + * Returns an unmodifiable singleton instance. + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFDInstance() { + return Norm2AllModes.getNFCInstance().decomp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFKC normalization. + * Same as getInstance(null, "nfkc", Mode.COMPOSE). + * Returns an unmodifiable singleton instance. + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFKCInstance() { + return Norm2AllModes.getNFKCInstance().comp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFKD normalization. + * Same as getInstance(null, "nfkc", Mode.DECOMPOSE). + * Returns an unmodifiable singleton instance. + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFKDInstance() { + return Norm2AllModes.getNFKCInstance().decomp; + } + + /** + * Returns the normalized form of the source string. + * @param src source string + * @return normalized src + * @stable ICU 4.4 + */ + public String normalize(CharSequence src) { + if(src instanceof String) { + // Fastpath: Do not construct a new String if the src is a String + // and is already normalized. + int spanLength=spanQuickCheckYes(src); + if(spanLength==src.length()) { + return (String)src; + } + if (spanLength != 0) { + StringBuilder sb=new StringBuilder(src.length()).append(src, 0, spanLength); + return normalizeSecondAndAppend(sb, src.subSequence(spanLength, src.length())).toString(); + } + } + return normalize(src, new StringBuilder(src.length())).toString(); + } + + /** + * Writes the normalized form of the source string to the destination string + * (replacing its contents) and returns the destination string. + * The source and destination strings must be different objects. + * @param src source string + * @param dest destination string; its contents is replaced with normalized src + * @return dest + * @stable ICU 4.4 + */ + public abstract StringBuilder normalize(CharSequence src, StringBuilder dest); + + /** + * Writes the normalized form of the source string to the destination Appendable + * and returns the destination Appendable. + * The source and destination strings must be different objects. + * + *

Any {@link java.io.IOException} is wrapped into a {@link com.ibm.icu.util.ICUUncheckedIOException}. + * + * @param src source string + * @param dest destination Appendable; gets normalized src appended + * @return dest + * @stable ICU 4.6 + */ + public abstract Appendable normalize(CharSequence src, Appendable dest); + + /** + * Appends the normalized form of the second string to the first string + * (merging them at the boundary) and returns the first string. + * The result is normalized if the first string was normalized. + * The first and second strings must be different objects. + * @param first string, should be normalized + * @param second string, will be normalized + * @return first + * @stable ICU 4.4 + */ + public abstract StringBuilder normalizeSecondAndAppend( + StringBuilder first, CharSequence second); + + /** + * Appends the second string to the first string + * (merging them at the boundary) and returns the first string. + * The result is normalized if both the strings were normalized. + * The first and second strings must be different objects. + * @param first string, should be normalized + * @param second string, should be normalized + * @return first + * @stable ICU 4.4 + */ + public abstract StringBuilder append(StringBuilder first, CharSequence second); + + /** + * Gets the decomposition mapping of c. + * Roughly equivalent to normalizing the String form of c + * on a DECOMPOSE Normalizer2 instance, but much faster, and except that this function + * returns null if c does not have a decomposition mapping in this instance's data. + * This function is independent of the mode of the Normalizer2. + * @param c code point + * @return c's decomposition mapping, if any; otherwise null + * @stable ICU 4.6 + */ + public abstract String getDecomposition(int c); + + /** + * Gets the combining class of c. + * The default implementation returns 0 + * but all standard implementations return the Unicode Canonical_Combining_Class value. + * @param c code point + * @return c's combining class + * @stable ICU 49 + */ + public int getCombiningClass(int c) { return 0; } + + /** + * Tests if the string is normalized. + * Internally, in cases where the quickCheck() method would return "maybe" + * (which is only possible for the two COMPOSE modes) this method + * resolves to "yes" or "no" to provide a definitive result, + * at the cost of doing more work in those cases. + * @param s input string + * @return true if s is normalized + * @stable ICU 4.4 + */ + public abstract boolean isNormalized(CharSequence s); + + /** + * Returns the end of the normalized substring of the input string. + * In other words, with end=spanQuickCheckYes(s); + * the substring s.subSequence(0, end) + * will pass the quick check with a "yes" result. + *

+ * The returned end index is usually one or more characters before the + * "no" or "maybe" character: The end index is at a normalization boundary. + * (See the class documentation for more about normalization boundaries.) + *

+ * When the goal is a normalized string and most input strings are expected + * to be normalized already, then call this method, + * and if it returns a prefix shorter than the input string, + * copy that prefix and use normalizeSecondAndAppend() for the remainder. + * @param s input string + * @return "yes" span end index + * @stable ICU 4.4 + */ + public abstract int spanQuickCheckYes(CharSequence s); + + /** + * Tests if the character always has a normalization boundary before it, + * regardless of context. + * If true, then the character does not normalization-interact with + * preceding characters. + * In other words, a string containing this character can be normalized + * by processing portions before this character and starting from this + * character independently. + * This is used for iterative normalization. See the class documentation for details. + * @param c character to test + * @return true if c has a normalization boundary before it + * @stable ICU 4.4 + */ + public abstract boolean hasBoundaryBefore(int c); + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + * @internal + * deprecated This API is ICU internal only. + */ + protected Normalizer2() { + } +} diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$1.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$1.class new file mode 100644 index 0000000000000000000000000000000000000000..0f54c051e183a075b8b7f5cbd59df67bbd6bfa93 GIT binary patch literal 848 zcma)4T~8B16g|@}-L@`LONAB`QC4h4Ss~FEjZwF3XlTnr4LtBP-A?F~W!KDZ(fD(G z@mWobF@_)Dk22ob)HGr=ZZ>o0+}ye6+>h@+zMcbcv0X$4SrdkZ8RQshBYwu6M7&9y zZlq3mAm0jQdvs;Uo$+8SVuqD^1HqQ?*c=@H91Ews1{jqwDRt+OcBc#xFaRS|HKbuD3hlt@c}(|qk&+UYs*k{$ESUvUh;lGo^m_#d2qm$)Og~Y z?Iqklp~g&bu@{Y%FFdJV%uidSTe+#(Df3R~2T?4;h( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$Mode.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$Mode.class new file mode 100644 index 0000000000000000000000000000000000000000..8f14d9562b1e42d83a62a4b93f066311f63bfc5b GIT binary patch literal 592 zcma)3O-lnY5PfOWuGVVnSGC>*5v$-rJt~4$#KKxZrT26@XzDgAyIB$cl_$Z2KfoU) zPO7j64>n=)n6Ec8na{8H4*(r(R8TT!Pmx8VpQboF!L=vTfY}4V-@KaN={WuTbJ>W1Y~CdwLlx{W#a)Qw`vfv zV=0J374=o3o&IZ-_Fks~d%@Hd4h1S_^q5enEDZ&k*O{?;Onsed<~=bcw#w?*Fl{5q zr^|DgVd0K!-hEqOd#Bs_w}-Z?eG_L%Naxy(w48IeAJ})*1ZH}a+KV`~9@Yf5rkPBj z+BJrfPNdS5xO3?~Q*OfJZMjo`bo)XPv#cFJ@C8b{ZxF8&cZFZKT8J{F@G!@E^(TmN qp0x!QpvF>WdmWGxi&)~EKOQc#%y9**V0D5GtTR?P&qD)EIr|OKgpOMP literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$ModeImpl.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$ModeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..d32695786002dcd89b5d3156efb6f46b152b206d GIT binary patch literal 571 zcma)3O-}+b5Pe-%7M2xI{KTWg07lnv)p(GENP>9Ka4$=vg{5nDi!uHr_2R*pc<=}K zql{DhNH}2+(|I$~>3cIDpKtE~n%Ht-A?3jKuz)l}ama7EA98i&pZA9%&x+2l1QKB7eFjVGAHQz9JZKXuq40)0WVwd?H z9S&&l7Ojlbn9)x?i*~k1kvyRmWli3#zk=0wU*J3wvQQwKM~dtNY&;^1Clm>-eOF_N d`kCXRL|tjgSRrI#l`71=j?HP7xR75)`3uX7jPd{g literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFC32ModeImpl.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFC32ModeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..254c9a76b3de0ca3b18062b44089dd94a07ea87b GIT binary patch literal 1085 zcma)5-*3`T6#fpdmDY|;rf#BcZn8-?M^O zHrvuwg!w}+@YEARvS2kdqzQZN)*IUklnevm+n(FAm3*&kryF*J?|qQrGZD%Bi*8F+ zJ8yjr2En?Ra^(5!MYcxNk^vJ78Zsspu|(Lom^eltWX_~=jw;n4QX+6AVXI)(F6EVV zWU;K_nu+VUK`36v7*zEt@LVqJphQSlo%+dBr}CVzIVIfCx-M1OfR5F;%Qp$fg(>!9 zWtFFxjJdQL1~lA?o!%yF&*Ic-=vc$LhP!dq8-&tKRdaU_O8+jDU{A?yl>Wp7lnJQ{ zH;u4Z^8)GgI!zg#h^Eh)Y_01Gzac^|mWRredhJDoN3(^QNRDHr4_$vavPQkz3th=$ z#-Wxc(<{cK&eo2M)Nwab8Xgexv$TU?R)au>6<*63pcvM`Yu_PO&3eszRg z+4QEFj_>gr9|J#-=hggcfGupZl*ax4b_TeMJ;ogCHSD6uyDX#4xW>4T F+#jtvBD4Si literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFCMode.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFCMode.class new file mode 100644 index 0000000000000000000000000000000000000000..6a857685aca39bf51dc25889553647b85d9a6a67 GIT binary patch literal 1074 zcmb7D%Wl(95IvJPag#c&Ng*vQkCuj#gf^~>5TGI?uv%d$^(IyKx5*W_b?nG?5Msf9 z@C9t4LPBD}2k=pdxo$!co20hnGc&$(=5c3!{r>S2fCEcMj!-}CpILsG$~Y8(<@ZKb zD&MD;7sUe+_#b5aN+hxj4Fw%V13Kmi%~^cvhf!Y=iqHMfPhSx7jplI)Wz6d^3{NJ5ww!b&{-(n}qGFco8%wYx!cw52ZI6oXGe{oCJIc)lSqC!Lf*arH_qT z`qobf?WuLB38;@#+aoNzk?G}la3{7JZgVP$&7OKRO#LY2pyU!N-Bk3>4#hCbN5_4_ z#NL@)m%w%9_PUjD^;BP;^xlo1Q?Yr!eUmYAh@28WXVlm|962 zxX0w1Y~}4X_jS~nVvE%r9-xsS?=NEu1tul5G_{n3hn$hgxXoB&++kc{Y-9Bg_#Y2f literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFCModeImpl.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFCModeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..f47f68d5dcea20a2d245fb8d86f5c2b8406a9d52 GIT binary patch literal 810 zcma)4+fLg+5IvIwY>WvsX(`Zh2@O$#)Ee;$sst9Oky7&jip1l_tYA}TUD+E{^{=Wv zK#Rl&@KK0yxIZOYX=mr`%$}Judvp8$8i0?QgBv`U@Yv7WT z0QWusAMlYq8;eiLHRKrqidV3XFEMd}>AxstuMnPJ`NvU9jODP5m4U6`6WbCa7AmMR KOPTE&7VZE-AI((& literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFD32ModeImpl.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFD32ModeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..76e93f4506d0faddfb52706c7f8ffd5f26dbd8bc GIT binary patch literal 1085 zcma)5-*3`T6#fpdwbYJHrf#B6H`%0{qm%hy!eXN6G7_v0Op-lb%FQg6V%m!_{#WV) z#w9+f5B^ccQ$&GeWVFfs?m72-=hr>=*YB_2095e6Kmth(DHC&;CoHwaJ7N1GIJI9k z+tO8p`2#QT)MG-jU^O)8gxz-QjqL?WhJo;H&+XYtzE`%>4Lid3KFIK?h-Cgnw?l z4z)a)UNIhZwsvHsj=GW3aG#K$r5yyb8U!+|_#%oVC#sKHlO7w8g^A3t$DL2`t0Uy% z-t#WOKR-LxY_McA664%e3#ew82FAnujXF^Y+{Qg9ryl|AMq~!R?ncFoFRSk z1(!bIavv*wh%L9*DsIAmf)JkwqBDnaEo(F-NG+;!{0|`jU`;=7+v|PRQ2kX9W~7Z^E)r!UDma ziN`yB_0-j5?ZGf0%(cDl=?kxQL~uGY5lnm!3$Ss=MA^a;?h^KISjE+6FaqbeJY8|o@O*ueiU+0Y7_(%wCy#wy*wRfRI?LvTcqe#7JejE1QKAS|I}Byq3Ph4fj%!>GW$FK!nsl8n z`JX%BjK>-du);f_pA5ge1t6@l<}eatuJIk&uj%hK{^qrjw()>v>-qp5;t^{G*0I4B z?c7hvfaNuN zvf#RyMuAWsmApkLoJivzd}`^$2pvd5wccot%-eQgVK!}Kj!>(Qk>qp4@LV3Q@!@aH2er=s&I!;60(BTMXgY>Dl}hbz$K@cK3H={0b{ zNq~DFfHzoS&&J#T$u(pd0SbR%eZNNj3Nyb^OkW{9y>iJ>?-=ANYe*QF!#rWJ?Ywg=-wDpF zSIxF?C1HNw3q1Lh5YL+p4N1aoyYfv|8Uq_$?q6NVZkcw>;qU904Fatxzl9w{PU)nnwNRv*II*t$i4}XEL z$~fbU5B>mul;hse$b%2WWF}|#CVS5AX7|_cA3p)uuyhm%&C}tTIGi%oKS4Fk1MERR)=9=4mHAd zE*^LPwY}X{Y|d!x6J{K@f3)k`djzYOiy@2MsldcF9d!c>xK7youV}(-@V6^n!upls zT^4Mpf)@!-a%rhrvut(T%$s5sM$qiE>+?M?knUu3BBLX5;`4u~_rihjk45Aue|o4T zZ@oBo8#9$1LhX%AE=Po$vC(qcIr>4+!*Sw;0jrWjnCmBEaCRuhX+k>g6V|S36suMH z;UpT!eNR=kaG8jj)vZ(UPVkhtGENS{I3XBL5Xi{(MI1}k)h-6J_Rm~pjpvB0)ak@! zE*@ivS3z9`zIhoySZ2>+B*s$bJBnY^*DL%it3!H*TWlK_AK*6bu&3cJR{2B)4^uK= zam8Hy_zA{2D&H{w8I^O~VB-saQiP(bD{XoKonFGET{PHM)D0%!@F}&j)^Lx>*ZGu} t+}zXAWQq-T3wVH5ioC{*9h8`q(9zUx5*~6!CgUT<2ID5<65|$@{{RK@5t9G_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKCModeImpl.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKCModeImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..1a9903867f9a2a6d361eb0652af5328d0dbc1403 GIT binary patch literal 814 zcma)4+fLg+5IvIwY+Q3`QrdEDQ$mzfYE9u0R0%8)5y3owBK2`&R;e!q2OW!qlBrB_%6Ii=o9at-I1Xo zjBY5c%x6NrR&QCb2_HJgUp=LbOtgqR74|$Me;6-_ldg!=Pnm3qR95!mW7+6_iySz3 zX2EqajtN3}Q1U8a@-zIniIiE+6L;KHS_ZvtTP8=M9WhdD#-WH> zB2k%t3l_|&N(pPj(L64bsqBp~y8TM$FzzLx+))`*>FLLP%tnBt1DTrLI5igD5h}yz zLU0>e%fydFno6$Ieh|rhTntuN^&Af%VK&p9PdQ#ZfsDLn&tpq$N8Vq6&idCgyl2T^R~0+zrX(gP{BhTF~l__49sDku-JA!IF|1Or`GFc zTey-if8Yh4d_sul&4z{~VXxhKXL*4XVc__d=k_cqK1$2(h8@TEK8f&|6N%ibZc9`< z?|ltA!MvDq==tnLv_{mT4g*&;qzx=!k+6O-ag0D%I2F=9eEGZ@MA8XdLDCHRw@#bRl9!t)ULcBY)lC^w5|(T){(-hYV%FPQGSa3 zSY72QCSxwmh7Jw4l+)XU?OB|fjTF{!SHnG3^*W(6Q`M@yrQ*LUC0J9E8|6PS17$*@ z!d>ILs(FF1d!42TkDaE^noOw->sC zCyiq*Pv%!p)6Ukmh~!Z>k{TWmaRUa7c5;T) z$v0g2f~7uI`pAC89p#Up{G}1+^(V7`VTCb{Jj*ed*csq1_87CQ*RYEM?=p-Q;~L{W GvVQ>0@*~gy literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKDMode.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$NFKDMode.class new file mode 100644 index 0000000000000000000000000000000000000000..b7173616a36b9d5e873c891cb8e4a7b05a0da505 GIT binary patch literal 1081 zcmb7D%Wl(95IvJPag(~KNg*vQkCuj#1X8!@vIq%6DFQgwfuT!CB1j_ezRSnwZw z0b8h$kXY~md=z4?8`A}g8e8(2x%QkhGoJbN`^QfJT{tFkg!qd@qMH=H_3 zzE_SLMq}Z7A7u1G#Ig(n1rtRJCgupuEHU+?a3l%Er(WQxXM}vCc~U|d^Cm0{3#btG zGV!>FuV3zUG+S>x@dN!J(qULf7+_*6#6;?(E=Q0<39;h%`e)Bfzx zP;b3Ba~o5YeM04pR97Ry&Dd)6ni={*FvE%R!hlt&M_3prF+4vKlO!P%4+$IBHHy{B zgK!!R<)No5Te?a_&+7J>cqe#DTp6oZVXO#NF9>AR^+g;@)-^5%v+~berH$u^wA9(e zr7m``!mFUK9N)YQAgr?IFcM>-^&R=I$?G+K7WE;uaffZ|@&nw(J@yRT$2yyQs0PscTHY;WKJ&ZQucuZ}KTG txqV=w&Jdk#p+M=4K!_3~Fl`?}NHi^K)YN?dMdEQ|RC4VH0A4ubGfB#a~i4i)Ggr!Qg(Km73frW{*lSx9kGC)GLIf4SFEWC6v zjTyp+ek8rt(%SyDN3iSu&hD09`%3Woaz2x0osg@sOx$rpY3X-6EgA2MR>(-c5d|V_ zidd!o1DG?1Dj|FtjOJ;XOl5Bb;lo!tJ5e_dqo-JaLZJrSe MMU6@0?@=t5jo^tI36Z2NvNM3pZY2?GLA&( ztM0%z@`v#Q9rr}2e#-cRNMvnSA4|gIdlf0OMaZw#4-1$=!9~%-19*g$OdZwhhiRS0 zb{N_M3855pI(uJ(&i?LpyY*#fzd?A{z6Y}wXx$%cYHYfgCcMrt|E4|Y1Up0hPBXp6 zOj|`V81#;0{8=1@e6iWK?uzhG#LC(ur(?b=mh5Ns{p*xX!t^(3ZfPaFT5Z+;TcyEF zSNDz55uZveLh(Qk;;#Itti-u-MLUrLe8jcv1w3I^9#7N!MU+#l;5lQN W{W(hw|W_iEW3g#%6|aQ=FMaP literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$Unicode32.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase$Unicode32.class new file mode 100644 index 0000000000000000000000000000000000000000..f0d6d0babdad2c283760c76d9f926e60727ee971 GIT binary patch literal 713 zcma)4U279T6g@XdyUBL7X=44TUu{hx=|i@(Z%q|6C>Fx{kQxy2VY0nVC*97%>_nvh zN(2iEqObla@oo(*f~7JrckY>U@40iBpTE9*1JK2qj{=GwN&#jtOQ??3dle?ijKWvL zF~^QDyQ7VEPYA_kYv7?wSRU^mh1xi_MkS$+C!ymHE_`itobGd8sv=m097oA;(=v8VM3$X>RqMPsi2M<9u@=K#4SSm z-vv=>k5!^i*gjJkH>R_0Z4%16QGf4g)O}7^y;_Y>>dGSt^F3`inj8<=?x|rSNUfK~ zDj6uN^Lz@H+@a108<%vxY^;vVwG$^(=ly;ipg zF@X^58pF1ms4Qa{vU2VUHpJ9|{1C!YZmXOMvgC^ha$B-cB1xQCKLvd}yS^iPehqw= zA|Uufz+K#vtc?5T#Z43i0jgi&y{T1BG4~nQKcSZQAzbwNA-o5I74Q(tXK@9OB>KXt JV+9Q?{RSOus!0F< literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase.class b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase.class new file mode 100644 index 0000000000000000000000000000000000000000..a16a4fdad8d70f345ed111dcfa6acb8e52560a5a GIT binary patch literal 9245 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/NormalizerBase.java b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase.java new file mode 100644 index 00000000..f2566d9d --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/text/NormalizerBase.java @@ -0,0 +1,784 @@ +/* + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2000-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package jdk.internal.icu.text; + +import jdk.internal.icu.impl.Norm2AllModes; + +import java.text.CharacterIterator; +import java.text.Normalizer; + +/** + * Unicode Normalization + * + *

Unicode normalization API

+ * + * normalize transforms Unicode text into an equivalent composed or + * decomposed form, allowing for easier sorting and searching of text. + * normalize supports the standard normalization forms described in + * + * Unicode Standard Annex #15 — Unicode Normalization Forms. + * + * Characters with accents or other adornments can be encoded in + * several different ways in Unicode. For example, take the character A-acute. + * In Unicode, this can be encoded as a single character (the + * "composed" form): + * + *
+ *      00C1    LATIN CAPITAL LETTER A WITH ACUTE
+ * 
+ * + * or as two separate characters (the "decomposed" form): + * + *
+ *      0041    LATIN CAPITAL LETTER A
+ *      0301    COMBINING ACUTE ACCENT
+ * 
+ * + * To a user of your program, however, both of these sequences should be + * treated as the same "user-level" character "A with acute accent". When you + * are searching or comparing text, you must ensure that these two sequences are + * treated equivalently. In addition, you must handle characters with more than + * one accent. Sometimes the order of a character's combining accents is + * significant, while in other cases accent sequences in different orders are + * really equivalent. + * + * Similarly, the string "ffi" can be encoded as three separate letters: + * + *
+ *      0066    LATIN SMALL LETTER F
+ *      0066    LATIN SMALL LETTER F
+ *      0069    LATIN SMALL LETTER I
+ * 
+ * + * or as the single character + * + *
+ *      FB03    LATIN SMALL LIGATURE FFI
+ * 
+ * + * The ffi ligature is not a distinct semantic character, and strictly speaking + * it shouldn't be in Unicode at all, but it was included for compatibility + * with existing character sets that already provided it. The Unicode standard + * identifies such characters by giving them "compatibility" decompositions + * into the corresponding semantic characters. When sorting and searching, you + * will often want to use these mappings. + * + * normalize helps solve these problems by transforming text into + * the canonical composed and decomposed forms as shown in the first example + * above. In addition, you can have it perform compatibility decompositions so + * that you can treat compatibility characters the same as their equivalents. + * Finally, normalize rearranges accents into the proper canonical + * order, so that you do not have to worry about accent rearrangement on your + * own. + * + * Form FCD, "Fast C or D", is also designed for collation. + * It allows to work on strings that are not necessarily normalized + * with an algorithm (like in collation) that works under "canonical closure", + * i.e., it treats precomposed characters and their decomposed equivalents the + * same. + * + * It is not a normalization form because it does not provide for uniqueness of + * representation. Multiple strings may be canonically equivalent (their NFDs + * are identical) and may all conform to FCD without being identical themselves. + * + * The form is defined such that the "raw decomposition", the recursive + * canonical decomposition of each character, results in a string that is + * canonically ordered. This means that precomposed characters are allowed for + * as long as their decompositions do not need canonical reordering. + * + * Its advantage for a process like collation is that all NFD and most NFC texts + * - and many unnormalized texts - already conform to FCD and do not need to be + * normalized (NFD) for such a process. The FCD quick check will return YES for + * most strings in practice. + * + * normalize(FCD) may be implemented with NFD. + * + * For more details on FCD see Unicode Technical Note #5 (Canonical Equivalence in Applications): + * http://www.unicode.org/notes/tn5/#FCD + * + * ICU collation performs either NFD or FCD normalization automatically if + * normalization is turned on for the collator object. Beyond collation and + * string search, normalized strings may be useful for string equivalence + * comparisons, transliteration/transcription, unique representations, etc. + * + * The W3C generally recommends to exchange texts in NFC. + * Note also that most legacy character encodings use only precomposed forms and + * often do not encode any combining marks by themselves. For conversion to such + * character encodings the Unicode text needs to be normalized to NFC. + * For more usage examples, see the Unicode Standard Annex. + * + * Note: The Normalizer class also provides API for iterative normalization. + * While the setIndex() and getIndex() refer to indices in the + * underlying Unicode input text, the next() and previous() methods + * iterate through characters in the normalized output. + * This means that there is not necessarily a one-to-one correspondence + * between characters returned by next() and previous() and the indices + * passed to and returned from setIndex() and getIndex(). + * It is for this reason that Normalizer does not implement the CharacterIterator interface. + * + * @stable ICU 2.8 + */ +// Original filename in ICU4J: Normalizer.java +public final class NormalizerBase implements Cloneable { + + // The input text and our position in it + private UCharacterIterator text; + private Normalizer2 norm2; + private Mode mode; + private int options; + + // The normalization buffer is the result of normalization + // of the source in [currentIndex..nextIndex] . + private int currentIndex; + private int nextIndex; + + // A buffer for holding intermediate results + private StringBuilder buffer; + private int bufferPos; + + // Helper classes to defer loading of normalization data. + private static final class ModeImpl { + private ModeImpl(Normalizer2 n2) { + normalizer2 = n2; + } + private final Normalizer2 normalizer2; + } + + private static final class NFDModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFDInstance()); + } + + private static final class NFKDModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFKDInstance()); + } + + private static final class NFCModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFCInstance()); + } + + private static final class NFKCModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFKCInstance()); + } + + private static final class Unicode32 { + private static final UnicodeSet INSTANCE = new UnicodeSet("[:age=3.2:]").freeze(); + } + + private static final class NFD32ModeImpl { + private static final ModeImpl INSTANCE = + new ModeImpl(new FilteredNormalizer2(Normalizer2.getNFDInstance(), + Unicode32.INSTANCE)); + } + + private static final class NFKD32ModeImpl { + private static final ModeImpl INSTANCE = + new ModeImpl(new FilteredNormalizer2(Normalizer2.getNFKDInstance(), + Unicode32.INSTANCE)); + } + + private static final class NFC32ModeImpl { + private static final ModeImpl INSTANCE = + new ModeImpl(new FilteredNormalizer2(Normalizer2.getNFCInstance(), + Unicode32.INSTANCE)); + } + + private static final class NFKC32ModeImpl { + private static final ModeImpl INSTANCE = + new ModeImpl(new FilteredNormalizer2(Normalizer2.getNFKCInstance(), + Unicode32.INSTANCE)); + } + + /** + * Options bit set value to select Unicode 3.2 normalization + * (except NormalizationCorrections). + * At most one Unicode version can be selected at a time. + * @stable ICU 2.6 + */ + public static final int UNICODE_3_2=0x20; + + public static final int UNICODE_3_2_0_ORIGINAL=UNICODE_3_2; + + /* + * Default option for the latest Unicode normalization. This option is + * provided mainly for testing. + * The value zero means that normalization is done with the fixes for + * - Corrigendum 4 (Five CJK Canonical Mapping Errors) + * - Corrigendum 5 (Normalization Idempotency) + */ + public static final int UNICODE_LATEST = 0x00; + + /** + * Constant indicating that the end of the iteration has been reached. + * This is guaranteed to have the same value as {@link UCharacterIterator#DONE}. + * @stable ICU 2.8 + */ + public static final int DONE = UCharacterIterator.DONE; + + /** + * Constants for normalization modes. + *

+ * The Mode class is not intended for public subclassing. + * Only the Mode constants provided by the Normalizer class should be used, + * and any fields or methods should not be called or overridden by users. + * @stable ICU 2.8 + */ + public abstract static class Mode { + + /** + * Sole constructor + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected Mode() { + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected abstract Normalizer2 getNormalizer2(int options); + } + + private static Mode toMode(Normalizer.Form form) { + switch (form) { + case NFC : + return NFC; + case NFD : + return NFD; + case NFKC : + return NFKC; + case NFKD : + return NFKD; + } + + throw new IllegalArgumentException("Unexpected normalization form: " + + form); + } + + private static final class NONEMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { return Norm2AllModes.NOOP_NORMALIZER2; } + } + + private static final class NFDMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options&UNICODE_3_2) != 0 ? + NFD32ModeImpl.INSTANCE.normalizer2 : + NFDModeImpl.INSTANCE.normalizer2; + } + } + + private static final class NFKDMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options&UNICODE_3_2) != 0 ? + NFKD32ModeImpl.INSTANCE.normalizer2 : + NFKDModeImpl.INSTANCE.normalizer2; + } + } + + private static final class NFCMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options&UNICODE_3_2) != 0 ? + NFC32ModeImpl.INSTANCE.normalizer2 : + NFCModeImpl.INSTANCE.normalizer2; + } + } + + private static final class NFKCMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options&UNICODE_3_2) != 0 ? + NFKC32ModeImpl.INSTANCE.normalizer2 : + NFKCModeImpl.INSTANCE.normalizer2; + } + } + + /** + * No decomposition/composition. + * @stable ICU 2.8 + */ + public static final Mode NONE = new NONEMode(); + + /** + * Canonical decomposition. + * @stable ICU 2.8 + */ + public static final Mode NFD = new NFDMode(); + + /** + * Compatibility decomposition. + * @stable ICU 2.8 + */ + public static final Mode NFKD = new NFKDMode(); + + /** + * Canonical decomposition followed by canonical composition. + * @stable ICU 2.8 + */ + public static final Mode NFC = new NFCMode(); + + public static final Mode NFKC =new NFKCMode(); + + //------------------------------------------------------------------------- + // Iterator constructors + //------------------------------------------------------------------------- + + /** + * Creates a new {@code NormalizerBase} object for iterating over the + * normalized form of a given string. + *

+ * The {@code options} parameter specifies which optional + * {@code NormalizerBase} features are to be enabled for this object. + *

+ * @param str The string to be normalized. The normalization + * will start at the beginning of the string. + * + * @param mode The normalization mode. + * + * @param opt Any optional features to be enabled. + * Currently the only available option is {@link #UNICODE_3_2}. + * If you want the default behavior corresponding to one of the + * standard Unicode Normalization Forms, use 0 for this argument. + * @stable ICU 2.6 + */ + public NormalizerBase(String str, Mode mode, int opt) { + this.text = UCharacterIterator.getInstance(str); + this.mode = mode; + this.options=opt; + norm2 = mode.getNormalizer2(opt); + buffer = new StringBuilder(); + } + + public NormalizerBase(String str, Mode mode) { + this(str, mode, 0); + } + + + /** + * Creates a new {@code NormalizerBase} object for iterating over the + * normalized form of the given text. + *

+ * @param iter The input text to be normalized. The normalization + * will start at the beginning of the string. + * + * @param mode The normalization mode. + * + * @param opt Any optional features to be enabled. + * Currently the only available option is {@link #UNICODE_3_2}. + * If you want the default behavior corresponding to one of the + * standard Unicode Normalization Forms, use 0 for this argument. + * @stable ICU 2.6 + */ + public NormalizerBase(CharacterIterator iter, Mode mode, int opt) { + this.text = UCharacterIterator.getInstance((CharacterIterator)iter.clone()); + this.mode = mode; + this.options = opt; + norm2 = mode.getNormalizer2(opt); + buffer = new StringBuilder(); + } + + public NormalizerBase(CharacterIterator iter, Mode mode) { + this(iter, mode, 0); + } + + /** + * Clones this {@code NormalizerBase} object. All properties of this + * object are duplicated in the new object, including the cloning of any + * {@link CharacterIterator} that was passed in to the constructor + * or to {@link #setText(CharacterIterator) setText}. + * However, the text storage underlying + * the {@code CharacterIterator} is not duplicated unless the + * iterator's {@code clone} method does so. + * @stable ICU 2.8 + */ + public Object clone() { + try { + NormalizerBase copy = (NormalizerBase) super.clone(); + copy.text = (UCharacterIterator) text.clone(); + copy.mode = mode; + copy.options = options; + copy.norm2 = norm2; + copy.buffer = new StringBuilder(buffer); + copy.bufferPos = bufferPos; + copy.currentIndex = currentIndex; + copy.nextIndex = nextIndex; + return copy; + } + catch (CloneNotSupportedException e) { + throw new InternalError(e.toString(), e); + } + } + + /** + * Normalizes a {@code String} using the given normalization operation. + *

+ * The {@code options} parameter specifies which optional + * {@code NormalizerBase} features are to be enabled for this operation. + * Currently the only available option is {@link #UNICODE_3_2}. + * If you want the default behavior corresponding to one of the standard + * Unicode Normalization Forms, use 0 for this argument. + *

+ * @param str the input string to be normalized. + * @param mode the normalization mode + * @param options the optional features to be enabled. + * @return String the normalized string + * @stable ICU 2.6 + */ + public static String normalize(String str, Mode mode, int options) { + return mode.getNormalizer2(options).normalize(str); + } + + public static String normalize(String str, Normalizer.Form form) { + return NormalizerBase.normalize(str, toMode(form), UNICODE_LATEST); + } + + public static String normalize(String str, Normalizer.Form form, int options) { + return NormalizerBase.normalize(str, toMode(form), options); + } + + /** + * Test if a string is in a given normalization form. + * This is semantically equivalent to source.equals(normalize(source, mode)). + * + * Unlike quickCheck(), this function returns a definitive result, + * never a "maybe". + * For NFD, NFKD, and FCD, both functions work exactly the same. + * For NFC and NFKC where quickCheck may return "maybe", this function will + * perform further tests to arrive at a true/false result. + * @param str the input string to be checked to see if it is + * normalized + * @param mode the normalization mode + * @param options Options for use with exclusion set and tailored Normalization + * The only option that is currently recognized is UNICODE_3_2 + * @see #isNormalized + * @stable ICU 2.6 + */ + public static boolean isNormalized(String str, Mode mode, int options) { + return mode.getNormalizer2(options).isNormalized(str); + } + + public static boolean isNormalized(String str, Normalizer.Form form) { + return NormalizerBase.isNormalized(str, toMode(form), UNICODE_LATEST); + } + + public static boolean isNormalized(String str, Normalizer.Form form, int options) { + return NormalizerBase.isNormalized(str, toMode(form), options); + } + + //------------------------------------------------------------------------- + // Iteration API + //------------------------------------------------------------------------- + + /** + * Return the current character in the normalized text. + * @return The codepoint as an int + * @stable ICU 2.8 + */ + public int current() { + if(bufferPos0 || previousNormalize()) { + int c=buffer.codePointBefore(bufferPos); + bufferPos-=Character.charCount(c); + return c; + } else { + return DONE; + } + } + + /** + * Reset the index to the beginning of the text. + * This is equivalent to setIndexOnly(startIndex)). + * @stable ICU 2.8 + */ + public void reset() { + text.setIndex(0); + currentIndex=nextIndex=0; + clearBuffer(); + } + + /** + * Set the iteration position in the input text that is being normalized, + * without any immediate normalization. + * After setIndexOnly(), getIndex() will return the same index that is + * specified here. + * + * @param index the desired index in the input text. + * @stable ICU 2.8 + */ + public void setIndexOnly(int index) { + text.setIndex(index); // validates index + currentIndex=nextIndex=index; + clearBuffer(); + } + + /** + * Set the iteration position in the input text that is being normalized + * and return the first normalized character at that position. + *

+ * Note: This method sets the position in the input text, + * while {@link #next} and {@link #previous} iterate through characters + * in the normalized output. This means that there is not + * necessarily a one-to-one correspondence between characters returned + * by {@code next} and {@code previous} and the indices passed to and + * returned from {@code setIndex} and {@link #getIndex}. + *

+ * @param index the desired index in the input text. + * + * @return the first normalized character that is the result of iterating + * forward starting at the given index. + * + * @throws IllegalArgumentException if the given index is less than + * {@link #getBeginIndex} or greater than {@link #getEndIndex}. + * deprecated ICU 3.2 + * @obsolete ICU 3.2 + */ + public int setIndex(int index) { + setIndexOnly(index); + return current(); + } + + /** + * Retrieve the index of the start of the input text. This is the begin + * index of the {@code CharacterIterator} or the start (i.e. 0) of the + * {@code String} over which this {@code NormalizerBase} is iterating + * @deprecated ICU 2.2. Use startIndex() instead. + * @return The codepoint as an int + * @see #startIndex + */ + @Deprecated + public int getBeginIndex() { + return 0; + } + + /** + * Retrieve the index of the end of the input text. This is the end index + * of the {@code CharacterIterator} or the length of the {@code String} + * over which this {@code NormalizerBase} is iterating + * @deprecated ICU 2.2. Use endIndex() instead. + * @return The codepoint as an int + * @see #endIndex + */ + @Deprecated + public int getEndIndex() { + return endIndex(); + } + + /** + * Retrieve the current iteration position in the input text that is + * being normalized. This method is useful in applications such as + * searching, where you need to be able to determine the position in + * the input text that corresponds to a given normalized output character. + *

+ * Note: This method sets the position in the input, while + * {@link #next} and {@link #previous} iterate through characters in the + * output. This means that there is not necessarily a one-to-one + * correspondence between characters returned by {@code next} and + * {@code previous} and the indices passed to and returned from + * {@code setIndex} and {@link #getIndex}. + * @return The current iteration position + * @stable ICU 2.8 + */ + public int getIndex() { + if(bufferPos + * Note:If the normalization mode is changed while iterating + * over a string, calls to {@link #next} and {@link #previous} may + * return previously buffers characters in the old normalization mode + * until the iteration is able to re-sync at the next base character. + * It is safest to call {@link #setText setText()}, {@link #first}, + * {@link #last}, etc. after calling {@code setMode}. + *

+ * @param newMode the new mode for this {@code NormalizerBase}. + * The supported modes are: + *

    + *
  • {@link #NFC} - Unicode canonical decompositiion + * followed by canonical composition. + *
  • {@link #NFKC} - Unicode compatibility decompositiion + * follwed by canonical composition. + *
  • {@link #NFD} - Unicode canonical decomposition + *
  • {@link #NFKD} - Unicode compatibility decomposition. + *
  • {@link #NONE} - Do nothing but return characters + * from the underlying input text. + *
+ * + * @see #getMode + * @stable ICU 2.8 + */ + public void setMode(Mode newMode) { + mode = newMode; + norm2 = mode.getNormalizer2(options); + } + + /** + * Return the basic operation performed by this {@code NormalizerBase} + * + * @see #setMode + * @stable ICU 2.8 + */ + public Mode getMode() { + return mode; + } + + /** + * Set the input text over which this {@code NormalizerBase} will iterate. + * The iteration position is set to the beginning of the input text. + * @param newText The new string to be normalized. + * @stable ICU 2.8 + */ + public void setText(String newText) { + UCharacterIterator newIter = UCharacterIterator.getInstance(newText); + if (newIter == null) { + throw new IllegalStateException("Could not create a new UCharacterIterator"); + } + text = newIter; + reset(); + } + + /** + * Set the input text over which this {@code NormalizerBase} will iterate. + * The iteration position is set to the beginning of the input text. + * @param newText The new string to be normalized. + * @stable ICU 2.8 + */ + public void setText(CharacterIterator newText) { + UCharacterIterator newIter = UCharacterIterator.getInstance(newText); + if (newIter == null) { + throw new IllegalStateException("Could not create a new UCharacterIterator"); + } + text = newIter; + currentIndex=nextIndex=0; + clearBuffer(); + } + + private void clearBuffer() { + buffer.setLength(0); + bufferPos=0; + } + + private boolean nextNormalize() { + clearBuffer(); + currentIndex=nextIndex; + text.setIndex(nextIndex); + // Skip at least one character so we make progress. + int c=text.nextCodePoint(); + if(c<0) { + return false; + } + StringBuilder segment=new StringBuilder().appendCodePoint(c); + while((c=text.nextCodePoint())>=0) { + if(norm2.hasBoundaryBefore(c)) { + text.moveCodePointIndex(-1); + break; + } + segment.appendCodePoint(c); + } + nextIndex=text.getIndex(); + norm2.normalize(segment, buffer); + return buffer.length()!=0; + } + + private boolean previousNormalize() { + clearBuffer(); + nextIndex=currentIndex; + text.setIndex(currentIndex); + StringBuilder segment=new StringBuilder(); + int c; + while((c=text.previousCodePoint())>=0) { + if(c<=0xffff) { + segment.insert(0, (char)c); + } else { + segment.insert(0, Character.toChars(c)); + } + if(norm2.hasBoundaryBefore(c)) { + break; + } + } + currentIndex=text.getIndex(); + norm2.normalize(segment, buffer); + bufferPos=buffer.length(); + return buffer.length()!=0; + } + +} diff --git a/tests/test_data/std/jdk/internal/icu/text/Replaceable.class b/tests/test_data/std/jdk/internal/icu/text/Replaceable.class new file mode 100644 index 0000000000000000000000000000000000000000..52332199127b353a61e44cd894361c097234d42e GIT binary patch literal 202 zcmYk0O$x#=5QSgb+SaPz72LHOa|Q_rSqTbmT*Wx_$55rF;@Mny01qWjUAdWg^B%l! z-k;|SfWj<6Ah2joXIZzNy4E;Z+g^Hlc)6vkGnUNJQG!Td-k7_Q&a|c692>G;Aa>N2 zz7h!YLi1@W)2-N#a$P8av?QAY|wW TF$Q>o^tZ>zI1!le3^4ry+Wjoh literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/Replaceable.java b/tests/test_data/std/jdk/internal/icu/text/Replaceable.java new file mode 100644 index 00000000..cf55270a --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/text/Replaceable.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk.internal.icu.text; + +/** + * Replaceable is an interface representing a + * string of characters that supports the replacement of a range of + * itself with a new string of characters. It is used by APIs that + * change a piece of text while retaining metadata. Metadata is data + * other than the Unicode characters returned by char32At(). One + * example of metadata is style attributes; another is an edit + * history, marking each character with an author and revision number. + * + *

An implicit aspect of the Replaceable API is that + * during a replace operation, new characters take on the metadata of + * the old characters. For example, if the string "the bold + * font" has range (4, 8) replaced with "strong", then it becomes "the + * strong font". + * + *

Replaceable specifies ranges using a start + * offset and a limit offset. The range of characters thus specified + * includes the characters at offset start..limit-1. That is, the + * start offset is inclusive, and the limit offset is exclusive. + * + *

Replaceable also includes API to access characters + * in the string: length(), charAt(), + * char32At(), and extractBetween(). + * + *

For a subclass to support metadata, typical behavior of + * replace() is the following: + *

    + *
  • Set the metadata of the new text to the metadata of the first + * character replaced
  • + *
  • If no characters are replaced, use the metadata of the + * previous character
  • + *
  • If there is no previous character (i.e. start == 0), use the + * following character
  • + *
  • If there is no following character (i.e. the replaceable was + * empty), use default metadata
  • + *
  • If the code point U+FFFF is seen, it should be interpreted as + * a special marker having no metadata
  • + *
+ * If this is not the behavior, the subclass should document any differences. + * + *

Copyright © IBM Corporation 1999. All rights reserved. + * + * @author Alan Liu + * @stable ICU 2.0 + */ +public interface Replaceable { + /** + * Returns the number of 16-bit code units in the text. + * @return number of 16-bit code units in text + * @stable ICU 2.0 + */ + int length(); + + /** + * Returns the 16-bit code unit at the given offset into the text. + * @param offset an integer between 0 and length()-1 + * inclusive + * @return 16-bit code unit of text at given offset + * @stable ICU 2.0 + */ + char charAt(int offset); + + /** + * Copies characters from this object into the destination + * character array. The first character to be copied is at index + * srcStart; the last character to be copied is at + * index srcLimit-1 (thus the total number of + * characters to be copied is srcLimit-srcStart). The + * characters are copied into the subarray of dst + * starting at index dstStart and ending at index + * dstStart + (srcLimit-srcStart) - 1. + * + * @param srcStart the beginning index to copy, inclusive; + * {@code 0 <= start <= limit}. + * @param srcLimit the ending index to copy, exclusive; + * {@code start <= limit <= length()}. + * @param dst the destination array. + * @param dstStart the start offset in the destination array. + * @stable ICU 2.0 + */ + void getChars(int srcStart, int srcLimit, char dst[], int dstStart); +} diff --git a/tests/test_data/std/jdk/internal/icu/text/ReplaceableString.class b/tests/test_data/std/jdk/internal/icu/text/ReplaceableString.class new file mode 100644 index 0000000000000000000000000000000000000000..ff068eb62524ec1a7e68e7bdcba993760da4da97 GIT binary patch literal 1071 zcmaiyUr*Ce7{;Ho6}HvF*pvxwD)^6W2vy>hLla$sHW?blEHQY~b!S^)bfjyI-^MTC zjfp~{i66iZWqeNCOu|gK=;{0K{Lb^f=luTj;}?J?wsfSB&OkFTgIR%v1N)TX{UR9cg!lGRE`hPS_JznqtNWH`K|O4P3z@ z+&e>&aK)QAhgklyZS$YvkC&w(YyhPl8%7aCuCvbs;%!y}>@lfv;#&^Aspg zPdS-Lt<8o?c+qWzBdYe zNA9?)tY$|0~<=v(raD!h;-7nwQ3~fFKt}FC*p)ms#>ZcI(pUAvlKSl04jIRu) z2mt1h=K7e04I;L2i(V<-gxk17kK1t<_lQ*JwFJGx8im#)^!k68FUWj}9IP`;eZtfu z!HUT@lrXpW7i4DZ-(Z}e_=R??ayE*;iAY9VlaTmEvCPN{Yo8>Va%zA11f}zU4`-z0 zCQ@>!qDF*JZ!ReplaceableString is an adapter class that implements the + * Replaceable API around an ordinary StringBuffer. + * + *

Note: This class does not support attributes and is not + * intended for general use. Most clients will need to implement + * {@link Replaceable} in their text representation class. + * + *

Copyright © IBM Corporation 1999. All rights reserved. + * + * @see Replaceable + * @author Alan Liu + * @stable ICU 2.0 + */ +public class ReplaceableString implements Replaceable { + + private StringBuffer buf; + + /** + * Construct a new object with the given initial contents. + * @param str initial contents + * @stable ICU 2.0 + */ + public ReplaceableString(String str) { + buf = new StringBuffer(str); + } + + /** + * Construct a new object using buf for internal + * storage. The contents of buf at the time of + * construction are used as the initial contents. Note! + * Modifications to buf will modify this object, and + * vice versa. + * @param buf object to be used as internal storage + * @stable ICU 2.0 + */ + public ReplaceableString(StringBuffer buf) { + this.buf = buf; + } + + /** + * Return the number of characters contained in this object. + * Replaceable API. + * @stable ICU 2.0 + */ + public int length() { + return buf.length(); + } + + /** + * Return the character at the given position in this object. + * Replaceable API. + * @param offset offset into the contents, from 0 to + * length() - 1 + * @stable ICU 2.0 + */ + public char charAt(int offset) { + return buf.charAt(offset); + } + + /** + * Copies characters from this object into the destination + * character array. The first character to be copied is at index + * srcStart; the last character to be copied is at + * index srcLimit-1 (thus the total number of + * characters to be copied is srcLimit-srcStart). The + * characters are copied into the subarray of dst + * starting at index dstStart and ending at index + * dstStart + (srcLimit-srcStart) - 1. + * + * @param srcStart the beginning index to copy, inclusive; + * {@code 0 <= start <= limit}. + * @param srcLimit the ending index to copy, exclusive; + * {@code start <= limit <= length()}. + * @param dst the destination array. + * @param dstStart the start offset in the destination array. + * @stable ICU 2.0 + */ + public void getChars(int srcStart, int srcLimit, char dst[], int dstStart) { + if (srcStart != srcLimit) { + buf.getChars(srcStart, srcLimit, dst, dstStart); + } + } +} diff --git a/tests/test_data/std/jdk/internal/icu/text/StringPrep$StringPrepTrieImpl.class b/tests/test_data/std/jdk/internal/icu/text/StringPrep$StringPrepTrieImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..c6edc906b31b829b91632037743fbcd25d948ca8 GIT binary patch literal 732 zcmah{-A)rh6#mY3>9%#DSOk@-py7gY!I~He3C5cmVv`Cc5bme#P^J#E&Fn1UA@J6x z@Wu;5;)M^uLmAI3HI3H9Y;?K5FLVlTo1q4jT&2W-3(PJ9qXjdLv=R}9X4bztA;cYHq-|@FWs;k3 zOe_8-Il?+&b*555?H%z8fAWTx{IUTE^ZW2#}%Ld0QXyO@r=dp(8{Ay literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/StringPrep$Values.class b/tests/test_data/std/jdk/internal/icu/text/StringPrep$Values.class new file mode 100644 index 0000000000000000000000000000000000000000..4c536e77dc44c17261dd6ec302e16635f2009222 GIT binary patch literal 589 zcma)3O-sW-5Ph4ZO^wmU`u$O@AZU9q-W4weu~4d@^x$pVF1j^tB-u*+Ssq02;1BS} zc=6*X&emeRDIxQiH~=0gskBHGk3!k*guZeW3afcvZmr68xS1pm8@>WDlp&qw+)Z~dY z`H*zNYK#J!{~4x|y!kJjHdb}-}`BGrd+s$Hxyl>X9Z@M}tm zq#E%wHOFVaUBC{VXp!$Wz2qN77#9XecN1Fl(2oGa3}qo9Bg|AD!0ra+S&F6%ykL%^ z|J{IjEKtU<`1A1rNtwQ&V&B6xVWMK)V``*RfJ60H8u$he@3hLtFU?@6X=91HEG%PX QfJLkkdZe905hW~r0gV52&;S4c literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/StringPrep.class b/tests/test_data/std/jdk/internal/icu/text/StringPrep.class new file mode 100644 index 0000000000000000000000000000000000000000..48a9a669c7eb66b7b715b2dd46b8730addd873be GIT binary patch literal 7637 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 H8_WI|kAPvw literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/StringPrep.java b/tests/test_data/std/jdk/internal/icu/text/StringPrep.java new file mode 100644 index 00000000..f05d0403 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/text/StringPrep.java @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* +/* + ******************************************************************************* + * Copyright (C) 2003-2004, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +// +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/text/StringPrep.java +// - move from package com.ibm.icu.text to package sun.net.idn +// - use ParseException instead of StringPrepParseException +// - change 'Normalizer.getUnicodeVersion()' to 'NormalizerImpl.getUnicodeVersion()' +// - remove all @deprecated tag to make compiler happy +// 2007-08-14 Martin Buchholz +// - remove redundant casts +// +package jdk.internal.icu.text; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.ParseException; + +import sun.text.Normalizer; +import jdk.internal.icu.impl.CharTrie; +import jdk.internal.icu.impl.StringPrepDataReader; +import jdk.internal.icu.impl.Trie; +import jdk.internal.icu.lang.UCharacter; +import jdk.internal.icu.lang.UCharacterDirection; +import jdk.internal.icu.util.VersionInfo; + +/** + * StringPrep API implements the StingPrep framework as described by + * RFC 3454. + * StringPrep prepares Unicode strings for use in network protocols. + * Profiles of StingPrep are set of rules and data according to which the + * Unicode Strings are prepared. Each profiles contains tables which describe + * how a code point should be treated. The tables are broadly classied into + *

    + *
  • Unassigned Table: Contains code points that are unassigned + * in the Unicode Version supported by StringPrep. Currently + * RFC 3454 supports Unicode 3.2.
  • + *
  • Prohibited Table: Contains code points that are prohibited from + * the output of the StringPrep processing function.
  • + *
  • Mapping Table: Contains code points that are deleted from the output or case mapped.
  • + *
+ * + * The procedure for preparing Unicode strings: + *
    + *
  1. Map: For each character in the input, check if it has a mapping + * and, if so, replace it with its mapping.
  2. + *
  3. Normalize: Possibly normalize the result of step 1 using Unicode + * normalization.
  4. + *
  5. Prohibit: Check for any characters that are not allowed in the + * output. If any are found, return an error.
  6. + *
  7. Check bidi: Possibly check for right-to-left characters, and if + * any are found, make sure that the whole string satisfies the + * requirements for bidirectional strings. If the string does not + * satisfy the requirements for bidirectional strings, return an + * error.
  8. + *
+ * @author Ram Viswanadha + * @draft ICU 2.8 + */ +public final class StringPrep { + /** + * Option to prohibit processing of unassigned code points in the input + * + * @see #prepare + * @draft ICU 2.8 + */ + public static final int DEFAULT = 0x0000; + + /** + * Option to allow processing of unassigned code points in the input + * + * @see #prepare + * @draft ICU 2.8 + */ + public static final int ALLOW_UNASSIGNED = 0x0001; + + private static final int UNASSIGNED = 0x0000; + private static final int MAP = 0x0001; + private static final int PROHIBITED = 0x0002; + private static final int DELETE = 0x0003; + private static final int TYPE_LIMIT = 0x0004; + + private static final int NORMALIZATION_ON = 0x0001; + private static final int CHECK_BIDI_ON = 0x0002; + + private static final int TYPE_THRESHOLD = 0xFFF0; + private static final int MAX_INDEX_VALUE = 0x3FBF; /*16139*/ + private static final int MAX_INDEX_TOP_LENGTH = 0x0003; + + /* indexes[] value names */ + private static final int INDEX_TRIE_SIZE = 0; /* number of bytes in normalization trie */ + private static final int INDEX_MAPPING_DATA_SIZE = 1; /* The array that contains the mapping */ + private static final int NORM_CORRECTNS_LAST_UNI_VERSION = 2; /* The index of Unicode version of last entry in NormalizationCorrections.txt */ + private static final int ONE_UCHAR_MAPPING_INDEX_START = 3; /* The starting index of 1 UChar mapping index in the mapping data array */ + private static final int TWO_UCHARS_MAPPING_INDEX_START = 4; /* The starting index of 2 UChars mapping index in the mapping data array */ + private static final int THREE_UCHARS_MAPPING_INDEX_START = 5; + private static final int FOUR_UCHARS_MAPPING_INDEX_START = 6; + private static final int OPTIONS = 7; /* Bit set of options to turn on in the profile */ + private static final int INDEX_TOP = 16; /* changing this requires a new formatVersion */ + + + /** + * Default buffer size of datafile + */ + private static final int DATA_BUFFER_SIZE = 25000; + + /* Wrappers for Trie implementations */ + private static final class StringPrepTrieImpl implements Trie.DataManipulate{ + private CharTrie sprepTrie = null; + /** + * Called by com.ibm.icu.util.Trie to extract from a lead surrogate's + * data the index array offset of the indexes for that lead surrogate. + * @param property data value for a surrogate from the trie, including + * the folding offset + * @return data offset or 0 if there is no data for the lead surrogate + */ + public int getFoldingOffset(int value){ + return value; + } + } + + // CharTrie implementation for reading the trie data + private StringPrepTrieImpl sprepTrieImpl; + // Indexes read from the data file + private int[] indexes; + // mapping data read from the data file + private char[] mappingData; + // format version of the data file + private byte[] formatVersion; + // the version of Unicode supported by the data file + private VersionInfo sprepUniVer; + // the Unicode version of last entry in the + // NormalizationCorrections.txt file if normalization + // is turned on + private VersionInfo normCorrVer; + // Option to turn on Normalization + private boolean doNFKC; + // Option to turn on checking for BiDi rules + private boolean checkBiDi; + + + private char getCodePointValue(int ch){ + return sprepTrieImpl.sprepTrie.getCodePointValue(ch); + } + + private static VersionInfo getVersionInfo(int comp){ + int micro = comp & 0xFF; + int milli =(comp >> 8) & 0xFF; + int minor =(comp >> 16) & 0xFF; + int major =(comp >> 24) & 0xFF; + return VersionInfo.getInstance(major,minor,milli,micro); + } + private static VersionInfo getVersionInfo(byte[] version){ + if(version.length != 4){ + return null; + } + return VersionInfo.getInstance((int)version[0],(int) version[1],(int) version[2],(int) version[3]); + } + /** + * Creates an StringPrep object after reading the input stream. + * The object does not hold a reference to the input steam, so the stream can be + * closed after the method returns. + * + * @param inputStream The stream for reading the StringPrep profile binarySun + * @throws IOException + * @draft ICU 2.8 + */ + public StringPrep(InputStream inputStream) throws IOException{ + + BufferedInputStream b = new BufferedInputStream(inputStream,DATA_BUFFER_SIZE); + + StringPrepDataReader reader = new StringPrepDataReader(b); + + // read the indexes + indexes = reader.readIndexes(INDEX_TOP); + + byte[] sprepBytes = new byte[indexes[INDEX_TRIE_SIZE]]; + + + //indexes[INDEX_MAPPING_DATA_SIZE] store the size of mappingData in bytes + mappingData = new char[indexes[INDEX_MAPPING_DATA_SIZE]/2]; + // load the rest of the data and initialize the data members + reader.read(sprepBytes,mappingData); + + sprepTrieImpl = new StringPrepTrieImpl(); + sprepTrieImpl.sprepTrie = new CharTrie( new ByteArrayInputStream(sprepBytes),sprepTrieImpl ); + + // get the data format version + formatVersion = reader.getDataFormatVersion(); + + // get the options + doNFKC = ((indexes[OPTIONS] & NORMALIZATION_ON) > 0); + checkBiDi = ((indexes[OPTIONS] & CHECK_BIDI_ON) > 0); + sprepUniVer = getVersionInfo(reader.getUnicodeVersion()); + normCorrVer = getVersionInfo(indexes[NORM_CORRECTNS_LAST_UNI_VERSION]); + VersionInfo normUniVer = UCharacter.getUnicodeVersion(); + if(normUniVer.compareTo(sprepUniVer) < 0 && /* the Unicode version of SPREP file must be less than the Unicode Version of the normalization data */ + normUniVer.compareTo(normCorrVer) < 0 && /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Version of the normalization data */ + ((indexes[OPTIONS] & NORMALIZATION_ON) > 0) /* normalization turned on*/ + ){ + throw new IOException("Normalization Correction version not supported"); + } + b.close(); + } + + private static final class Values{ + boolean isIndex; + int value; + int type; + public void reset(){ + isIndex = false; + value = 0; + type = -1; + } + } + + private static final void getValues(char trieWord,Values values){ + values.reset(); + if(trieWord == 0){ + /* + * Initial value stored in the mapping table + * just return TYPE_LIMIT .. so that + * the source codepoint is copied to the destination + */ + values.type = TYPE_LIMIT; + }else if(trieWord >= TYPE_THRESHOLD){ + values.type = (trieWord - TYPE_THRESHOLD); + }else{ + /* get the type */ + values.type = MAP; + /* ascertain if the value is index or delta */ + if((trieWord & 0x02)>0){ + values.isIndex = true; + values.value = trieWord >> 2; //mask off the lower 2 bits and shift + + }else{ + values.isIndex = false; + values.value = (trieWord<<16)>>16; + values.value = (values.value >> 2); + + } + + if((trieWord>>2) == MAX_INDEX_VALUE){ + values.type = DELETE; + values.isIndex = false; + values.value = 0; + } + } + } + + + + private StringBuffer map( UCharacterIterator iter, int options) + throws ParseException { + + Values val = new Values(); + char result = 0; + int ch = UCharacterIterator.DONE; + StringBuffer dest = new StringBuffer(); + boolean allowUnassigned = ((options & ALLOW_UNASSIGNED)>0); + + while((ch=iter.nextCodePoint())!= UCharacterIterator.DONE){ + + result = getCodePointValue(ch); + getValues(result,val); + + // check if the source codepoint is unassigned + if(val.type == UNASSIGNED && allowUnassigned == false){ + throw new ParseException("An unassigned code point was found in the input " + + iter.getText(), iter.getIndex()); + }else if((val.type == MAP)){ + int index, length; + + if(val.isIndex){ + index = val.value; + if(index >= indexes[ONE_UCHAR_MAPPING_INDEX_START] && + index < indexes[TWO_UCHARS_MAPPING_INDEX_START]){ + length = 1; + }else if(index >= indexes[TWO_UCHARS_MAPPING_INDEX_START] && + index < indexes[THREE_UCHARS_MAPPING_INDEX_START]){ + length = 2; + }else if(index >= indexes[THREE_UCHARS_MAPPING_INDEX_START] && + index < indexes[FOUR_UCHARS_MAPPING_INDEX_START]){ + length = 3; + }else{ + length = mappingData[index++]; + } + /* copy mapping to destination */ + dest.append(mappingData,index,length); + continue; + + }else{ + ch -= val.value; + } + }else if(val.type == DELETE){ + // just consume the codepoint and continue + continue; + } + //copy the source into destination + UTF16.append(dest,ch); + } + + return dest; + } + + + private StringBuffer normalize(StringBuffer src){ + /* + * Option UNORM_BEFORE_PRI_29: + * + * IDNA as interpreted by IETF members (see unicode mailing list 2004H1) + * requires strict adherence to Unicode 3.2 normalization, + * including buggy composition from before fixing Public Review Issue #29. + * Note that this results in some valid but nonsensical text to be + * either corrupted or rejected, depending on the text. + * See http://www.unicode.org/review/resolved-pri.html#pri29 + * See unorm.cpp and cnormtst.c + */ + return new StringBuffer( + Normalizer.normalize( + src.toString(), + java.text.Normalizer.Form.NFKC, + Normalizer.UNICODE_3_2)); + } + /* + boolean isLabelSeparator(int ch){ + int result = getCodePointValue(ch); + if( (result & 0x07) == LABEL_SEPARATOR){ + return true; + } + return false; + } + */ + /* + 1) Map -- For each character in the input, check if it has a mapping + and, if so, replace it with its mapping. + + 2) Normalize -- Possibly normalize the result of step 1 using Unicode + normalization. + + 3) Prohibit -- Check for any characters that are not allowed in the + output. If any are found, return an error. + + 4) Check bidi -- Possibly check for right-to-left characters, and if + any are found, make sure that the whole string satisfies the + requirements for bidirectional strings. If the string does not + satisfy the requirements for bidirectional strings, return an + error. + [Unicode3.2] defines several bidirectional categories; each character + has one bidirectional category assigned to it. For the purposes of + the requirements below, an "RandALCat character" is a character that + has Unicode bidirectional categories "R" or "AL"; an "LCat character" + is a character that has Unicode bidirectional category "L". Note + + + that there are many characters which fall in neither of the above + definitions; Latin digits ( through ) are examples of + this because they have bidirectional category "EN". + + In any profile that specifies bidirectional character handling, all + three of the following requirements MUST be met: + + 1) The characters in section 5.8 MUST be prohibited. + + 2) If a string contains any RandALCat character, the string MUST NOT + contain any LCat character. + + 3) If a string contains any RandALCat character, a RandALCat + character MUST be the first character of the string, and a + RandALCat character MUST be the last character of the string. + */ + /** + * Prepare the input buffer for use in applications with the given profile. This operation maps, normalizes(NFKC), + * checks for prohited and BiDi characters in the order defined by RFC 3454 + * depending on the options specified in the profile. + * + * @param src A UCharacterIterator object containing the source string + * @param options A bit set of options: + * + * - StringPrep.NONE Prohibit processing of unassigned code points in the input + * + * - StringPrep.ALLOW_UNASSIGNED Treat the unassigned code points are in the input + * as normal Unicode code points. + * + * @return StringBuffer A StringBuffer containing the output + * @throws ParseException + * @draft ICU 2.8 + */ + public StringBuffer prepare(UCharacterIterator src, int options) + throws ParseException{ + + // map + StringBuffer mapOut = map(src,options); + StringBuffer normOut = mapOut;// initialize + + if(doNFKC){ + // normalize + normOut = normalize(mapOut); + } + + int ch; + char result; + UCharacterIterator iter = UCharacterIterator.getInstance(normOut); + Values val = new Values(); + int direction=UCharacterDirection.CHAR_DIRECTION_COUNT, + firstCharDir=UCharacterDirection.CHAR_DIRECTION_COUNT; + int rtlPos=-1, ltrPos=-1; + boolean rightToLeft=false, leftToRight=false; + + while((ch=iter.nextCodePoint())!= UCharacterIterator.DONE){ + result = getCodePointValue(ch); + getValues(result,val); + + if(val.type == PROHIBITED ){ + throw new ParseException("A prohibited code point was found in the input" + + iter.getText(), val.value); + } + + direction = UCharacter.getDirection(ch); + if(firstCharDir == UCharacterDirection.CHAR_DIRECTION_COUNT){ + firstCharDir = direction; + } + if(direction == UCharacterDirection.LEFT_TO_RIGHT){ + leftToRight = true; + ltrPos = iter.getIndex()-1; + } + if(direction == UCharacterDirection.RIGHT_TO_LEFT || direction == UCharacterDirection.RIGHT_TO_LEFT_ARABIC){ + rightToLeft = true; + rtlPos = iter.getIndex()-1; + } + } + if(checkBiDi == true){ + // satisfy 2 + if( leftToRight == true && rightToLeft == true){ + throw new ParseException("The input does not conform to the rules for BiDi code points." + + iter.getText(), + (rtlPos>ltrPos) ? rtlPos : ltrPos); + } + + //satisfy 3 + if( rightToLeft == true && + !((firstCharDir == UCharacterDirection.RIGHT_TO_LEFT || firstCharDir == UCharacterDirection.RIGHT_TO_LEFT_ARABIC) && + (direction == UCharacterDirection.RIGHT_TO_LEFT || direction == UCharacterDirection.RIGHT_TO_LEFT_ARABIC)) + ){ + throw new ParseException("The input does not conform to the rules for BiDi code points." + + iter.getText(), + (rtlPos>ltrPos) ? rtlPos : ltrPos); + } + } + return normOut; + + } +} diff --git a/tests/test_data/std/jdk/internal/icu/text/UCharacterIterator.class b/tests/test_data/std/jdk/internal/icu/text/UCharacterIterator.class new file mode 100644 index 0000000000000000000000000000000000000000..6777fd3c41388722c0a6c663c732e367b384c53a GIT binary patch literal 2681 zcmbVOU2_vv7=BK^woR9h6k0w~w0udD7Q&ZkDIZEG8VxPBrL|PWZF1UfyWNeO4dOkw z-Y_HB@$=3bF7yT%i!hEeUib&}Z+PpB;&V1j5)wKNW@fXy?|IMjKIeU(_niIhpC2Cr z$ia;xgs_H)jwoURo0p7hM%FUyh3week}P@xu~VjPdS?W}sq~bF4uNA!rRA(?d(yQH zD{B_3S#zaqWyfXNGK$iev*hL6qTw1vdgOT-p2IjA;wng&Ku@aB2s7ciroAwno>Cqg zl*dMaWV^??>ioQP>8D|{z@cYTXbU^-8s)NN^iAki*johp18h%T_p)shd?G#Q)v!&+ zcI*&HwT1F$wl7g2ViVI(R6dR*`ZVm)@d94tg4O|blN?;YlK; z^64uIW4Dey3ShHYnRE@)s{6#T5BoK|q~icm&tmDo5`CCjwg*q&IGSJW(x| zEx96X&v0ptrgFJ7Y4;$bV?ZsuqwLCSrcSm{ z_L`2@72XDw>zq@PmmEq_Vdiw4S0jlhyz8SHE(q*xXwF~2Sk)VwKj&2KQf1_NQIAM?j?MVM+Rn6@0PuFOeyvNo~1;1msO%5Y8f9vCCuqFE8h z6xNYeyR-$m{N<>?MFu+4-etpFQEPLrBX^c8R&lDXLh5eHL(tFy=iA|*H1YEU+1`d7 zpa|suqm`d0%&uCPb#?_db#d{i|9^zloA8X{@w-pJ2>6R!Jp&Fi3KgCqU7!T!~f|(+LzYvlTXTz?{;hvfQ*Tz@9lU&!^>|IL->i_cZoHFuorRLY2D z!gn#)D!Sjv;*X|^#cKKBs(Bi5Rze*yL4}5yJC!pnGeD@rD)~*)6CFNGZ_Oo0E1fZq z1p+9*#Q|>}*wTdG8{ljFCNTs2 zB`gQ{pOS+jI+XkxJ-qfZ&RMD^c|$z@?(v_=FOi_-94(zUgisciYz-qb_wdFej=b5> z)lTLS;s7O_La)g1D`60W;vkNT!%cLC>dPI1Raa3Akw_xZMN&NRNJ#AfS-z=is2$+# b#!CI>6(^et5e*<$=p5k`n^&37A$;^NOL0VD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/UCharacterIterator.java b/tests/test_data/std/jdk/internal/icu/text/UCharacterIterator.java new file mode 100644 index 00000000..93978372 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/text/UCharacterIterator.java @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ + +package jdk.internal.icu.text; + +import jdk.internal.icu.impl.CharacterIteratorWrapper; +import jdk.internal.icu.impl.ReplaceableUCharacterIterator; +import jdk.internal.icu.impl.UCharacterProperty; + +import java.text.CharacterIterator; + +/** + * Abstract class that defines an API for iteration on text objects.This is an + * interface for forward and backward iteration and random access into a text + * object. Forward iteration is done with post-increment and backward iteration + * is done with pre-decrement semantics, while the + * java.text.CharacterIterator interface methods provided forward + * iteration with "pre-increment" and backward iteration with pre-decrement + * semantics. This API is more efficient for forward iteration over code points. + * The other major difference is that this API can do both code unit and code point + * iteration, java.text.CharacterIterator can only iterate over + * code units and is limited to BMP (0 - 0xFFFF) + * @author Ram + * @stable ICU 2.4 + */ +public abstract class UCharacterIterator + implements Cloneable { + + /** + * Protected default constructor for the subclasses + * @stable ICU 2.4 + */ + protected UCharacterIterator(){ + } + + /** + * Indicator that we have reached the ends of the UTF16 text. + * Moved from UForwardCharacterIterator.java + * @stable ICU 2.4 + */ + public static final int DONE = -1; + + // static final methods ---------------------------------------------------- + + /** + * Returns a UCharacterIterator object given a + * source string. + * @param source a string + * @return UCharacterIterator object + * @exception IllegalArgumentException if the argument is null + * @stable ICU 2.4 + */ + public static final UCharacterIterator getInstance(String source){ + return new ReplaceableUCharacterIterator(source); + } + + /** + * Returns a UCharacterIterator object given a + * source StringBuffer. + * @param source an string buffer of UTF-16 code units + * @return UCharacterIterator object + * @exception IllegalArgumentException if the argument is null + * @stable ICU 2.4 + */ + public static final UCharacterIterator getInstance(StringBuffer source){ + return new ReplaceableUCharacterIterator(source); + } + + /** + * Returns a UCharacterIterator object given a + * CharacterIterator. + * @param source a valid CharacterIterator object. + * @return UCharacterIterator object + * @exception IllegalArgumentException if the argument is null + * @stable ICU 2.4 + */ + public static final UCharacterIterator getInstance(CharacterIterator source){ + return new CharacterIteratorWrapper(source); + } + + // public methods ---------------------------------------------------------- + + /** + * Returns the length of the text + * @return length of the text + * @stable ICU 2.4 + */ + public abstract int getLength(); + + /** + * Gets the current index in text. + * @return current index in text. + * @stable ICU 2.4 + */ + public abstract int getIndex(); + + /** + * Returns the UTF16 code unit at index, and increments to the next + * code unit (post-increment semantics). If index is out of + * range, DONE is returned, and the iterator is reset to the limit + * of the text. + * @return the next UTF16 code unit, or DONE if the index is at the limit + * of the text. + * @stable ICU 2.4 + */ + public abstract int next(); + + /** + * Returns the code point at index, and increments to the next code + * point (post-increment semantics). If index does not point to a + * valid surrogate pair, the behavior is the same as + * next(). Otherwise the iterator is incremented past + * the surrogate pair, and the code point represented by the pair + * is returned. + * @return the next codepoint in text, or DONE if the index is at + * the limit of the text. + * @stable ICU 2.4 + */ + public int nextCodePoint(){ + int ch1 = next(); + if(UTF16.isLeadSurrogate(ch1)){ + int ch2 = next(); + if(UTF16.isTrailSurrogate(ch2)){ + return UCharacterProperty.getRawSupplementary((char)ch1, + (char)ch2); + }else if (ch2 != DONE) { + // unmatched surrogate so back out + previous(); + } + } + return ch1; + } + + /** + * Decrement to the position of the previous code unit in the + * text, and return it (pre-decrement semantics). If the + * resulting index is less than 0, the index is reset to 0 and + * DONE is returned. + * @return the previous code unit in the text, or DONE if the new + * index is before the start of the text. + * @stable ICU 2.4 + */ + public abstract int previous(); + + + /** + * Retreat to the start of the previous code point in the text, + * and return it (pre-decrement semantics). If the index is not + * preceded by a valid surrogate pair, the behavior is the same + * as previous(). Otherwise the iterator is + * decremented to the start of the surrogate pair, and the code + * point represented by the pair is returned. + * @return the previous code point in the text, or DONE if the new + * index is before the start of the text. + * @stable ICU 2.4 + */ + public int previousCodePoint(){ + int ch1 = previous(); + if(UTF16.isTrailSurrogate(ch1)){ + int ch2 = previous(); + if(UTF16.isLeadSurrogate(ch2)){ + return UCharacterProperty.getRawSupplementary((char)ch2, + (char)ch1); + }else if (ch2 != DONE) { + //unmatched trail surrogate so back out + next(); + } + } + return ch1; + } + + /** + * Sets the index to the specified index in the text. + * @param index the index within the text. + * @exception IndexOutOfBoundsException is thrown if an invalid index is + * supplied + * @stable ICU 2.4 + */ + public abstract void setIndex(int index); + + /** + * Sets the current index to the start. + * @stable ICU 2.4 + */ + public void setToStart() { + setIndex(0); + } + + /** + * Fills the buffer with the underlying text storage of the iterator + * If the buffer capacity is not enough a exception is thrown. The capacity + * of the fill in buffer should at least be equal to length of text in the + * iterator obtained by calling getLength(). + * Usage: + * + *
{@code
+     *         UChacterIterator iter = new UCharacterIterator.getInstance(text);
+     *         char[] buf = new char[iter.getLength()];
+     *         iter.getText(buf);
+     *
+     *         OR
+     *         char[] buf= new char[1];
+     *         int len = 0;
+     *         for(;;){
+     *             try{
+     *                 len = iter.getText(buf);
+     *                 break;
+     *             }catch(IndexOutOfBoundsException e){
+     *                 buf = new char[iter.getLength()];
+     *             }
+     *         }
+     * }
+ * + * @param fillIn an array of chars to fill with the underlying UTF-16 code + * units. + * @param offset the position within the array to start putting the data. + * @return the number of code units added to fillIn, as a convenience + * @exception IndexOutOfBoundsException exception if there is not enough + * room after offset in the array, or if offset < 0. + * @stable ICU 2.4 + */ + public abstract int getText(char[] fillIn, int offset); + + /** + * Convenience override for getText(char[], int) that provides + * an offset of 0. + * @param fillIn an array of chars to fill with the underlying UTF-16 code + * units. + * @return the number of code units added to fillIn, as a convenience + * @exception IndexOutOfBoundsException exception if there is not enough + * room in the array. + * @stable ICU 2.4 + */ + public final int getText(char[] fillIn) { + return getText(fillIn, 0); + } + + /** + * Convenience method for returning the underlying text storage as a string + * @return the underlying text storage in the iterator as a string + * @stable ICU 2.4 + */ + public String getText() { + char[] text = new char[getLength()]; + getText(text); + return new String(text); + } + + /** + * Moves the current position by the number of code points + * specified, either forward or backward depending on the sign of + * delta (positive or negative respectively). If the current index + * is at a trail surrogate then the first adjustment is by code + * unit, and the remaining adjustments are by code points. If the + * resulting index would be less than zero, the index is set to + * zero, and if the resulting index would be greater than limit, + * the index is set to limit. + * @param delta the number of code units to move the current index. + * @return the new index + * @exception IndexOutOfBoundsException is thrown if an invalid delta is + * supplied + * @stable ICU 2.4 + * + */ + public int moveCodePointIndex(int delta){ + if(delta>0){ + while(delta>0 && nextCodePoint() != DONE){delta--;} + }else{ + while(delta<0 && previousCodePoint() != DONE){delta++;} + } + if(delta!=0){ + throw new IndexOutOfBoundsException(); + } + + return getIndex(); + } + + /** + * Creates a copy of this iterator, independent from other iterators. + * If it is not possible to clone the iterator, returns null. + * @return copy of this iterator + * @stable ICU 2.4 + */ + public Object clone() throws CloneNotSupportedException{ + return super.clone(); + } + +} diff --git a/tests/test_data/std/jdk/internal/icu/text/UTF16.class b/tests/test_data/std/jdk/internal/icu/text/UTF16.class new file mode 100644 index 0000000000000000000000000000000000000000..3cc2a28478c83d681097652413845111cb28bb05 GIT binary patch literal 5220 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/UTF16.java b/tests/test_data/std/jdk/internal/icu/text/UTF16.java new file mode 100644 index 00000000..e84e1d4c --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/text/UTF16.java @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk.internal.icu.text; + +import jdk.internal.icu.impl.UCharacterProperty; + +/** + *

Standalone utility class providing UTF16 character conversions and + * indexing conversions. + *

Code that uses strings alone rarely need modification. + * By design, UTF-16 does not allow overlap, so searching for strings is a safe + * operation. Similarly, concatenation is always safe. Substringing is safe if + * the start and end are both on UTF-32 boundaries. In normal code, the values + * for start and end are on those boundaries, since they arose from operations + * like searching. If not, the nearest UTF-32 boundaries can be determined + * using bounds(). + * Examples: + *

The following examples illustrate use of some of these methods. + *

{@code
+ * // iteration forwards: Original
+ * for (int i = 0; i < s.length(); ++i) {
+ *     char ch = s.charAt(i);
+ *     doSomethingWith(ch);
+ * }
+ *
+ * // iteration forwards: Changes for UTF-32
+ * int ch;
+ * for (int i = 0; i < s.length(); i += UTF16.getCharCount(ch)) {
+ *     ch = UTF16.charAt(s, i);
+ *     doSomethingWith(ch);
+ * }
+ *
+ * // iteration backwards: Original
+ * for (int i = s.length() - 1; i >= 0; --i) {
+ *     char ch = s.charAt(i);
+ *     doSomethingWith(ch);
+ * }
+ *
+ * // iteration backwards: Changes for UTF-32
+ * int ch;
+ * for (int i = s.length() - 1; i > 0; i -= UTF16.getCharCount(ch)) {
+ *     ch = UTF16.charAt(s, i);
+ *     doSomethingWith(ch);
+ * }
+ * }
+ * Notes: + *
    + *
  • + * Naming: For clarity, High and Low surrogates are called + * Lead and Trail in the API, which gives a better + * sense of their ordering in a string. offset16 and + * offset32 are used to distinguish offsets to UTF-16 + * boundaries vs offsets to UTF-32 boundaries. int char32 is + * used to contain UTF-32 characters, as opposed to char16, + * which is a UTF-16 code unit. + *
  • + *
  • + * Roundtripping Offsets: You can always roundtrip from a + * UTF-32 offset to a UTF-16 offset and back. Because of the difference in + * structure, you can roundtrip from a UTF-16 offset to a UTF-32 offset and + * back if and only if bounds(string, offset16) != TRAIL. + *
  • + *
  • + * Exceptions: The error checking will throw an exception + * if indices are out of bounds. Other than that, all methods will + * behave reasonably, even if unmatched surrogates or out-of-bounds UTF-32 + * values are present. UCharacter.isLegal() can be used to check + * for validity if desired. + *
  • + *
  • + * Unmatched Surrogates: If the string contains unmatched + * surrogates, then these are counted as one UTF-32 value. This matches + * their iteration behavior, which is vital. It also matches common display + * practice as missing glyphs (see the Unicode Standard Section 5.4, 5.5). + *
  • + *
  • + * Optimization: The method implementations may need + * optimization if the compiler doesn't fold static final methods. Since + * surrogate pairs will form an exceeding small percentage of all the text + * in the world, the singleton case should always be optimized for. + *
  • + *
+ * @author Mark Davis, with help from Markus Scherer + * @stable ICU 2.1 + */ + +public final class UTF16 +{ + // public variables --------------------------------------------------- + + /** + * The lowest Unicode code point value. + * @stable ICU 2.1 + */ + public static final int CODEPOINT_MIN_VALUE = 0; + /** + * The highest Unicode code point value (scalar value) according to the + * Unicode Standard. + * @stable ICU 2.1 + */ + public static final int CODEPOINT_MAX_VALUE = 0x10ffff; + /** + * The minimum value for Supplementary code points + * @stable ICU 2.1 + */ + public static final int SUPPLEMENTARY_MIN_VALUE = 0x10000; + /** + * Lead surrogate minimum value + * @stable ICU 2.1 + */ + public static final int LEAD_SURROGATE_MIN_VALUE = 0xD800; + /** + * Trail surrogate minimum value + * @stable ICU 2.1 + */ + public static final int TRAIL_SURROGATE_MIN_VALUE = 0xDC00; + /** + * Lead surrogate maximum value + * @stable ICU 2.1 + */ + public static final int LEAD_SURROGATE_MAX_VALUE = 0xDBFF; + /** + * Trail surrogate maximum value + * @stable ICU 2.1 + */ + public static final int TRAIL_SURROGATE_MAX_VALUE = 0xDFFF; + /** + * Surrogate minimum value + * @stable ICU 2.1 + */ + public static final int SURROGATE_MIN_VALUE = LEAD_SURROGATE_MIN_VALUE; + /** + * Lead surrogate bitmask + */ + private static final int LEAD_SURROGATE_BITMASK = 0xFFFFFC00; + /** + * Trail surrogate bitmask + */ + private static final int TRAIL_SURROGATE_BITMASK = 0xFFFFFC00; + /** + * Surrogate bitmask + */ + private static final int SURROGATE_BITMASK = 0xFFFFF800; + /** + * Lead surrogate bits + */ + private static final int LEAD_SURROGATE_BITS = 0xD800; + /** + * Trail surrogate bits + */ + private static final int TRAIL_SURROGATE_BITS = 0xDC00; + /** + * Surrogate bits + */ + private static final int SURROGATE_BITS = 0xD800; + + // constructor -------------------------------------------------------- + + // /CLOVER:OFF + /** + * Prevent instance from being created. + */ + private UTF16() { + } + + // /CLOVER:ON + // public method ------------------------------------------------------ + + /** + * Extract a single UTF-32 value from a string. + * Used when iterating forwards or backwards (with + * UTF16.getCharCount(), as well as random access. If a + * validity check is required, use + * + * UCharacter.isLegal() on the return value. + * If the char retrieved is part of a surrogate pair, its supplementary + * character will be returned. If a complete supplementary character is + * not found the incomplete character will be returned + * @param source array of UTF-16 chars + * @param offset16 UTF-16 offset to the start of the character. + * @return UTF-32 value for the UTF-32 value that contains the char at + * offset16. The boundaries of that codepoint are the same as in + * bounds32(). + * @exception IndexOutOfBoundsException thrown if offset16 is out of + * bounds. + * @stable ICU 2.1 + */ + public static int charAt(String source, int offset16) { + char single = source.charAt(offset16); + if (single < LEAD_SURROGATE_MIN_VALUE) { + return single; + } + return _charAt(source, offset16, single); + } + + private static int _charAt(String source, int offset16, char single) { + if (single > TRAIL_SURROGATE_MAX_VALUE) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + + if (single <= LEAD_SURROGATE_MAX_VALUE) { + ++offset16; + if (source.length() != offset16) { + char trail = source.charAt(offset16); + if (trail >= TRAIL_SURROGATE_MIN_VALUE && trail <= TRAIL_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } + } else { + --offset16; + if (offset16 >= 0) { + // single is a trail surrogate so + char lead = source.charAt(offset16); + if (lead >= LEAD_SURROGATE_MIN_VALUE && lead <= LEAD_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(lead, single); + } + } + } + return single; // return unmatched surrogate + } + + /** + * Extract a single UTF-32 value from a string. + * Used when iterating forwards or backwards (with + * UTF16.getCharCount(), as well as random access. If a + * validity check is required, use + * UCharacter.isLegal() + * on the return value. + * If the char retrieved is part of a surrogate pair, its supplementary + * character will be returned. If a complete supplementary character is + * not found the incomplete character will be returned + * @param source array of UTF-16 chars + * @param offset16 UTF-16 offset to the start of the character. + * @return UTF-32 value for the UTF-32 value that contains the char at + * offset16. The boundaries of that codepoint are the same as in + * bounds32(). + * @exception IndexOutOfBoundsException thrown if offset16 is out of bounds. + * @stable ICU 2.1 + */ + public static int charAt(CharSequence source, int offset16) { + char single = source.charAt(offset16); + if (single < UTF16.LEAD_SURROGATE_MIN_VALUE) { + return single; + } + return _charAt(source, offset16, single); + } + + private static int _charAt(CharSequence source, int offset16, char single) { + if (single > UTF16.TRAIL_SURROGATE_MAX_VALUE) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + + if (single <= UTF16.LEAD_SURROGATE_MAX_VALUE) { + ++offset16; + if (source.length() != offset16) { + char trail = source.charAt(offset16); + if (trail >= UTF16.TRAIL_SURROGATE_MIN_VALUE + && trail <= UTF16.TRAIL_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } + } else { + --offset16; + if (offset16 >= 0) { + // single is a trail surrogate so + char lead = source.charAt(offset16); + if (lead >= UTF16.LEAD_SURROGATE_MIN_VALUE + && lead <= UTF16.LEAD_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(lead, single); + } + } + } + return single; // return unmatched surrogate + } + + /** + * Extract a single UTF-32 value from a substring. Used when iterating forwards or backwards + * (with UTF16.getCharCount(), as well as random access. If a validity check is + * required, use UCharacter.isLegal() + * + * on the return value. If the char retrieved is part of a surrogate pair, its supplementary + * character will be returned. If a complete supplementary character is not found the incomplete + * character will be returned + * + * @param source Array of UTF-16 chars + * @param start Offset to substring in the source array for analyzing + * @param limit Offset to substring in the source array for analyzing + * @param offset16 UTF-16 offset relative to start + * @return UTF-32 value for the UTF-32 value that contains the char at offset16. The boundaries + * of that codepoint are the same as in bounds32(). + * @exception IndexOutOfBoundsException Thrown if offset16 is not within the range of start and limit. + * @stable ICU 2.1 + */ + public static int charAt(char source[], int start, int limit, int offset16) { + offset16 += start; + if (offset16 < start || offset16 >= limit) { + throw new ArrayIndexOutOfBoundsException(offset16); + } + + char single = source[offset16]; + if (!isSurrogate(single)) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + if (single <= LEAD_SURROGATE_MAX_VALUE) { + offset16++; + if (offset16 >= limit) { + return single; + } + char trail = source[offset16]; + if (isTrailSurrogate(trail)) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } + else { // isTrailSurrogate(single), so + if (offset16 == start) { + return single; + } + offset16--; + char lead = source[offset16]; + if (isLeadSurrogate(lead)) + return UCharacterProperty.getRawSupplementary(lead, single); + } + return single; // return unmatched surrogate + } + + /** + * Determines how many chars this char32 requires. + * If a validity check is required, use + * isLegal() on + * char32 before calling. + * @param char32 the input codepoint. + * @return 2 if is in supplementary space, otherwise 1. + * @stable ICU 2.1 + */ + public static int getCharCount(int char32) + { + if (char32 < SUPPLEMENTARY_MIN_VALUE) { + return 1; + } + return 2; + } + + /** + * Determines whether the code point is a surrogate. + * + * @param codePoint The input character. + * (In ICU 2.1-69 the type of this parameter was char.) + * @return true If the input code point is a surrogate. + * @stable ICU 70 + */ + public static boolean isSurrogate(int codePoint) { + return (codePoint & SURROGATE_BITMASK) == SURROGATE_BITS; + } + + /** + * Determines whether the code point is a trail surrogate. + * + * @param codePoint The input character. + * (In ICU 2.1-69 the type of this parameter was char.) + * @return true If the input code point is a trail surrogate. + * @stable ICU 70 + */ + public static boolean isTrailSurrogate(int codePoint) { + return (codePoint & TRAIL_SURROGATE_BITMASK) == TRAIL_SURROGATE_BITS; + } + + /** + * Determines whether the code point is a lead surrogate. + * + * @param codePoint The input character. + * (In ICU 2.1-69 the type of this parameter was char.) + * @return true If the input code point is a lead surrogate + * @stable ICU 70 + */ + public static boolean isLeadSurrogate(int codePoint) { + return (codePoint & LEAD_SURROGATE_BITMASK) == LEAD_SURROGATE_BITS; + } + + /** + * Returns the lead surrogate. + * If a validity check is required, use + * isLegal() + * on char32 before calling. + * @param char32 the input character. + * @return lead surrogate if the getCharCount(ch) is 2;
+ * and 0 otherwise (note: 0 is not a valid lead surrogate). + * @stable ICU 2.1 + */ + public static char getLeadSurrogate(int char32) + { + if (char32 >= SUPPLEMENTARY_MIN_VALUE) { + return (char)(LEAD_SURROGATE_OFFSET_ + + (char32 >> LEAD_SURROGATE_SHIFT_)); + } + + return 0; + } + + /** + * Returns the trail surrogate. + * If a validity check is required, use + * isLegal() + * on char32 before calling. + * @param char32 the input character. + * @return the trail surrogate if the getCharCount(ch) is 2;
otherwise + * the character itself + * @stable ICU 2.1 + */ + public static char getTrailSurrogate(int char32) + { + if (char32 >= SUPPLEMENTARY_MIN_VALUE) { + return (char)(TRAIL_SURROGATE_MIN_VALUE + + (char32 & TRAIL_SURROGATE_MASK_)); + } + + return (char) char32; + } + + /** + * Convenience method corresponding to String.valueOf(char). Returns a one + * or two char string containing the UTF-32 value in UTF16 format. If a + * validity check is required, use + * isLegal() + * on char32 before calling. + * @param char32 the input character. + * @return string value of char32 in UTF16 format + * @exception IllegalArgumentException thrown if char32 is a invalid + * codepoint. + * @stable ICU 2.1 + */ + public static String valueOf(int char32) + { + if (char32 < CODEPOINT_MIN_VALUE || char32 > CODEPOINT_MAX_VALUE) { + throw new IllegalArgumentException("Illegal codepoint"); + } + return toString(char32); + } + + /** + * Append a single UTF-32 value to the end of a StringBuffer. + * If a validity check is required, use + * isLegal() + * on char32 before calling. + * @param target the buffer to append to + * @param char32 value to append. + * @return the updated StringBuffer + * @exception IllegalArgumentException thrown when char32 does not lie + * within the range of the Unicode codepoints + * @stable ICU 2.1 + */ + public static StringBuffer append(StringBuffer target, int char32) + { + // Check for irregular values + if (char32 < CODEPOINT_MIN_VALUE || char32 > CODEPOINT_MAX_VALUE) { + throw new IllegalArgumentException("Illegal codepoint: " + Integer.toHexString(char32)); + } + + // Write the UTF-16 values + if (char32 >= SUPPLEMENTARY_MIN_VALUE) + { + target.append(getLeadSurrogate(char32)); + target.append(getTrailSurrogate(char32)); + } + else { + target.append((char) char32); + } + return target; + } + + /** + * Shifts offset16 by the argument number of codepoints within a subarray. + * @param source char array + * @param start position of the subarray to be performed on + * @param limit position of the subarray to be performed on + * @param offset16 UTF16 position to shift relative to start + * @param shift32 number of codepoints to shift + * @return new shifted offset16 relative to start + * @exception IndexOutOfBoundsException if the new offset16 is out of + * bounds with respect to the subarray or the subarray bounds + * are out of range. + * @stable ICU 2.1 + */ + public static int moveCodePointOffset(char source[], int start, int limit, + int offset16, int shift32) + { + int size = source.length; + int count; + char ch; + int result = offset16 + start; + if (start < 0 || limit < start) { + throw new StringIndexOutOfBoundsException(start); + } + if (limit > size) { + throw new StringIndexOutOfBoundsException(limit); + } + if (offset16 < 0 || result > limit) { + throw new StringIndexOutOfBoundsException(offset16); + } + if (shift32 > 0) { + if (shift32 + result > size) { + throw new StringIndexOutOfBoundsException(result); + } + count = shift32; + while (result < limit && count > 0) + { + ch = source[result]; + if (isLeadSurrogate(ch) && (result + 1 < limit) && + isTrailSurrogate(source[result + 1])) { + result++; + } + count--; + result++; + } + } else { + if (result + shift32 < start) { + throw new StringIndexOutOfBoundsException(result); + } + for (count = -shift32; count > 0; count--) { + result--; + if (result < start) { + break; + } + ch = source[result]; + if (isTrailSurrogate(ch) && result > start && isLeadSurrogate(source[result - 1])) { + result--; + } + } + } + if (count != 0) { + throw new StringIndexOutOfBoundsException(shift32); + } + result -= start; + return result; + } + + // private data members ------------------------------------------------- + + /** + * Shift value for lead surrogate to form a supplementary character. + */ + private static final int LEAD_SURROGATE_SHIFT_ = 10; + + /** + * Mask to retrieve the significant value from a trail surrogate. + */ + private static final int TRAIL_SURROGATE_MASK_ = 0x3FF; + + /** + * Value that all lead surrogate starts with + */ + private static final int LEAD_SURROGATE_OFFSET_ = + LEAD_SURROGATE_MIN_VALUE - + (SUPPLEMENTARY_MIN_VALUE + >> LEAD_SURROGATE_SHIFT_); + + // private methods ------------------------------------------------------ + + /** + *

Converts argument code point and returns a String object representing + * the code point's value in UTF16 format. + *

This method does not check for the validity of the codepoint, the + * results are not guaranteed if a invalid codepoint is passed as + * argument. + *

The result is a string whose length is 1 for non-supplementary code + * points, 2 otherwise. + * @param ch code point + * @return string representation of the code point + */ + private static String toString(int ch) + { + if (ch < SUPPLEMENTARY_MIN_VALUE) { + return String.valueOf((char) ch); + } + + StringBuilder result = new StringBuilder(); + result.append(getLeadSurrogate(ch)); + result.append(getTrailSurrogate(ch)); + return result.toString(); + } +} diff --git a/tests/test_data/std/jdk/internal/icu/text/UnicodeSet$Filter.class b/tests/test_data/std/jdk/internal/icu/text/UnicodeSet$Filter.class new file mode 100644 index 0000000000000000000000000000000000000000..a420eda40a5cac39e3db7fbbfe8b5153c7f79600 GIT binary patch literal 253 zcmah^OAY}+5Pdb6VSJBZA;Cr;LLz3vLTv0>t4NPYPcq%a*(@Bup+sR}X;Uxtd7pYb zZ+8H5^b$mbaeg={>jGC!7s{Hm3VaP}>#Qjcyx}lf*h01m>V!eAFIpAa9o2fDvk8Qz zDP7Rkc|v`XO?QNJQ=TisLSsVzCp3GLg|K2DmZc8~+JxahdqO93j;nd0y=QTWzjYRsCn=bqE^Jm=+}^X>bmuK@DMDF`s6_v^28n|qeaO-HwDZQZlp zc={H%Yt6c4Sl*=Z+T{5ruiKv8{c&XlSy)3v zkVSqG3F|oxny`k9;`&CZAWY{q3?Rm!OjcJ*TLpt5^Q_;1D&n}PAf{muml))l)8rPz zU@}$OHxEqRG5M}u+1a;hURK30E-M((kiZoR|J$L!+YQR&z;xPH&n6Ku>|JhpZI__IWU5L-l&d-24nFMR5`E6~ zo9Z$ps~XL=TeBY7q5%WHcOfl?fWnonmiM^X@)X=>82?`{7_=himg|p(MFm99tkg<| z?sJ${Qd$`iiv^IRo$w`X0T4@w(I*d?>`6?Ke~PpTlHyT2h#xPCakoYG* zA^!ws5b*sMND71+XVb?RIsp^@fiwQM$)cTl;SSQI>GaA3dn;UNS`qZgG9-iaOPQV- zJ;LY*I{u4E!K|plXNm-<96HmR@gZ|DRZKF46ea19=nD*ozJP59I|v%vQU{8$EqCZv zM80S13u7L0UGUQ`IQ^Nh@$ujht{)=kD-)8hD86z-_7(LQlZS|k%uhMv0xv&DRBj+4 gzrz&uPwJ+*fJO2P;4bd@atRMeicMr#LUv{32TEr$qyPW_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/UnicodeSet$VersionFilter.class b/tests/test_data/std/jdk/internal/icu/text/UnicodeSet$VersionFilter.class new file mode 100644 index 0000000000000000000000000000000000000000..0e1919f23215147a26170fc88d40e36e46f51bc2 GIT binary patch literal 1020 zcma)5O>fgc5Pj=7abg_WhEiJ6w1I{;Nkd$?7FD1Kgrzo-NSgx}v~icjscTpECh%uC zA}(A&e2D`;fZv1=<0OC@Uvk);o!K{UW_D(O{{H?0Km+%6C`f2f4J46bSRC*XH(l=a z%vN_GY{`&%;CPNaU`UiJoea{*XwVH@fx%E8oSvDECq>|K*L3WmDaC7Po_LP!pNh7S zrH%+f$M>E%E`b=d(L`t1I*j=arQ@1Y2g`fu@9VgV1r3V^mXKp8#yrM}o;3PA;P#k5 z)f4hjPcUqkt;!q`GFZlS4J!t2MD@fY%+$l6H(M_{kDs-zR#V3sZfeLISVw{3RxG{Q zf*3Nke}2IOaqLGa&XHin(y+;}6XTvqtn~MV=VR?Ks10fn!@{BCiRSRUD}rO*b;*)D z^lk2Tc;H0()Tqk76Ef_@Q=U!aQpfih(zfqO?s(*_Qd6EYD0ZKLS+qtB*|y~N*%7~( z2GZO9Ft7!c6D9Y5lIqc95?fP*@~I!vU>cU^iJ;-~Fcd_dy%d<{cJd-9(#R@c*r0`I zY-v|$CFzEmMyCVPBa2@B3Rd0y4DG`hbDQ>5xB{hq6l2NGQgydhS z0?MdRh$L1~r4khE5{f?WFXT0>J*3}>8d((FMSU!nVUo;|B~3HFN7xOL_fq;F^vv=p literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/UnicodeSet.class b/tests/test_data/std/jdk/internal/icu/text/UnicodeSet.class new file mode 100644 index 0000000000000000000000000000000000000000..c6f34d15c3a66015cb867845c618e89c4b291f85 GIT binary patch literal 14311 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 KDs}t9;{OAHhXkJh literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/text/UnicodeSet.java b/tests/test_data/std/jdk/internal/icu/text/UnicodeSet.java new file mode 100644 index 00000000..6f5919e0 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/text/UnicodeSet.java @@ -0,0 +1,1412 @@ +/* + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2015, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package jdk.internal.icu.text; + +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.TreeSet; + +import jdk.internal.icu.impl.BMPSet; +import jdk.internal.icu.impl.UCharacterProperty; +import jdk.internal.icu.impl.UnicodeSetStringSpan; +import jdk.internal.icu.impl.Utility; +import jdk.internal.icu.lang.UCharacter; +import jdk.internal.icu.util.OutputInt; +import jdk.internal.icu.util.VersionInfo; + +/** + * A mutable set of Unicode characters and multicharacter strings. + * Objects of this class represent character classes used + * in regular expressions. A character specifies a subset of Unicode + * code points. Legal code points are U+0000 to U+10FFFF, inclusive. + * + * Note: method freeze() will not only make the set immutable, but + * also makes important methods much higher performance: + * contains(c), containsNone(...), span(...), spanBack(...) etc. + * After the object is frozen, any subsequent call that wants to change + * the object will throw UnsupportedOperationException. + * + *

The UnicodeSet class is not designed to be subclassed. + * + *

UnicodeSet supports two APIs. The first is the + * operand API that allows the caller to modify the value of + * a UnicodeSet object. It conforms to Java 2's + * java.util.Set interface, although + * UnicodeSet does not actually implement that + * interface. All methods of Set are supported, with the + * modification that they take a character range or single character + * instead of an Object, and they take a + * UnicodeSet instead of a Collection. The + * operand API may be thought of in terms of boolean logic: a boolean + * OR is implemented by add, a boolean AND is implemented + * by retain, a boolean XOR is implemented by + * complement taking an argument, and a boolean NOT is + * implemented by complement with no argument. In terms + * of traditional set theory function names, add is a + * union, retain is an intersection, remove + * is an asymmetric difference, and complement with no + * argument is a set complement with respect to the superset range + * MIN_VALUE-MAX_VALUE + * + *

The second API is the + * applyPattern()/toPattern() API from the + * java.text.Format-derived classes. Unlike the + * methods that add characters, add categories, and control the logic + * of the set, the method applyPattern() sets all + * attributes of a UnicodeSet at once, based on a + * string pattern. + * + *

Pattern syntax

+ * + * Patterns are accepted by the constructors and the + * applyPattern() methods and returned by the + * toPattern() method. These patterns follow a syntax + * similar to that employed by version 8 regular expression character + * classes. Here are some simple examples: + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
[]No characters
[a]The character 'a'
[ae]The characters 'a' and 'e'
[a-e]The characters 'a' through 'e' inclusive, in Unicode code + * point order
[\\u4E01]The character U+4E01
[a{ab}{ac}]The character 'a' and the multicharacter strings "ab" and + * "ac"
[\p{Lu}]All characters in the general category Uppercase Letter
+ *
+ * + * Any character may be preceded by a backslash in order to remove any special + * meaning. White space characters, as defined by the Unicode Pattern_White_Space property, are + * ignored, unless they are escaped. + * + *

Property patterns specify a set of characters having a certain + * property as defined by the Unicode standard. Both the POSIX-like + * "[:Lu:]" and the Perl-like syntax "\p{Lu}" are recognized. For a + * complete list of supported property patterns, see the User's Guide + * for UnicodeSet at + * + * https://unicode-org.github.io/icu/userguide/strings/unicodeset. + * Actual determination of property data is defined by the underlying + * Unicode database as implemented by UCharacter. + * + *

Patterns specify individual characters, ranges of characters, and + * Unicode property sets. When elements are concatenated, they + * specify their union. To complement a set, place a '^' immediately + * after the opening '['. Property patterns are inverted by modifying + * their delimiters; "[:^foo]" and "\P{foo}". In any other location, + * '^' has no special meaning. + * + *

Since ICU 70, "[^...]", "[:^foo]", "\P{foo}", and "[:binaryProperty=No:]" + * perform a "code point complement" (all code points minus the original set), + * removing all multicharacter strings, + * equivalent to .{@link #complement()}.{@link #removeAllStrings()} . + * The {@link #complement()} API function continues to perform a + * symmetric difference with all code points and thus retains all multicharacter strings. + * + *

Ranges are indicated by placing two a '-' between two + * characters, as in "a-z". This specifies the range of all + * characters from the left to the right, in Unicode order. If the + * left character is greater than or equal to the + * right character it is a syntax error. If a '-' occurs as the first + * character after the opening '[' or '[^', or if it occurs as the + * last character before the closing ']', then it is taken as a + * literal. Thus "[a\\-b]", "[-ab]", and "[ab-]" all indicate the same + * set of three characters, 'a', 'b', and '-'. + * + *

Sets may be intersected using the {@literal '&'} operator or the asymmetric + * set difference may be taken using the '-' operator, for example, + * "{@code [[:L:]&[\\u0000-\\u0FFF]]}" indicates the set of all Unicode letters + * with values less than 4096. Operators ({@literal '&'} and '|') have equal + * precedence and bind left-to-right. Thus + * "[[:L:]-[a-z]-[\\u0100-\\u01FF]]" is equivalent to + * "[[[:L:]-[a-z]]-[\\u0100-\\u01FF]]". This only really matters for + * difference; intersection is commutative. + * + * + *
[a]The set containing 'a' + *
[a-z]The set containing 'a' + * through 'z' and all letters in between, in Unicode order + *
[^a-z]The set containing + * all characters but 'a' through 'z', + * that is, U+0000 through 'a'-1 and 'z'+1 through U+10FFFF + *
[[pat1][pat2]] + * The union of sets specified by pat1 and pat2 + *
[[pat1]&[pat2]] + * The intersection of sets specified by pat1 and pat2 + *
[[pat1]-[pat2]] + * The asymmetric difference of sets specified by pat1 and + * pat2 + *
[:Lu:] or \p{Lu} + * The set of characters having the specified + * Unicode property; in + * this case, Unicode uppercase letters + *
[:^Lu:] or \P{Lu} + * The set of characters not having the given + * Unicode property + *
+ * + *

Formal syntax

+ * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
pattern :=  ('[' '^'? item* ']') | + * property
item :=  char | (char '-' char) | pattern-expr
+ *
pattern-expr :=  pattern | pattern-expr pattern | + * pattern-expr op pattern
+ *
op :=  '&' | '-'
+ *
special :=  '[' | ']' | '-'
+ *
char :=  any character that is not special
+ * | ('\\'
any character)
+ * | ('\u' hex hex hex hex)
+ *
hex :=  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
+ *     'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
property :=  a Unicode property set pattern
+ *
+ * + * + * + * + *
Legend: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
a := b  a may be replaced by b
a?zero or one instance of a
+ *
a*one or more instances of a
+ *
a | beither a or b
+ *
'a'the literal string between the quotes
+ *
+ *
+ *

To iterate over contents of UnicodeSet, the following are available: + *

  • {@link #ranges()} to iterate through the ranges
  • + *
  • {@link #strings()} to iterate through the strings
  • + *
  • {@link #iterator()} to iterate through the entire contents in a single loop. + * That method is, however, not particularly efficient, since it "boxes" each code point into a String. + *
+ * All of the above can be used in for loops. + * The {@link com.ibm.icu.text.UnicodeSetIterator UnicodeSetIterator} can also be used, but not in for loops. + *

To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @author Alan Liu + * @stable ICU 2.0 + */ +public class UnicodeSet { + + private static final int LOW = 0x000000; // LOW <= all valid values. ZERO for codepoints + private static final int HIGH = 0x110000; // HIGH > all valid values. 10000 for code units. + // 110000 for codepoints + + /** + * Minimum value that can be stored in a UnicodeSet. + * @stable ICU 2.0 + */ + public static final int MIN_VALUE = LOW; + + /** + * Maximum value that can be stored in a UnicodeSet. + * @stable ICU 2.0 + */ + public static final int MAX_VALUE = HIGH - 1; + + private int len; // length used; list may be longer to minimize reallocs + private int[] list; // MUST be terminated with HIGH + private int[] rangeList; // internal buffer + private int[] buffer; // internal buffer + + // NOTE: normally the field should be of type SortedSet; but that is missing a public clone!! + // is not private so that UnicodeSetIterator can get access + TreeSet strings = new TreeSet(); + + /** + * The pattern representation of this set. This may not be the + * most economical pattern. It is the pattern supplied to + * applyPattern(), with variables substituted and whitespace + * removed. For sets constructed without applyPattern(), or + * modified using the non-pattern API, this string will be null, + * indicating that toPattern() must generate a pattern + * representation from the inversion list. + */ + + private static final int START_EXTRA = 16; // initial storage. Must be >= 0 + private static final int GROW_EXTRA = START_EXTRA; // extra amount for growth. Must be >= 0 + + private static UnicodeSet INCLUSION = null; + + private volatile BMPSet bmpSet; // The set is frozen if bmpSet or stringSpan is not null. + private volatile UnicodeSetStringSpan stringSpan; + + //---------------------------------------------------------------- + // Public API + //---------------------------------------------------------------- + + /** + * Constructs an empty set. + * @stable ICU 2.0 + */ + private UnicodeSet() { + list = new int[1 + START_EXTRA]; + list[len++] = HIGH; + } + + /** + * Constructs a copy of an existing set. + * @stable ICU 2.0 + */ + private UnicodeSet(UnicodeSet other) { + set(other); + } + + /** + * Constructs a set containing the given range. If end > + * start then an empty set is created. + * + * @param start first character, inclusive, of range + * @param end last character, inclusive, of range + * @stable ICU 2.0 + */ + public UnicodeSet(int start, int end) { + this(); + complement(start, end); + } + + /** + * Constructs a set from the given pattern. See the class description + * for the syntax of the pattern language. Whitespace is ignored. + * @param pattern a string specifying what characters are in the set + * @exception java.lang.IllegalArgumentException if the pattern contains + * a syntax error. + * @stable ICU 2.0 + */ + public UnicodeSet(String pattern) { + this(); + applyPattern(pattern, null); + } + + /** + * Make this object represent the same set as other. + * @param other a UnicodeSet whose value will be + * copied to this object + * @stable ICU 2.0 + */ + public UnicodeSet set(UnicodeSet other) { + checkFrozen(); + list = other.list.clone(); + len = other.len; + strings = new TreeSet(other.strings); + return this; + } + + /** + * Returns the number of elements in this set (its cardinality) + * Note than the elements of a set may include both individual + * codepoints and strings. + * + * @return the number of elements in this set (its cardinality). + * @stable ICU 2.0 + */ + public int size() { + int n = 0; + int count = getRangeCount(); + for (int i = 0; i < count; ++i) { + n += getRangeEnd(i) - getRangeStart(i) + 1; + } + return n + strings.size(); + } + + // for internal use, after checkFrozen has been called + private UnicodeSet add_unchecked(int start, int end) { + if (start < MIN_VALUE || start > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(start, 6)); + } + if (end < MIN_VALUE || end > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(end, 6)); + } + if (start < end) { + add(range(start, end), 2, 0); + } else if (start == end) { + add(start); + } + return this; + } + + /** + * Adds the specified character to this set if it is not already + * present. If this set already contains the specified character, + * the call leaves this set unchanged. + * @stable ICU 2.0 + */ + public final UnicodeSet add(int c) { + checkFrozen(); + return add_unchecked(c); + } + + // for internal use only, after checkFrozen has been called + private final UnicodeSet add_unchecked(int c) { + if (c < MIN_VALUE || c > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(c, 6)); + } + + // find smallest i such that c < list[i] + // if odd, then it is IN the set + // if even, then it is OUT of the set + int i = findCodePoint(c); + + // already in set? + if ((i & 1) != 0) return this; + + // HIGH is 0x110000 + // assert(list[len-1] == HIGH); + + // empty = [HIGH] + // [start_0, limit_0, start_1, limit_1, HIGH] + + // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH] + // ^ + // list[i] + + // i == 0 means c is before the first range + + if (c == list[i]-1) { + // c is before start of next range + list[i] = c; + // if we touched the HIGH mark, then add a new one + if (c == MAX_VALUE) { + ensureCapacity(len+1); + list[len++] = HIGH; + } + if (i > 0 && c == list[i-1]) { + // collapse adjacent ranges + + // [..., start_k-1, c, c, limit_k, ..., HIGH] + // ^ + // list[i] + System.arraycopy(list, i+1, list, i-1, len-i-1); + len -= 2; + } + } + + else if (i > 0 && c == list[i-1]) { + // c is after end of prior range + list[i-1]++; + // no need to check for collapse here + } + + else { + // At this point we know the new char is not adjacent to + // any existing ranges, and it is not 10FFFF. + + + // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH] + // ^ + // list[i] + + // [..., start_k-1, limit_k-1, c, c+1, start_k, limit_k, ..., HIGH] + // ^ + // list[i] + + // Don't use ensureCapacity() to save on copying. + // NOTE: This has no measurable impact on performance, + // but it might help in some usage patterns. + if (len+2 > list.length) { + int[] temp = new int[len + 2 + GROW_EXTRA]; + if (i != 0) System.arraycopy(list, 0, temp, 0, i); + System.arraycopy(list, i, temp, i+2, len-i); + list = temp; + } else { + System.arraycopy(list, i, list, i+2, len-i); + } + + list[i] = c; + list[i+1] = c+1; + len += 2; + } + + return this; + } + + /** + * Adds the specified multicharacter to this set if it is not already + * present. If this set already contains the multicharacter, + * the call leaves this set unchanged. + * Thus {@code "ch" => {"ch"}} + * @param s the source string + * @return this object, for chaining + * @stable ICU 2.0 + */ + public final UnicodeSet add(CharSequence s) { + checkFrozen(); + int cp = getSingleCP(s); + if (cp < 0) { + strings.add(s.toString()); + } else { + add_unchecked(cp, cp); + } + return this; + } + + /** + * Utility for getting code point from single code point CharSequence. + * See the public UTF16.getSingleCodePoint() (which returns -1 for null rather than throwing NPE). + * + * @return a code point IF the string consists of a single one. + * otherwise returns -1. + * @param s to test + */ + private static int getSingleCP(CharSequence s) { + if (s.length() == 1) return s.charAt(0); + if (s.length() == 2) { + int cp = Character.codePointAt(s, 0); + if (cp > 0xFFFF) { // is surrogate pair + return cp; + } + } + return -1; + } + + /** + * Complements the specified range in this set. Any character in + * the range will be removed if it is in this set, or will be + * added if it is not in this set. If start > end + * then an empty range is complemented, leaving the set unchanged. + * + * @param start first character, inclusive, of range + * @param end last character, inclusive, of range + * @stable ICU 2.0 + */ + public UnicodeSet complement(int start, int end) { + checkFrozen(); + if (start < MIN_VALUE || start > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(start, 6)); + } + if (end < MIN_VALUE || end > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(end, 6)); + } + if (start <= end) { + xor(range(start, end), 2, 0); + } + return this; + } + + /** + * Returns true if this set contains the given character. + * @param c character to be checked for containment + * @return true if the test condition is met + * @stable ICU 2.0 + */ + public boolean contains(int c) { + if (c < MIN_VALUE || c > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(c, 6)); + } + if (bmpSet != null) { + return bmpSet.contains(c); + } + if (stringSpan != null) { + return stringSpan.contains(c); + } + + /* + // Set i to the index of the start item greater than ch + // We know we will terminate without length test! + int i = -1; + while (true) { + if (c < list[++i]) break; + } + */ + + int i = findCodePoint(c); + + return ((i & 1) != 0); // return true if odd + } + + /** + * Returns the smallest value i such that c < list[i]. Caller + * must ensure that c is a legal value or this method will enter + * an infinite loop. This method performs a binary search. + * @param c a character in the range MIN_VALUE..MAX_VALUE + * inclusive + * @return the smallest integer i in the range 0..len-1, + * inclusive, such that c < list[i] + */ + private final int findCodePoint(int c) { + /* Examples: + findCodePoint(c) + set list[] c=0 1 3 4 7 8 + === ============== =========== + [] [110000] 0 0 0 0 0 0 + [\u0000-\u0003] [0, 4, 110000] 1 1 1 2 2 2 + [\u0004-\u0007] [4, 8, 110000] 0 0 0 1 1 2 + [:all:] [0, 110000] 1 1 1 1 1 1 + */ + + // Return the smallest i such that c < list[i]. Assume + // list[len - 1] == HIGH and that c is legal (0..HIGH-1). + if (c < list[0]) return 0; + // High runner test. c is often after the last range, so an + // initial check for this condition pays off. + if (len >= 2 && c >= list[len-2]) return len-1; + int lo = 0; + int hi = len - 1; + // invariant: c >= list[lo] + // invariant: c < list[hi] + for (;;) { + int i = (lo + hi) >>> 1; + if (i == lo) return hi; + if (c < list[i]) { + hi = i; + } else { + lo = i; + } + } + } + + /** + * Retains only the elements in this set that are contained in the + * specified set. In other words, removes from this set all of + * its elements that are not contained in the specified set. This + * operation effectively modifies this set so that its value is + * the intersection of the two sets. + * + * @param c set that defines which elements this set will retain. + * @stable ICU 2.0 + */ + public UnicodeSet retainAll(UnicodeSet c) { + checkFrozen(); + retain(c.list, c.len, 0); + strings.retainAll(c.strings); + return this; + } + + /** + * Removes all of the elements from this set. This set will be + * empty after this call returns. + * @stable ICU 2.0 + */ + public UnicodeSet clear() { + checkFrozen(); + list[0] = HIGH; + len = 1; + strings.clear(); + return this; + } + + /** + * Iteration method that returns the number of ranges contained in + * this set. + * @see #getRangeStart + * @see #getRangeEnd + * @stable ICU 2.0 + */ + public int getRangeCount() { + return len/2; + } + + /** + * Iteration method that returns the first character in the + * specified range of this set. + * @exception ArrayIndexOutOfBoundsException if index is outside + * the range 0..getRangeCount()-1 + * @see #getRangeCount + * @see #getRangeEnd + * @stable ICU 2.0 + */ + public int getRangeStart(int index) { + return list[index*2]; + } + + /** + * Iteration method that returns the last character in the + * specified range of this set. + * @exception ArrayIndexOutOfBoundsException if index is outside + * the range 0..getRangeCount()-1 + * @see #getRangeStart + * @see #getRangeEnd + * @stable ICU 2.0 + */ + public int getRangeEnd(int index) { + return (list[index*2 + 1] - 1); + } + + //---------------------------------------------------------------- + // Implementation: Pattern parsing + //---------------------------------------------------------------- + + /** + * Parses the given pattern, starting at the given position. The character + * at pattern.charAt(pos.getIndex()) must be '[', or the parse fails. + * Parsing continues until the corresponding closing ']'. If a syntax error + * is encountered between the opening and closing brace, the parse fails. + * Upon return from a successful parse, the ParsePosition is updated to + * point to the character following the closing ']', and an inversion + * list for the parsed pattern is returned. This method + * calls itself recursively to parse embedded subpatterns. + * + * @param pattern the string containing the pattern to be parsed. The + * portion of the string from pos.getIndex(), which must be a '[', to the + * corresponding closing ']', is parsed. + * @param pos upon entry, the position at which to being parsing. The + * character at pattern.charAt(pos.getIndex()) must be a '['. Upon return + * from a successful parse, pos.getIndex() is either the character after the + * closing ']' of the parsed pattern, or pattern.length() if the closing ']' + * is the last character of the pattern string. + * @return an inversion list for the parsed substring + * of pattern + * @exception java.lang.IllegalArgumentException if the parse fails. + */ + private UnicodeSet applyPattern(String pattern, + ParsePosition pos) { + if ("[:age=3.2:]".equals(pattern)) { + checkFrozen(); + VersionInfo version = VersionInfo.getInstance("3.2"); + applyFilter(new VersionFilter(version), UCharacterProperty.SRC_PROPSVEC); + } else { + throw new IllegalStateException("UnicodeSet.applyPattern(unexpected pattern " + + pattern + ")"); + } + + return this; + } + + //---------------------------------------------------------------- + // Implementation: Utility methods + //---------------------------------------------------------------- + + private void ensureCapacity(int newLen) { + if (newLen <= list.length) return; + int[] temp = new int[newLen + GROW_EXTRA]; + System.arraycopy(list, 0, temp, 0, len); + list = temp; + } + + private void ensureBufferCapacity(int newLen) { + if (buffer != null && newLen <= buffer.length) return; + buffer = new int[newLen + GROW_EXTRA]; + } + + /** + * Assumes start <= end. + */ + private int[] range(int start, int end) { + if (rangeList == null) { + rangeList = new int[] { start, end+1, HIGH }; + } else { + rangeList[0] = start; + rangeList[1] = end+1; + } + return rangeList; + } + + //---------------------------------------------------------------- + // Implementation: Fundamental operations + //---------------------------------------------------------------- + + // polarity = 0, 3 is normal: x xor y + // polarity = 1, 2: x xor ~y == x === y + + private UnicodeSet xor(int[] other, int otherLen, int polarity) { + ensureBufferCapacity(len + otherLen); + int i = 0, j = 0, k = 0; + int a = list[i++]; + int b; + if (polarity == 1 || polarity == 2) { + b = LOW; + if (other[j] == LOW) { // skip base if already LOW + ++j; + b = other[j]; + } + } else { + b = other[j++]; + } + // simplest of all the routines + // sort the values, discarding identicals! + while (true) { + if (a < b) { + buffer[k++] = a; + a = list[i++]; + } else if (b < a) { + buffer[k++] = b; + b = other[j++]; + } else if (a != HIGH) { // at this point, a == b + // discard both values! + a = list[i++]; + b = other[j++]; + } else { // DONE! + buffer[k++] = HIGH; + len = k; + break; + } + } + // swap list and buffer + int[] temp = list; + list = buffer; + buffer = temp; + return this; + } + + // polarity = 0 is normal: x union y + // polarity = 2: x union ~y + // polarity = 1: ~x union y + // polarity = 3: ~x union ~y + + private UnicodeSet add(int[] other, int otherLen, int polarity) { + ensureBufferCapacity(len + otherLen); + int i = 0, j = 0, k = 0; + int a = list[i++]; + int b = other[j++]; + // change from xor is that we have to check overlapping pairs + // polarity bit 1 means a is second, bit 2 means b is. + main: + while (true) { + switch (polarity) { + case 0: // both first; take lower if unequal + if (a < b) { // take a + // Back up over overlapping ranges in buffer[] + if (k > 0 && a <= buffer[k-1]) { + // Pick latter end value in buffer[] vs. list[] + a = max(list[i], buffer[--k]); + } else { + // No overlap + buffer[k++] = a; + a = list[i]; + } + i++; // Common if/else code factored out + polarity ^= 1; + } else if (b < a) { // take b + if (k > 0 && b <= buffer[k-1]) { + b = max(other[j], buffer[--k]); + } else { + buffer[k++] = b; + b = other[j]; + } + j++; + polarity ^= 2; + } else { // a == b, take a, drop b + if (a == HIGH) break main; + // This is symmetrical; it doesn't matter if + // we backtrack with a or b. - liu + if (k > 0 && a <= buffer[k-1]) { + a = max(list[i], buffer[--k]); + } else { + // No overlap + buffer[k++] = a; + a = list[i]; + } + i++; + polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + case 3: // both second; take higher if unequal, and drop other + if (b <= a) { // take a + if (a == HIGH) break main; + buffer[k++] = a; + } else { // take b + if (b == HIGH) break main; + buffer[k++] = b; + } + a = list[i++]; polarity ^= 1; // factored common code + b = other[j++]; polarity ^= 2; + break; + case 1: // a second, b first; if b < a, overlap + if (a < b) { // no overlap, take a + buffer[k++] = a; a = list[i++]; polarity ^= 1; + } else if (b < a) { // OVERLAP, drop b + b = other[j++]; polarity ^= 2; + } else { // a == b, drop both! + if (a == HIGH) break main; + a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + case 2: // a first, b second; if a < b, overlap + if (b < a) { // no overlap, take b + buffer[k++] = b; b = other[j++]; polarity ^= 2; + } else if (a < b) { // OVERLAP, drop a + a = list[i++]; polarity ^= 1; + } else { // a == b, drop both! + if (a == HIGH) break main; + a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + } + } + buffer[k++] = HIGH; // terminate + len = k; + // swap list and buffer + int[] temp = list; + list = buffer; + buffer = temp; + return this; + } + + // polarity = 0 is normal: x intersect y + // polarity = 2: x intersect ~y == set-minus + // polarity = 1: ~x intersect y + // polarity = 3: ~x intersect ~y + + private UnicodeSet retain(int[] other, int otherLen, int polarity) { + ensureBufferCapacity(len + otherLen); + int i = 0, j = 0, k = 0; + int a = list[i++]; + int b = other[j++]; + // change from xor is that we have to check overlapping pairs + // polarity bit 1 means a is second, bit 2 means b is. + main: + while (true) { + switch (polarity) { + case 0: // both first; drop the smaller + if (a < b) { // drop a + a = list[i++]; polarity ^= 1; + } else if (b < a) { // drop b + b = other[j++]; polarity ^= 2; + } else { // a == b, take one, drop other + if (a == HIGH) break main; + buffer[k++] = a; a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + case 3: // both second; take lower if unequal + if (a < b) { // take a + buffer[k++] = a; a = list[i++]; polarity ^= 1; + } else if (b < a) { // take b + buffer[k++] = b; b = other[j++]; polarity ^= 2; + } else { // a == b, take one, drop other + if (a == HIGH) break main; + buffer[k++] = a; a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + case 1: // a second, b first; + if (a < b) { // NO OVERLAP, drop a + a = list[i++]; polarity ^= 1; + } else if (b < a) { // OVERLAP, take b + buffer[k++] = b; b = other[j++]; polarity ^= 2; + } else { // a == b, drop both! + if (a == HIGH) break main; + a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + case 2: // a first, b second; if a < b, overlap + if (b < a) { // no overlap, drop b + b = other[j++]; polarity ^= 2; + } else if (a < b) { // OVERLAP, take a + buffer[k++] = a; a = list[i++]; polarity ^= 1; + } else { // a == b, drop both! + if (a == HIGH) break main; + a = list[i++]; polarity ^= 1; + b = other[j++]; polarity ^= 2; + } + break; + } + } + buffer[k++] = HIGH; // terminate + len = k; + // swap list and buffer + int[] temp = list; + list = buffer; + buffer = temp; + return this; + } + + private static final int max(int a, int b) { + return (a > b) ? a : b; + } + + //---------------------------------------------------------------- + // Generic filter-based scanning code + //---------------------------------------------------------------- + + private static interface Filter { + boolean contains(int codePoint); + } + + private static final VersionInfo NO_VERSION = VersionInfo.getInstance(0, 0, 0, 0); + + private static class VersionFilter implements Filter { + VersionInfo version; + VersionFilter(VersionInfo version) { this.version = version; } + public boolean contains(int ch) { + VersionInfo v = UCharacter.getAge(ch); + // Reference comparison ok; VersionInfo caches and reuses + // unique objects. + return v != NO_VERSION && + v.compareTo(version) <= 0; + } + } + + private static synchronized UnicodeSet getInclusions(int src) { + if (src != UCharacterProperty.SRC_PROPSVEC) { + throw new IllegalStateException("UnicodeSet.getInclusions(unknown src "+src+")"); + } + + if (INCLUSION == null) { + UnicodeSet incl = new UnicodeSet(); + UCharacterProperty.INSTANCE.upropsvec_addPropertyStarts(incl); + INCLUSION = incl; + } + return INCLUSION; + } + + /** + * Generic filter-based scanning code for UCD property UnicodeSets. + */ + private UnicodeSet applyFilter(Filter filter, int src) { + // Logically, walk through all Unicode characters, noting the start + // and end of each range for which filter.contain(c) is + // true. Add each range to a set. + // + // To improve performance, use an inclusions set which + // encodes information about character ranges that are known + // to have identical properties. + // getInclusions(src) contains exactly the first characters of + // same-value ranges for the given properties "source". + + clear(); + + int startHasProperty = -1; + UnicodeSet inclusions = getInclusions(src); + int limitRange = inclusions.getRangeCount(); + + for (int j=0; j= 0) { + add_unchecked(startHasProperty, ch-1); + startHasProperty = -1; + } + } + } + if (startHasProperty >= 0) { + add_unchecked(startHasProperty, 0x10FFFF); + } + + return this; + } + + /** + * Is this frozen, according to the Freezable interface? + * + * @return value + * @stable ICU 3.8 + */ + public boolean isFrozen() { + return (bmpSet != null || stringSpan != null); + } + + /** + * Freeze this class, according to the Freezable interface. + * + * @return this + * @stable ICU 4.4 + */ + public UnicodeSet freeze() { + if (!isFrozen()) { + // Do most of what compact() does before freezing because + // compact() will not work when the set is frozen. + // Small modification: Don't shrink if the savings would be tiny (<=GROW_EXTRA). + + // Delete buffer first to defragment memory less. + buffer = null; + if (list.length > (len + GROW_EXTRA)) { + // Make the capacity equal to len or 1. + // We don't want to realloc of 0 size. + int capacity = (len == 0) ? 1 : len; + int[] oldList = list; + list = new int[capacity]; + for (int i = capacity; i-- > 0;) { + list[i] = oldList[i]; + } + } + + // Optimize contains() and span() and similar functions. + if (!strings.isEmpty()) { + stringSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), UnicodeSetStringSpan.ALL); + } + if (stringSpan == null || !stringSpan.needsStringSpanUTF16()) { + // Optimize for code point spans. + // There are no strings, or + // all strings are irrelevant for span() etc. because + // all of each string's code points are contained in this set. + // However, fully contained strings are relevant for spanAndCount(), + // so we create both objects. + bmpSet = new BMPSet(list, len); + } + } + return this; + } + + /** + * Span a string using this UnicodeSet. + *

To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * @param s The string to be spanned + * @param spanCondition The span condition + * @return the length of the span + * @stable ICU 4.4 + */ + public int span(CharSequence s, SpanCondition spanCondition) { + return span(s, 0, spanCondition); + } + + /** + * Span a string using this UnicodeSet. + * If the start index is less than 0, span will start from 0. + * If the start index is greater than the string length, span returns the string length. + *

To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @return the string index which ends the span (i.e. exclusive) + * @stable ICU 4.4 + */ + public int span(CharSequence s, int start, SpanCondition spanCondition) { + int end = s.length(); + if (start < 0) { + start = 0; + } else if (start >= end) { + return end; + } + if (bmpSet != null) { + // Frozen set without strings, or no string is relevant for span(). + return bmpSet.span(s, start, spanCondition, null); + } + if (stringSpan != null) { + return stringSpan.span(s, start, spanCondition); + } else if (!strings.isEmpty()) { + int which = spanCondition == SpanCondition.NOT_CONTAINED ? UnicodeSetStringSpan.FWD_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.FWD_UTF16_CONTAINED; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), which); + if (strSpan.needsStringSpanUTF16()) { + return strSpan.span(s, start, spanCondition); + } + } + + return spanCodePointsAndCount(s, start, spanCondition, null); + } + + /** + * Same as span() but also counts the smallest number of set elements on any path across the span. + *

To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * @param outCount An output-only object (must not be null) for returning the count. + * @return the limit (exclusive end) of the span + */ + public int spanAndCount(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + if (outCount == null) { + throw new IllegalArgumentException("outCount must not be null"); + } + int end = s.length(); + if (start < 0) { + start = 0; + } else if (start >= end) { + return end; + } + if (stringSpan != null) { + // We might also have bmpSet != null, + // but fully-contained strings are relevant for counting elements. + return stringSpan.spanAndCount(s, start, spanCondition, outCount); + } else if (bmpSet != null) { + return bmpSet.span(s, start, spanCondition, outCount); + } else if (!strings.isEmpty()) { + int which = spanCondition == SpanCondition.NOT_CONTAINED ? UnicodeSetStringSpan.FWD_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.FWD_UTF16_CONTAINED; + which |= UnicodeSetStringSpan.WITH_COUNT; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), which); + return strSpan.spanAndCount(s, start, spanCondition, outCount); + } + + return spanCodePointsAndCount(s, start, spanCondition, outCount); + } + + private int spanCodePointsAndCount(CharSequence s, int start, + SpanCondition spanCondition, OutputInt outCount) { + // Pin to 0/1 values. + boolean spanContained = (spanCondition != SpanCondition.NOT_CONTAINED); + + int c; + int next = start; + int length = s.length(); + int count = 0; + do { + c = Character.codePointAt(s, next); + if (spanContained != contains(c)) { + break; + } + ++count; + next += Character.charCount(c); + } while (next < length); + if (outCount != null) { outCount.value = count; } + return next; + } + + /** + * Span a string backwards (from the fromIndex) using this UnicodeSet. + * If the fromIndex is less than 0, spanBack will return 0. + * If fromIndex is greater than the string length, spanBack will start from the string length. + *

To replace, count elements, or delete spans, see {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * @param s The string to be spanned + * @param fromIndex The index of the char (exclusive) that the string should be spanned backwards + * @param spanCondition The span condition + * @return The string index which starts the span (i.e. inclusive). + * @stable ICU 4.4 + */ + public int spanBack(CharSequence s, int fromIndex, SpanCondition spanCondition) { + if (fromIndex <= 0) { + return 0; + } + if (fromIndex > s.length()) { + fromIndex = s.length(); + } + if (bmpSet != null) { + // Frozen set without strings, or no string is relevant for spanBack(). + return bmpSet.spanBack(s, fromIndex, spanCondition); + } + if (stringSpan != null) { + return stringSpan.spanBack(s, fromIndex, spanCondition); + } else if (!strings.isEmpty()) { + int which = (spanCondition == SpanCondition.NOT_CONTAINED) + ? UnicodeSetStringSpan.BACK_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.BACK_UTF16_CONTAINED; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), which); + if (strSpan.needsStringSpanUTF16()) { + return strSpan.spanBack(s, fromIndex, spanCondition); + } + } + + // Pin to 0/1 values. + boolean spanContained = (spanCondition != SpanCondition.NOT_CONTAINED); + + int c; + int prev = fromIndex; + do { + c = Character.codePointBefore(s, prev); + if (spanContained != contains(c)) { + break; + } + prev -= Character.charCount(c); + } while (prev > 0); + return prev; + } + + /** + * Clone a thawed version of this class, according to the Freezable interface. + * @return the clone, not frozen + * @stable ICU 4.4 + */ + public UnicodeSet cloneAsThawed() { + UnicodeSet result = new UnicodeSet(this); + assert !result.isFrozen(); + return result; + } + + // internal function + private void checkFrozen() { + if (isFrozen()) { + throw new UnsupportedOperationException("Attempt to modify frozen object"); + } + } + + /** + * Argument values for whether span() and similar functions continue while the current character is contained vs. + * not contained in the set. + *

+ * The functionality is straightforward for sets with only single code points, without strings (which is the common + * case): + *

    + *
  • CONTAINED and SIMPLE work the same. + *
  • CONTAINED and SIMPLE are inverses of NOT_CONTAINED. + *
  • span() and spanBack() partition any string the + * same way when alternating between span(NOT_CONTAINED) and span(either "contained" condition). + *
  • Using a + * complemented (inverted) set and the opposite span conditions yields the same results. + *
+ * When a set contains multi-code point strings, then these statements may not be true, depending on the strings in + * the set (for example, whether they overlap with each other) and the string that is processed. For a set with + * strings: + *
    + *
  • The complement of the set contains the opposite set of code points, but the same set of strings. + * Therefore, complementing both the set and the span conditions may yield different results. + *
  • When starting spans + * at different positions in a string (span(s, ...) vs. span(s+1, ...)) the ends of the spans may be different + * because a set string may start before the later position. + *
  • span(SIMPLE) may be shorter than + * span(CONTAINED) because it will not recursively try all possible paths. For example, with a set which + * contains the three strings "xy", "xya" and "ax", span("xyax", CONTAINED) will return 4 but span("xyax", + * SIMPLE) will return 3. span(SIMPLE) will never be longer than span(CONTAINED). + *
  • With either "contained" condition, span() and spanBack() may partition a string in different ways. For example, + * with a set which contains the two strings "ab" and "ba", and when processing the string "aba", span() will yield + * contained/not-contained boundaries of { 0, 2, 3 } while spanBack() will yield boundaries of { 0, 1, 3 }. + *
+ * Note: If it is important to get the same boundaries whether iterating forward or backward through a string, then + * either only span() should be used and the boundaries cached for backward operation, or an ICU BreakIterator could + * be used. + *

+ * Note: Unpaired surrogates are treated like surrogate code points. Similarly, set strings match only on code point + * boundaries, never in the middle of a surrogate pair. + * + * @stable ICU 4.4 + */ + public enum SpanCondition { + /** + * Continues a span() while there is no set element at the current position. + * Increments by one code point at a time. + * Stops before the first set element (character or string). + * (For code points only, this is like while contains(current)==false). + *

+ * When span() returns, the substring between where it started and the position it returned consists only of + * characters that are not in the set, and none of its strings overlap with the span. + * + * @stable ICU 4.4 + */ + NOT_CONTAINED, + + /** + * Spans the longest substring that is a concatenation of set elements (characters or strings). + * (For characters only, this is like while contains(current)==true). + *

+ * When span() returns, the substring between where it started and the position it returned consists only of set + * elements (characters or strings) that are in the set. + *

+ * If a set contains strings, then the span will be the longest substring for which there + * exists at least one non-overlapping concatenation of set elements (characters or strings). + * This is equivalent to a POSIX regular expression for (OR of each set element)*. + * (Java/ICU/Perl regex stops at the first match of an OR.) + * + * @stable ICU 4.4 + */ + CONTAINED, + + /** + * Continues a span() while there is a set element at the current position. + * Increments by the longest matching element at each position. + * (For characters only, this is like while contains(current)==true). + *

+ * When span() returns, the substring between where it started and the position it returned consists only of set + * elements (characters or strings) that are in the set. + *

+ * If a set only contains single characters, then this is the same as CONTAINED. + *

+ * If a set contains strings, then the span will be the longest substring with a match at each position with the + * longest single set element (character or string). + *

+ * Use this span condition together with other longest-match algorithms, such as ICU converters + * (ucnv_getUnicodeSet()). + * + * @stable ICU 4.4 + */ + SIMPLE, + } + +} diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointMap$Range.class b/tests/test_data/std/jdk/internal/icu/util/CodePointMap$Range.class new file mode 100644 index 0000000000000000000000000000000000000000..12d55fd4577431e0a97031eeae3d38c5c0f1b1f4 GIT binary patch literal 871 zcma)4O>fgc5PfUMacbPw4dtV>1zK7u^#O}Bh)V>*C=^6d4%{}$s@>GsmA&qN;N!%F z3wNOE1&IiW13!Qtg_v<7R8^MXGP5(@_x8;j|N8yoCx9-tJy@_^G<-N{3It<$ETcrG z`_a?ESPhLp^PWz%xi4UMcKUN@Va|o;;{tqv&Ukbf>C~t^l}V(BWmFoSMBQwpo@La3 zB9FG76PY5kN=E`BW`+eHiwt)PBXh%@B_Hjob1ajRZa0`hV6mrDwOhU#sQiT-B-Cm5 zvY|}+GS^(snhkTH3xTlrzjE#hwDy(RPAtg89&%AoyCLmMOOB7Vw(l8!X^0A>ZK= zb^Iw7mvMzEfvZ@V@kW%H*9pI2{*(?Dn24VR-k$+Gf5F#k!R~qRhg$GzEjTz2{#XlM z!}?72h;;I(LAc5;tdSexdW{vI$imO?@P$l1sW`(aZZ-`uRQB_(=*@qoy*McKgT}+%;Q-AF1RIlWO(6YnA|FDr&ZnJ zrmkpdwOCKrEmcd;8zsJCkbg<3##a@6lV>SJu?&;JXO-1je3Bu)*!plL2tNW6f-*WF zGlaL49VM+1VtRRFix(}zn^twznqhD!k_8Eu7!s{<8=`^;As{m9k`X~SgVz*V8B%RX zYd~ZIgwZSGGOmyUu9p~C){XG#X%JBiNVqB^hHDJNtwk~TH@Rh(i{Wh|+m48WqSg6x zRipA|+KIQ(Gs!gxLkvT9HSLb&jC{RVUeI`j>(;_`;3Ur(pMj%Kfy(wc92?meOcd1L`iDdioB%~N3=i<(XXEf0UN+ww#UNM6V zor|i@bM?vwH(x0m8hIj%Mp4lUim8fy)9DdI$uQLhdZX`Wk}@=tOWZ0Or4_|gDxCU2 zI8s@u{++J4$=P(e&O3Y!62n{{pUZPMm|UA!*_a9jvag>4n8+n3|+Wqrz+T{n%VeIFie1P z0oW)|L-;QTkiP*Go+GvQn`+Z!MK!#sLyYWQIP9#dx2eK|2X@p$JhJU$WNaJ7G})-# UyeOVfi$k=VK|h|7o%03$0vxG}8UO$Q literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointMap$RangeOption.class b/tests/test_data/std/jdk/internal/icu/util/CodePointMap$RangeOption.class new file mode 100644 index 0000000000000000000000000000000000000000..507270d1a6522a604e7280c102f7afe26fdbe321 GIT binary patch literal 1388 zcmb7DYfsZ)6n@^VTenhROfG`p1yMH8m2pvY3t__0C54d{7SRu+j0(lllCI^mKS@U- zM5E!eKgxLCZpPsyW=-1jp3~<%=klKO?fa*%09KF}5n{+3?Y~t_+cR8Sw-mGHE52u1 z%8IjZY&v9L*H0!Yx_w}jPdwAH<6sbEL=a_&Zj>wQ1(jh&?TjSHSz0R zs}>8ZyV`c8Qhr|8Dry|jB}3+j{wAWJs=onxWb`7zAWl>Z>UL3M$iD706$wdP6OoY7 zj{$~A&2nsmVy4pSk$$Qx7S*nl_l}I3mymr6_jNk@C&o4mH_Kzu#Q{D27@*9SQ zRGasTrPu4ZHiPE5rhSlWkH856{xKOhaf_OpH*M2fVi;_vYI&B@)fgfY^=K@HcnmT> z-ji`3le`;28g+)bRJ!ASP~@NP0v`f~Ue&aX4gYx0aJTe5i!7^uNr{T-XpnLYN!6+8 zR#kURPTS%ZZ2g!*B>!v|Lt@?V4xRl?-6af7ER`sDhbD=*W**qO=ey(@PNl0fUiq5U z>fp0BF5c&Sr>QPcvXbWbZp~OTc?0^|*CWHnfC6q9b?=2!_e4Bl82^7a803;|8*VTj z1{KlOwr9&(y3rxpQ(<|SZyP|8_9c+C6+mKy4?iIyWKUs|@M+SmWO`;ogg;( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointMap$StringIterator.class b/tests/test_data/std/jdk/internal/icu/util/CodePointMap$StringIterator.class new file mode 100644 index 0000000000000000000000000000000000000000..607b0c60753dc9271d9947ff63e4e5a7cc499d44 GIT binary patch literal 1883 zcma)-UsD@p6vm%Jvg8jN2-L(tp+ZGXwkavLS~0Z(skKpBJK|(UuUs~-ur%z}&4%fC z)muM=7vA^AnMSJ@egHpE{Ws(Iyqg#xhM~+PZ{GKu^PJy%_MGLne}4HDKn)+KFoswH zaT5l{1*`kb2Nl-~Rp8mJitBVLozQJnYJOAQ_j!KTez?3H2ClbTr;i=_fnYq`bKA>T z1j}1zM_1EGB9%be!~{%1cHcgnNbMX9wHr>yGjqRn?9&CeGm{DzxifQ$1otT_5L7ysVGK(Ysj_b9!eS+O3Y7z&sWb zxM1QHEDG|Y)hXFh-fp-TLDkc^h*uL>Ht`x>7o0m8WIHU4V8Z#YXdArLeDO5!dMVN? znkc~%q#WL==65^>#fy=#jLQkEn5by`#j|Tn$Xyj`$W;?>YQm`j%clCu50oH%OFayf zV~46KnEjOL+ym8c+wM+FZFrs^+M(-vEO`DH_fbq$u+AHu*(}v#(I*~Pz0~0SbYGEf z%k|W~&cTifKC_u$Ftg=5cB^3ruHN?#+%}dsl^fe)GN^*awQwheAf6 z+Ukr)qai)@h+b^QF9ezG&~_eh3i?b*7V*&aJCsYZ=KZ!a`ExKbJxfD38_T}!cLGP< zcJ(c%2R;;B(M?3(d#WAY@!QO3);&)JwU*s(E9y_4oI5PBmy;Y~193eb++F1kxW>;o z1aEPT>v=fE!jU+|!toeo$!7ICf~tI7aCqP5_jT^Rp>Le)1?y55V*P}KRqi5VEp#z$ zjdhW;VqFw|pvM^A;rCpm@f<1qj!FDM!aq^KUs%B3SfkzQso`Bzxub5BRiaOh_6awlIGN$$<^bz)A8SqL z|89up$`DQS1!#&$NC_#qgo2b&l*_m-E5~ToPST_>&Hp}&{UTMk>LMAMM&Gm7DY}ax x*N&+eeU)k48X24$4qh7>{K3fJ!f^2Vh~OA*M|>aRPPCR$=b9$z7|Qqv@-G1nV~GF& literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointMap$ValueFilter.class b/tests/test_data/std/jdk/internal/icu/util/CodePointMap$ValueFilter.class new file mode 100644 index 0000000000000000000000000000000000000000..6d7e8429e59c2966d1a828a93eb32ad2d4669c41 GIT binary patch literal 266 zcmaivJqp4=5QX2UNi>O~R}c$r+(QJ!6#jrXHak&;rc~<+9?;Baoj#4*jm1{Ny=n=++yh)*@ zxrp7VP?;lmva0l*(3_`=ln@@urq0@oB20dtE!!-izg5<)OX~tegz0|>LYx|->O@Ox ll_f+!R6c>w zIF7GAsH5VKDI-I52DP>V)8go(Gmh_$Dvnz$L*g!vim&VP08O;sr&Yi;vIFt2vY4?bme893Z$N(Mdmi@Jpzb5r9lM zI-kED*K|`gbfpm2a^-m0)C%#TVqU#aWcjGFK-k}*luD{$YDK+tRx2s91vO8gOA_h{ z&ASGZ+gihhQ8a2%2UjhdYm^bheu8gKH8bp(O1Kh9rT^V>$D~pyt0P*0-Ag#px6l*O zOMZlKK*B>Znh_@SI51@$9bXW440!M4URwc~o@~{}jXgV!?FDhzJbNq6nA( zj>$M~NlK<-m=Yf0yErwF;&3abNMJYOf>tL8T@eS7NJJ+kJWA+wU@2=Fnm)H{su!n( zsmBO|j!dO@X*YCDF|z6_WmV6qiBxp57LVfz34Jo2M1rudO0&R3CLGACCCyOtJABQW zidp6jE)XX5Q-t8|8OudxJi#rhg7MOtu8x&oo>h$rQ3|Y`F6NZNq+)2|yCQU(*EELg za1uAR%(cN5BB^MK@V2w+sG@A*e=R32h+?HO>Puy=?K#C%t=iyPx_S&B-R2qGzO5L6U z+&*`l+Gg~BylHK=ST=H^9dqm&t0zQ{z$OI7)RH->ioz&Kc+pwktzra0PU*U842ddL z`PP9wn;we+EUn@_lfe4g&M@a=Z~WXxcmUOa&<|>87Bi2hCQnN-ELl3hUnhAbUOll* z&^P>2gQxi^<|^ns+?2u~f6KNKk~jkv^5{KltvuRzmzw~F`N@EEli__V+qw;D3H!Q# zL|_Yb)0^1$L#!q24tqAxumq25t@}2bR^f4rmxHVD1zT^z6Fhv{8}@vQw$oBb3U)5T z-xBh!2rVH!)_MbSND6tE5p%D#1Uo;29QFh|*U=^vTGw$*?5+rD$ZJVsA+P&t#q5V@ z+C~Y4JuT~qic?~(sM`?kHFn=+g<&2C`AY8~Nblk>y@z&sA6@hTqO^oQ`Ur#cF-GYV zjMEKF(K2Re1qz2?jy{J@Utod0#3Fr#*Xe7#Nw@G8t>aVLzzS_*mF{AV?%@t?;Vyk= zg*jt~&JME(qL^b==(jL}ut*Ba&asTAAHSVPio-45p24%6)jqs|H1B#D?KLr3IoqSW zA4DKn=L;n14}^%Qu|CwssACvsM4JUJ%Zh&s-P6p3o?Cp#W`ZCJ=x574n+5)gdlxL7 z=XgJZEI$QMik%Ryan5_EW5*9|;^c!+zgkf3w%X231DL=?%ZC6a+3y;T#Pd5WJ!S0x zjX~cAPA@@nGtFFgAnh{N@)J?(x*pWXgFH}RyEuhu%hgMGfmbnTdwICG<1+uQTwzI! gC70RWj92_T_;8gY9pY6P46~jOvmC!(UUQ(o05);2;{X5v literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointMap.java b/tests/test_data/std/jdk/internal/icu/util/CodePointMap.java new file mode 100644 index 00000000..d52ecd46 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/util/CodePointMap.java @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +// (c) 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html#License + +// created: 2018may10 Markus W. Scherer + +package jdk.internal.icu.util; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Abstract map from Unicode code points (U+0000..U+10FFFF) to integer values. + * This does not implement java.util.Map. + * + * @stable ICU 63 + */ +public abstract class CodePointMap implements Iterable { + /** + * Selectors for how getRange() should report value ranges overlapping with surrogates. + * Most users should use NORMAL. + * + * @see #getRange + * @stable ICU 63 + */ + public enum RangeOption { + /** + * getRange() enumerates all same-value ranges as stored in the map. + * Most users should use this option. + * + * @stable ICU 63 + */ + NORMAL, + /** + * getRange() enumerates all same-value ranges as stored in the map, + * except that lead surrogates (U+D800..U+DBFF) are treated as having the + * surrogateValue, which is passed to getRange() as a separate parameter. + * The surrogateValue is not transformed via filter(). + * See {@link Character#isHighSurrogate}. + * + *

Most users should use NORMAL instead. + * + *

This option is useful for maps that map surrogate code units to + * special values optimized for UTF-16 string processing + * or for special error behavior for unpaired surrogates, + * but those values are not to be associated with the lead surrogate code points. + * + * @stable ICU 63 + */ + FIXED_LEAD_SURROGATES, + /** + * getRange() enumerates all same-value ranges as stored in the map, + * except that all surrogates (U+D800..U+DFFF) are treated as having the + * surrogateValue, which is passed to getRange() as a separate parameter. + * The surrogateValue is not transformed via filter(). + * See {@link Character#isSurrogate}. + * + *

Most users should use NORMAL instead. + * + *

This option is useful for maps that map surrogate code units to + * special values optimized for UTF-16 string processing + * or for special error behavior for unpaired surrogates, + * but those values are not to be associated with the lead surrogate code points. + * + * @stable ICU 63 + */ + FIXED_ALL_SURROGATES + } + + /** + * Callback function interface: Modifies a map value. + * Optionally called by getRange(). + * The modified value will be returned by the getRange() function. + * + *

Can be used to ignore some of the value bits, + * make a filter for one of several values, + * return a value index computed from the map value, etc. + * + * @see #getRange + * @see #iterator + * @stable ICU 63 + */ + public interface ValueFilter { + /** + * Modifies the map value. + * + * @param value map value + * @return modified value + * @stable ICU 63 + */ + public int apply(int value); + } + + /** + * Range iteration result data. + * Code points from start to end map to the same value. + * The value may have been modified by {@link ValueFilter#apply(int)}, + * or it may be the surrogateValue if a RangeOption other than "normal" was used. + * + * @see #getRange + * @see #iterator + * @stable ICU 63 + */ + public static final class Range { + private int start; + private int end; + private int value; + + /** + * Constructor. Sets start and end to -1 and value to 0. + * + * @stable ICU 63 + */ + public Range() { + start = end = -1; + value = 0; + } + + /** + * @return the start code point + * @stable ICU 63 + */ + public int getStart() { return start; } + /** + * @return the (inclusive) end code point + * @stable ICU 63 + */ + public int getEnd() { return end; } + /** + * @return the range value + * @stable ICU 63 + */ + public int getValue() { return value; } + /** + * Sets the range. When using {@link #iterator()}, + * iteration will resume after the newly set end. + * + * @param start new start code point + * @param end new end code point + * @param value new value + * @stable ICU 63 + */ + public void set(int start, int end, int value) { + this.start = start; + this.end = end; + this.value = value; + } + } + + private final class RangeIterator implements Iterator { + private Range range = new Range(); + + @Override + public boolean hasNext() { + return -1 <= range.end && range.end < 0x10ffff; + } + + @Override + public Range next() { + if (getRange(range.end + 1, null, range)) { + return range; + } else { + throw new NoSuchElementException(); + } + } + + @Override + public final void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Iterates over code points of a string and fetches map values. + * This does not implement java.util.Iterator. + * + *

+     * void onString(CodePointMap map, CharSequence s, int start) {
+     *     CodePointMap.StringIterator iter = map.stringIterator(s, start);
+     *     while (iter.next()) {
+     *         int end = iter.getIndex();  // code point from between start and end
+     *         useValue(s, start, end, iter.getCodePoint(), iter.getValue());
+     *         start = end;
+     *     }
+     * }
+     * 
+ * + *

This class is not intended for public subclassing. + * + * @stable ICU 63 + */ + public class StringIterator { + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected CharSequence s; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected int sIndex; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected int c; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected int value; + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected StringIterator(CharSequence s, int sIndex) { + this.s = s; + this.sIndex = sIndex; + c = -1; + value = 0; + } + + /** + * Resets the iterator to a new string and/or a new string index. + * + * @param s string to iterate over + * @param sIndex string index where the iteration will start + * @stable ICU 63 + */ + public void reset(CharSequence s, int sIndex) { + this.s = s; + this.sIndex = sIndex; + c = -1; + value = 0; + } + + /** + * Reads the next code point, post-increments the string index, + * and gets a value from the map. + * Sets an implementation-defined error value if the code point is an unpaired surrogate. + * + * @return true if the string index was not yet at the end of the string; + * otherwise the iterator did not advance + * @stable ICU 63 + */ + public boolean next() { + if (sIndex >= s.length()) { + return false; + } + c = Character.codePointAt(s, sIndex); + sIndex += Character.charCount(c); + value = get(c); + return true; + } + + /** + * Reads the previous code point, pre-decrements the string index, + * and gets a value from the map. + * Sets an implementation-defined error value if the code point is an unpaired surrogate. + * + * @return true if the string index was not yet at the start of the string; + * otherwise the iterator did not advance + * @stable ICU 63 + */ + public boolean previous() { + if (sIndex <= 0) { + return false; + } + c = Character.codePointBefore(s, sIndex); + sIndex -= Character.charCount(c); + value = get(c); + return true; + } + /** + * @return the string index + * @stable ICU 63 + */ + public final int getIndex() { return sIndex; } + /** + * @return the code point + * @stable ICU 63 + */ + public final int getCodePoint() { return c; } + /** + * @return the map value, + * or an implementation-defined error value if + * the code point is an unpaired surrogate + * @stable ICU 63 + */ + public final int getValue() { return value; } + } + + /** + * Protected no-args constructor. + * + * @stable ICU 63 + */ + protected CodePointMap() { + } + + /** + * Returns the value for a code point as stored in the map, with range checking. + * Returns an implementation-defined error value if c is not in the range 0..U+10FFFF. + * + * @param c the code point + * @return the map value, + * or an implementation-defined error value if + * the code point is not in the range 0..U+10FFFF + * @stable ICU 63 + */ + public abstract int get(int c); + + /** + * Sets the range object to a range of code points beginning with the start parameter. + * The range start is the same as the start input parameter + * (even if there are preceding code points that have the same value). + * The range end is the last code point such that + * all those from start to there have the same value. + * Returns false if start is not 0..U+10FFFF. + * Can be used to efficiently iterate over all same-value ranges in a map. + * (This is normally faster than iterating over code points and get()ting each value, + * but may be much slower than a data structure that stores ranges directly.) + * + *

If the {@link ValueFilter} parameter is not null, then + * the value to be delivered is passed through that filter, and the return value is the end + * of the range where all values are modified to the same actual value. + * The value is unchanged if that parameter is null. + * + *

Example: + *

+     * int start = 0;
+     * CodePointMap.Range range = new CodePointMap.Range();
+     * while (map.getRange(start, null, range)) {
+     *     int end = range.getEnd();
+     *     int value = range.getValue();
+     *     // Work with the range start..end and its value.
+     *     start = end + 1;
+     * }
+     * 
+ * + * @param start range start + * @param filter an object that may modify the map data value, + * or null if the values from the map are to be used unmodified + * @param range the range object that will be set to the code point range and value + * @return true if start is 0..U+10FFFF; otherwise no new range is fetched + * @stable ICU 63 + */ + public abstract boolean getRange(int start, ValueFilter filter, Range range); + + /** + * Sets the range object to a range of code points beginning with the start parameter. + * The range start is the same as the start input parameter + * (even if there are preceding code points that have the same value). + * The range end is the last code point such that + * all those from start to there have the same value. + * Returns false if start is not 0..U+10FFFF. + * + *

Same as the simpler {@link #getRange(int, ValueFilter, Range)} but optionally + * modifies the range if it overlaps with surrogate code points. + * + * @param start range start + * @param option defines whether surrogates are treated normally, + * or as having the surrogateValue; usually {@link RangeOption#NORMAL} + * @param surrogateValue value for surrogates; ignored if option=={@link RangeOption#NORMAL} + * @param filter an object that may modify the map data value, + * or null if the values from the map are to be used unmodified + * @param range the range object that will be set to the code point range and value + * @return true if start is 0..U+10FFFF; otherwise no new range is fetched + * @stable ICU 63 + */ + public boolean getRange(int start, RangeOption option, int surrogateValue, + ValueFilter filter, Range range) { + assert option != null; + if (!getRange(start, filter, range)) { + return false; + } + if (option == RangeOption.NORMAL) { + return true; + } + int surrEnd = option == RangeOption.FIXED_ALL_SURROGATES ? 0xdfff : 0xdbff; + int end = range.end; + if (end < 0xd7ff || start > surrEnd) { + return true; + } + // The range overlaps with surrogates, or ends just before the first one. + if (range.value == surrogateValue) { + if (end >= surrEnd) { + // Surrogates followed by a non-surrValue range, + // or surrogates are part of a larger surrValue range. + return true; + } + } else { + if (start <= 0xd7ff) { + range.end = 0xd7ff; // Non-surrValue range ends before surrValue surrogates. + return true; + } + // Start is a surrogate with a non-surrValue code *unit* value. + // Return a surrValue code *point* range. + range.value = surrogateValue; + if (end > surrEnd) { + range.end = surrEnd; // Surrogate range ends before non-surrValue rest of range. + return true; + } + } + // See if the surrValue surrogate range can be merged with + // an immediately following range. + if (getRange(surrEnd + 1, filter, range) && range.value == surrogateValue) { + range.start = start; + return true; + } + range.start = start; + range.end = surrEnd; + range.value = surrogateValue; + return true; + } + + /** + * Convenience iterator over same-map-value code point ranges. + * Same as looping over all ranges with {@link #getRange(int, ValueFilter, Range)} + * without filtering. + * Adjacent ranges have different map values. + * + *

The iterator always returns the same Range object. + * + * @return a Range iterator + * @stable ICU 63 + */ + @Override + public Iterator iterator() { + return new RangeIterator(); + } + + /** + * Returns an iterator (not a java.util.Iterator) over code points of a string + * for fetching map values. + * + * @param s string to iterate over + * @param sIndex string index where the iteration will start + * @return the iterator + * @stable ICU 63 + */ + public StringIterator stringIterator(CharSequence s, int sIndex) { + return new StringIterator(s, sIndex); + } +} diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data.class new file mode 100644 index 0000000000000000000000000000000000000000..78c8c9b9df4d739f23da8a1074eb822383a807f6 GIT binary patch literal 722 zcma)4O-~y!5Pg$uSP0=Od=y%~;jnOEC9WV;DFt<<6{!SD&(6jQ4jV7>dMSUaCnOI1 z0Dcr=yal4(;)9>(dER*D$uF-@&j4E3tD}Od53hk5CJ6HbaWBGD=ziGl4rF2p6Q@cm zdq$`R2OS@igkaFS4VAXiXpx30DZ;|4G;C!(`72}o+9b@(& zqeg@Vm%cFBFw#Bwz_SFAV{3nmvOK{?5SM1DEOgR#VebliWsMZW6PH&%e@Nt=RhiCx ztP&PKvZMCr4QE|tg-PUvDoy#%!XqajOkT>|{>*agV}r0ahBe%Iq_s4yROGp2Lp|4^ zj~&9%81ns*HQe7Q@V4ReZ*i-}$o~a|DUL!$a_r$F=r12CsPpcwQOPmQ=f=MT#u>l^ xW-(XdJQhl9VzI;}EOX`xD?G+8sA8?G_Z8ntT*oG3lV9+$jxDc_ZN}a2Yj2R4wF&?L literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data16.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data16.class new file mode 100644 index 0000000000000000000000000000000000000000..3ef75482c9c120aa11fbccc9c1f55c3376237d76 GIT binary patch literal 1334 zcmb7ETTc@~6#izr?b1>}!EzNvLG8`9Al6F>F|HDu6fh~N4?LKmozR7{OSV(Q#C!ZD zzWCyU8ZU_t`~d%of50d8%(j+FLQ)@Q&&)UH`_5%f`~BCq0{|u#LeStdpoif{fFZh7 z*-l%w6t2x{X{+2wH>6cdn@&aCcL-l|EirS4OU@8juxv{%GWepgQV=}|8VH5ai!ejH zTbbD`gP*%Df6Sn*n?dwrz`%(xPGXQD)s0Mv*Bau1RgqN&<92?n_)v*v3jfE=g>VWH z1H)mAV3c8Wi|_HY<)l@ys|~r^kVWYVzQYiFY+T5_c_iZh^Y2T6KnGSE;HzX0tg4M!oOb6tc7KxoE5_kwXp% zDG{Yw5cZ~O9=&6pAx!9!>+Iz1ir8-!NT}ax9+}#E^)pOH3&%Anr! zim1zbPF)(f#xUK*R8SA{wk=$<#_M%Ksq3wQZ$1G9J!~T~H250*lo%}x;f6j_DnAJO-o zY^TaoPo>Gw+bZWV-Qs3i+(7&jjDvSa*v~rHfi`;v7h3Eb#ZpxmiajxZl>WS<1fxwi za1ochgrkTNUA5x{*#Oyu5?W3kEc&u~M4x+J3CA6};ZstV@w z`lbG>puNPj_R0%5MfeEG#gXv3o@j?oAc@NqIz`+*Xur^FAkElMa?cQ?)731Iuh3q@ eJg#~+i|b^^3D=Ot4Lw9po5f8+`pM>Qjr{>I92`~v literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data32.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data32.class new file mode 100644 index 0000000000000000000000000000000000000000..6f735a5869af56bcd0e1072078394c60465f9685 GIT binary patch literal 1329 zcmb7EOHUI~6#njX+6$$Cg5@cSg4&mDErO34Vnm6P6fh~N3l`?m-oQYaA=6vLoeLK} zqCdio8y9MPBrf;?{uTd#EA-rHEl5IA7c=MH@80h_=X`V8AN$|;0L&pDhJgTw89@*s zhS)}BGh;hSdXA`O>~cL*S9Ucs=T_tcm+)oJmXmjd5)7eRwqvVVhCnP{>O==RIl>Wi zA;OSoS7s{55EPy#o-i0IRwsJU%W)!tljvhewT0{LiprB>i=pGOXDewriouLo@e*|qTk)f*ePZY> z*p6JRZ>>siS*%tG=_|NpQ7sA2*83)Cs&%`@kZP+^UB*-{&%ns~?lq|nx1Ec{+Y&k8 zkdPM9ss-t+Y47MWS_~0F=RJ4Jaw>AS(IBBgyRl_@?YGY`7AqX*QC=&t9n!40)ZxhS z7paV*66MVWvF*FU_4I`A?Uv=XvR$XfafPA(Zysx@bwam_Zrv-(dD}Pmp9xKC0)41O zSyT7jn&OyYm}p}lsDI0Gq&HU;wVI^T&E~8(?5Cs$79vYCZ_uxZ(L+;D@1Xw-6EZ@p zSvu9{;lwwvMDh#xN7@+}rFTfPjORE_>w(5CjNuIJ=swPpnpPdhxu#Z{qDIV5=>9=#|n5M04@LJI=Kufz literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data8.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Data8.class new file mode 100644 index 0000000000000000000000000000000000000000..793b818747da4b9e8f34cd2aeea594fece895f33 GIT binary patch literal 1332 zcmb7E%Tg0T6g@qe$&d#iV33C>3Th_7B!WgX6k0(kQx(9fP;tS+8j>y;2s6~AgRo)c zC-^8`x^d$|Egw}b_yB*!A8-ZUp2QHTqAD(WZujjz=iYnz_WV5jaR6WrGeIcu=}^Pa z;Ae<#lsA)>Ex2o&m84awC2PW}B<{pExk`15>-8#;M(Su%wL^~`+vr^+vtg=|Al(MOU}HBk^QH@6r9&s5k zJ5=P*>4zzmf-p;)3+A>bj4t~p_;9zxw}s`{RUMNIeSc%+mYO?ss^HYz5}&s`jsNM< zgaj~jEb^*&NKw-(^o$q{YJ2)> z-WVj$5Y1+3SMCR6-@#(>uh2iyO2IIF{Su|TznJWYxDsTg zNBxY>k7Qd}UV1EbgxX}ejIjnb)xi2=U!Wg+IDvlEg7!DjQq{bN3?I~d#$-gLJuR+$B#J+06aHKfQDvU;qFB literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast$FastStringIterator.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast$FastStringIterator.class new file mode 100644 index 0000000000000000000000000000000000000000..d3c701b72c7ca12ab82898d548c3d0166f7c584a GIT binary patch literal 2528 zcmbtV-BTM?6#rfBLP%IX1g%9%Z3~qoAc0oVHhiZ>q5%V;P_V^bk|kMKc42pewCdQ} z2cJ6Qj8E+dGy38S(;1yosSo}E{!4Zo&s}0H1tl|PCVTHad(ZEj^E)5=`=7u51|WtF zA1WByma{7n-E=kE6h=hP6e0yzHzF}BtEDWGPusfYhk{BUs#N$;%@8d^r9Cbj*L$R0 zTQ_qFG9X;bW~g%Wy3^jn5Kfkh6Ad7M8Xr^@wWwq0Jw|a{thFC9+pn9tJIF8`JkBnu zN0ZB9LqrT=<|47Yu+!RlK{GR2G!dGSY&58N35^ttlQ6T|CId@I@yjY+!3jD!3@85$ zq6R0??89p+T5yWt#L<=r+tAFMn`hv`P(mu5R`EK{(2ERtG~zNS!9*w~?VeN7Cf#9~ z0M6qLA39V75n^aM2re>|28J5lNf&I}$_ZDKD6!Cd0G;Ua;Y}6Yh%f|?VOUm$mt6+` z5@ou`f^;YmKrb%%a8bouc$=a75R|^UW<(||dsP_vZOu;5vHj|Fytgl96o|O`=e$d5 zBD)_ad3YZ0sCZX~Ri`^i>(f#U^3`P(QS?)6u2rgChRR?p7NXP)V#tSK6(bleGq~wn zYm%GzNP4>5Qk5!Hs-3u^;yuI}0uF^}6uId>w(dMqJrH8iPdH;L5;CoUtZ+rrs|G3l zP(>2s)aK(OU`|Sln;|CrpnH;RAf+dnj5#RRWBG>a?>iVO5Z9sgi+9B24+=U zlgXj{jp@03DLV}D@G}TdZo-KLn|m+9vfMHRe1ufJ{R%$(61xbb}f(Mwbk) zcx%(H$gI#zDSB1CW@{U|B`ZCUwhDGei|bwprLvX&bj!wNsGiUqcg%9gn3^z6&5jwu zaWv_IWQziq%fVUagT-*}P}dzC>*No$(Tj>S8`=*k9?`B8^m7fX6njNh3VNtE0`z@h z4Gr>ZK|78L8ryU9oTpQo-Yc}$hC6q`!<}8Nzrg?JpH-B zJ@h?5(8Kj$!!50QxI~~5?Pu>g0mcZhR!Sb@eI+{(-rs(3>Io)xkydsn6z-97nP>r@ zK?9#fBcDSDpGOzJj*I*TMmfdF1x&t(O`gGBp2fF(30qvp4qx^N97Gj{2y2nZs=zm; zU7m(X23a}-kBanm;A?0kW7r~c_cfO2eI1m>XEZeaK%pGL&T;2Hil?vl3OKP;&Z0NXO{57t)%dO`Ly8UYw&X$r@4bRUO<>{;1a)u zNq!p({4?bF=UC@o;2!@H_xV@&j^8Ws*;iumPHA_I_>|m9KDUc}p2i)IV}|=L^6B5_ zGvV>ckteMR=vekvh80>bQ06*`YeSJUw-c+B!2nFGk*pW%aL`QOHU@XNnMON9K?(c? D%#?3$ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast.class new file mode 100644 index 0000000000000000000000000000000000000000..1237414cab84916d1504aa33bfe18f390dc0c9f5 GIT binary patch literal 2398 zcmb_eU31e$6g_Jx5q3myQep^!kbs*yPHOYfZ->=5Shh>IS zoWunP`+*hf+MRAau)IJZ9fDoo8aU3~cH5U+8ds2q7oNo9=6_LRSf&zd{q#WF0$1Yb zID05QN!no>klCrXHim%Fk-@ORmvgb&BpdcNZ=s#t{w+n5;Sc)JsM(LiEt&!+$!zoS z9jhOeIJGJJo@`oyYza)?AGm?NE4OXmrV7?ww-;D}-E*00W|(TIt5oN19t@qaT@)V1gN0H6J7NVd+^Omz(7Ob>M`JNl4gLt ze(Csatlm+!^?BZCg0De(Q5&J%c#zbRU1qZrc+ z8^27DZm8Pw4*>jQrBC zIQb_gexUC#vdRxyCXAYiaIfP7K3BLO;v+tvz{mI`LMza62Xvynjxrmfn8WA8+;xFZ zafa>!pDByeDA8&mC(okH7G}Q3?9Ajl&ymc}{DRZ_Gm~eZlPQMabb3GkGcM?@eeTvm zw$3Sbv=!*u4WzVHq_vyKXluBrl@Fa`;efpbtdJFf8!B%k(&OY;eQxrr&c8-Gfpu(f ztZG#ygNoO&-!cDfe(C%RTz>tiwJ^}!(Cr}582|ljhQ}Yn=M0(P^9q3yxP{xH6$A%M nGm0@=;wO$#d(J^{S80~brB(k>_PKU z&ahnFwlp(mG`hL2YnZuGyQ$xAQ@m;$dU`{1wfwRK20=yyQHJP>VHxf!LqypvWoi;) zh>MW;>JWnxB~z#DL|{4ztlNom$?TRUP1 z?Uv#g$4erTGA1w?kazW{qmvMu>y;{j2jb3;6yli1jEGqoFXJM^LXb<>G_$KeFq-Z@ zgIH9nm52Ni*8+i_pDjp8;S~|D%6JWz87>EaW{_HT`><$OnoU}LtpvjKE*fa(0K4*m z_Jx+SjCQVg7zo7^XZ9re^Ks*3Y)yvhB7l;VQ0iTjv?V3U~T2uFF{B zi18M=%EJs(X&{Wz(^I~FL&n>9hZJ-UHPh^oTKEqN5`76Pcvr-#jGI_vxNy#|WYT3A zCYriq*m|>1x8iDUmllZS4q;PW?UuZHAwhUKQ08~yx^7pw1`LUEyP=si%{KUZ zFDSVC2IZL#@&(dWP5x#dY zP$H53uNelY)X7J5gXF&^BZc-jIBQTFs~>i5^Os>F+IVzV>-01boo>fpiLEruUaylX z?XKO>Hw{m^=UU_fr_B)C(jE6sn>RLDwJhECJ{IQ^<^7AxB5=h-d>XLZ@MCnyAEIY% zOz@kKbY4ZslksBI*h5J0z6gv?ar09oN>2pqWYHqczM^*?naW;y2DUwag7C$pkc^x_ z%+CJ|`3G7H(eD8mAxA?Hkq}~-6yn&R*s6aPx3EcXlm)j5i_A~6J2VS(=38Gb)dUFCO2pgKRI%Y#4+*t1(*K7@Dqyo_))$pBt2Z&--#{UqxCV|$6PPV zP0GSihq6CG&dxqXdg=QYQe5&FIoB+%41A~XTL#wHZlJ# zhMwW-_6c&opP?*zC}B@1iDwq(FfAwpNa;ROx`$LDUIId6B4Jkhm4Xx6D5kAkz|I< z@H=?uE6ni1LkZAy=nU}8k0RWa9LFs@2p%-Mdw2JqbI;y;_2*x|{sy3omWU8Tdbhoo zH7r-REzQgttzNe08fLcKZR-!ZWUt$Xo?6vhZ7C;#L68walp(roScbd85K$WH!n%YJ z#6(DZca%X1;&e@OT!x&|C|80U=N$5?N?F(%@ijB!i^jDUkJ4QR+U^d6 zSW@e?hdhXDfk4mh<|QO?QN*hkO)FBz6*lUCm-fiS&51DzaVSJ~CR z)UuY*&6W;bz0~V;bUVKg#0v!$$LliQz-7{>b)Z^p{VRGKMO~n$jblMZ8dn(3r!>dW zZP(~p&Z^;PO;c|(u&pp~av~zbFynDBHETOtJUx2bw!5~3tGLF~`Z_~c;h7%Cl8hT1 zG1j51@-V|x8VF-|Dk7g0Xs0~&7Om5N{esk;yi6i3k6tDb&_+zs8_))$qR6ShTKZ*NzK>HK; z5SRO2Zjl#`I-33&a(ey=QkfrKaIxXJnDUPesE^_!qQuBqZQ!iaca}PW@(5Gm`EL=M zPb_|i(Py~2d5rAurzklOCF}_$anHgRm=&}kq|^W@)kmrmF9D$mkuX0VVD54o?I<4R zbmC1P^sN^`NhONz?SJ6zVoul_!c_*i%JaAhkrHH`62(u18=j;jW+M3n`9~0i?;(VL zf^wDt{tM*6iANBU3sgJU@YMYTo8Fkj7L7Sd3r2sM2IdGOiBE+XKBMuWz?)(cqz(OU Olh6vYG)tmcnEe|O$pZ5L literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast8.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Fast8.class new file mode 100644 index 0000000000000000000000000000000000000000..d53887d2d5ba6d0bbf040f6338ee503bdce933fc GIT binary patch literal 2193 zcmbVN&vV;E6#mwhqga*m!y&&ZE;LZtapN{A5O4^Iou(DIX~D)NF;HY%PLwLLN0J!= z3|Fq4m?778h6@Ksp<(C@aORJ~yp>!#?erixXmvuDT_%;cMO{Z^CgCEL*FHZ)gTmcSs$h+u$WV8yTucaLD^gaposcu~enIL~lC05XHru$u=t!_sV$>N_P6rWa?Rlc(4f z_O;KnjAb-4xkFdawHpoH&L)F+p}=BzS;i~4z#!IIs#VuNr>9ZWq{?$7DIhOs%# zadg`?nwGO+I9k=z>kMos40Jjo78s^H4yI=9X4W4cy=vP{Tf#+L;z@m(A*}E`k6}s1 z6^Q6VJZxSG1BSq{bd<%;7wA{InYeAOKRaiC`j}rtl%vXt1{lk8pCj(U*4o( z7$)kvW7vAVN4Mx|ZkslUlCNTXej&1zIs)q~bGzK9Xe+T9yktE+YdI)je6@if{p8RAPpf7@TO3@t6zM?g^Or_=@fo-Qx5I#FD zj7Lr&rqaJc{+aed^lt!$D5D`9A})M^N#RRukZsk!i>uhA6?wrmT<6J8GnG(7-s~N` z%kPq{Kr_Lc-Jn?nQR+ZjT_($PhTj}IM*Nug{Dv3)LhL89`1k{SSNO)mmHm^riCeTk ziuZ7#>m^TKIO=ff7s#pEhnQO$Md#}upK|l9=Vrn`+M_>=_lXuGhsB=5{jNjh7|IbQ z!n5}fosFmOg zqVNNR@B=9QZ17*h1t%XtNM55V!fj9G53%iy3GC3gNGZbThf~1}VI=U85XHwd-Vu0j UOyE=c4UW;MtxeM`f$G}yzxLP&kpKVy literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Small$SmallStringIterator.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Small$SmallStringIterator.class new file mode 100644 index 0000000000000000000000000000000000000000..b8655a18975cb4f580f7370e130f11cf4ddb6035 GIT binary patch literal 2536 zcmbtVT}&KR6#g!EmSLCSN6=cNU|Y7bKgdF>Xv;raX;&AdT}lfocGw+v2ZkA#okjGi z#s{C8nE2F2Nc6=Q(nM1#^}#naQKQksznJKYMx%*;G10`vc<$`FEv1!B++^q8d*+_+ zob#QZdH3%(-UJZEl8iEjmf6%?L^mDHHdP~{Cv%aUqZ^T^mD0v6l8@WE=7j{0jB*7s zDj0f8Q1K_`Rl~?X6OOH$=@^+%9m{4YcQSg`-@y=$myFcygAbK56a`hNX6W2Tb3|S6 zZ?W5>o4V7-Fc8?zFsXOPXVoP&VyI?163wV~LR-vfW>V{p1t$a{wF+)Q9YvFknJI0V zfyIRQRt2|V2c5DEJ8uS2iJfSWafgCN>|)q)V@rf>XlB~UFz`SyCX|{L+=<=vB1s+% zIt)@E7K{qJdlj?@cUaPgeYi_TtAYT64E3AA)gj z zZQWf3AsW4eb5uc0q}7*F9X0M&gAhNYAdV5@MTkpv?l9dY=N`tGjAIIpi!7JKgivHq z(wZ}DTk~!(qU6REoDjZwmQ*9Bi4>eva7tu{5_nWkXNu`zI8s{Z?$r3N&ZCe;a>+zo zH?`5+{ETLgt1|{k>f%;XH6~PB7w3Xd60?S(zohKlbY^uk)Q)IQ#!8K;wmPp-3lXSf zYRlAu)SFWbUXh7Ho;{AO>IU^BkV);Vfr$(Rx|P0fxPYBsBpuE%wmn%rGC4?Gzb!`^Kwojjsux?Yh6 zgnx_T4Vsq1zNT%Ze8)(lT+l%U;-l{jtF0AZ4cc*((d?e2=MFwiUPnXE%zdwf4 zP{D*vb{rnp=7rEj)X=~FGHz#hiHxj?Q)rUJQ_|^m)LceW8G1sE>)6w{0snc_(FIQb zJ(m#beFf7b?Kp=Kl3WFP8NDtH$z1)(z72GpL%_v#VMC2g8#qXy0_`>TIsrxruu4cS z;)s;$4du5F?z)80btI%U3Wd9*93oo4-$N~bA9ef#wDJ$p#y`RV{xOF5Cs6sPF!^U# z=AYvk{sms(Ut)!Sg*E=QOJE<$(N9=2L{=G|FYYolQIbf}8MsiOw-wJpBN@XAk(<|e zg5Fm{s=Gpy<1dU|ftP9==_0>Fg`BQZ1T`z0Xq8e^CD3|O(0U%jLVp$gwA72Olq&K$ zQRFj4c%ddz_`iI91DSsdFaHkB{Cl+U9}wa{;voMC$N0~f=D#4rf5jsI4bSr5ahCsq z7x|w>KD&x6o+<855ubuP!RKm$&t{x)Ic7L}J)hn@pD~wDjtps)LC37SGR)DspE4IF jt_?{H-Z17VgFcv8AXz6CkwpW2;TW8O2Ab~-Im!1Ao@9X4 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Small.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie$Small.class new file mode 100644 index 0000000000000000000000000000000000000000..3c762a195e83978e285fa4c0f9a44566d6a33be0 GIT binary patch literal 2368 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie.class b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie.class new file mode 100644 index 0000000000000000000000000000000000000000..6743fdee0d4151769fb464d2d805af646a33e3ae GIT binary patch literal 11830 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 L4DBxC+bI11+jP0T literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/CodePointTrie.java b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie.java new file mode 100644 index 00000000..7aaa0be6 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/util/CodePointTrie.java @@ -0,0 +1,1266 @@ +/* + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +// (c) 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html#License + +// created: 2018may04 Markus W. Scherer + +package jdk.internal.icu.util; + +import jdk.internal.icu.impl.ICUBinary; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import static jdk.internal.icu.impl.NormalizerImpl.UTF16Plus; + +/** + * Immutable Unicode code point trie. + * Fast, reasonably compact, map from Unicode code points (U+0000..U+10FFFF) to integer values. + * For details see https://icu.unicode.org/design/struct/utrie + * + *

This class is not intended for public subclassing. + * + * @see MutableCodePointTrie + * @stable ICU 63 + */ +@SuppressWarnings("deprecation") +public abstract class CodePointTrie extends CodePointMap { + /** + * Selectors for the type of a CodePointTrie. + * Different trade-offs for size vs. speed. + * + *

Use null for {@link #fromBinary} to accept any type; + * {@link #getType} will return the actual type. + * + * @see MutableCodePointTrie#buildImmutable(CodePointTrie.Type, CodePointTrie.ValueWidth) + * @see #fromBinary + * @see #getType + * @stable ICU 63 + */ + public enum Type { + /** + * Fast/simple/larger BMP data structure. + * The {@link Fast} subclasses have additional functions for lookup for BMP and supplementary code points. + * + * @see Fast + * @stable ICU 63 + */ + FAST, + /** + * Small/slower BMP data structure. + * + * @see Small + * @stable ICU 63 + */ + SMALL + } + + /** + * Selectors for the number of bits in a CodePointTrie data value. + * + *

Use null for {@link #fromBinary} to accept any data value width; + * {@link #getValueWidth} will return the actual data value width. + * + * @stable ICU 63 + */ + public enum ValueWidth { + /** + * The trie stores 16 bits per data value. + * It returns them as unsigned values 0..0xffff=65535. + * + * @stable ICU 63 + */ + BITS_16, + /** + * The trie stores 32 bits per data value. + * + * @stable ICU 63 + */ + BITS_32, + /** + * The trie stores 8 bits per data value. + * It returns them as unsigned values 0..0xff=255. + * + * @stable ICU 63 + */ + BITS_8 + } + + private CodePointTrie(char[] index, Data data, int highStart, + int index3NullOffset, int dataNullOffset) { + this.ascii = new int[ASCII_LIMIT]; + this.index = index; + this.data = data; + this.dataLength = data.getDataLength(); + this.highStart = highStart; + this.index3NullOffset = index3NullOffset; + this.dataNullOffset = dataNullOffset; + + for (int c = 0; c < ASCII_LIMIT; ++c) { + ascii[c] = data.getFromIndex(c); + } + + int nullValueOffset = dataNullOffset; + if (nullValueOffset >= dataLength) { + nullValueOffset = dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + } + nullValue = data.getFromIndex(nullValueOffset); + } + + /** + * Creates a trie from its binary form, + * stored in the ByteBuffer starting at the current position. + * Advances the buffer position to just after the trie data. + * Inverse of {@link #toBinary(OutputStream)}. + * + *

The data is copied from the buffer; + * later modification of the buffer will not affect the trie. + * + * @param type selects the trie type; this method throws an exception + * if the type does not match the binary data; + * use null to accept any type + * @param valueWidth selects the number of bits in a data value; this method throws an exception + * if the valueWidth does not match the binary data; + * use null to accept any data value width + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @see MutableCodePointTrie#MutableCodePointTrie(int, int) + * @see MutableCodePointTrie#buildImmutable(CodePointTrie.Type, CodePointTrie.ValueWidth) + * @see #toBinary(OutputStream) + * @stable ICU 63 + */ + public static CodePointTrie fromBinary(Type type, ValueWidth valueWidth, ByteBuffer bytes) { + ByteOrder outerByteOrder = bytes.order(); + try { + // Enough data for a trie header? + if (bytes.remaining() < 16 /* sizeof(UCPTrieHeader) */) { + throw new InternalError("Buffer too short for a CodePointTrie header"); + } + + // struct UCPTrieHeader + /** "Tri3" in big-endian US-ASCII (0x54726933) */ + int signature = bytes.getInt(); + + // Check the signature. + switch (signature) { + case 0x54726933: + // The buffer is already set to the trie data byte order. + break; + case 0x33697254: + // Temporarily reverse the byte order. + boolean isBigEndian = outerByteOrder == ByteOrder.BIG_ENDIAN; + bytes.order(isBigEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); + signature = 0x54726933; + break; + default: + throw new InternalError("Buffer does not contain a serialized CodePointTrie"); + } + + // struct UCPTrieHeader continued + /** + * Options bit field: + * Bits 15..12: Data length bits 19..16. + * Bits 11..8: Data null block offset bits 19..16. + * Bits 7..6: UCPTrieType + * Bits 5..3: Reserved (0). + * Bits 2..0: UCPTrieValueWidth + */ + int options = bytes.getChar(); + + /** Total length of the index tables. */ + int indexLength = bytes.getChar(); + + /** Data length bits 15..0. */ + int dataLength = bytes.getChar(); + + /** Index-3 null block offset, 0x7fff or 0xffff if none. */ + int index3NullOffset = bytes.getChar(); + + /** Data null block offset bits 15..0, 0xfffff if none. */ + int dataNullOffset = bytes.getChar(); + + /** + * First code point of the single-value range ending with U+10ffff, + * rounded up and then shifted right by SHIFT_2. + */ + int shiftedHighStart = bytes.getChar(); + // struct UCPTrieHeader end + + int typeInt = (options >> 6) & 3; + Type actualType; + switch (typeInt) { + case 0: actualType = Type.FAST; break; + case 1: actualType = Type.SMALL; break; + default: + throw new InternalError("CodePointTrie data header has an unsupported type"); + } + + int valueWidthInt = options & OPTIONS_VALUE_BITS_MASK; + ValueWidth actualValueWidth; + switch (valueWidthInt) { + case 0: actualValueWidth = ValueWidth.BITS_16; break; + case 1: actualValueWidth = ValueWidth.BITS_32; break; + case 2: actualValueWidth = ValueWidth.BITS_8; break; + default: + throw new InternalError("CodePointTrie data header has an unsupported value width"); + } + + if ((options & OPTIONS_RESERVED_MASK) != 0) { + throw new InternalError("CodePointTrie data header has unsupported options"); + } + + if (type == null) { + type = actualType; + } + if (valueWidth == null) { + valueWidth = actualValueWidth; + } + if (type != actualType || valueWidth != actualValueWidth) { + throw new InternalError("CodePointTrie data header has a different type or value width than required"); + } + + // Get the length values and offsets. + dataLength |= ((options & OPTIONS_DATA_LENGTH_MASK) << 4); + dataNullOffset |= ((options & OPTIONS_DATA_NULL_OFFSET_MASK) << 8); + + int highStart = shiftedHighStart << SHIFT_2; + + // Calculate the actual length, minus the header. + int actualLength = indexLength * 2; + if (valueWidth == ValueWidth.BITS_16) { + actualLength += dataLength * 2; + } else if (valueWidth == ValueWidth.BITS_32) { + actualLength += dataLength * 4; + } else { + actualLength += dataLength; + } + if (bytes.remaining() < actualLength) { + throw new InternalError("Buffer too short for the CodePointTrie data"); + } + + char[] index = ICUBinary.getChars(bytes, indexLength, 0); + switch (valueWidth) { + case BITS_16: { + char[] data16 = ICUBinary.getChars(bytes, dataLength, 0); + return type == Type.FAST ? + new Fast16(index, data16, highStart, index3NullOffset, dataNullOffset) : + new Small16(index, data16, highStart, index3NullOffset, dataNullOffset); + } + case BITS_32: { + int[] data32 = ICUBinary.getInts(bytes, dataLength, 0); + return type == Type.FAST ? + new Fast32(index, data32, highStart, index3NullOffset, dataNullOffset) : + new Small32(index, data32, highStart, index3NullOffset, dataNullOffset); + } + case BITS_8: { + byte[] data8 = ICUBinary.getBytes(bytes, dataLength, 0); + return type == Type.FAST ? + new Fast8(index, data8, highStart, index3NullOffset, dataNullOffset) : + new Small8(index, data8, highStart, index3NullOffset, dataNullOffset); + } + default: + throw new AssertionError("should be unreachable"); + } + } finally { + bytes.order(outerByteOrder); + } + } + + /** + * Returns the trie type. + * + * @return the trie type + * @stable ICU 63 + */ + public abstract Type getType(); + /** + * Returns the number of bits in a trie data value. + * + * @return the number of bits in a trie data value + * @stable ICU 63 + */ + public final ValueWidth getValueWidth() { return data.getValueWidth(); } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public int get(int c) { + return data.getFromIndex(cpIndex(c)); + } + + /** + * Returns a trie value for an ASCII code point, without range checking. + * + * @param c the input code point; must be U+0000..U+007F + * @return The ASCII code point's trie value. + * @stable ICU 63 + */ + public final int asciiGet(int c) { + return ascii[c]; + } + + private static final int MAX_UNICODE = 0x10ffff; + + private static final int ASCII_LIMIT = 0x80; + + private static final int maybeFilterValue(int value, int trieNullValue, int nullValue, + ValueFilter filter) { + if (value == trieNullValue) { + value = nullValue; + } else if (filter != null) { + value = filter.apply(value); + } + return value; + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final boolean getRange(int start, ValueFilter filter, Range range) { + if (start < 0 || MAX_UNICODE < start) { + return false; + } + if (start >= highStart) { + int di = dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + int value = data.getFromIndex(di); + if (filter != null) { value = filter.apply(value); } + range.set(start, MAX_UNICODE, value); + return true; + } + + int nullValue = this.nullValue; + if (filter != null) { nullValue = filter.apply(nullValue); } + Type type = getType(); + + int prevI3Block = -1; + int prevBlock = -1; + int c = start; + // Initialize to make compiler happy. Real value when haveValue is true. + int trieValue = 0, value = 0; + boolean haveValue = false; + do { + int i3Block; + int i3; + int i3BlockLength; + int dataBlockLength; + if (c <= 0xffff && (type == Type.FAST || c <= SMALL_MAX)) { + i3Block = 0; + i3 = c >> FAST_SHIFT; + i3BlockLength = type == Type.FAST ? BMP_INDEX_LENGTH : SMALL_INDEX_LENGTH; + dataBlockLength = FAST_DATA_BLOCK_LENGTH; + } else { + // Use the multi-stage index. + int i1 = c >> SHIFT_1; + if (type == Type.FAST) { + assert(0xffff < c && c < highStart); + i1 += BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH; + } else { + assert(c < highStart && highStart > SMALL_LIMIT); + i1 += SMALL_INDEX_LENGTH; + } + i3Block = index[index[i1] + ((c >> SHIFT_2) & INDEX_2_MASK)]; + if (i3Block == prevI3Block && (c - start) >= CP_PER_INDEX_2_ENTRY) { + // The index-3 block is the same as the previous one, and filled with value. + assert((c & (CP_PER_INDEX_2_ENTRY - 1)) == 0); + c += CP_PER_INDEX_2_ENTRY; + continue; + } + prevI3Block = i3Block; + if (i3Block == index3NullOffset) { + // This is the index-3 null block. + if (haveValue) { + if (nullValue != value) { + range.set(start, c - 1, value); + return true; + } + } else { + trieValue = this.nullValue; + value = nullValue; + haveValue = true; + } + prevBlock = dataNullOffset; + c = (c + CP_PER_INDEX_2_ENTRY) & ~(CP_PER_INDEX_2_ENTRY - 1); + continue; + } + i3 = (c >> SHIFT_3) & INDEX_3_MASK; + i3BlockLength = INDEX_3_BLOCK_LENGTH; + dataBlockLength = SMALL_DATA_BLOCK_LENGTH; + } + // Enumerate data blocks for one index-3 block. + do { + int block; + if ((i3Block & 0x8000) == 0) { + block = index[i3Block + i3]; + } else { + // 18-bit indexes stored in groups of 9 entries per 8 indexes. + int group = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3); + int gi = i3 & 7; + block = (index[group++] << (2 + (2 * gi))) & 0x30000; + block |= index[group + gi]; + } + if (block == prevBlock && (c - start) >= dataBlockLength) { + // The block is the same as the previous one, and filled with value. + assert((c & (dataBlockLength - 1)) == 0); + c += dataBlockLength; + } else { + int dataMask = dataBlockLength - 1; + prevBlock = block; + if (block == dataNullOffset) { + // This is the data null block. + if (haveValue) { + if (nullValue != value) { + range.set(start, c - 1, value); + return true; + } + } else { + trieValue = this.nullValue; + value = nullValue; + haveValue = true; + } + c = (c + dataBlockLength) & ~dataMask; + } else { + int di = block + (c & dataMask); + int trieValue2 = data.getFromIndex(di); + if (haveValue) { + if (trieValue2 != trieValue) { + if (filter == null || + maybeFilterValue(trieValue2, this.nullValue, nullValue, + filter) != value) { + range.set(start, c - 1, value); + return true; + } + trieValue = trieValue2; // may or may not help + } + } else { + trieValue = trieValue2; + value = maybeFilterValue(trieValue2, this.nullValue, nullValue, filter); + haveValue = true; + } + while ((++c & dataMask) != 0) { + trieValue2 = data.getFromIndex(++di); + if (trieValue2 != trieValue) { + if (filter == null || + maybeFilterValue(trieValue2, this.nullValue, nullValue, + filter) != value) { + range.set(start, c - 1, value); + return true; + } + trieValue = trieValue2; // may or may not help + } + } + } + } + } while (++i3 < i3BlockLength); + } while (c < highStart); + assert(haveValue); + int di = dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + int highValue = data.getFromIndex(di); + if (maybeFilterValue(highValue, this.nullValue, nullValue, filter) != value) { + --c; + } else { + c = MAX_UNICODE; + } + range.set(start, c, value); + return true; + } + + /** + * Writes a representation of the trie to the output stream. + * Inverse of {@link #fromBinary}. + * + * @param os the output stream + * @return the number of bytes written + * @stable ICU 63 + */ + public final int toBinary(OutputStream os) { + try { + DataOutputStream dos = new DataOutputStream(os); + + // Write the UCPTrieHeader + dos.writeInt(0x54726933); // signature="Tri3" + dos.writeChar( // options + ((dataLength & 0xf0000) >> 4) | + ((dataNullOffset & 0xf0000) >> 8) | + (getType().ordinal() << 6) | + getValueWidth().ordinal()); + dos.writeChar(index.length); + dos.writeChar(dataLength); + dos.writeChar(index3NullOffset); + dos.writeChar(dataNullOffset); + dos.writeChar(highStart >> SHIFT_2); // shiftedHighStart + int length = 16; // sizeof(UCPTrieHeader) + + for (char i : index) { dos.writeChar(i); } + length += index.length * 2; + length += data.write(dos); + return length; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** @internal */ + static final int FAST_SHIFT = 6; + + /** Number of entries in a data block for code points below the fast limit. 64=0x40 @internal */ + static final int FAST_DATA_BLOCK_LENGTH = 1 << FAST_SHIFT; + + /** Mask for getting the lower bits for the in-fast-data-block offset. @internal */ + private static final int FAST_DATA_MASK = FAST_DATA_BLOCK_LENGTH - 1; + + /** @internal */ + private static final int SMALL_MAX = 0xfff; + + /** + * Offset from dataLength (to be subtracted) for fetching the + * value returned for out-of-range code points and ill-formed UTF-8/16. + * @internal + */ + private static final int ERROR_VALUE_NEG_DATA_OFFSET = 1; + /** + * Offset from dataLength (to be subtracted) for fetching the + * value returned for code points highStart..U+10FFFF. + * @internal + */ + private static final int HIGH_VALUE_NEG_DATA_OFFSET = 2; + + // ucptrie_impl.h + + /** The length of the BMP index table. 1024=0x400 */ + private static final int BMP_INDEX_LENGTH = 0x10000 >> FAST_SHIFT; + + static final int SMALL_LIMIT = 0x1000; + private static final int SMALL_INDEX_LENGTH = SMALL_LIMIT >> FAST_SHIFT; + + /** Shift size for getting the index-3 table offset. */ + static final int SHIFT_3 = 4; + + /** Shift size for getting the index-2 table offset. */ + private static final int SHIFT_2 = 5 + SHIFT_3; + + /** Shift size for getting the index-1 table offset. */ + private static final int SHIFT_1 = 5 + SHIFT_2; + + /** + * Difference between two shift sizes, + * for getting an index-2 offset from an index-3 offset. 5=9-4 + */ + static final int SHIFT_2_3 = SHIFT_2 - SHIFT_3; + + /** + * Difference between two shift sizes, + * for getting an index-1 offset from an index-2 offset. 5=14-9 + */ + static final int SHIFT_1_2 = SHIFT_1 - SHIFT_2; + + /** + * Number of index-1 entries for the BMP. (4) + * This part of the index-1 table is omitted from the serialized form. + */ + private static final int OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1; + + /** Number of entries in an index-2 block. 32=0x20 */ + static final int INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2; + + /** Mask for getting the lower bits for the in-index-2-block offset. */ + static final int INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1; + + /** Number of code points per index-2 table entry. 512=0x200 */ + static final int CP_PER_INDEX_2_ENTRY = 1 << SHIFT_2; + + /** Number of entries in an index-3 block. 32=0x20 */ + static final int INDEX_3_BLOCK_LENGTH = 1 << SHIFT_2_3; + + /** Mask for getting the lower bits for the in-index-3-block offset. */ + private static final int INDEX_3_MASK = INDEX_3_BLOCK_LENGTH - 1; + + /** Number of entries in a small data block. 16=0x10 */ + static final int SMALL_DATA_BLOCK_LENGTH = 1 << SHIFT_3; + + /** Mask for getting the lower bits for the in-small-data-block offset. */ + static final int SMALL_DATA_MASK = SMALL_DATA_BLOCK_LENGTH - 1; + + // ucptrie_impl.h: Constants for use with UCPTrieHeader.options. + private static final int OPTIONS_DATA_LENGTH_MASK = 0xf000; + private static final int OPTIONS_DATA_NULL_OFFSET_MASK = 0xf00; + private static final int OPTIONS_RESERVED_MASK = 0x38; + private static final int OPTIONS_VALUE_BITS_MASK = 7; + /** + * Value for index3NullOffset which indicates that there is no index-3 null block. + * Bit 15 is unused for this value because this bit is used if the index-3 contains + * 18-bit indexes. + */ + static final int NO_INDEX3_NULL_OFFSET = 0x7fff; + static final int NO_DATA_NULL_OFFSET = 0xfffff; + + private abstract static class Data { + abstract ValueWidth getValueWidth(); + abstract int getDataLength(); + abstract int getFromIndex(int index); + abstract int write(DataOutputStream dos) throws IOException; + } + + private static final class Data16 extends Data { + char[] array; + Data16(char[] a) { array = a; } + @Override ValueWidth getValueWidth() { return ValueWidth.BITS_16; } + @Override int getDataLength() { return array.length; } + @Override int getFromIndex(int index) { return array[index]; } + @Override int write(DataOutputStream dos) throws IOException { + for (char v : array) { dos.writeChar(v); } + return array.length * 2; + } + } + + private static final class Data32 extends Data { + int[] array; + Data32(int[] a) { array = a; } + @Override ValueWidth getValueWidth() { return ValueWidth.BITS_32; } + @Override int getDataLength() { return array.length; } + @Override int getFromIndex(int index) { return array[index]; } + @Override int write(DataOutputStream dos) throws IOException { + for (int v : array) { dos.writeInt(v); } + return array.length * 4; + } + } + + private static final class Data8 extends Data { + byte[] array; + Data8(byte[] a) { array = a; } + @Override ValueWidth getValueWidth() { return ValueWidth.BITS_8; } + @Override int getDataLength() { return array.length; } + @Override int getFromIndex(int index) { return array[index] & 0xff; } + @Override int write(DataOutputStream dos) throws IOException { + for (byte v : array) { dos.writeByte(v); } + return array.length; + } + } + + /** @internal */ + private final int[] ascii; + + /** @internal */ + private final char[] index; + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final Data data; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int dataLength; + /** + * Start of the last range which ends at U+10FFFF. + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int highStart; + + /** + * Internal index-3 null block offset. + * Set to an impossibly high value (e.g., 0xffff) if there is no dedicated index-3 null block. + * @internal + */ + private final int index3NullOffset; + /** + * Internal data null block offset, not shifted. + * Set to an impossibly high value (e.g., 0xfffff) if there is no dedicated data null block. + * @internal + */ + private final int dataNullOffset; + /** @internal */ + private final int nullValue; + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int fastIndex(int c) { + return index[c >> FAST_SHIFT] + (c & FAST_DATA_MASK); + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int smallIndex(Type type, int c) { + // Split into two methods to make this part inline-friendly. + // In C, this part is a macro. + if (c >= highStart) { + return dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + } + return internalSmallIndex(type, c); + } + + private final int internalSmallIndex(Type type, int c) { + int i1 = c >> SHIFT_1; + if (type == Type.FAST) { + assert(0xffff < c && c < highStart); + i1 += BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH; + } else { + assert(0 <= c && c < highStart && highStart > SMALL_LIMIT); + i1 += SMALL_INDEX_LENGTH; + } + int i3Block = index[index[i1] + ((c >> SHIFT_2) & INDEX_2_MASK)]; + int i3 = (c >> SHIFT_3) & INDEX_3_MASK; + int dataBlock; + if ((i3Block & 0x8000) == 0) { + // 16-bit indexes + dataBlock = index[i3Block + i3]; + } else { + // 18-bit indexes stored in groups of 9 entries per 8 indexes. + i3Block = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3); + i3 &= 7; + dataBlock = (index[i3Block++] << (2 + (2 * i3))) & 0x30000; + dataBlock |= index[i3Block + i3]; + } + return dataBlock + (c & SMALL_DATA_MASK); + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected abstract int cpIndex(int c); + + /** + * A CodePointTrie with {@link Type#FAST}. + * + * @stable ICU 63 + */ + public abstract static class Fast extends CodePointTrie { + private Fast(char[] index, Data data, int highStart, + int index3NullOffset, int dataNullOffset) { + super(index, data, highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. + * Same as {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} + * with {@link Type#FAST}. + * + * @param valueWidth selects the number of bits in a data value; this method throws an exception + * if the valueWidth does not match the binary data; + * use null to accept any data value width + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast fromBinary(ValueWidth valueWidth, ByteBuffer bytes) { + return (Fast) CodePointTrie.fromBinary(Type.FAST, valueWidth, bytes); + } + + /** + * @return {@link Type#FAST} + * @stable ICU 63 + */ + @Override + public final Type getType() { return Type.FAST; } + + /** + * Returns a trie value for a BMP code point (U+0000..U+FFFF), without range checking. + * Can be used to look up a value for a UTF-16 code unit if other parts of + * the string processing check for surrogates. + * + * @param c the input code point, must be U+0000..U+FFFF + * @return The BMP code point's trie value. + * @stable ICU 63 + */ + public abstract int bmpGet(int c); + + /** + * Returns a trie value for a supplementary code point (U+10000..U+10FFFF), + * without range checking. + * + * @param c the input code point, must be U+10000..U+10FFFF + * @return The supplementary code point's trie value. + * @stable ICU 63 + */ + public abstract int suppGet(int c); + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + @Override + protected final int cpIndex(int c) { + if (c >= 0) { + if (c <= 0xffff) { + return fastIndex(c); + } else if (c <= 0x10ffff) { + return smallIndex(Type.FAST, c); + } + } + return dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final StringIterator stringIterator(CharSequence s, int sIndex) { + return new FastStringIterator(s, sIndex); + } + + private final class FastStringIterator extends StringIterator { + private FastStringIterator(CharSequence s, int sIndex) { + super(s, sIndex); + } + + @Override + public boolean next() { + if (sIndex >= s.length()) { + return false; + } + char lead = s.charAt(sIndex++); + c = lead; + int dataIndex; + if (!Character.isSurrogate(lead)) { + dataIndex = fastIndex(c); + } else { + char trail; + if (UTF16Plus.isSurrogateLead(lead) && sIndex < s.length() && + Character.isLowSurrogate(trail = s.charAt(sIndex))) { + ++sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.FAST, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + + @Override + public boolean previous() { + if (sIndex <= 0) { + return false; + } + char trail = s.charAt(--sIndex); + c = trail; + int dataIndex; + if (!Character.isSurrogate(trail)) { + dataIndex = fastIndex(c); + } else { + char lead; + if (!UTF16Plus.isSurrogateLead(trail) && sIndex > 0 && + Character.isHighSurrogate(lead = s.charAt(sIndex - 1))) { + --sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.FAST, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + } + } + + /** + * A CodePointTrie with {@link Type#SMALL}. + * + * @stable ICU 63 + */ + public abstract static class Small extends CodePointTrie { + private Small(char[] index, Data data, int highStart, + int index3NullOffset, int dataNullOffset) { + super(index, data, highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. + * Same as {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} + * with {@link Type#SMALL}. + * + * @param valueWidth selects the number of bits in a data value; this method throws an exception + * if the valueWidth does not match the binary data; + * use null to accept any data value width + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small fromBinary(ValueWidth valueWidth, ByteBuffer bytes) { + return (Small) CodePointTrie.fromBinary(Type.SMALL, valueWidth, bytes); + } + + /** + * @return {@link Type#SMALL} + * @stable ICU 63 + */ + @Override + public final Type getType() { return Type.SMALL; } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + @Override + protected final int cpIndex(int c) { + if (c >= 0) { + if (c <= SMALL_MAX) { + return fastIndex(c); + } else if (c <= 0x10ffff) { + return smallIndex(Type.SMALL, c); + } + } + return dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final StringIterator stringIterator(CharSequence s, int sIndex) { + return new SmallStringIterator(s, sIndex); + } + + private final class SmallStringIterator extends StringIterator { + private SmallStringIterator(CharSequence s, int sIndex) { + super(s, sIndex); + } + + @Override + public boolean next() { + if (sIndex >= s.length()) { + return false; + } + char lead = s.charAt(sIndex++); + c = lead; + int dataIndex; + if (!Character.isSurrogate(lead)) { + dataIndex = cpIndex(c); + } else { + char trail; + if (UTF16Plus.isSurrogateLead(lead) && sIndex < s.length() && + Character.isLowSurrogate(trail = s.charAt(sIndex))) { + ++sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.SMALL, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + + @Override + public boolean previous() { + if (sIndex <= 0) { + return false; + } + char trail = s.charAt(--sIndex); + c = trail; + int dataIndex; + if (!Character.isSurrogate(trail)) { + dataIndex = cpIndex(c); + } else { + char lead; + if (!UTF16Plus.isSurrogateLead(trail) && sIndex > 0 && + Character.isHighSurrogate(lead = s.charAt(sIndex - 1))) { + --sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.SMALL, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + } + } + + /** + * A CodePointTrie with {@link Type#FAST} and {@link ValueWidth#BITS_16}. + * + * @stable ICU 63 + */ + public static final class Fast16 extends Fast { + private final char[] dataArray; + + Fast16(char[] index, char[] data16, int highStart, + int index3NullOffset, int dataNullOffset) { + super(index, new Data16(data16), highStart, index3NullOffset, dataNullOffset); + this.dataArray = data16; + } + + /** + * Creates a trie from its binary form. + * Same as {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} + * with {@link Type#FAST} and {@link ValueWidth#BITS_16}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast16 fromBinary(ByteBuffer bytes) { + return (Fast16) CodePointTrie.fromBinary(Type.FAST, ValueWidth.BITS_16, bytes); + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final int get(int c) { + return dataArray[cpIndex(c)]; + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final int bmpGet(int c) { + assert 0 <= c && c <= 0xffff; + return dataArray[fastIndex(c)]; + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final int suppGet(int c) { + assert 0x10000 <= c && c <= 0x10ffff; + return dataArray[smallIndex(Type.FAST, c)]; + } + } + + /** + * A CodePointTrie with {@link Type#FAST} and {@link ValueWidth#BITS_32}. + * + * @stable ICU 63 + */ + public static final class Fast32 extends Fast { + private final int[] dataArray; + + Fast32(char[] index, int[] data32, int highStart, + int index3NullOffset, int dataNullOffset) { + super(index, new Data32(data32), highStart, index3NullOffset, dataNullOffset); + this.dataArray = data32; + } + + /** + * Creates a trie from its binary form. + * Same as {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} + * with {@link Type#FAST} and {@link ValueWidth#BITS_32}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast32 fromBinary(ByteBuffer bytes) { + return (Fast32) CodePointTrie.fromBinary(Type.FAST, ValueWidth.BITS_32, bytes); + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final int get(int c) { + return dataArray[cpIndex(c)]; + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final int bmpGet(int c) { + assert 0 <= c && c <= 0xffff; + return dataArray[fastIndex(c)]; + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final int suppGet(int c) { + assert 0x10000 <= c && c <= 0x10ffff; + return dataArray[smallIndex(Type.FAST, c)]; + } + } + + /** + * A CodePointTrie with {@link Type#FAST} and {@link ValueWidth#BITS_8}. + * + * @stable ICU 63 + */ + public static final class Fast8 extends Fast { + private final byte[] dataArray; + + Fast8(char[] index, byte[] data8, int highStart, + int index3NullOffset, int dataNullOffset) { + super(index, new Data8(data8), highStart, index3NullOffset, dataNullOffset); + this.dataArray = data8; + } + + /** + * Creates a trie from its binary form. + * Same as {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} + * with {@link Type#FAST} and {@link ValueWidth#BITS_8}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast8 fromBinary(ByteBuffer bytes) { + return (Fast8) CodePointTrie.fromBinary(Type.FAST, ValueWidth.BITS_8, bytes); + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final int get(int c) { + return dataArray[cpIndex(c)] & 0xff; + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final int bmpGet(int c) { + assert 0 <= c && c <= 0xffff; + return dataArray[fastIndex(c)] & 0xff; + } + + /** + * {@inheritDoc} + * @stable ICU 63 + */ + @Override + public final int suppGet(int c) { + assert 0x10000 <= c && c <= 0x10ffff; + return dataArray[smallIndex(Type.FAST, c)] & 0xff; + } + } + + /** + * A CodePointTrie with {@link Type#SMALL} and {@link ValueWidth#BITS_16}. + * + * @stable ICU 63 + */ + public static final class Small16 extends Small { + Small16(char[] index, char[] data16, int highStart, + int index3NullOffset, int dataNullOffset) { + super(index, new Data16(data16), highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. + * Same as {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} + * with {@link Type#SMALL} and {@link ValueWidth#BITS_16}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small16 fromBinary(ByteBuffer bytes) { + return (Small16) CodePointTrie.fromBinary(Type.SMALL, ValueWidth.BITS_16, bytes); + } + } + + /** + * A CodePointTrie with {@link Type#SMALL} and {@link ValueWidth#BITS_32}. + * + * @stable ICU 63 + */ + public static final class Small32 extends Small { + Small32(char[] index, int[] data32, int highStart, + int index3NullOffset, int dataNullOffset) { + super(index, new Data32(data32), highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. + * Same as {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} + * with {@link Type#SMALL} and {@link ValueWidth#BITS_32}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small32 fromBinary(ByteBuffer bytes) { + return (Small32) CodePointTrie.fromBinary(Type.SMALL, ValueWidth.BITS_32, bytes); + } + } + + /** + * A CodePointTrie with {@link Type#SMALL} and {@link ValueWidth#BITS_8}. + * + * @stable ICU 63 + */ + public static final class Small8 extends Small { + Small8(char[] index, byte[] data8, int highStart, + int index3NullOffset, int dataNullOffset) { + super(index, new Data8(data8), highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. + * Same as {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} + * with {@link Type#SMALL} and {@link ValueWidth#BITS_8}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small8 fromBinary(ByteBuffer bytes) { + return (Small8) CodePointTrie.fromBinary(Type.SMALL, ValueWidth.BITS_8, bytes); + } + } +} diff --git a/tests/test_data/std/jdk/internal/icu/util/OutputInt.class b/tests/test_data/std/jdk/internal/icu/util/OutputInt.class new file mode 100644 index 0000000000000000000000000000000000000000..ab3a2b2fb7e642f5f2548167fdc9fa63458d6c4a GIT binary patch literal 316 zcmah_yH3ME5S(@F7#x#8egLH-6uA#bL=y=ql0^zo`m=L_HOCp5yZjdwQi^;4AB9*) z5iQMVW>)){{r=e>04y=i5TTbM&XJ%`xUBU~E34hJT9>t{JfXi}$NrAcyP0lMoDr_; z?W`q+HQ2q zoj#edf8h_pr1)pYoRB>>p{>k4cf*E%+h<(_Opr=4KyJV}vJ;bxq6ebXu>vHwU!YGh ZBIJTy8JOZiFhBAHLySbpZv-P;{Q`x*M412p literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/OutputInt.java b/tests/test_data/std/jdk/internal/icu/util/OutputInt.java new file mode 100644 index 00000000..13c65841 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/util/OutputInt.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package jdk.internal.icu.util; + +/** + * Simple struct-like class for int output parameters. + * Like Output<Integer> but without auto-boxing. + * + * @internal but could become public + * deprecated This API is ICU internal only. + */ +public class OutputInt { + + /** + * The value field. + * + * @internal + * deprecated This API is ICU internal only. + */ + public int value; +} diff --git a/tests/test_data/std/jdk/internal/icu/util/VersionInfo.class b/tests/test_data/std/jdk/internal/icu/util/VersionInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..4bb4d3a049d1774a15fd2e0bf029606ade4d4166 GIT binary patch literal 2813 zcma)8Yf~Fl7=8}fTnRMLh7tmrUTg`a!PedcL{kbjl}igWimlQmS;9iH!DWLu<8-Rl z@w=aN(D6FsmyVaJP;I@8UmTtBi=X`^PN(%by9>l#rp?Umo^$p+&-=d5`@CoK=dB-q z2GEb?5NhD@LkYtRpFm_zT~fP>s!`|~w@lqA2>6PcQLttOJnhMhG!KLkM2IhPv#Oc4 z1eEqnvfq!ez|PI>nPO2ZsKvBdsFXCr8d%P03zl9s{HPb$F_)k3(hW;94Yk;%=PF$l zOD}e1HFJ?B8Dpj#Kt$kF##mB|dOoq_yhs?8(zIrFCtO2!o+zoWC8o86L5G&Uq$SE` zqF`z&;S<)ZY9tOGJ{&?V8pGI%Z4A6uH*~8{Alg2(8L*RYPcrLAlfd>nUmUOK#k^*Q z5Jj`ZiP?l?1BeSG?iZ(nnb<3LwT1Br9;J76VL>zU0{idf{jPvqzdZr$5NO_;&`6|~ zU)-Q%rfil}OFGyU#%??&5U|SYwcFO7ybG`=ggWdEqa8_s+Ja_fj73W|a+*N0J;NWj zJg7Q0#=bB*v7ZUq7}SB^*-nvk;c-6>gmDm02sCU`nPJHbnn_dEwW5vA2sBYVRWZ62 zJwXO}IE*7WN_`EdPfrPKbXr@#%{b#36q$ko-*@3a~%;?C}>GTAF8mnBp3KppAFWWV>vXbQh z&M@|)homR{1b`l3Ev)Y67gw%9-1%BobsZtm$32#)IoL$xX< z<Sb4maSRYjY?jhVJp_#4s+H97lGbf(LE|d zE((*|`(XT&{!x52+WpG6{%l@&iT7zdKeTdi^&-lOE6Lq{7R~%jX##_Vjs< zC~f{vF&0(gpJJ#Zs;t6)#2fWSQXeCD*(1Kd0ZtyzzbhA45aJ~GIqI&XcCvBH8XA7- zY&)Ndgl0$OGwQuCdRY-)-2RGiA7PiYx{m1N8n!pKtfG~1v^FMqTg6Vf*CRpceRpTn zn_5Agd^F(p|L`w+iT6*ZC)KH>I=!h*U+Nn6e9f#pc#-!P(Zu@@GaV+6BZ!lWM{ov7 zvUq?T9wUE!WNDDBjFFY|IEOs%MZAnMreNX%mZ9Q3u6_ayS22Sd9RG$nT7s*vow?T*6f*jdZOuAL9^= z6?K~=?_of|>-=_IqyR7BX}m!~-=tLEq7*MP>9;YDcQy!Pu%uB6R*nibIdU}1QH{N( zbL1h;L6RuR8N@ykKF`!oV+V^hiN)1PqqVmNzUScxbb;<2wu} zukW+(`KManhqv{Ly>`)FyO_U1D@QKGh7ju%)C`4&!i8L?ABa!7xt&za;rM62l2?tu93cw#WWQSwCL3hIj-3=RbH^8Ag kfC@G0khjYY1*pA_C)uAv-{O#rUD&ZZ4!-1U$#(kce_Tm`qyPW_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/icu/util/VersionInfo.java b/tests/test_data/std/jdk/internal/icu/util/VersionInfo.java new file mode 100644 index 00000000..12228446 --- /dev/null +++ b/tests/test_data/std/jdk/internal/icu/util/VersionInfo.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk.internal.icu.util; + +import java.util.HashMap; + +/** + * Class to store version numbers of the form major.minor.milli.micro. + * @author synwee + * @stable ICU 2.6 + */ +public final class VersionInfo +{ + // public data members ------------------------------------------------- + + /** + * Data version string for ICU's internal data. + * Used for appending to data path (e.g. icudt43b) + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + public static final String ICU_DATA_VERSION_PATH = "74b"; + + // public methods ------------------------------------------------------ + + /** + * Returns an instance of VersionInfo with the argument version. + * @param version version String in the format of "major.minor.milli.micro" + * or "major.minor.milli" or "major.minor" or "major", + * where major, minor, milli, micro are non-negative numbers + * {@literal <=} 255. If the trailing version numbers are + * not specified they are taken as 0s. E.g. Version "3.1" is + * equivalent to "3.1.0.0". + * @return an instance of VersionInfo with the argument version. + * @exception throws an IllegalArgumentException when the argument version + * is not in the right format + * @stable ICU 2.6 + */ + public static VersionInfo getInstance(String version) + { + int length = version.length(); + int array[] = {0, 0, 0, 0}; + int count = 0; + int index = 0; + + while (count < 4 && index < length) { + char c = version.charAt(index); + if (c == '.') { + count ++; + } + else { + c -= '0'; + if (c < 0 || c > 9) { + throw new IllegalArgumentException(INVALID_VERSION_NUMBER_); + } + array[count] *= 10; + array[count] += c; + } + index ++; + } + if (index != length) { + throw new IllegalArgumentException( + "Invalid version number: String '" + version + "' exceeds version format"); + } + for (int i = 0; i < 4; i ++) { + if (array[i] < 0 || array[i] > 255) { + throw new IllegalArgumentException(INVALID_VERSION_NUMBER_); + } + } + + return getInstance(array[0], array[1], array[2], array[3]); + } + + /** + * Returns an instance of VersionInfo with the argument version. + * @param major major version, non-negative number {@literal <=} 255. + * @param minor minor version, non-negative number {@literal <=} 255. + * @param milli milli version, non-negative number {@literal <=} 255. + * @param micro micro version, non-negative number {@literal <=} 255. + * @exception throws an IllegalArgumentException when either arguments are + * negative or {@literal >} 255 + * @stable ICU 2.6 + */ + public static VersionInfo getInstance(int major, int minor, int milli, + int micro) + { + // checks if it is in the hashmap + // else + if (major < 0 || major > 255 || minor < 0 || minor > 255 || + milli < 0 || milli > 255 || micro < 0 || micro > 255) { + throw new IllegalArgumentException(INVALID_VERSION_NUMBER_); + } + int version = getInt(major, minor, milli, micro); + Integer key = Integer.valueOf(version); + Object result = MAP_.get(key); + if (result == null) { + result = new VersionInfo(version); + MAP_.put(key, result); + } + return (VersionInfo)result; + } + + /** + * Compares other with this VersionInfo. + * @param other VersionInfo to be compared + * @return 0 if the argument is a VersionInfo object that has version + * information equal to this object. + * Less than 0 if the argument is a VersionInfo object that has + * version information greater than this object. + * Greater than 0 if the argument is a VersionInfo object that + * has version information less than this object. + * @stable ICU 2.6 + */ + public int compareTo(VersionInfo other) + { + // m_version_ is an int, a signed 32-bit integer. + // When the major version is >=128, then the version int is negative. + // Compare it in two steps to simulate an unsigned-int comparison. + // (Alternatively we could turn each int into a long and reset the upper 32 bits.) + // Compare the upper bits first, using logical shift right (unsigned). + int diff = (m_version_ >>> 1) - (other.m_version_ >>> 1); + if (diff != 0) { return diff; } + // Compare the remaining bits. + return (m_version_ & 1) - (other.m_version_ & 1); + } + + // private data members ---------------------------------------------- + + /** + * Version number stored as a byte for each of the major, minor, milli and + * micro numbers in the 32 bit int. + * Most significant for the major and the least significant contains the + * micro numbers. + */ + private int m_version_; + /** + * Map of singletons + */ + private static final HashMap MAP_ = new HashMap<>(); + /** + * Error statement string + */ + private static final String INVALID_VERSION_NUMBER_ = + "Invalid version number: Version number may be negative or greater than 255"; + + // private constructor ----------------------------------------------- + + /** + * Constructor with int + * @param compactversion a 32 bit int with each byte representing a number + */ + private VersionInfo(int compactversion) + { + m_version_ = compactversion; + } + + /** + * Gets the int from the version numbers + * @param major non-negative version number + * @param minor non-negativeversion number + * @param milli non-negativeversion number + * @param micro non-negativeversion number + */ + private static int getInt(int major, int minor, int milli, int micro) + { + return (major << 24) | (minor << 16) | (milli << 8) | micro; + } +} diff --git a/tests/test_data/std/jdk/internal/io/JdkConsole.class b/tests/test_data/std/jdk/internal/io/JdkConsole.class new file mode 100644 index 0000000000000000000000000000000000000000..167d4ee7f2205ca5cb53ee21635dd199bbfd75f0 GIT binary patch literal 745 zcmbtS%TB^T6g`7L5m69Oe6TjKvF^KU;zCIz5_Q39YzHWet(g{C`&%yj06)rjXDHZ& z7!%#h$=rL-xzCT!w|4+8+7@yQCsTiB2Vo*q$fX@b_LV<#qcD!7u#jh{P5BGAB@f5; z&Er&f2}5zA0*Ys7b-F#{CR$&S$b)e>6ru$8bx1uEa%*hlwVrjb3>hvuOM#5OLz+L9 zMC5`Yrzy0?Syp3^kn~t>%Wy&(p~q0 zP%vEoBgJOr&D9jmoYoChbiO{1<3*%=2ItQ?hb}|D)74NI$$30s*y?oeX;a>Wt60#? z+N%;mT6Su+-KCedQXWKe<%!EcQuEdC8#>o}C^C>B9UV}ilPaJHeOeYu2Dec*xRYW9 nyYzp>9;yaw*f;(f>gL}-)BGDaFnEZT!6O_~20Ceab2$A1!k5jf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/io/JdkConsole.java b/tests/test_data/std/jdk/internal/io/JdkConsole.java new file mode 100644 index 00000000..6c911ed6 --- /dev/null +++ b/tests/test_data/std/jdk/internal/io/JdkConsole.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.io; + +import java.io.PrintWriter; +import java.io.Reader; +import java.nio.charset.Charset; +import java.util.Locale; + +/** + * Delegate interface for custom Console implementations. + * Methods defined here duplicates the ones in Console class. + * Providers should implement jdk.internal.io.JdkConsoleProvider + * to instantiate an implementation of this interface. + */ +public interface JdkConsole { + PrintWriter writer(); + Reader reader(); + JdkConsole println(Object obj); + JdkConsole print(Object obj); + String readln(String prompt); + JdkConsole format(Locale locale, String format, Object ... args); + String readLine(Locale locale, String format, Object ... args); + String readLine(); + char[] readPassword(Locale locale, String format, Object ... args); + char[] readPassword(); + void flush(); + Charset charset(); +} diff --git a/tests/test_data/std/jdk/internal/io/JdkConsoleImpl$1.class b/tests/test_data/std/jdk/internal/io/JdkConsoleImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..4c60b18cbb6b5da591578cf38a8ac386fd787060 GIT binary patch literal 954 zcmah{T~8B16g|@}Y*`kl6j4x1g$n&Z3eOlGtQar_j1Y{xE$xIZU1rGcR($kl=r7=z z1cN~XM&A5M#u(3TF@8M2COdcL&bjB@x%Ynid3pw*in$&nkThY~=t8$ZZnx2@xGI#s za=ePGE6*COs#byaHX;|2x=vRAVU4EQn#wJ#UzO{Z<$c%bGgx!T^_mi|U3e31D&-lpTb(fQJ8M1>X@zlJ$KH_zIx$grs! z&mG^{lk6Vjl73qW^sR?Zy|v=($D}5Tzh4&jVWa8mgH8(8x^DY*`P7Y`lliypGtrZo z_oAwMI&jraN6p4e)Ypuwg3$52^=3P4=mWK+HG7d-Wp|czz%JX%N=d)!IYA%;M#|K?OmK?(A$0w~h>6q_6NT?E g9-AbCffDZ$C}Wz|;8;FHCHC}VmewLqR1ki@0Fg%2wg3PC literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/io/JdkConsoleImpl$2.class b/tests/test_data/std/jdk/internal/io/JdkConsoleImpl$2.class new file mode 100644 index 0000000000000000000000000000000000000000..176904a2c81abe1ee31634aa63d88d43300d6603 GIT binary patch literal 755 zcmah{%}yIJ5dMbUWFZYD5GZYFfTA3LR-{6`rQ)(GDpg96S_O%lNvy`Ou`Ao#GY^1x zm!2y1zytK55aZqS&>z7_>lx2{^UaU<*Uiss04bi=Foh^VTt@{}Li0>~6CGtbM^G^%G1J*3X9L9Zr!}i!2blAD*X1JCn(S@z<=qOL)!6 zcY?bAAt%JC8A`%jPic9Wk58rjEKW1_EcDDkWPM>(xKEt1A1O!JxTjQmx65M%Z2J{A ze-E0mk;y%w@pp%W8IgOlpXF{upc96CkbY!_N5YD+HIt6 zc$oTu*3zb#a85d`BjH~mNH{B)VO?YEBO=7ClkJzSAE56A-~pdi5I~oxv%OtHFpGzL zV=(5>2ywRNu~1MZXkwAcme@NR0T+#cEQIg~%M1_oUho$Z|EY9URH~Q3Nu?N%89Ie0 Wc*;7)3R+kzJS#j9n2@-GLT&+D{4Vo%NQxoN-sbFFo>?P?#o4(Z-lRlKBF|m(*u}zhJXO;zQQr+at_nmXT%kR6L z{qgzzIRIgt_P_zB3`v0tZi0U#G1{CoGJ4w3Qq4)T`DkJ^Y#NrC(j#N%Qnk^fp`XyT zgq|k2Gs8)%b~B+S`f{x{FY@4#;Z=|ig-|%6o!5l%B}==LMl!RP;H>xe2}FeoR>4Pb zBn^Tu`l5WBkSJDAg4HY$ALLIgEY3<5l%bq~8R20qZ4oFUjw=6K?#`rjZS0U9H#uf6YOqm3tq7ucD49wP z=xMXZ>@uxnCTSWX%sK^|P)~5NTH=x&5gQE=a$0~o}y-alrd#9WjpB{9MR($JN4TXY{w3QBqRxP zeJmV__&GO?*r}jJq|up<4|;jus-O+KS@dk$yuhU19}5$<)xWC3|1FWfkCnrmGr}s- zGsniq2K980Hkjg*Vn(Z_`m}UX>=zFu(M^QlD?F{}z&37;4m~q$Cc3n=Hl}mavH|&B zt_dfXyTamNE2IBcOja-G&S>$`4(;3`2JccOEEz`$CAr3nbS~X+Y2zu=;xLGNlj6KM zLr&cs;)vse<4oM<(2%7w0(VL`&Sr-Bnoop~k&wZe@h$g4woEcs%jnNJwCmS1%oWJy z%iC>^r{nsOq)1-Lixb%-OmPz&)2&RqX|Yo!Vi63)lJK=_ z21S8@b6^JQ3@QT78B~42q7LliZ>2CsCGgN{6q1TED&>JILmic4Ki}76&EfzK@{S$Y z?#bo^U5*5?@7ly}>TYPDGGTg*YvT=oSaG*0w6d zgg`bN5--Cd)~$Rh?(ziIS-dvQd^SZ{{q-yK^A`12Lg0DMT5^8MDavOjPpU#vRrQ&W ztLiE$s)BPjP*Qyrt5nxjcvV+$?k4iTg1`SBf)Cgy-9S#i>)D#>X}&hL-kxkYe4mIO+`T~RF5q%g^L@~+@Is-=*83uUTQ zmAHaDM}_ls^f}fDO+u-Zo8Z0{?1ls z0@VS*@>xv;@31eOy}%xX56;9SUcYr(f9C{H}s za+_8!C$GZ$fM<9Irf8mf<_2!t^bVB?O6AmU(+J(M=`{Uf(}(n%P3P&cpo^1mA5E;Y z2~Mg<9{I6>g8Wz2$o~~hXrV0#({_HYb|6L}oS~fca1I98c*4d8nIw)WfKHX&v=Z9mQx1ouu7#iVo0eiqIf)BV^GiU8FI( z%unhSGU+D0L(`O|FZpJUGV}wD)6aB)9@2aCh~B4p`oNx#lklJqy@>Lg<-t?@iVhs( z?6lBrbn^Qpi@C@>Cd_s5TPLRT368Ud!{$yf=j04LMmKX3=V2Z_%()ZlGzw{6G&_<;xDA)WAd4b;qS%yQ#o5Vks1%KXJ@oqRVzy=+N;iOF) P@itR019I>m?gg}Z?iW6(a@Gu&J5(GnRahSOz6DBjm%%nkG zxA;QViWOb7Ag!*}Mf(J65?W9!7VX-lwN`iA?so0gZnbrFwflBi>Gz*|XL9pEZ5t)$ z-ZTICU*G>aljq<2_EP|w)%0R`;5Fbg;YX3eSv|4Mjqzm8$|NI+#(1jn(%9zaR5F`N zSS`Kjgn}pCuQ0i_C-Uite0+I^#OpF~9%vF)0TaatDimd`NX*J8Oem19);mo>m?$++ zW}+Mu6e`Ezq+q0lZz4%iwKju9B-z!tYGaQT%{A4n6($o+R0;>brj?z^CZ?c@JDU=H z*=_}IZQWW?DrDjeoT*UUFN(INqMH>aj%6#PQ%#&Dqyf=iD24BIk#zPbUD|V0u}kaX z!AujgaE@~<5l>oFqIP{i<3V6_4aPzzUd*}e@D@3kh@;i`Nb>wvs$tcX7dDp&l{IuF*H=#*@$ zj3=|XNFveR-It4{`jeNWQkx~@K561pl1k+nE1OGYtYy*el$}u?Tw@}FjS4=Cn_QSH z>*Y+$goRBCC9X3HionlDw~4sKd1)jTYwt^^Ns_fgHWIWg3@&dQ`#_2ncAKP}~}N>tuz;#yI8 za@J*ki|rCo?|S^1fg4QxIXbayrjjCY&32Y*SBqeLTXF(uEi6;0A5&R%1) z{h97`_nNp5pJ!dlL>b7Q&gLNY;(i1BOnd=fR4CK7@UR_7j6+eF0vLxaEp;tHJcz$C z@Q{gz@uhs=+BtSD9oNfR9gzr*rqZlA^^SR(z$u|EE>GsSTBJ8_#$QW1>}UFGVGMgQ z@i7x$mPoCfMXy;IX)4*J@vH#AIQ=TVX5i~4zJUWHv|%UFdKY)660xi#@Tf-Uh^||2 z;Bj`LVF;Jxr8uqXAfAw@s|unWPXsZ9Lk7NO;@ddPpx4KA-rD?_2xS>-OJ6)=wWX46 zeUien$8myF8{K{}@MK;Ox_@~*VKHgbeK|HGE7Dtxqj=iDcT60^GYV7kFbUmKD;v$k z)2vp+HPy!;sJ4CV@EQJ`74Qg-i#gA-4>)>_r4ls0hrcoKyovAQZ^>sn7ISI6=X#2G&%>;-F`kLXPET6KU9Cp3y(?8Yoj#P$F8vi0z z|61X^5AQZxIX!s3j^7ygt%)~eRI+D7?Y8CwGn}y4725XrD*G4jNd3QE_x$Za>n*Kqt!Q(E8 zj-?78amR!c?4ueYbMMl^Ri#PNcViC?VaCVg8Zn}DI8&*+bU0g#ooIvu$JWAhOunum zoQ#XonG`3|kvE9Kai2Z>m(tVG%_}2mZNH&B`9WI4Qy9(_u5>JOO@{99a`<+-QsTpz zUzE_ZctJ}ye}WgubP zf6P#ZAwASr%d3(?O5SpazCbp10mx%RA}G>1U_sqIYUM$Fo-UOh?)`dO_+WNJ>+AA zi$lfVL3$6$L&Z-c&7-8s?1x{N91RCtOx|C7Fhude4ovF)JGg%U&*KEw6)X-fa(#`p`6TI1 zDy7#~80<_5)yQ7oYSSr6zZda}tg2J>sx;TM>eFjG=e6re|FC*eJwUxC|M7Cy@qzJvPjqLp_usqaBQc9ZIUQrt_5`KSGOk;w9Y4d&(|);cm9_d)NYZDtv2Ew)k7Xz$>VzRxPd%wB9FVs<394(M;;H8 z$071~l02R!k7MLg#+;4V_OZ-`+DR(cUw$LhVo`%4FeVy~r0iRt~2raL;K9+_Rg4SG}Q1=}}$e z*g9%YG1LMEJO)~&*r_r@mD|mWzoG2jb+PoZlbB>+{z**b2Tlc)eZAfAE{e{PH)U_l z`~VuIPN7=!|&5mz~Nd>h9+ z>7uikw*7nHJ9r4!dA*0Rt)qSjH+>7Y`mi6q)_UIn`VaC?;Q5XUvntt zZ5nkR=Yb*$-AM%u{@d-9Ur!BU&&O-_F`y5~YmG0qa6;*WD89vWYCq-_wt^4h3~tqY z5tW5Kk`>9`5q}%^KPLO$dES~sc;L)EsMW7E(w83Lqaov`Q>6V;q5oLIQ3LBUuIB=1#BLRlt&w4-!PgS^=BZYs;DXn_`?ylnpKN`e&EKi zp8SecRXg$WCSywU+{w%tn0p9=>qP#p`on0angau<8GfuDe!QBGM>-zIQ$zSJb*<*f z=LT?syDxOqbK`_>2rmvmabvMeLnnst@&L}`Yr2EKe!`x|J4g$1HUl|3 0 && rcb[len-1] == '\r') + len--; //remove the CR, if there is one + } + char[] b = new char[len]; + if (len > 0) { + System.arraycopy(rcb, 0, b, 0, len); + if (zeroOut) { + Arrays.fill(rcb, 0, len, ' '); + if (reader instanceof LineReader lr) { + lr.zeroOut(); + } + } + } + return b; + } + + private char[] grow() { + assert Thread.holdsLock(readLock); + char[] t = new char[rcb.length * 2]; + System.arraycopy(rcb, 0, t, 0, rcb.length); + rcb = t; + return rcb; + } + + /* + * Sets the console echo status to {@code on} and returns the previous + * console on/off status. + * @param on the echo status to set to. {@code true} for echo on and + * {@code false} for echo off + * @return true if the previous console echo status is on + */ + private static native boolean echo(boolean on) throws IOException; + + class LineReader extends Reader { + private final Reader in; + private final char[] cb; + private int nChars, nextChar; + boolean leftoverLF; + LineReader(Reader in) { + this.in = in; + cb = new char[1024]; + nextChar = nChars = 0; + leftoverLF = false; + } + public void zeroOut() throws IOException { + if (in instanceof StreamDecoder sd) { + sd.fillZeroToPosition(); + } + } + public void close () {} + public boolean ready() throws IOException { + //in.ready synchronizes on readLock already + return in.ready(); + } + + public int read(char[] cbuf, int offset, int length) + throws IOException + { + int off = offset; + int end = offset + length; + if (offset < 0 || offset > cbuf.length || length < 0 || + end < 0 || end > cbuf.length) { + throw new IndexOutOfBoundsException(); + } + synchronized(readLock) { + boolean eof = false; + char c; + for (;;) { + if (nextChar >= nChars) { //fill + int n; + do { + n = in.read(cb, 0, cb.length); + } while (n == 0); + if (n > 0) { + nChars = n; + nextChar = 0; + if (n < cb.length && + cb[n-1] != '\n' && cb[n-1] != '\r') { + /* + * we're in canonical mode so each "fill" should + * come back with an eol. if there is no lf or nl at + * the end of returned bytes we reached an eof. + */ + eof = true; + } + } else { /*EOF*/ + if (off - offset == 0) + return -1; + return off - offset; + } + } + if (leftoverLF && cbuf == rcb && cb[nextChar] == '\n') { + /* + * if invoked by our readline, skip the leftover, otherwise + * return the LF. + */ + nextChar++; + } + leftoverLF = false; + while (nextChar < nChars) { + c = cbuf[off++] = cb[nextChar]; + cb[nextChar++] = 0; + if (c == '\n') { + return off - offset; + } else if (c == '\r') { + if (off == end) { + /* no space left even the next is LF, so return + * whatever we have if the invoker is not our + * readLine() + */ + if (cbuf == rcb) { + cbuf = grow(); + } else { + leftoverLF = true; + return off - offset; + } + } + if (nextChar == nChars && in.ready()) { + /* + * we have a CR and we reached the end of + * the read in buffer, fill to make sure we + * don't miss a LF, if there is one, it's possible + * that it got cut off during last round reading + * simply because the read in buffer was full. + */ + nChars = in.read(cb, 0, cb.length); + nextChar = 0; + } + if (nextChar < nChars && cb[nextChar] == '\n') { + cbuf[off++] = '\n'; + nextChar++; + } + return off - offset; + } else if (off == end) { + if (cbuf == rcb) { + cbuf = grow(); + end = cbuf.length; + } else { + return off - offset; + } + } + } + if (eof) + return off - offset; + } + } + } + } + + public JdkConsoleImpl(Charset charset) { + Objects.requireNonNull(charset); + this.charset = charset; + readLock = new Object(); + writeLock = new Object(); + restoreEchoLock = new Object(); + out = StreamEncoder.forOutputStreamWriter( + new FileOutputStream(FileDescriptor.out), + writeLock, + charset); + pw = new PrintWriter(out, true) { + public void close() { + } + }; + formatter = new Formatter(out); + reader = new LineReader(StreamDecoder.forInputStreamReader( + new FileInputStream(FileDescriptor.in), + readLock, + charset)); + rcb = new char[1024]; + } +} diff --git a/tests/test_data/std/jdk/internal/io/JdkConsoleProvider.class b/tests/test_data/std/jdk/internal/io/JdkConsoleProvider.class new file mode 100644 index 0000000000000000000000000000000000000000..d2946d6c12d96d0069c692cb683874f543fc01c0 GIT binary patch literal 316 zcmZ{gK~KU!5QX2MQbbYX#h7^Vq?hj5a3XC}p7FEf*Q^S$}{{@ekGa1o$IxUb3;liCTZxnk0=QMrnYUK=GQ)@)@dY=C3JRmHcQ zDXy0+d#^;{2zPNZ9L&?#d@{`z&v7!%$5}j2ll)~cP6*fO@5;Fa<^Yo0w=c9yq#-H&4qLYMgA@hKcc1<{MHhof!qgSM%Tp@Ix6} z4{#yz(C2;o^m%`2)9;_pF91G{9aI=j$FFa$P?}1`r90+xp1b`bE@>|4!$FmyZB18l zHFBfjm~!o)&TzhRxl)DZS`^ClmMudgEoNm-Jt2vqwPaq|L57oLrnH#QlbDL3q}AY* z;VfJW&v-c^eZx?jb2&56%k{ZH(u9=G7Vl)j^~WH)i@FR=KkBDhGVrq~F^t}Q5E|Es zJ^#VG4Qw##4nosZv**~9i}mz`w1Jz)8g}QONL)yfFYJx|&`Z+}1H*<{HS+;L1JifI>)}>o6j!*L!3rv5pJ`$ccHCkXQdIDtfUf&bY3gHlAeo4n>emCe?-_N z^lCsDX%}KL&sg~g9m3VNE3M7F^g6d<@Rt(0X+;}PMynVzx_aQH}I`~M(G vZnRq0FBryyH0=`zJ0aR((Lf8)@41Kla9@PF8)gTuAjTn%a9mf66ZC!n7(#i8 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/javac/ParticipatesInPreview.java b/tests/test_data/std/jdk/internal/javac/ParticipatesInPreview.java new file mode 100644 index 00000000..c291ca9f --- /dev/null +++ b/tests/test_data/std/jdk/internal/javac/ParticipatesInPreview.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.javac; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates, when declared on a module declaration, that the module participates + * in preview features and therefore does not need to be compiled with "--enable-preview". + */ +@Target(ElementType.MODULE) +@Retention(RetentionPolicy.CLASS) +public @interface ParticipatesInPreview { +} diff --git a/tests/test_data/std/jdk/internal/javac/PreviewFeature$Feature.class b/tests/test_data/std/jdk/internal/javac/PreviewFeature$Feature.class new file mode 100644 index 0000000000000000000000000000000000000000..1dc609c3e0757e73cd61f62a9fbd1ab846d0b74c GIT binary patch literal 2489 zcmb7FZF3V<6n?f%n@!l#SYG5!NU=a$kP3otEzpo|)5W}*-BcrJ+-@)JmUL4$n3Y+G$SCJ7EcjFk) zFtxFIXT}dA5e9B!X2acfy_s?-wtaDTQMge%6cat0fQFcXAq;C6UA8JtHIuJ9OBFM- zU~4#=e`cat$)p=dNT&E=sbX5WqFmc!z>sSx+o@Q^T-`AX<$T65Z5iBaU{nPyE?Qa3 zsb}*U+wKNmFfb;ABX+h_HW%v4nS8Yy*>B*0j2t9qHS1I>jAl#4Y_(D`i`klFe$l`o zm8=LCt-M*!lr0%KV&JISlgVbLP|szYC9`5y)PY_ya9jrW7D@|M=I~slilahl1LG=` z&lGdjOwOzmW9B90%LXQ7D8{lJxp3OR8B9`$iSD5_oV)oPS|%}#vvEusIEPm>40(-a zAT;csoXX3~oN2hh+DvI>LwM0_5;J%;jtd4Z;x!)pUw|33H+h6@x6u}*+ZrxU?#j+K z+*WIL*Mc2|ey}#Xdk0CN_%9oH9dBqDp7R4gx=P`9Q}r^fsbw8QNmhSZM?#08V^qhO zjsrRl={Tz6xQ=lh6B1$?SVT?=q>k6paDH;?c_h+sw9*bDe^Xe&w%_ts8X^+}&B%@X zW*9@Foo7lhYvL$R7xGK*H)CEN-~5O^Y8aQz@%5Yc*bm24x&SrX5h8MPz2sR8U2MRYOh7VA=2!0x%g|h4B>93b8fUQ zLJ=ye-}nd$&DA!MJaaRQdgtBIF1}OPXOAC0)?hfI6{ULvgEH*gSS;IIrBb7LKM+Nw zq2uxzG+g_S?qFX%>rCREjOCl2+gNr(Uo!S+V}ZL#_Obq^Wu09)%Wg;v=N@&9Me9CI z!uHn!HS;tKPEIXzO3itVULRlC#U;Ca?m13*mFG;_&35PsDY}MzPmb90@+ES&BGp@J zwxT#b(J=m06{xor1S0HpjvS`lksU`{!>Om{Pq3?5DL>~g@S)A{--0oJSWb9=mh)Lz z&SXZH7(GC1VGuVgyn}oT1r%E-5z5Kj4=GE?yAo0%g!8!{VoQj#1L2_Vhg2nGc?ZHl z-4A(BLf+pw3nz9zq$VLB>_9lT`yn?aobuTuqK?(+_d}5j2S( zcmlu56{CxSz-@YK{2OB0=Mu_^%Uh9T7ijsO5uZML>;W!)!>|9x6vw)(Q86V3fE2&; z&sQlMsid5`+)}a%#P|smQhR=YRvYYK(5}Tgh}*TH4m-Ox+~F9i#XFpZHNAsHyQ&`_F_cE2h*?qH+0?xdRB$ WRCWs??HE@yY@x*#jA*w{C;kDrnlj-4 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/javac/PreviewFeature$JEP.class b/tests/test_data/std/jdk/internal/javac/PreviewFeature$JEP.class new file mode 100644 index 0000000000000000000000000000000000000000..c49f3f8c4c7ba9d7f27f4881ca735b39a5fac247 GIT binary patch literal 628 zcmah`%T5A85Uh65ReUSH-$sdE+z;?X5F&;s5#zX?;j&=9Vb?qsH^&_9W@f}Yksb>a#_L$7nMec9AVC* zkx{l2UA4O0b|JT9uABr|zqHX6?WKz-2QbIV`kC1Q1S<>dJ_Rki7uYKYr2y54wb-Ks5I@K-1!`ULV z^<&JB-EUOVVJ8zu`^sdZy#F_^Vz|fF-Ml=pCs%8g`Wa#OZ}K%e;fggvE&fAk#74JY zyk@yxYBmYumz=uuI2Fe?2z&pYj4)NRmXoqkY0C1`KyFwh@i_24i`#+RGsL)56TYe; zFO5k|!5?~B;s8i7gB)gsGlDtHOWcrbLEyzZ5Tk%4Ec=SFf>o@25!bOPF)wYxI<|@v EpO0{*+W-In literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/javac/PreviewFeature.class b/tests/test_data/std/jdk/internal/javac/PreviewFeature.class new file mode 100644 index 0000000000000000000000000000000000000000..326394218a80b74baf47a1ddac858ef58f6a6b95 GIT binary patch literal 769 zcmah{O>fgc5Pe&xG5rAg2?Qu@p+wCAeCdq~k>fzYt*ykZL^*B3q}s6AAbXvve~kk_ zfFFgJg@_0#QVu)&H1p=o%+CJ&_5BBc5Jx_i1P+H^z6Q!z%8k^)P)=k&NOPJfx@nWN zWllaS0vj$8Xlbs4q&K9#^-&erpLwM*V=Jv1o1pm*3iyM+A_A|D8}Y(gN7I^b1Xgnz zXfC8CB;Xx4t^_t`$}JkmQd^HF0du?KGVfDcY36SK-~MaYqd=`w8mmThsS4H8G*c=B z_Tss7WHP@d%dIR=q%K+c`FviaX+*|mx8I1#)w3vjpR@$l!sNW0buPjz>99uoG>X~l zr_JzV^IhbKN$VnJP{}@}d>zbJ?~rA2eplA6FQBAjt@^jF<1lV^yWGP$750oqJ<1Co z&jemBUcrYb^>HB3SWKO6OJM!f7|KH}i-Pz;J=Wk+r{TKb6?uG?d09*RnS9)V`&27f zW$zk$y(_Gvg1e4@d$`Z{38M`TZ+=FVu!U`BcAVLD=7BR0oq2?sqY)nC37&Fhl{5FS Uk3+^=e=x7EzQP`X7jJ970dxV*3;+NC literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/javac/PreviewFeature.java b/tests/test_data/std/jdk/internal/javac/PreviewFeature.java new file mode 100644 index 00000000..05049eff --- /dev/null +++ b/tests/test_data/std/jdk/internal/javac/PreviewFeature.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.javac; + +import java.lang.annotation.*; + +/** + * Indicates the API declaration in question is associated with a + * preview feature. See JEP 12: "Preview Language and VM + * Features" (https://openjdk.org/jeps/12). + * + * Note this internal annotation is handled specially by the javac compiler. + * To work properly with {@code --release older-release}, it requires special + * handling in {@code make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java} + * and {@code src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java}. + * + * @since 14 + */ +// Match the meaningful targets of java.lang.Deprecated, omit local +// variables and parameter declarations +@Target({ElementType.METHOD, + ElementType.CONSTRUCTOR, + ElementType.FIELD, + ElementType.PACKAGE, + ElementType.MODULE, + ElementType.TYPE}) + // CLASS retention will hopefully be sufficient for the purposes at hand +@Retention(RetentionPolicy.CLASS) +// *Not* @Documented +public @interface PreviewFeature { + /** + * Name of the preview feature the annotated API is associated + * with. + */ + public Feature feature(); + + public boolean reflective() default false; + + /** + * Enum of preview features in the current release. + * Values should be annotated with the feature's {@code JEP}. + */ + public enum Feature { + // not used, but required for interim javac to not warn. + VIRTUAL_THREADS, + FOREIGN, + @JEP(number=459, title="String Templates", status="Second Preview") + STRING_TEMPLATES, + @JEP(number=477, title="Implicitly Declared Classes and Instance Main Methods", status="Third Preview") + IMPLICIT_CLASSES, + @JEP(number=481, title="Scoped Values", status="Third Preview") + SCOPED_VALUES, + @JEP(number=480, title="Structured Concurrency", status="Third Preview") + STRUCTURED_CONCURRENCY, + @JEP(number=466, title="ClassFile API", status="Second Preview") + CLASSFILE_API, + @JEP(number=473, title="Stream Gatherers", status="Second Preview") + STREAM_GATHERERS, + @JEP(number=476, title="Module Import Declarations", status="Preview") + MODULE_IMPORTS, + LANGUAGE_MODEL, + /** + * A key for testing. + */ + @JEP(number=2_147_483_647, title="Test Feature") + TEST, + ; + } + + /** + * Annotation identifying the JEP associated with a preview feature. + */ + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.CLASS) + @interface JEP { + /** JEP number */ + int number() default 0; + /** JEP title in plain text */ + String title(); + /** JEP status such as "Preview", "Second Preview", etc */ + String status() default "Preview"; + } +} diff --git a/tests/test_data/std/jdk/internal/javac/Restricted.class b/tests/test_data/std/jdk/internal/javac/Restricted.class new file mode 100644 index 0000000000000000000000000000000000000000..0c6a44a891331c73b2864a182a0d33a7de80b6de GIT binary patch literal 392 zcmaiwJ5Iwu5QhH=Bn#n@P$Gmt6e-yQP$4iP5+TSK8mf&miq>q_$X-Xv)hIXshe8=s z;KmZgyubN1n(v>_F90_^aMpB<_jxeE=3Za_rG)--UKJ_dS;vGyBYIhH5{~1_2fO4~TiTi9X0w#59$M8C zQ!F@K5xOhmDp9>?=OV{T_90n+u)w`Zl-y5m3Fqx}%t2teUf9t;$W!iYx)xByFOSK1 l5{(FiEwQdV73e_y`W@^_JdwIDv%NPEV;=`NtSiOrestricted methods in the Java SE API + * (e.g. {@link java.lang.foreign.MemorySegment#reinterpret(long)}). + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Restricted { +} diff --git a/tests/test_data/std/jdk/internal/jimage/BasicImageReader$1.class b/tests/test_data/std/jdk/internal/jimage/BasicImageReader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..df519673d7c26e5c06695b41c61a60ebb2a73417 GIT binary patch literal 1283 zcmbVLSx*yD6#i}(h7O|?EOp1NVmmA&Zh*x`ATA^b#F{?vc9~wvEyIk?LehVw2_W&o zAK;HNo|%qzpqdaTx%b@pa?W@5A3wi+2e5)#4k@G+WHe+kz%bEn?itedg==%mXv=-x z62>z3q`4YC-wWOpZfTYwcfhR@oj@>*uC@6AH!N`6P*wn z(xCmpnqo)AMGPy*YZ$>OL%v6}vE3G?&oHnkZRyt-(&b7+MFC?9iW)BC$|?1F$MeNL z!%$23o38UwxPFIWzT6*LKT_$3R9wS#1vfO@#Q14PQGyhg_!MxN=tfbMh~w^TdW8B+rs_8x2>r4 zj>)YCcV+k=gBgEUQenv7xrV7q(^Qu&oBM%Fl!a3{#sy_~lZY$^yU0INUQAg0E@_RN zsdXoCP4Sw_Llr$c+%sVvDb-iDX*nLv@;l-0I!y)h45jlVq~STpOI~{2ne0vDe|KPu zVQ^h|{#(bRjnGzYTevG0_dMazn5Afk7%E8T^WhQ$Bx&&?Ny|oio~AQ`Nz$C6SB+$b zWI>-i0@J6Cpy<;_Q1!34@P+Ucrs*CaPGBB0bZgPO00R%{Z^QYG3HN&0>P=ZrP? literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/BasicImageReader$2.class b/tests/test_data/std/jdk/internal/jimage/BasicImageReader$2.class new file mode 100644 index 0000000000000000000000000000000000000000..c51e211c2660b74762a5209adff57e18002f4280 GIT binary patch literal 1894 zcma)6ZBrXn6n-uQHlz!r5wNtiMWvVon$`MRgIGwxMngbS@q?e1%_Uh_c5!!;kr`+7 z-}tr8RCJutubpxHO^(mqU0_pmhRkH|-LvOB=Q*!`{qy^u0BYD7!w`lwWOR&RRAAwt zeQ4NjD1Fy-j05|~>_}tH3~Z~et~=6fOMm`>z-ZXDgZZ~<(YT69HHR$5G~{$#gD#Li zF#D$Am~O||+B=X|NW^8^wZj#G;bLi5!-T;6RgiPYa7ea~;2 zM^fNkF$LEOecSC+FL@yLZGl1{!>`;ZzkcsHwD%mTFz@KNi#dTYQr(nc*J}$r`VZ7^ zQjVgK2K@MP-(e<=7@<0balE19P0W+56$c@3H-=z*Mj{K0RFtgK0^ZV4)KNlN;KoIw z2H{yR+wFUYjQ?SpX4&$oEzjg9`EURA0MzU z{hrGb4s_41XSb^wJ`%VSp$5|G`F40>Z2NYf&C`+XRZHOtl$fR~3|FMg3`122{9KSew+osPB=CIRxa(}Sb1+HJ} zHV#Khc9y)P-vnj`$(SXcP4hU4L&Ilk|D5lIow%LtzT7&N zepHS~41H+*E#zZ8PjvV=qd!b`r`hpIa%adbTNp@QD|28R~WJ z96!pH3^2zo%tGKph)x$@#K5anN?{mi!^RQVjGCE#G0 z&zV>YpU^`6auJ%qr@W6)?Z-To+3kEP*uUvUIWh|4ryxLeS+#3D^`BS{M zxm11*@f@%7J$s6KU;l(mLp(!HHRJJ?3ql5)DI+h7IIb8QGI0 zGJ~f|%SibY?>^(@a;_8-6%yCmEiARI8o`| literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/BasicImageReader.class b/tests/test_data/std/jdk/internal/jimage/BasicImageReader.class new file mode 100644 index 0000000000000000000000000000000000000000..ee2484b82f13dc90b93fcda9fdcb50548f66322e GIT binary patch literal 14703 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 Z{%O!UwFM~YQ(ILyH&6AesJe*C{~rjMYLx&0 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/BasicImageReader.java b/tests/test_data/std/jdk/internal/jimage/BasicImageReader.java new file mode 100644 index 00000000..07879353 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/BasicImageReader.java @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Objects; +import java.util.stream.IntStream; +import jdk.internal.jimage.decompressor.Decompressor; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class BasicImageReader implements AutoCloseable { + @SuppressWarnings("removal") + private static boolean isSystemProperty(String key, String value, String def) { + // No lambdas during bootstrap + return AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Boolean run() { + return value.equals(System.getProperty(key, def)); + } + }); + } + + private static final boolean IS_64_BIT = + isSystemProperty("sun.arch.data.model", "64", "32"); + private static final boolean USE_JVM_MAP = + isSystemProperty("jdk.image.use.jvm.map", "true", "true"); + private static final boolean MAP_ALL = + isSystemProperty("jdk.image.map.all", "true", IS_64_BIT ? "true" : "false"); + + private final Path imagePath; + private final ByteOrder byteOrder; + private final String name; + private final ByteBuffer memoryMap; + private final FileChannel channel; + private final ImageHeader header; + private final long indexSize; + private final IntBuffer redirect; + private final IntBuffer offsets; + private final ByteBuffer locations; + private final ByteBuffer strings; + private final ImageStringsReader stringsReader; + private final Decompressor decompressor; + + @SuppressWarnings({ "removal", "this-escape" }) + protected BasicImageReader(Path path, ByteOrder byteOrder) + throws IOException { + this.imagePath = Objects.requireNonNull(path); + this.byteOrder = Objects.requireNonNull(byteOrder); + this.name = this.imagePath.toString(); + + ByteBuffer map; + + if (USE_JVM_MAP && BasicImageReader.class.getClassLoader() == null) { + // Check to see if the jvm has opened the file using libjimage + // native entry when loading the image for this runtime + map = NativeImageBuffer.getNativeMap(name); + } else { + map = null; + } + + // Open the file only if no memory map yet or is 32 bit jvm + if (map != null && MAP_ALL) { + channel = null; + } else { + channel = FileChannel.open(imagePath, StandardOpenOption.READ); + // No lambdas during bootstrap + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + if (BasicImageReader.class.getClassLoader() == null) { + try { + Class fileChannelImpl = + Class.forName("sun.nio.ch.FileChannelImpl"); + Method setUninterruptible = + fileChannelImpl.getMethod("setUninterruptible"); + setUninterruptible.invoke(channel); + } catch (ClassNotFoundException | + NoSuchMethodException | + IllegalAccessException | + InvocationTargetException ex) { + // fall thru - will only happen on JDK-8 systems where this code + // is only used by tools using jrt-fs (non-critical.) + } + } + + return null; + } + }); + } + + // If no memory map yet and 64 bit jvm then memory map entire file + if (MAP_ALL && map == null) { + map = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); + } + + // Assume we have a memory map to read image file header + ByteBuffer headerBuffer = map; + int headerSize = ImageHeader.getHeaderSize(); + + // If no memory map then read header from image file + if (headerBuffer == null) { + headerBuffer = ByteBuffer.allocateDirect(headerSize); + if (channel.read(headerBuffer, 0L) == headerSize) { + headerBuffer.rewind(); + } else { + throw new IOException("\"" + name + "\" is not an image file"); + } + } else if (headerBuffer.capacity() < headerSize) { + throw new IOException("\"" + name + "\" is not an image file"); + } + + // Interpret the image file header + header = readHeader(intBuffer(headerBuffer, 0, headerSize)); + indexSize = header.getIndexSize(); + + // If no memory map yet then must be 32 bit jvm not previously mapped + if (map == null) { + // Just map the image index + map = channel.map(FileChannel.MapMode.READ_ONLY, 0, indexSize); + } + + memoryMap = map.asReadOnlyBuffer(); + + // Interpret the image index + if (memoryMap.capacity() < indexSize) { + throw new IOException("The image file \"" + name + "\" is corrupted"); + } + redirect = intBuffer(memoryMap, header.getRedirectOffset(), header.getRedirectSize()); + offsets = intBuffer(memoryMap, header.getOffsetsOffset(), header.getOffsetsSize()); + locations = slice(memoryMap, header.getLocationsOffset(), header.getLocationsSize()); + strings = slice(memoryMap, header.getStringsOffset(), header.getStringsSize()); + + stringsReader = new ImageStringsReader(this); + decompressor = new Decompressor(); + } + + protected BasicImageReader(Path imagePath) throws IOException { + this(imagePath, ByteOrder.nativeOrder()); + } + + public static BasicImageReader open(Path imagePath) throws IOException { + return new BasicImageReader(imagePath, ByteOrder.nativeOrder()); + } + + public ImageHeader getHeader() { + return header; + } + + private ImageHeader readHeader(IntBuffer buffer) throws IOException { + ImageHeader result = ImageHeader.readFrom(buffer); + + if (result.getMagic() != ImageHeader.MAGIC) { + throw new IOException("\"" + name + "\" is not an image file"); + } + + if (result.getMajorVersion() != ImageHeader.MAJOR_VERSION || + result.getMinorVersion() != ImageHeader.MINOR_VERSION) { + throw new IOException("The image file \"" + name + "\" is not " + + "the correct version. Major: " + result.getMajorVersion() + + ". Minor: " + result.getMinorVersion()); + } + + return result; + } + + private static ByteBuffer slice(ByteBuffer buffer, int position, int capacity) { + // Note that this is the only limit and position manipulation of + // BasicImageReader private ByteBuffers. The synchronize could be avoided + // by cloning the buffer to make a local copy, but at the cost of creating + // a new object. + synchronized(buffer) { + buffer.limit(position + capacity); + buffer.position(position); + return buffer.slice(); + } + } + + private IntBuffer intBuffer(ByteBuffer buffer, int offset, int size) { + return slice(buffer, offset, size).order(byteOrder).asIntBuffer(); + } + + public static void releaseByteBuffer(ByteBuffer buffer) { + Objects.requireNonNull(buffer); + + if (!MAP_ALL) { + ImageBufferCache.releaseBuffer(buffer); + } + } + + public String getName() { + return name; + } + + public ByteOrder getByteOrder() { + return byteOrder; + } + + public Path getImagePath() { + return imagePath; + } + + @Override + public void close() throws IOException { + if (channel != null) { + channel.close(); + } + } + + public ImageStringsReader getStrings() { + return stringsReader; + } + + public ImageLocation findLocation(String module, String name) { + int index = getLocationIndex(module, name); + if (index < 0) { + return null; + } + long[] attributes = getAttributes(offsets.get(index)); + if (!ImageLocation.verify(module, name, attributes, stringsReader)) { + return null; + } + return new ImageLocation(attributes, stringsReader); + } + + public ImageLocation findLocation(String name) { + int index = getLocationIndex(name); + if (index < 0) { + return null; + } + long[] attributes = getAttributes(offsets.get(index)); + if (!ImageLocation.verify(name, attributes, stringsReader)) { + return null; + } + return new ImageLocation(attributes, stringsReader); + } + + public boolean verifyLocation(String module, String name) { + int index = getLocationIndex(module, name); + if (index < 0) { + return false; + } + int locationOffset = offsets.get(index); + return ImageLocation.verify(module, name, locations, locationOffset, stringsReader); + } + + // Details of the algorithm used here can be found in + // jdk.tools.jlink.internal.PerfectHashBuilder. + public int getLocationIndex(String name) { + int count = header.getTableLength(); + int index = redirect.get(ImageStringsReader.hashCode(name) % count); + if (index < 0) { + // index is twos complement of location attributes index. + return -index - 1; + } else if (index > 0) { + // index is hash seed needed to compute location attributes index. + return ImageStringsReader.hashCode(name, index) % count; + } else { + // No entry. + return -1; + } + } + + private int getLocationIndex(String module, String name) { + int count = header.getTableLength(); + int index = redirect.get(ImageStringsReader.hashCode(module, name) % count); + if (index < 0) { + // index is twos complement of location attributes index. + return -index - 1; + } else if (index > 0) { + // index is hash seed needed to compute location attributes index. + return ImageStringsReader.hashCode(module, name, index) % count; + } else { + // No entry. + return -1; + } + } + + public String[] getEntryNames() { + int[] attributeOffsets = new int[offsets.capacity()]; + offsets.get(attributeOffsets); + return IntStream.of(attributeOffsets) + .filter(o -> o != 0) + .mapToObj(o -> ImageLocation.readFrom(this, o).getFullName()) + .sorted() + .toArray(String[]::new); + } + + ImageLocation getLocation(int offset) { + return ImageLocation.readFrom(this, offset); + } + + public long[] getAttributes(int offset) { + if (offset < 0 || offset >= locations.limit()) { + throw new IndexOutOfBoundsException("offset"); + } + return ImageLocation.decompress(locations, offset); + } + + public String getString(int offset) { + if (offset < 0 || offset >= strings.limit()) { + throw new IndexOutOfBoundsException("offset"); + } + return ImageStringsReader.stringFromByteBuffer(strings, offset); + } + + public int match(int offset, String string, int stringOffset) { + if (offset < 0 || offset >= strings.limit()) { + throw new IndexOutOfBoundsException("offset"); + } + return ImageStringsReader.stringFromByteBufferMatches(strings, offset, string, stringOffset); + } + + private byte[] getBufferBytes(ByteBuffer buffer) { + Objects.requireNonNull(buffer); + byte[] bytes = new byte[buffer.limit()]; + buffer.get(bytes); + + return bytes; + } + + private ByteBuffer readBuffer(long offset, long size) { + if (offset < 0 || Integer.MAX_VALUE <= offset) { + throw new IndexOutOfBoundsException("Bad offset: " + offset); + } + + if (size < 0 || Integer.MAX_VALUE <= size) { + throw new IndexOutOfBoundsException("Bad size: " + size); + } + + if (MAP_ALL) { + ByteBuffer buffer = slice(memoryMap, (int)offset, (int)size); + buffer.order(ByteOrder.BIG_ENDIAN); + + return buffer; + } else { + if (channel == null) { + throw new InternalError("Image file channel not open"); + } + + ByteBuffer buffer = ImageBufferCache.getBuffer(size); + int read; + try { + read = channel.read(buffer, offset); + buffer.rewind(); + } catch (IOException ex) { + ImageBufferCache.releaseBuffer(buffer); + throw new RuntimeException(ex); + } + + if (read != size) { + ImageBufferCache.releaseBuffer(buffer); + throw new RuntimeException("Short read: " + read + + " instead of " + size + " bytes"); + } + + return buffer; + } + } + + public byte[] getResource(String name) { + Objects.requireNonNull(name); + ImageLocation location = findLocation(name); + + return location != null ? getResource(location) : null; + } + + public byte[] getResource(ImageLocation loc) { + ByteBuffer buffer = getResourceBuffer(loc); + + if (buffer != null) { + byte[] bytes = getBufferBytes(buffer); + ImageBufferCache.releaseBuffer(buffer); + + return bytes; + } + + return null; + } + + public ByteBuffer getResourceBuffer(ImageLocation loc) { + Objects.requireNonNull(loc); + long offset = loc.getContentOffset() + indexSize; + long compressedSize = loc.getCompressedSize(); + long uncompressedSize = loc.getUncompressedSize(); + + if (compressedSize < 0 || Integer.MAX_VALUE < compressedSize) { + throw new IndexOutOfBoundsException( + "Bad compressed size: " + compressedSize); + } + + if (uncompressedSize < 0 || Integer.MAX_VALUE < uncompressedSize) { + throw new IndexOutOfBoundsException( + "Bad uncompressed size: " + uncompressedSize); + } + + if (compressedSize == 0) { + return readBuffer(offset, uncompressedSize); + } else { + ByteBuffer buffer = readBuffer(offset, compressedSize); + + if (buffer != null) { + byte[] bytesIn = getBufferBytes(buffer); + ImageBufferCache.releaseBuffer(buffer); + byte[] bytesOut; + + try { + bytesOut = decompressor.decompressResource(byteOrder, + (int strOffset) -> getString(strOffset), bytesIn); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + return ByteBuffer.wrap(bytesOut); + } + } + + return null; + } + + public InputStream getResourceStream(ImageLocation loc) { + Objects.requireNonNull(loc); + byte[] bytes = getResource(loc); + + return new ByteArrayInputStream(bytes); + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/ImageBufferCache$1.class b/tests/test_data/std/jdk/internal/jimage/ImageBufferCache$1.class new file mode 100644 index 0000000000000000000000000000000000000000..9e4f0e3c98162ecaef696d60b74588111bef99b6 GIT binary patch literal 950 zcmb_aO>Yx15Pfbo*(PjhNgF8N1w|<7ffeUO6>3^Uq_jx13WuJYjk9s;dXd+Q=)Zys zNJ#Jl_)&;iCx;{oQV*=O9{YLb>3Qb;{`2D(fDWGfSYxP9hL@q#Rv67yIFVO87GXDE z53|uom=2G|q5=;^AEf|3)){IO{)vZ*>o`0g8^MRYB;typ)RtP>1BODQ+4oUl*mjwj zl`1^pAM3~3n(GPzZ1}hxU=v#mFK!~B{)!>U$t72Pt}?-}+h|_&R?xQ?yiPKtjLn|Z z;xxM&2y@N{ijb-k+UG{*=NahPu}m2ny_*Rk{_>fOHMf}|O8yTS?Ws1`BqK)Q2f;7j z3u>s)k(ga-nS_VecGl_EL2It2OCyPeA&_CG(VV+^H<*aX68w1%oSQ>?Wn2EAo?KDo zEXhnH-pIVGwPm}!%*R6gKh}{-QmNw;VaLgkVf|F3_HB|{nr2sPa+l(1DpDVN3>yo> zWGFhfV2|wLkzs)X{p3F|+@W1akx?w}e@EdfZPrkwwdBCp*rt6jO~4LnbnUfRYnfz~f+D6g_wm5dJ;WoYD}TmghcG;$SS6KZ MJjJt8ncm>OziwRO%K!iX literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageBufferCache$2.class b/tests/test_data/std/jdk/internal/jimage/ImageBufferCache$2.class new file mode 100644 index 0000000000000000000000000000000000000000..a8b528e6b5bf90ca53ed3942958fbd59eb35d180 GIT binary patch literal 1465 zcmcIk-A)rh6#k|yEG=6pEg=4*7HIif#S1S=NTk8INkJn9?@Xr4v`pFVHoH@kzJYJx zg|Fa^H%h!vuYD-vneA$eDG3+2$?VLWIdi`A_s!2=U%vsU;!y?(Bn_lYjA5K1*Wz!v z<#MlSJ+HTfqZr1wq$kxjL$Xvp%wPg(0~r&OFd2%iqZ3PdN(3Hvt(I)_rm$@N-|03Q zBB*lbSTIaBg{txncckhu%$I5rN>@qO+T)$#uBU=trEF(#1ycrcCZ>^Rm>&3I6GT%4 z42I*kJ3JtpV9@}aQBc0QtxA7N*&9PfzU6I(c)%>%25v_&M8kS5_{mE_WfYzx;zLjR)=p2w^{s4IhVH~wA|XTi zKsG(Dy1G=~N9OeM(Ee{MWt(9+j$nuw!-4myLLE#5+7s&7KYGCf-WJ3Qs_DC-6vdiD z9uHb3PRLnWTwa!RRWb*DH*myLsrzvDU!rd4My8J4^&Hm^rPu7o!Z5KfLiNlK=`}EI z&m&&DJPbu>fI2WcXn!Iz5i_DQ7KnfeFkGj1CP{;y7uwyVl|?htl9exDpJk4w(V1iNmC&FE{jir8QPhVXVL^c-sda(^{^Dgd1c1_%; zRRTr2r=9GdE&e@QB-s*46IjkYA?y;ZH1=b%sIjvvt3Oa!qwyKD8vMKfvN3p>bkc;A oqnXB7Y<&f*(d9L))10EG71)R*6O<$%PlgM4fX(qV`5Aq`0WghsU;qFB literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageBufferCache.class b/tests/test_data/std/jdk/internal/jimage/ImageBufferCache.class new file mode 100644 index 0000000000000000000000000000000000000000..c16cce9879e1c6c319d355360c4cde59ef2a7766 GIT binary patch literal 3915 zcmcInT~iy^8Geq?2Z#m77#Xms@C{3n4SUaQ0%g=j(mn z=Xsy^oTGpK?{9wxkiaKFcu*C9SAh?Hfyd_6Yicy7=4YcLQ}bHZ6!7=xdEM+4sA}&R z_i+`UeOtaQ>-i6YP*4{@y@GvsOyGcJAg>pqeJiHcSDKm841szzmn&pdQ|s3a%V=|Z zvLm&})K~xw0{bgbB=e>=s~MKx8*~}KL4l{;E;_F-soO$iKl?4leKsnA`mYg_uMK7rzP%wxgfpGso zVss#$Nv4M;6Y=x$L~?9mGJPSH%1ox>nK6>);w({ETv83yEEtS2iL(KmQ;@=NxmYYe zal=qoic)X|gX!pMcUX6)V{e;MeIo)-TIscIO%+W;&6+Y<8GUgnr&)Ldcv0YRMFoa7 z6TPUZ3!@rKOv`7f^Yh3^ofE(go!ga6od>ZW;|ea~C4s;-HCNI`W(an>7OiNViX+%G zE=hBj1)g!2jbqLw+ieH6xPq$zOe%OqYS!Kib|!)c zB&?Sj8QXvz1hQbZEetC{UBpXY;CAGBkl@7dftK?b)*ydt8&hmQ-hOm&AKx zt~KR^^~QQxXxHo!i}Z?g9Wy&q@n{`;6NPC)-(&NU zEah0c2X}_MvQ!TF>RwhJ9ftyw-?BWY5M?;{u+k zDS^^AjDOqA)H3sl?X#sE>iuiM_;@2R~xlaJA2{&07!0i`KZw3lxvy?RE*( z?B^AfJ=gdZL!4kwMjm8xc?& zQFG(Y25SGp9uF#3k}fOtXvS+Cuf~tdR>T~w1lV^wT(f!?wT(CsUi}1hn+Q!bG~GkX zKg2NYhgbiA+VBRR7+%BpXJ}hT`+Xcs`%Zd8-n)n$4SBmy`C5Dr5NYvk;CrY1E&c}x zhgIMI*n5 zQP1RKd>=aMbEKj*q-2SsgdX3ZHKW#$l+&P;h`PiAb;(Z zx46=tf1C4v&aq|$>TCXs{Q)RnK?&fPIQb=fUy}1`+`%uL-2I!gy_`K1Awdmi{six* z+pMOlPPh91h}O>5?)1?Is6R?Vzd)d~Rb*~@#M;)sI{lFi{4mq`8TvQyLZ@G3q;zcB zx+xeCcnwMv%Q8uP4TqWT#|bz>0LR!qK`1c-=_9;B1}$lcaQ)-_ZzIX5BEYakhLqQk zMHOi2S&J62O@TfC7U$bzw+T*CP!DhLE7VHtO~lSPc&{a8QnX37rMR0mk)GJZ`3Wk2 zRFbfP3->TlQExrX0&k%XZ!?^?tRU@LXkzOPj@c#lHqF0-cOCOD)3`Jrijc9YHSCN0 z6)y|i$NqJwf98PAl3if$xr~PJOCpDb&2}SuZm~xq^1)Mmu3Xgb(Ifv*I388UW3%)q z*3dwYy#L?F`E|_Rhf-0r?eu+@)8?-^l|5yr0Xj`nMh?(lQ9!@8wg$=Lak`gJXcKc2 z_b~rC+BUJkuf@;NFXbStDw6+ufisNwcjWUo{Py5|tn$~-uLWKpf6MQuNXr$@_|RX& R+V}`}DW5s^%V)v<`9F@H+Drfd literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageBufferCache.java b/tests/test_data/std/jdk/internal/jimage/ImageBufferCache.java new file mode 100644 index 00000000..c2cc4a02 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/ImageBufferCache.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage; + +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Map; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrt-fs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +class ImageBufferCache { + private static final int MAX_CACHED_BUFFERS = 3; + private static final int LARGE_BUFFER = 0x10000; + + /* + * We used to have a class BufferReference extending from WeakReference. + * BufferReference class had an instance field called "capacity". This field was + * used to make DECREASING_CAPACITY_NULLS_LAST comparator stable in the presence + * of GC clearing the WeakReference concurrently. + * + * But this scheme results in metaspace leak. The thread local is alive till the + * the thread is alive. And so ImageBufferCache$BufferReference class was kept alive. + * Because this class and ImageBufferCache$BufferReference are all loaded by a URL + * class loader from jrt-fs.jar, the class loader and so all the classes loaded by it + * were alive! + * + * Solution is to avoid using a URL loader loaded class type with thread local. All we + * need is a pair of WeakReference, Integer (saved capacity for stability + * of comparator). We use Map.Entry as pair implementation. With this, all types used + * with thread local are bootstrap types and so no metaspace leak. + */ + @SuppressWarnings("unchecked") + private static final ThreadLocal, Integer>[]> CACHE = + new ThreadLocal, Integer>[]>() { + @Override + protected Map.Entry, Integer>[] initialValue() { + // 1 extra slot to simplify logic of releaseBuffer() + return (Map.Entry, Integer>[])new Map.Entry[MAX_CACHED_BUFFERS + 1]; + } + }; + + private static ByteBuffer allocateBuffer(long size) { + return ByteBuffer.allocateDirect((int)((size + 0xFFF) & ~0xFFF)); + } + + static ByteBuffer getBuffer(long size) { + if (size < 0 || Integer.MAX_VALUE < size) { + throw new IndexOutOfBoundsException("size"); + } + + ByteBuffer result = null; + + if (size > LARGE_BUFFER) { + result = allocateBuffer(size); + } else { + Map.Entry, Integer>[] cache = CACHE.get(); + + // buffers are ordered by decreasing capacity + // cache[MAX_CACHED_BUFFERS] is always null + for (int i = MAX_CACHED_BUFFERS - 1; i >= 0; i--) { + Map.Entry, Integer> reference = cache[i]; + + if (reference != null) { + ByteBuffer buffer = getByteBuffer(reference); + + if (buffer != null && size <= buffer.capacity()) { + cache[i] = null; + result = buffer; + result.rewind(); + break; + } + } + } + + if (result == null) { + result = allocateBuffer(size); + } + } + + result.limit((int)size); + + return result; + } + + static void releaseBuffer(ByteBuffer buffer) { + if (buffer.capacity() > LARGE_BUFFER) { + return; + } + + Map.Entry, Integer>[] cache = CACHE.get(); + + // expunge cleared BufferRef(s) + for (int i = 0; i < MAX_CACHED_BUFFERS; i++) { + Map.Entry, Integer> reference = cache[i]; + if (reference != null && getByteBuffer(reference) == null) { + cache[i] = null; + } + } + + // insert buffer back with new BufferRef wrapping it + cache[MAX_CACHED_BUFFERS] = newCacheEntry(buffer); + Arrays.sort(cache, DECREASING_CAPACITY_NULLS_LAST); + // squeeze the smallest one out + cache[MAX_CACHED_BUFFERS] = null; + } + + private static Map.Entry, Integer> newCacheEntry(ByteBuffer bb) { + return new AbstractMap.SimpleEntry, Integer>( + new WeakReference(bb), bb.capacity()); + } + + private static int getCapacity(Map.Entry, Integer> e) { + return e == null? 0 : e.getValue(); + } + + private static ByteBuffer getByteBuffer(Map.Entry, Integer> e) { + return e == null? null : e.getKey().get(); + } + + private static Comparator, Integer>> DECREASING_CAPACITY_NULLS_LAST = + new Comparator, Integer>>() { + @Override + public int compare(Map.Entry, Integer> br1, + Map.Entry, Integer> br2) { + return Integer.compare(getCapacity(br1), getCapacity(br2)); + } + }; +} diff --git a/tests/test_data/std/jdk/internal/jimage/ImageHeader.class b/tests/test_data/std/jdk/internal/jimage/ImageHeader.class new file mode 100644 index 0000000000000000000000000000000000000000..783e9a8438bb2c561960bc95e8e5473bde6ec06b GIT binary patch literal 3953 zcma)8-%}gc75>%|S|Kk+5M*3_B)CpoSZq@h*Kxsi3>a+L2x4&LkT|u4SYWYO;nm8q z-Na4PHciqtZPPYw)0w2{Lm$%4B%Lw1Q_r;TdFpfin55siyOI{6x@894ALpL$ob#P? z&)v_z{Kr25OyCbXc4>HGZRy64?Rb{!p&_}JyOkR%qlD^JL43gIIJD%kW7>0%y4ZMV_8uV9O+p{hgHS7xl zsyi$f?K`-p0A(6DCUhKQ0BO^5G|V6Gc*DtdnQs(Kp+Zi=WaWX^{c#gYN9f*KgC z32zyAMTG5PlfIaZBr|p{&3b8>;QjS-j+f09%FISfX6(Z3+_miF+hCSq(c=oKA)i`mve zDA#ZKjg>sid%66LOl~7^`$^jTZ}5Jdj|vyDQc&}ch%Y$KOIdTGR-E)A&Map9<}am} z33YtG7&D<(?;oF%9`BdjT)4UW1*&53yE>Ce$h5O$-Ih}JRf0mS6ii}Xy$(~hBrzF! z>W;`|!ckU4GmAjpm)l5kb%(26h;V&3wEiyFuZGsIp$qpy>+hjmUOMWw%iE?#K4og; z%cVxXS8C+zq(;6*YUJC)F-6-kyw2b6b7j%1CXTIUdn6i(bocb8q7M-L8@G1h4gMxL z0w=HsBlrPl$Nb~?A%4Ua73Fy(n9SbfOis7T1IW;1CPt&mq#l_3H_r$a!{!6T&F)RK zm_3_lGkZ7DVWy&+=rmJJo9HrAu}$=vDSZ=tW-7jk12wNq`UN~odM3Oy!?7M?;VetP24!%WX5EO znYs+R8J8h$Ce?29Lud=#%xLJB-jL1(Zu65!+uDFiV%3f7T&G@PESUW@(U&7CPF7Z6!C55R$;gUbo zTbMNmxA6QH7HU<~u5xNI#${f_6?E`9lA7M@D_5%{g?I6DLW_y3fr*dFlbFc(Cd~V2 z*}}_L203XP`RsK`OSvP?>AKLtyg}hp)$X7g5o$zdWB4#Z1?J` z_3H12)b%Rg{1p2C)Zc5U&d;SlJ)G;ldfV@Zlxw->=Trmb1NF)uG*td=RXH2Py^lAJ zjVgbgKg;rC%TM8Y4X;bJ&JTG3KVqf-kv0A?o57#Zi4Q|I_El?|A9aC)M>q<%QQD~C z`Gx%FkZ!c9%TK;Q_hjH-g5DJQpAUJoN45G-cme)Gk3I<@C8|jLK5T&G5@~q{(x*iF hj7Xn0MEYGrq%x809Z2_yv`M7<4UjbaUR~x7{sUi^?5O|% literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageHeader.java b/tests/test_data/std/jdk/internal/jimage/ImageHeader.java new file mode 100644 index 00000000..f6366511 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/ImageHeader.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jimage; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.Objects; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public final class ImageHeader { + public static final int MAGIC = 0xCAFEDADA; + public static final int MAJOR_VERSION = 1; + public static final int MINOR_VERSION = 0; + private static final int HEADER_SLOTS = 7; + + private final int magic; + private final int majorVersion; + private final int minorVersion; + private final int flags; + private final int resourceCount; + private final int tableLength; + private final int locationsSize; + private final int stringsSize; + + public ImageHeader(int resourceCount, int tableCount, + int locationsSize, int stringsSize) { + this(MAGIC, MAJOR_VERSION, MINOR_VERSION, 0, resourceCount, + tableCount, locationsSize, stringsSize); + } + + public ImageHeader(int magic, int majorVersion, int minorVersion, + int flags, int resourceCount, + int tableLength, int locationsSize, int stringsSize) + { + this.magic = magic; + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + this.flags = flags; + this.resourceCount = resourceCount; + this.tableLength = tableLength; + this.locationsSize = locationsSize; + this.stringsSize = stringsSize; + } + + public static int getHeaderSize() { + return HEADER_SLOTS * 4; + } + + static ImageHeader readFrom(IntBuffer buffer) { + Objects.requireNonNull(buffer); + + if (buffer.capacity() != HEADER_SLOTS) { + throw new InternalError( + "jimage header not the correct size: " + buffer.capacity()); + } + + int magic = buffer.get(0); + int version = buffer.get(1); + int majorVersion = version >>> 16; + int minorVersion = version & 0xFFFF; + int flags = buffer.get(2); + int resourceCount = buffer.get(3); + int tableLength = buffer.get(4); + int locationsSize = buffer.get(5); + int stringsSize = buffer.get(6); + + return new ImageHeader(magic, majorVersion, minorVersion, flags, + resourceCount, tableLength, locationsSize, stringsSize); + } + + public void writeTo(ImageStream stream) { + Objects.requireNonNull(stream); + stream.ensure(getHeaderSize()); + writeTo(stream.getBuffer()); + } + + public void writeTo(ByteBuffer buffer) { + Objects.requireNonNull(buffer); + buffer.putInt(magic); + buffer.putInt(majorVersion << 16 | minorVersion); + buffer.putInt(flags); + buffer.putInt(resourceCount); + buffer.putInt(tableLength); + buffer.putInt(locationsSize); + buffer.putInt(stringsSize); + } + + public int getMagic() { + return magic; + } + + public int getMajorVersion() { + return majorVersion; + } + + public int getMinorVersion() { + return minorVersion; + } + + public int getFlags() { + return flags; + } + + public int getResourceCount() { + return resourceCount; + } + + public int getTableLength() { + return tableLength; + } + + public int getRedirectSize() { + return tableLength * 4; + } + + public int getOffsetsSize() { + return tableLength * 4; + } + + public int getLocationsSize() { + return locationsSize; + } + + public int getStringsSize() { + return stringsSize; + } + + public int getIndexSize() { + return getHeaderSize() + + getRedirectSize() + + getOffsetsSize() + + getLocationsSize() + + getStringsSize(); + } + + int getRedirectOffset() { + return getHeaderSize(); + } + + int getOffsetsOffset() { + return getRedirectOffset() + + getRedirectSize(); + } + + int getLocationsOffset() { + return getOffsetsOffset() + + getOffsetsSize(); + } + + int getStringsOffset() { + return getLocationsOffset() + + getLocationsSize(); + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/ImageLocation.class b/tests/test_data/std/jdk/internal/jimage/ImageLocation.class new file mode 100644 index 0000000000000000000000000000000000000000..8e886c41c90de0e5f15a508c0dc48fdc8f701efb GIT binary patch literal 7599 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 3; + if (ATTRIBUTE_COUNT <= kind) { + throw new InternalError( + "Invalid jimage attribute kind: " + kind); + } + + int length = (data & 0x7) + 1; + attributes[kind] = readValue(length, bytes, offset, limit); + offset += length; + } + return attributes; + } + + public static byte[] compress(long[] attributes) { + Objects.requireNonNull(attributes); + ImageStream stream = new ImageStream(16); + + for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) { + long value = attributes[kind]; + + if (value != 0) { + int n = (63 - Long.numberOfLeadingZeros(value)) >> 3; + stream.put((kind << 3) | n); + + for (int i = n; i >= 0; i--) { + stream.put((int)(value >> (i << 3))); + } + } + } + + stream.put(ATTRIBUTE_END << 3); + + return stream.toArray(); + } + + public boolean verify(String name) { + return verify(name, attributes, strings); + } + + /** + * A simpler verification would be {@code name.equals(getFullName())}, but + * by not creating the full name and enabling early returns we allocate + * fewer objects. + */ + static boolean verify(String name, long[] attributes, ImageStrings strings) { + Objects.requireNonNull(name); + final int length = name.length(); + int index = 0; + int moduleOffset = (int)attributes[ATTRIBUTE_MODULE]; + if (moduleOffset != 0 && length >= 1) { + int moduleLen = strings.match(moduleOffset, name, 1); + index = moduleLen + 1; + if (moduleLen < 0 + || length <= index + || name.charAt(0) != '/' + || name.charAt(index++) != '/') { + return false; + } + } + return verifyName(null, name, index, length, 0, + (int) attributes[ATTRIBUTE_PARENT], + (int) attributes[ATTRIBUTE_BASE], + (int) attributes[ATTRIBUTE_EXTENSION], + strings); + } + + static boolean verify(String module, String name, ByteBuffer locations, + int locationOffset, ImageStrings strings) { + int moduleOffset = 0; + int parentOffset = 0; + int baseOffset = 0; + int extOffset = 0; + + int limit = locations.limit(); + while (locationOffset < limit) { + int data = locations.get(locationOffset++) & 0xFF; + if (data <= 0x7) { // ATTRIBUTE_END + break; + } + int kind = data >>> 3; + if (ATTRIBUTE_COUNT <= kind) { + throw new InternalError( + "Invalid jimage attribute kind: " + kind); + } + + int length = (data & 0x7) + 1; + switch (kind) { + case ATTRIBUTE_MODULE: + moduleOffset = (int) readValue(length, locations, locationOffset, limit); + break; + case ATTRIBUTE_BASE: + baseOffset = (int) readValue(length, locations, locationOffset, limit); + break; + case ATTRIBUTE_PARENT: + parentOffset = (int) readValue(length, locations, locationOffset, limit); + break; + case ATTRIBUTE_EXTENSION: + extOffset = (int) readValue(length, locations, locationOffset, limit); + break; + } + locationOffset += length; + } + return verifyName(module, name, 0, name.length(), + moduleOffset, parentOffset, baseOffset, extOffset, strings); + } + + private static long readValue(int length, ByteBuffer buffer, int offset, int limit) { + long value = 0; + for (int j = 0; j < length; j++) { + value <<= 8; + if (offset >= limit) { + throw new InternalError("Missing jimage attribute data"); + } + value |= buffer.get(offset++) & 0xFF; + } + return value; + } + + static boolean verify(String module, String name, long[] attributes, + ImageStrings strings) { + Objects.requireNonNull(module); + Objects.requireNonNull(name); + return verifyName(module, name, 0, name.length(), + (int) attributes[ATTRIBUTE_MODULE], + (int) attributes[ATTRIBUTE_PARENT], + (int) attributes[ATTRIBUTE_BASE], + (int) attributes[ATTRIBUTE_EXTENSION], + strings); + } + + private static boolean verifyName(String module, String name, int index, int length, + int moduleOffset, int parentOffset, int baseOffset, int extOffset, ImageStrings strings) { + + if (moduleOffset != 0) { + if (strings.match(moduleOffset, module, 0) != module.length()) { + return false; + } + } + if (parentOffset != 0) { + int parentLen = strings.match(parentOffset, name, index); + if (parentLen < 0) { + return false; + } + index += parentLen; + if (length <= index || name.charAt(index++) != '/') { + return false; + } + } + int baseLen = strings.match(baseOffset, name, index); + if (baseLen < 0) { + return false; + } + index += baseLen; + if (extOffset != 0) { + if (length <= index + || name.charAt(index++) != '.') { + return false; + } + + int extLen = strings.match(extOffset, name, index); + if (extLen < 0) { + return false; + } + index += extLen; + } + return length == index; + } + + long getAttribute(int kind) { + if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) { + throw new InternalError( + "Invalid jimage attribute kind: " + kind); + } + return attributes[kind]; + } + + String getAttributeString(int kind) { + if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) { + throw new InternalError( + "Invalid jimage attribute kind: " + kind); + } + return getStrings().get((int)attributes[kind]); + } + + public String getModule() { + return getAttributeString(ATTRIBUTE_MODULE); + } + + public int getModuleOffset() { + return (int)getAttribute(ATTRIBUTE_MODULE); + } + + public String getBase() { + return getAttributeString(ATTRIBUTE_BASE); + } + + public int getBaseOffset() { + return (int)getAttribute(ATTRIBUTE_BASE); + } + + public String getParent() { + return getAttributeString(ATTRIBUTE_PARENT); + } + + public int getParentOffset() { + return (int)getAttribute(ATTRIBUTE_PARENT); + } + + public String getExtension() { + return getAttributeString(ATTRIBUTE_EXTENSION); + } + + public int getExtensionOffset() { + return (int)getAttribute(ATTRIBUTE_EXTENSION); + } + + public String getFullName() { + return getFullName(false); + } + + public String getFullName(boolean modulesPrefix) { + StringBuilder builder = new StringBuilder(); + + if (getModuleOffset() != 0) { + if (modulesPrefix) { + builder.append("/modules"); + } + + builder.append('/'); + builder.append(getModule()); + builder.append('/'); + } + + if (getParentOffset() != 0) { + builder.append(getParent()); + builder.append('/'); + } + + builder.append(getBase()); + + if (getExtensionOffset() != 0) { + builder.append('.'); + builder.append(getExtension()); + } + + return builder.toString(); + } + + String buildName(boolean includeModule, boolean includeParent, + boolean includeName) { + StringBuilder builder = new StringBuilder(); + + if (includeModule && getModuleOffset() != 0) { + builder.append("/modules/"); + builder.append(getModule()); + } + + if (includeParent && getParentOffset() != 0) { + builder.append('/'); + builder.append(getParent()); + } + + if (includeName) { + if (includeModule || includeParent) { + builder.append('/'); + } + + builder.append(getBase()); + + if (getExtensionOffset() != 0) { + builder.append('.'); + builder.append(getExtension()); + } + } + + return builder.toString(); + } + + public long getContentOffset() { + return getAttribute(ATTRIBUTE_OFFSET); + } + + public long getCompressedSize() { + return getAttribute(ATTRIBUTE_COMPRESSED); + } + + public long getUncompressedSize() { + return getAttribute(ATTRIBUTE_UNCOMPRESSED); + } + + static ImageLocation readFrom(BasicImageReader reader, int offset) { + Objects.requireNonNull(reader); + long[] attributes = reader.getAttributes(offset); + ImageStringsReader strings = reader.getStrings(); + + return new ImageLocation(attributes, strings); + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReader$Directory.class b/tests/test_data/std/jdk/internal/jimage/ImageReader$Directory.class new file mode 100644 index 0000000000000000000000000000000000000000..4f7574e00697237559450069a7aab0e7cdb001f2 GIT binary patch literal 2983 zcmb7GU2_v<6n@@K+D(&fp(%wT0u>@ONkb42k(5FjKq@6D#X_lH+hp5ryWPai2B_a3 z{09gA05@LvS*)E=W}NZDYj3?!XVme=8!wbW@SJzINuVPw&2&G``<`>2bIxT3WwTnR%#Kt)hP6Pg8L)5V#zX}gAF>sET&oYg0d^dMi)7<$ogV);_h5NPf*ZPV=+ z80Z(i6lNnE9o2B%GX&GtVCGmLGHPQom#Vi~rS$0WO$;3xggakUI zm8xr6>8#`Eb3QU1%3U0}n69^TiOsnV^ zw!m5so^-`tGGQ_s;LADql!l~Y{H`go%MKfCCefl zX34IQ_o_WxDw-3fK5iN8USOM_!aAb({SZ0wEgH6>n=%#CD;2|$_KunrwnIS0g$TA` zyNZ~G$FW18tq#C*6DpK!S2r0%XJgS$k53c2O#Fh19)YfUHM2`@jyX=rQIQbXP+#?G zJy4}I8BQ2+ghNOXF=XPpS&-JS8&8l(FP9CQFs2&a`dsltZJ>{DlFAatUN*7sKFuY- z%ZRt68Nz;wzgxE)qU>BZRnsW4wF4TS#zCsDTk^aMtm|10fIRO+AM@_e|D_;$woQk6wjPU)4rahWJZ-9mggiRU$(!LUHkmg0M(_4CLB z-~|mMY&K$6YE8o(abCkHE|C5u-I@{TZe;4R$Yd+OD6n;fjtS#syrSY&4LbW=Q|DC9 zB5G3#ibjQ6w^$?Ku&cXOT4)(ICvAFkXaXI$uSfb;*Qos&iY6y#*qR~JHuBZkal<*w zT|`+ODiw5VM0aF&`of?)Ws>jYiuP-nV;8nQD-G6z^9fH;@KodpNLEu`6sw$-#GL|h z+9k^$QYls#Om#fVI^`ip^h3BJh-IDTERj%9%ePYL3NxqlvY*Vzq~Xd5AxCla9fVGMzB`Bqrl#itZKtF%U66tq&LxAO?l4~Qm`y*D5di%>^z zpydl_pO936LDx3kq5Onqc_k!A?9uzfF=5TqZ_ zxro+Lb`;GgzC$RHnny?KV_FDEM^WCS{ED#h8`_lL(V_eyoh3YFlzeBMHD{f^voInk z(`o>(k+l%SZFH!V3c=&k2hmG+2B-u-;;Zz?X@K&l^rCsIenrTR@O`&&ciTz&`d%KI4JqkEJT6pZ2hAb;+S;RAI22jAfH?EnA( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReader$LinkNode.class b/tests/test_data/std/jdk/internal/jimage/ImageReader$LinkNode.class new file mode 100644 index 0000000000000000000000000000000000000000..a4915ae0ccb2644a322fda5442f335b2ff3e6ceb GIT binary patch literal 1611 zcmb7ETTc@~6#iy+X=zy~ML`4W?y>*_K)plC9b7%$%7y-}%mMe*OOX9Y6_>lhB~YVVD>|jA4Gieqc!_ z5T3(rYhN~bLs%PX+!DMly!nb-7Yyl!2-c)6R)WBj)m9*U1}l>-@AD&WInuS>(4oc8 zPOVk$%i6yRMP+%=L;^{M*c0i<;3>murj229r(taqxYH>97ixAV0TaV3>`_?sA0{4X#R&!yc*D2v&hB*rlj$0ZY!xXh4^GX6|@q87N` zTZTbiub1|uT_-hS(62oc(FA*J(2gB)PdEWXJ`(&dGX~9eC>_!-xy?gc1cFkkXR^Bt3CecM^W_nF%SayH z4tVWglOJ|M8~kaEf## zw|Ih!iyvvT*T@=@`g5f8_0UMJt%O_1&^=P`8cBDIBoRlJDClG;hkVCefo4TTGd`#> zbRwp9^vw|0Y@c?>Gu3Xiqhe8|+bULb)5n<3ea6sFn8!$~)eo4)38vmtct}#j^&a4@ z5O|`k+>Oc{3RooQCAuAlHdCU3M5_;`ug+nr<2C_lxP!alyo~!aPZ1Ff%Xna@*L4{W LDfHtsKf>f6zY2Xo literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReader$Node.class b/tests/test_data/std/jdk/internal/jimage/ImageReader$Node.class new file mode 100644 index 0000000000000000000000000000000000000000..8172c516a92f3fde8fb8030e714fcabd2b3b148a GIT binary patch literal 4056 zcmb7HOLG)e6#j0fCzDJ%E~T+ymHmmpvz%fx+R>3lr-8e0 zx4^Es!hFth0_i!Xotv{3%%aQ-7yz9bjGZd;ri3qB+wV~aV$4C zW7#ri1~fHY3S{n>>09}yxi+w}gS^edG63~a-8qU7C$ zMOy~4ARx}Eoo)j=uu~v4W1B@{i{T7ccNy4?JpwJB^j-Uc9I>2vf!>~T3|<{kpsPIs zJFB4|wryE7?E$Y?T98g~{9;}%2A1ojkrminl`BW;Sjn;(&8K5V*T% ztsWJ6@tA?fl|obCmSr>8i$f}d`vo>8*`I2{lT5C%2P&K;FE0;uw_qclGH?_F0!H4G zrV7WTrBY|tit&U4Rtch{`j!5mfgz>8!8ZM1AfK1MulCf|(*~YVTkUG=lv}W7ELl*S z8MI>9z_U0>CuU85b}-CZ78nn{6{if0VvI3mA(=MwVUgN8RzUvB~p8!{ZFz zpzHX7=>$`zU6KtfZb6?;4-B3hc;@(ol2L0Kv+2~>(3z3yk}hy8A!Pq6yL+cta%CUd zn5A;Gv@k8bNpso`i_p!R_LS*aY91}>!K_8c_SBcjWNrC_)v95j=)K{~AhxKpFvvr# z4*TP-8w^<w{mbTZcgI4q24YYnZ-0N~50YrfV$3lIL3&801FFFSiEdNB3y2k7X#_|A!2LZ2^6A$CqTn3X*4c*l1656u+!q1IM*!*>8h?h7cSZG>=U&^>f zV=v>C$YhSA+Dm1>!PXo6(4fE@)uMJj1T@M55um_%yvh~D_Xwp`TpF`mm$0=;O+7rI z<&n|~A;PAzRE1Kbx-5y&0W-9uu$~}oMWiKr_8WBRSC`OL3s^)(n~hOwi2yq=UGZm# zrW8yY{pr##Uq@R19D0NDtRd#vd<>>7g2_`R1+Dd{B34+3SSpE_OJa*L#40hFOf0o7 zF+T>ANNi>uV(BDeuanrt7-E%JF_~C;U1FDFFp0!w@dzWYjxwH8ZC`OAo>Nz1IH}43 zT9`{v-dwAEEm3(l<|E|;(djp488xdIH9rV7%W14d zn#wIZOk;tCN;LNoL*<_qrd-_d4`bF>Fa(@BG(Sqzbg@VVD&8m936#z4-(&CD@6mhq zCi*(}E#ragG7fTB#-lg!#7~MGZL>QR6a_1EQf_`i64 z5<^|#C2#?+N2vSgMHu1cFKaydG^SbQbFmK1FA_E1sAP2IR7GuOe3_{EW*s)aPSETC z->Z?I4|7z0X4uI#-va-n)!JT)A!I70#20Ha!m+gow-OQfuuVodz82w!L&AxQc6f^S@Qd@X7!H literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReader$Resource.class b/tests/test_data/std/jdk/internal/jimage/ImageReader$Resource.class new file mode 100644 index 0000000000000000000000000000000000000000..51fa6c55e5635df04a0ced419a87a05de0b040c9 GIT binary patch literal 2055 zcmb_dYflqF6g|@|v|W}00)qGe6txdv6?~xeMJxCSsfj3wd>h&U2A5s3yEW<`@{1;# zC?=Zt1N>3OJG*TurL~%vO?Gzf%(>@2&dmP&_3a0M0v_s!K#L)2pbOm$lRM>?rnG(G z+T1dCHuVr&o6PD{flc-ZEExSK3=S9dRUL z&<*s!V3=y__Nm}y;Z7BuGWqJhC2i^7VaTVBx(qG0bj(d@36uN8v{CVendhD?Et74r zX7Y0BwFHvri=p4Z0FE)FIz{kQcuvJFQ52fxlo-yfv_;fPL0Kj-q*5GaSf!9V)h_ps zIp`R{XbdL|jNv3hx-CJqiua`}O1|U1VTki`xv(v*GQs{3Sws1$W=agF4V=L^!yt9} zxm|L0_gvw5qP!~Ks@kN|kJYY8183E)0oqkKv`4K@890v%3a+bPo132S8KQ+i8GS3#7RAc$hH#(p4T~ZF&wQlDa5=u@=Is}~grv{N=ORnHPMf0w6jqA-J75rzRw0C$k-R?c^Qhgb+9Z?4n zGelH*dZeeCZ3$nHu1E{(47&7c#SE{8+Ua08uln6FRqC-9Xe-$)wuCs)PH)LMqzipD zIIZf~lWu|=D$I3O-9@DTqVW8Oj_1cvU>I*3MhGIQKC*4$7A#I$r%a>ag%m$XEm5xq zCg|A5>G~uQs>_AG5+r)M1;~=2*%~x@fc{K2x(_z}6|qeA3wl41ErKk)lWJW{Lf87x zr}bl+Y!e{{Gnl0rp#$G6_%d;cka1kbT$O_(N)Isb9myA2q8Kb@X7+J><|7#!Nd}2z zh)9M5l1vD~Jg(3_g4am~5R&MK;VOlo5z#eVuhLD^s6vTE->Y|!M7OeNV}V~IT&)Jr zu<#ei@s`LNxJkZL8BH1$XIJJkdJobHX{Q>%U3JPvaQ1GLAf! QqUx8J$1=@EXncUt-z4(WZ2$lO literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReader$SharedImageReader$LocationVisitor.class b/tests/test_data/std/jdk/internal/jimage/ImageReader$SharedImageReader$LocationVisitor.class new file mode 100644 index 0000000000000000000000000000000000000000..3fae44c9e2824a6c6b61e54bf26c2f9c3e05c262 GIT binary patch literal 402 zcmah_K}rKb5Uh?Sv#yCrJbLjWq8A6xo+JpBB7V;<+h2lyzlR}BP0 z$fb*}rmMQ^>-*yqzz9Qy7U8}sU$u3KgEO_R?3-D#o;3A|P08V6{$c``o6OV~CRy(m zHrnKa!XaT$nU&GCaZCO9Tyc>I?Nu`;TwYCgdaR}Ht`~%S?%zYfV_UNbZaCgF;)HC* zF+KR06pjh!J4OEvCv+#yaTwJmMve+6gxftk+s_h)TLBRI>%0FW=m3NRNmWq7XhR6; amDCn89Q|UBuHdOKJ>=-)Om=!0bh011L~(ck literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReader$SharedImageReader.class b/tests/test_data/std/jdk/internal/jimage/ImageReader$SharedImageReader.class new file mode 100644 index 0000000000000000000000000000000000000000..d54436e5e22e55ce706bfa0d8af56a02f83f3d38 GIT binary patch literal 14138 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 H#Nz(}Jl3-$ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReader.java b/tests/test_data/std/jdk/internal/jimage/ImageReader.java new file mode 100644 index 00000000..f12c39f3 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/ImageReader.java @@ -0,0 +1,858 @@ +/* + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.nio.file.Files; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public final class ImageReader implements AutoCloseable { + private final SharedImageReader reader; + + private volatile boolean closed; + + private ImageReader(SharedImageReader reader) { + this.reader = reader; + } + + public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException { + Objects.requireNonNull(imagePath); + Objects.requireNonNull(byteOrder); + + return SharedImageReader.open(imagePath, byteOrder); + } + + public static ImageReader open(Path imagePath) throws IOException { + return open(imagePath, ByteOrder.nativeOrder()); + } + + @Override + public void close() throws IOException { + if (closed) { + throw new IOException("image file already closed"); + } + reader.close(this); + closed = true; + } + + private void ensureOpen() throws IOException { + if (closed) { + throw new IOException("image file closed"); + } + } + + private void requireOpen() { + if (closed) { + throw new IllegalStateException("image file closed"); + } + } + + // directory management interface + public Directory getRootDirectory() throws IOException { + ensureOpen(); + return reader.getRootDirectory(); + } + + + public Node findNode(String name) throws IOException { + ensureOpen(); + return reader.findNode(name); + } + + public byte[] getResource(Node node) throws IOException { + ensureOpen(); + return reader.getResource(node); + } + + public byte[] getResource(Resource rs) throws IOException { + ensureOpen(); + return reader.getResource(rs); + } + + public ImageHeader getHeader() { + requireOpen(); + return reader.getHeader(); + } + + public static void releaseByteBuffer(ByteBuffer buffer) { + BasicImageReader.releaseByteBuffer(buffer); + } + + public String getName() { + requireOpen(); + return reader.getName(); + } + + public ByteOrder getByteOrder() { + requireOpen(); + return reader.getByteOrder(); + } + + public Path getImagePath() { + requireOpen(); + return reader.getImagePath(); + } + + public ImageStringsReader getStrings() { + requireOpen(); + return reader.getStrings(); + } + + public ImageLocation findLocation(String mn, String rn) { + requireOpen(); + return reader.findLocation(mn, rn); + } + + public boolean verifyLocation(String mn, String rn) { + requireOpen(); + return reader.verifyLocation(mn, rn); + } + + public ImageLocation findLocation(String name) { + requireOpen(); + return reader.findLocation(name); + } + + public String[] getEntryNames() { + requireOpen(); + return reader.getEntryNames(); + } + + public String[] getModuleNames() { + requireOpen(); + int off = "/modules/".length(); + return reader.findNode("/modules") + .getChildren() + .stream() + .map(Node::getNameString) + .map(s -> s.substring(off, s.length())) + .toArray(String[]::new); + } + + public long[] getAttributes(int offset) { + requireOpen(); + return reader.getAttributes(offset); + } + + public String getString(int offset) { + requireOpen(); + return reader.getString(offset); + } + + public byte[] getResource(String name) { + requireOpen(); + return reader.getResource(name); + } + + public byte[] getResource(ImageLocation loc) { + requireOpen(); + return reader.getResource(loc); + } + + public ByteBuffer getResourceBuffer(ImageLocation loc) { + requireOpen(); + return reader.getResourceBuffer(loc); + } + + public InputStream getResourceStream(ImageLocation loc) { + requireOpen(); + return reader.getResourceStream(loc); + } + + private static final class SharedImageReader extends BasicImageReader { + static final int SIZE_OF_OFFSET = Integer.BYTES; + + static final Map OPEN_FILES = new HashMap<>(); + + // List of openers for this shared image. + final Set openers; + + // attributes of the .jimage file. jimage file does not contain + // attributes for the individual resources (yet). We use attributes + // of the jimage file itself (creation, modification, access times). + // Iniitalized lazily, see {@link #imageFileAttributes()}. + BasicFileAttributes imageFileAttributes; + + // directory management implementation + final HashMap nodes; + volatile Directory rootDir; + + Directory packagesDir; + Directory modulesDir; + + private SharedImageReader(Path imagePath, ByteOrder byteOrder) throws IOException { + super(imagePath, byteOrder); + this.openers = new HashSet<>(); + this.nodes = new HashMap<>(); + } + + public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException { + Objects.requireNonNull(imagePath); + Objects.requireNonNull(byteOrder); + + synchronized (OPEN_FILES) { + SharedImageReader reader = OPEN_FILES.get(imagePath); + + if (reader == null) { + // Will fail with an IOException if wrong byteOrder. + reader = new SharedImageReader(imagePath, byteOrder); + OPEN_FILES.put(imagePath, reader); + } else if (reader.getByteOrder() != byteOrder) { + throw new IOException("\"" + reader.getName() + "\" is not an image file"); + } + + ImageReader image = new ImageReader(reader); + reader.openers.add(image); + + return image; + } + } + + public void close(ImageReader image) throws IOException { + Objects.requireNonNull(image); + + synchronized (OPEN_FILES) { + if (!openers.remove(image)) { + throw new IOException("image file already closed"); + } + + if (openers.isEmpty()) { + close(); + nodes.clear(); + rootDir = null; + + if (!OPEN_FILES.remove(this.getImagePath(), this)) { + throw new IOException("image file not found in open list"); + } + } + } + } + + void addOpener(ImageReader reader) { + synchronized (OPEN_FILES) { + openers.add(reader); + } + } + + boolean removeOpener(ImageReader reader) { + synchronized (OPEN_FILES) { + return openers.remove(reader); + } + } + + // directory management interface + Directory getRootDirectory() { + return buildRootDirectory(); + } + + /** + * Lazily build a node from a name. + */ + synchronized Node buildNode(String name) { + Node n; + boolean isPackages = name.startsWith("/packages"); + boolean isModules = !isPackages && name.startsWith("/modules"); + + if (!(isModules || isPackages)) { + return null; + } + + ImageLocation loc = findLocation(name); + + if (loc != null) { // A sub tree node + if (isPackages) { + n = handlePackages(name, loc); + } else { // modules sub tree + n = handleModulesSubTree(name, loc); + } + } else { // Asking for a resource? /modules/java.base/java/lang/Object.class + if (isModules) { + n = handleResource(name); + } else { + // Possibly ask for /packages/java.lang/java.base + // although /packages/java.base not created + n = handleModuleLink(name); + } + } + return n; + } + + synchronized Directory buildRootDirectory() { + Directory root = rootDir; // volatile read + if (root != null) { + return root; + } + + root = newDirectory(null, "/"); + root.setIsRootDir(); + + // /packages dir + packagesDir = newDirectory(root, "/packages"); + packagesDir.setIsPackagesDir(); + + // /modules dir + modulesDir = newDirectory(root, "/modules"); + modulesDir.setIsModulesDir(); + + root.setCompleted(true); + return rootDir = root; + } + + /** + * To visit sub tree resources. + */ + interface LocationVisitor { + void visit(ImageLocation loc); + } + + void visitLocation(ImageLocation loc, LocationVisitor visitor) { + byte[] offsets = getResource(loc); + ByteBuffer buffer = ByteBuffer.wrap(offsets); + buffer.order(getByteOrder()); + IntBuffer intBuffer = buffer.asIntBuffer(); + for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) { + int offset = intBuffer.get(i); + ImageLocation pkgLoc = getLocation(offset); + visitor.visit(pkgLoc); + } + } + + void visitPackageLocation(ImageLocation loc) { + // Retrieve package name + String pkgName = getBaseExt(loc); + // Content is array of offsets in Strings table + byte[] stringsOffsets = getResource(loc); + ByteBuffer buffer = ByteBuffer.wrap(stringsOffsets); + buffer.order(getByteOrder()); + IntBuffer intBuffer = buffer.asIntBuffer(); + // For each module, create a link node. + for (int i = 0; i < stringsOffsets.length / SIZE_OF_OFFSET; i++) { + // skip empty state, useless. + intBuffer.get(i); + i++; + int offset = intBuffer.get(i); + String moduleName = getString(offset); + Node targetNode = findNode("/modules/" + moduleName); + if (targetNode != null) { + String pkgDirName = packagesDir.getName() + "/" + pkgName; + Directory pkgDir = (Directory) nodes.get(pkgDirName); + newLinkNode(pkgDir, pkgDir.getName() + "/" + moduleName, targetNode); + } + } + } + + Node handlePackages(String name, ImageLocation loc) { + long size = loc.getUncompressedSize(); + Node n = null; + // Only possibilities are /packages, /packages/package/module + if (name.equals("/packages")) { + visitLocation(loc, (childloc) -> { + findNode(childloc.getFullName()); + }); + packagesDir.setCompleted(true); + n = packagesDir; + } else { + if (size != 0) { // children are offsets to module in StringsTable + String pkgName = getBaseExt(loc); + Directory pkgDir = newDirectory(packagesDir, packagesDir.getName() + "/" + pkgName); + visitPackageLocation(loc); + pkgDir.setCompleted(true); + n = pkgDir; + } else { // Link to module + String pkgName = loc.getParent(); + String modName = getBaseExt(loc); + Node targetNode = findNode("/modules/" + modName); + if (targetNode != null) { + String pkgDirName = packagesDir.getName() + "/" + pkgName; + Directory pkgDir = (Directory) nodes.get(pkgDirName); + Node linkNode = newLinkNode(pkgDir, pkgDir.getName() + "/" + modName, targetNode); + n = linkNode; + } + } + } + return n; + } + + // Asking for /packages/package/module although + // /packages// not yet created, need to create it + // prior to return the link to module node. + Node handleModuleLink(String name) { + // eg: unresolved /packages/package/module + // Build /packages/package node + Node ret = null; + String radical = "/packages/"; + String path = name; + if (path.startsWith(radical)) { + int start = radical.length(); + int pkgEnd = path.indexOf('/', start); + if (pkgEnd != -1) { + String pkg = path.substring(start, pkgEnd); + String pkgPath = radical + pkg; + Node n = findNode(pkgPath); + // If not found means that this is a symbolic link such as: + // /packages/java.util/java.base/java/util/Vector.class + // and will be done by a retry of the filesystem + for (Node child : n.getChildren()) { + if (child.name.equals(name)) { + ret = child; + break; + } + } + } + } + return ret; + } + + Node handleModulesSubTree(String name, ImageLocation loc) { + Node n; + assert (name.equals(loc.getFullName())); + Directory dir = makeDirectories(name); + visitLocation(loc, (childloc) -> { + String path = childloc.getFullName(); + if (path.startsWith("/modules")) { // a package + makeDirectories(path); + } else { // a resource + makeDirectories(childloc.buildName(true, true, false)); + // if we have already created a resource for this name previously, then don't + // recreate it + if (!nodes.containsKey(childloc.getFullName(true))) { + newResource(dir, childloc); + } + } + }); + dir.setCompleted(true); + n = dir; + return n; + } + + Node handleResource(String name) { + Node n = null; + if (!name.startsWith("/modules/")) { + return null; + } + // Make sure that the thing that follows "/modules/" is a module name. + int moduleEndIndex = name.indexOf('/', "/modules/".length()); + if (moduleEndIndex == -1) { + return null; + } + ImageLocation moduleLoc = findLocation(name.substring(0, moduleEndIndex)); + if (moduleLoc == null || moduleLoc.getModuleOffset() == 0) { + return null; + } + + String locationPath = name.substring("/modules".length()); + ImageLocation resourceLoc = findLocation(locationPath); + if (resourceLoc != null) { + Directory dir = makeDirectories(resourceLoc.buildName(true, true, false)); + Resource res = newResource(dir, resourceLoc); + n = res; + } + return n; + } + + String getBaseExt(ImageLocation loc) { + String base = loc.getBase(); + String ext = loc.getExtension(); + if (ext != null && !ext.isEmpty()) { + base = base + "." + ext; + } + return base; + } + + synchronized Node findNode(String name) { + buildRootDirectory(); + Node n = nodes.get(name); + if (n == null || !n.isCompleted()) { + n = buildNode(name); + } + return n; + } + + /** + * Returns the file attributes of the image file. + */ + BasicFileAttributes imageFileAttributes() { + BasicFileAttributes attrs = imageFileAttributes; + if (attrs == null) { + try { + Path file = getImagePath(); + attrs = Files.readAttributes(file, BasicFileAttributes.class); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + imageFileAttributes = attrs; + } + return attrs; + } + + Directory newDirectory(Directory parent, String name) { + Directory dir = Directory.create(parent, name, imageFileAttributes()); + nodes.put(dir.getName(), dir); + return dir; + } + + Resource newResource(Directory parent, ImageLocation loc) { + Resource res = Resource.create(parent, loc, imageFileAttributes()); + nodes.put(res.getName(), res); + return res; + } + + LinkNode newLinkNode(Directory dir, String name, Node link) { + LinkNode linkNode = LinkNode.create(dir, name, link); + nodes.put(linkNode.getName(), linkNode); + return linkNode; + } + + Directory makeDirectories(String parent) { + Directory last = rootDir; + for (int offset = parent.indexOf('/', 1); + offset != -1; + offset = parent.indexOf('/', offset + 1)) { + String dir = parent.substring(0, offset); + last = makeDirectory(dir, last); + } + return makeDirectory(parent, last); + + } + + Directory makeDirectory(String dir, Directory last) { + Directory nextDir = (Directory) nodes.get(dir); + if (nextDir == null) { + nextDir = newDirectory(last, dir); + } + return nextDir; + } + + byte[] getResource(Node node) throws IOException { + if (node.isResource()) { + return super.getResource(node.getLocation()); + } + throw new IOException("Not a resource: " + node); + } + + byte[] getResource(Resource rs) throws IOException { + return super.getResource(rs.getLocation()); + } + } + + // jimage file does not store directory structure. We build nodes + // using the "path" strings found in the jimage file. + // Node can be a directory or a resource + public abstract static class Node { + private static final int ROOT_DIR = 0b0000_0000_0000_0001; + private static final int PACKAGES_DIR = 0b0000_0000_0000_0010; + private static final int MODULES_DIR = 0b0000_0000_0000_0100; + + private int flags; + private final String name; + private final BasicFileAttributes fileAttrs; + private boolean completed; + + protected Node(String name, BasicFileAttributes fileAttrs) { + this.name = Objects.requireNonNull(name); + this.fileAttrs = Objects.requireNonNull(fileAttrs); + } + + /** + * A node is completed when all its direct children have been built. + * + * @return + */ + public boolean isCompleted() { + return completed; + } + + public void setCompleted(boolean completed) { + this.completed = completed; + } + + public final void setIsRootDir() { + flags |= ROOT_DIR; + } + + public final boolean isRootDir() { + return (flags & ROOT_DIR) != 0; + } + + public final void setIsPackagesDir() { + flags |= PACKAGES_DIR; + } + + public final boolean isPackagesDir() { + return (flags & PACKAGES_DIR) != 0; + } + + public final void setIsModulesDir() { + flags |= MODULES_DIR; + } + + public final boolean isModulesDir() { + return (flags & MODULES_DIR) != 0; + } + + public final String getName() { + return name; + } + + public final BasicFileAttributes getFileAttributes() { + return fileAttrs; + } + + // resolve this Node (if this is a soft link, get underlying Node) + public final Node resolveLink() { + return resolveLink(false); + } + + public Node resolveLink(boolean recursive) { + return this; + } + + // is this a soft link Node? + public boolean isLink() { + return false; + } + + public boolean isDirectory() { + return false; + } + + public List getChildren() { + throw new IllegalArgumentException("not a directory: " + getNameString()); + } + + public boolean isResource() { + return false; + } + + public ImageLocation getLocation() { + throw new IllegalArgumentException("not a resource: " + getNameString()); + } + + public long size() { + return 0L; + } + + public long compressedSize() { + return 0L; + } + + public String extension() { + return null; + } + + public long contentOffset() { + return 0L; + } + + public final FileTime creationTime() { + return fileAttrs.creationTime(); + } + + public final FileTime lastAccessTime() { + return fileAttrs.lastAccessTime(); + } + + public final FileTime lastModifiedTime() { + return fileAttrs.lastModifiedTime(); + } + + public final String getNameString() { + return name; + } + + @Override + public final String toString() { + return getNameString(); + } + + @Override + public final int hashCode() { + return name.hashCode(); + } + + @Override + public final boolean equals(Object other) { + if (this == other) { + return true; + } + + if (other instanceof Node) { + return name.equals(((Node) other).name); + } + + return false; + } + } + + // directory node - directory has full path name without '/' at end. + static final class Directory extends Node { + private final List children; + + private Directory(String name, BasicFileAttributes fileAttrs) { + super(name, fileAttrs); + children = new ArrayList<>(); + } + + static Directory create(Directory parent, String name, BasicFileAttributes fileAttrs) { + Directory d = new Directory(name, fileAttrs); + if (parent != null) { + parent.addChild(d); + } + return d; + } + + @Override + public boolean isDirectory() { + return true; + } + + @Override + public List getChildren() { + return Collections.unmodifiableList(children); + } + + void addChild(Node node) { + assert !children.contains(node) : "Child " + node + " already added"; + children.add(node); + } + + public void walk(Consumer consumer) { + consumer.accept(this); + for (Node child : children) { + if (child.isDirectory()) { + ((Directory)child).walk(consumer); + } else { + consumer.accept(child); + } + } + } + } + + // "resource" is .class or any other resource (compressed/uncompressed) in a jimage. + // full path of the resource is the "name" of the resource. + static class Resource extends Node { + private final ImageLocation loc; + + private Resource(ImageLocation loc, BasicFileAttributes fileAttrs) { + super(loc.getFullName(true), fileAttrs); + this.loc = loc; + } + + static Resource create(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) { + Resource rs = new Resource(loc, fileAttrs); + parent.addChild(rs); + return rs; + } + + @Override + public boolean isCompleted() { + return true; + } + + @Override + public boolean isResource() { + return true; + } + + @Override + public ImageLocation getLocation() { + return loc; + } + + @Override + public long size() { + return loc.getUncompressedSize(); + } + + @Override + public long compressedSize() { + return loc.getCompressedSize(); + } + + @Override + public String extension() { + return loc.getExtension(); + } + + @Override + public long contentOffset() { + return loc.getContentOffset(); + } + } + + // represents a soft link to another Node + static class LinkNode extends Node { + private final Node link; + + private LinkNode(String name, Node link) { + super(name, link.getFileAttributes()); + this.link = link; + } + + static LinkNode create(Directory parent, String name, Node link) { + LinkNode ln = new LinkNode(name, link); + parent.addChild(ln); + return ln; + } + + @Override + public boolean isCompleted() { + return true; + } + + @Override + public Node resolveLink(boolean recursive) { + return (recursive && link instanceof LinkNode) ? ((LinkNode)link).resolveLink(true) : link; + } + + @Override + public boolean isLink() { + return true; + } + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReaderFactory$1.class b/tests/test_data/std/jdk/internal/jimage/ImageReaderFactory$1.class new file mode 100644 index 0000000000000000000000000000000000000000..40a621d2a15bfbe6573f2a2f47ed73e577092b86 GIT binary patch literal 1185 zcma)5-%k@k5dNku96bxI{18+WRK&I*C;H$+35g+8NLnDGBtCAhOS|RRYwoT_{wsVD zqlx;smBN=GnIURK@TGH7z@|6@#84xmlS8BrZ zVl772%6ATxC!IYJwJW9CfcT1qF~UR~%8}cAQRbgvqP!g)q7w3HPWjx=H%Qq=Dxq!`$A5Vd0#Gx{TU>b58`~ zSn^yj=j^^}X%Y1TuI=!0Oy6>Km)5RgH>d@bb>?C3`@O)GRh~7%^tq8t8nj}#bN4s3 z>-nM5tv+uH4q@^CZksT&Bg1IR5BZhkwzZbQh9|;MhM4E^Nr5MTA6c4zep|e|!z+h1 z8B6&L^nn*C++}Hw&3l|_+$UWYXnLw5%STUG^%P)O`bz1*|{M+R-T>lmaWH`$x z9~-!_*saQzmkhlX!_Kp97+KuM15U~yNdmK4z(dAZWGfTdv@lwD!D%0{pGo_SwTZ}< zm%d~2BW|4X=3l(C32c#lh6pH_>PvAz8B4KV#$(nQtgw6%TUM~j+GY;Ztoi!|l;Is= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReaderFactory.class b/tests/test_data/std/jdk/internal/jimage/ImageReaderFactory.class new file mode 100644 index 0000000000000000000000000000000000000000..9519a4107c2a34a64d64ecc4062a8abca4111e42 GIT binary patch literal 2100 zcmbVOYgZdp6x}xoOb7#%KxqqYvGyTQCDMo0hEi!7AT$poJj7OUGP%G&GJ}(e%l@kh zYgsDG$7g?(%Y7#UCIw+F^I`6pd(UH^bN4xuzyAL9cK|8K7(xhZi0EiTyTFBQ<3}S= zG3?Dmp|mYcPoRC$vMp~)AUra<5UGbm1nM<`Zdd+Lw_KTb?0mga z5x6swecx+x^yF3ty3wQIf{tFqX|-M6Nm#ZgUE8Q6wymnMDH9p>T$Dyxx-*99Iqqu# z&Gp|Ixu@aOhm$jQlgeYij*A#z7KMd$KD{V#tx0L4ZkwLv*om1yNOs~fu4ow4F@&oE zUH|4shm2r4)!n)$GaJ*TnzUJ+)G5iG8R3-7HCz`MJ||xd9|&Ca@mNk`**3SNxg*P& zLi#6D?y4+e7{-S>ZsL|ebW?gMqh6B&mqvn+G;7lKt8+)kM;H<4dsZkct>+5Qm$T{O z`g|rgJ)0KjZzN*VaKoy|#Dd{%C1Wh=n2x*nn2cZ)fk#0JTJ;$8>m#1v-@V_?A;8k00VQ4UcqujxSnxTzp;gWL2P(U>96xSGpcq z(?ZIk=UVn=3n_ywMWLjQNjzb&`RSGE^|?ZhrHMC6<2Op6s^MvCT;FLF)2vg)Dn*eZ zSF29BUXisJ(wNaOtLiv+RD_oLk> zqZ1AK|J_DXPMI)!vX(9L^=e7FOGc@}op{zUjmnDQTIxO6jCflXuYfmjHi?6Z5O&CN z1gNmxFQZaCNFDVPO4fFl%BC|>82`1ttM-@!Nv&j6B5Co z>JCbSYLxgZ=QjijltWlROby`U_pfLXQr{ZxEK(!ERd8(^dkgWiZ&Kt_9jn77KJ|tI zma)RO4mEn{LK!;<`yhtK4xp{>p=)dpeeZB7j6ZShP4@0DxbX*#+t5!8!&FwT<3s=? zx%-5>Q^fYv4>Lel1KeH3*M7hutoiwTLv6xY*686SAPj^1A(UWpRVijsrWErf3cx?z=oB~r literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageReaderFactory.java b/tests/test_data/std/jdk/internal/jimage/ImageReaderFactory.java new file mode 100644 index 00000000..24ac9bfc --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/ImageReaderFactory.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jimage; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.ConcurrentHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; + +/** + * Factory to get ImageReader + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class ImageReaderFactory { + private ImageReaderFactory() {} + + private static final String JAVA_HOME = System.getProperty("java.home"); + private static final Path BOOT_MODULES_JIMAGE = + Paths.get(JAVA_HOME, "lib", "modules"); + + private static final Map readers = new ConcurrentHashMap<>(); + + /** + * Returns an {@code ImageReader} to read from the given image file + */ + public static ImageReader get(Path jimage) throws IOException { + Objects.requireNonNull(jimage); + try { + return readers.computeIfAbsent(jimage, OPENER); + } catch (UncheckedIOException io) { + throw io.getCause(); + } + } + + private static Function OPENER = new Function() { + public ImageReader apply(Path path) { + try { + return ImageReader.open(path); + } catch (IOException io) { + throw new UncheckedIOException(io); + } + } + }; + + /** + * Returns the {@code ImageReader} to read the image file in this + * run-time image. + * + * @throws UncheckedIOException if an I/O error occurs + */ + public static ImageReader getImageReader() { + try { + return get(BOOT_MODULES_JIMAGE); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/ImageStream.class b/tests/test_data/std/jdk/internal/jimage/ImageStream.class new file mode 100644 index 0000000000000000000000000000000000000000..e43fdca26aced1845f9f4bdc05f3d3305a9e5953 GIT binary patch literal 5042 zcma)AYj+dZ72RXW9%BZu6>JDH!8mDR%YZQrBw(N*0;#F7X${Y!DsK){u4GtERmumtqxY=9;Ps2Ha5?sW|lUf4XbUmJGdA3 zS!hx*3;ATqFq^WlIOm-zBy-+CCOuF{r7Yavp`ii^^co_;TawQG4jw>mBr9g9Urs%MT^bQ7Nk1Cr=)9 zuo0Vhoh?xF`#RzT`Trj1wehfpd&>puODDYP!9sp;ES@Q(6H~jVN4;!5nMvE&VqsZ% zAw85#kH-ti6b;&d&4|=v8;u%w6K$v6RKeTQCU?K#U zGjM6?&DbRnk638!=nIx%_QE|59>q85p?pR^w6L_)DFJMPK7_sE)o)p7u0}^$b)SO) zk$FMRn{?SH>2ayleh1&iW30HF%eiM+v5rn%!UJN3I$1L8;E-&r&t|5QBAwhkBBeQM zA<8D|E9Ft)h<4+>d&Od72;m;(J2Qxur=zu^i&~7gM}%* z5~Uz%oR;1cZv_XH-*EMqmPOR&fl{vXcu>fE$HCM1u83ABQD5FMGFaZ z_0fln);Y}Y5gr!YzO4EL;)(^b!W<_{XVy;L?Uky|yl-l%@ZD5$JS}>QdFRpFf|X=I zwPn&v(}s4|O(fVt^!HHS9X+|v&6>3Bw0A~NvD&ofC76Oe;ZDiXr~Js4sW;brBtGPw zu=EInkdIQE=41gfV`EdQFPJDFvH*`TpLwW$m1OFs%z0U>1{<-5LIUQFtP*=QGN378-^!h1{sOCn=U{3>@t1q%pCYjoidH z3?4FaRPxs<{^kMA&!6yWGeZ0YEQ~dUaSPT>*dOw;2Cwo{-bsKp{9cQn@|UBR;x+t? zR{}F-V0IEl)-H%etAng3j~)fmq8AzvZovgyB#glQd=^}nf?HI{=|RG6oCEH4#0=ao zX2CJZt|}=$Ot{T+!2J?$7&u8^G#g_EA%3^UZlX~VZoYwN>=Q)S+`_8AqNa$i9V!!! zAk4MB{MKK$Sn+8&Tz5HWH;mNA>T&>IyU+-8kPH`%D=)T zgZwi0i8k%ABD%wgaCADHcxGE@`^wh0u_P8M;_HXbhpek#{wwwYSA~=%Tljhm?8PGV z)5H6)g5Pb}uVTiCwuEl~HT@*@31;{k<*`L*#&7wn2ABDq_WmzlX|4aDk&JlOX;-Q>uq$}sIhig|5hX83f?hg+s$to8I3y0{x@KUuOb|}#(SE1oqC>7 zjP%SX8A0%CQL}i5K>QBB=cjbke&eyGlB8GWz?=w}tI22I6kt#EB?|p&sh&8;w8gEc#d@3yFzNA`^xzM^jvTBqYh4yZXSsqg|=^2I5)w;5X(ZHFzz!I#=^8-GxaK2J{@3L@3Z8qrD0jIKUul|xvKm59_sJcN}2en z_sAuv()p_U`B#tGU!Ga)sjMWy?#v%jb426lne`&g_!1W56@{lyrjk`@aJ-9aM6`I+ zlx9{hd5CIuEczM;lnkaIu~!2?wlBL)AbrH~jo45eF@=o8SVKioRrBy{k{3wwBFVh2 zuysizK6b<}X~ZvS#4qVayl3JKFrE-^iFN5&71G}ai#QXEsV(#-hwG(4E-ik%7QD~X zUqs=Xx4|yUU0as>To6^ueVLiOMY*p8kb`nx#|H+virg29c&1YBs{x>(+}DlV&--;N zQ?$zzzc-uWyQFxH6yFaZ&!nge`2s#P$?xOPlhdXt)>v<#R~2!7HuOiF%^&lCx)Fd5 z&amtFNM-*qJ~7bU>Y5W%99)_ErwT@o*IK^^Z_L$$2P=E<&w>5r9_IfPOz?^xp0)pP zRreS1SoQsbmHhu+b^lF&YR65dHJJ9*<5)MFHt9e3?)bSv(Vg4io3uf-f|&G{&u1&~ eWTr**OdHf+2XEoUN@o8IFe^2hg-=zhfA&8{D8hLF literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageStream.java b/tests/test_data/std/jdk/internal/jimage/ImageStream.java new file mode 100644 index 00000000..774e0e6e --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/ImageStream.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jimage; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.Objects; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class ImageStream { + private ByteBuffer buffer; + + public ImageStream() { + this(1024, ByteOrder.nativeOrder()); + } + + public ImageStream(int size) { + this(size, ByteOrder.nativeOrder()); + } + + public ImageStream(byte[] bytes) { + this(bytes, ByteOrder.nativeOrder()); + } + + public ImageStream(ByteOrder byteOrder) { + this(1024, byteOrder); + } + + public ImageStream(int size, ByteOrder byteOrder) { + buffer = ByteBuffer.allocate(size); + buffer.order(Objects.requireNonNull(byteOrder)); + } + + public ImageStream(byte[] bytes, ByteOrder byteOrder) { + buffer = ByteBuffer.wrap(Objects.requireNonNull(bytes)); + buffer.order(Objects.requireNonNull(byteOrder)); + } + + public ImageStream(ByteBuffer buffer) { + this.buffer = Objects.requireNonNull(buffer); + } + + public ImageStream align(int alignment) { + int padding = (getSize() - 1) & ((1 << alignment) - 1); + + for (int i = 0; i < padding; i++) { + put((byte)0); + } + + return this; + } + + public void ensure(int needs) { + if (needs < 0) { + throw new IndexOutOfBoundsException("Bad value: " + needs); + } + + if (needs > buffer.remaining()) { + byte[] bytes = buffer.array(); + ByteOrder byteOrder = buffer.order(); + int position = buffer.position(); + int newSize = needs <= bytes.length ? bytes.length << 1 : position + needs; + buffer = ByteBuffer.allocate(newSize); + buffer.order(byteOrder); + buffer.put(bytes, 0, position); + } + } + + public boolean hasByte() { + return buffer.remaining() != 0; + } + + public boolean hasBytes(int needs) { + return needs <= buffer.remaining(); + } + + public void skip(int n) { + if (n < 0) { + throw new IndexOutOfBoundsException("skip value = " + n); + } + + buffer.position(buffer.position() + n); + } + + public int get() { + return buffer.get() & 0xFF; + } + + public void get(byte bytes[], int offset, int size) { + buffer.get(bytes, offset, size); + } + + public int getShort() { + return buffer.getShort(); + } + + public int getInt() { + return buffer.getInt(); + } + + public long getLong() { + return buffer.getLong(); + } + + public ImageStream put(byte byt) { + ensure(1); + buffer.put(byt); + + return this; + } + + public ImageStream put(int byt) { + return put((byte)byt); + } + + public ImageStream put(byte bytes[], int offset, int size) { + ensure(size); + buffer.put(bytes, offset, size); + + return this; + } + + public ImageStream put(ImageStream stream) { + put(stream.buffer.array(), 0, stream.buffer.position()); + + return this; + } + + public ImageStream putShort(short value) { + ensure(2); + buffer.putShort(value); + + return this; + } + + public ImageStream putShort(int value) { + return putShort((short)value); + } + + public ImageStream putInt(int value) { + ensure(4); + buffer.putInt(value); + + return this; + } + + public ImageStream putLong(long value) { + ensure(8); + buffer.putLong(value); + + return this; + } + + public ByteBuffer getBuffer() { + return buffer; + } + + public int getPosition() { + return buffer.position(); + } + + public int getSize() { + return buffer.position(); + } + + public byte[] getBytes() { + return buffer.array(); + } + + public void setPosition(int offset) { + buffer.position(offset); + } + + public byte[] toArray() { + return Arrays.copyOf(buffer.array(), buffer.position()); + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/ImageStrings.class b/tests/test_data/std/jdk/internal/jimage/ImageStrings.class new file mode 100644 index 0000000000000000000000000000000000000000..eb09fb3d62e8d2a1966cd5cd7add348392d23117 GIT binary patch literal 547 zcmah`O;5r=5Pe%pi--y+;%8#K2p;GU(0C!5G-<>HCGohlOW9i5rY**QW}=DS{ZYnQ zAi)F^FK=hwdow$;`}O_y0icUx6B@%=z@NDl^2oOyqHLNZaheOSmxz?-GLEiaT#=}t z3ZoFRUK4BdK|n!gSVsk*a|4^i&?=}B)+oM%2A$5*JJ{nZ3ZE2fs1q9G06N$v gJfC~8g9c^f#x9yOy@WmNQ-$IVh$|3#NSTJCA4P3~VgLXD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageStrings.java b/tests/test_data/std/jdk/internal/jimage/ImageStrings.java new file mode 100644 index 00000000..eea62e44 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/ImageStrings.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jimage; + +/** + * @implNote This interface needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public interface ImageStrings { + String get(int offset); + + int add(final String string); + + /** + * If there's a string at {@code offset} matching in full a substring of + * {@code string} starting at {@code stringOffset}, return the length + * of that string. Otherwise returns -1. Optional operation. + */ + default int match(int offset, String string, int stringOffset) { + throw new UnsupportedOperationException(); + } + +} diff --git a/tests/test_data/std/jdk/internal/jimage/ImageStringsReader.class b/tests/test_data/std/jdk/internal/jimage/ImageStringsReader.class new file mode 100644 index 0000000000000000000000000000000000000000..e14d9e9fe76075d96fb7d1822378f8526c4f182c GIT binary patch literal 7256 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 S^OLpGj!F^vOR9F^`u_v(ra}k+ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/ImageStringsReader.java b/tests/test_data/std/jdk/internal/jimage/ImageStringsReader.java new file mode 100644 index 00000000..c4601ef3 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/ImageStringsReader.java @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jimage; + +import java.io.UTFDataFormatException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class ImageStringsReader implements ImageStrings { + public static final int HASH_MULTIPLIER = 0x01000193; + public static final int POSITIVE_MASK = 0x7FFFFFFF; + + private final BasicImageReader reader; + + ImageStringsReader(BasicImageReader reader) { + this.reader = Objects.requireNonNull(reader); + } + + @Override + public String get(int offset) { + return reader.getString(offset); + } + + @Override + public int match(int offset, String string, int stringOffset) { + return reader.match(offset, string, stringOffset); + } + + @Override + public int add(final String string) { + throw new InternalError("Can not add strings at runtime"); + } + + public static int hashCode(String s) { + return hashCode(s, HASH_MULTIPLIER); + } + + public static int hashCode(String s, int seed) { + return unmaskedHashCode(s, seed) & POSITIVE_MASK; + } + + public static int hashCode(String module, String name) { + return hashCode(module, name, HASH_MULTIPLIER); + } + + public static int hashCode(String module, String name, int seed) { + seed = (seed * HASH_MULTIPLIER) ^ ('/'); + seed = unmaskedHashCode(module, seed); + seed = (seed * HASH_MULTIPLIER) ^ ('/'); + seed = unmaskedHashCode(name, seed); + return seed & POSITIVE_MASK; + } + + public static int unmaskedHashCode(String s, int seed) { + int slen = s.length(); + byte[] buffer = null; + + for (int i = 0; i < slen; i++) { + int uch = s.charAt(i); + + if ((uch & ~0x7F) != 0) { + if (buffer == null) { + buffer = new byte[8]; + } + int mask = ~0x3F; + int n = 0; + + do { + buffer[n++] = (byte)(0x80 | (uch & 0x3F)); + uch >>= 6; + mask >>= 1; + } while ((uch & mask) != 0); + + buffer[n] = (byte)((mask << 1) | uch); + + do { + seed = (seed * HASH_MULTIPLIER) ^ (buffer[n--] & 0xFF); + } while (0 <= n); + } else if (uch == 0) { + seed = (seed * HASH_MULTIPLIER) ^ (0xC0); + seed = (seed * HASH_MULTIPLIER) ^ (0x80); + } else { + seed = (seed * HASH_MULTIPLIER) ^ (uch); + } + } + return seed; + } + + static int charsFromMUTF8Length(byte[] bytes, int offset, int count) { + int length = 0; + + for (int i = offset; i < offset + count; i++) { + byte ch = bytes[i]; + + if (ch == 0) { + break; + } + + if ((ch & 0xC0) != 0x80) { + length++; + } + } + + return length; + } + + static void charsFromMUTF8(char[] chars, byte[] bytes, int offset, int count) throws UTFDataFormatException { + int j = 0; + + for (int i = offset; i < offset + count; i++) { + byte ch = bytes[i]; + + if (ch == 0) { + break; + } + + boolean is_unicode = (ch & 0x80) != 0; + int uch = ch & 0x7F; + + if (is_unicode) { + int mask = 0x40; + + while ((uch & mask) != 0) { + ch = bytes[++i]; + + if ((ch & 0xC0) != 0x80) { + throw new UTFDataFormatException("bad continuation 0x" + Integer.toHexString(ch)); + } + + uch = ((uch & ~mask) << 6) | (ch & 0x3F); + mask <<= 6 - 1; + } + + if ((uch & 0xFFFF) != uch) { + throw new UTFDataFormatException("character out of range \\u" + Integer.toHexString(uch)); + } + } + + chars[j++] = (char)uch; + } + } + + public static String stringFromMUTF8(byte[] bytes, int offset, int count) { + int length = charsFromMUTF8Length(bytes, offset, count); + char[] chars = new char[length]; + + try { + charsFromMUTF8(chars, bytes, offset, count); + } catch (UTFDataFormatException ex) { + throw new InternalError("Attempt to convert non modified UTF-8 byte sequence", ex); + } + + return new String(chars); + } + + public static String stringFromMUTF8(byte[] bytes) { + return stringFromMUTF8(bytes, 0, bytes.length); + } + + /** + * Calculates the number of characters in the String present at the + * specified offset. As an optimization, the length returned will + * be positive if the characters are all ASCII, and negative otherwise. + */ + private static int charsFromByteBufferLength(ByteBuffer buffer, int offset) { + int length = 0; + + int limit = buffer.limit(); + boolean asciiOnly = true; + while (offset < limit) { + byte ch = buffer.get(offset++); + + if (ch < 0) { + asciiOnly = false; + } else if (ch == 0) { + return asciiOnly ? length : -length; + } + + if ((ch & 0xC0) != 0x80) { + length++; + } + } + throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); + } + + private static void charsFromByteBuffer(char[] chars, ByteBuffer buffer, int offset) { + int j = 0; + + int limit = buffer.limit(); + while (offset < limit) { + byte ch = buffer.get(offset++); + + if (ch == 0) { + return; + } + + boolean is_unicode = (ch & 0x80) != 0; + int uch = ch & 0x7F; + + if (is_unicode) { + int mask = 0x40; + + while ((uch & mask) != 0) { + ch = buffer.get(offset++); + + if ((ch & 0xC0) != 0x80) { + throw new InternalError("Bad continuation in " + + "modified UTF-8 byte sequence: " + ch); + } + + uch = ((uch & ~mask) << 6) | (ch & 0x3F); + mask <<= 6 - 1; + } + } + + if ((uch & 0xFFFF) != uch) { + throw new InternalError("UTF-32 char in modified UTF-8 " + + "byte sequence: " + uch); + } + + chars[j++] = (char)uch; + } + + throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); + } + + public static String stringFromByteBuffer(ByteBuffer buffer) { + return stringFromByteBuffer(buffer, 0); + } + + /* package-private */ + static String stringFromByteBuffer(ByteBuffer buffer, int offset) { + int length = charsFromByteBufferLength(buffer, offset); + if (length > 0) { + byte[] asciiBytes = new byte[length]; + // Ideally we could use buffer.get(offset, asciiBytes, 0, length) + // here, but that was introduced in JDK 13 + for (int i = 0; i < length; i++) { + asciiBytes[i] = buffer.get(offset++); + } + return new String(asciiBytes, StandardCharsets.US_ASCII); + } + char[] chars = new char[-length]; + charsFromByteBuffer(chars, buffer, offset); + return new String(chars); + } + + /* package-private */ + static int stringFromByteBufferMatches(ByteBuffer buffer, int offset, String string, int stringOffset) { + // ASCII fast-path + int limit = buffer.limit(); + int current = offset; + int slen = string.length(); + while (current < limit) { + byte ch = buffer.get(current); + if (ch <= 0) { + if (ch == 0) { + // Match + return current - offset; + } + // non-ASCII byte, run slow-path from current offset + break; + } + if (slen <= stringOffset || string.charAt(stringOffset) != (char)ch) { + // No match + return -1; + } + stringOffset++; + current++; + } + // invariant: remainder of the string starting at current is non-ASCII, + // so return value from charsFromByteBufferLength will be negative + int length = -charsFromByteBufferLength(buffer, current); + char[] chars = new char[length]; + charsFromByteBuffer(chars, buffer, current); + for (int i = 0; i < length; i++) { + if (string.charAt(stringOffset++) != chars[i]) { + return -1; + } + } + return current - offset + length; + } + + static int mutf8FromStringLength(String s) { + int length = 0; + int slen = s.length(); + + for (int i = 0; i < slen; i++) { + char ch = s.charAt(i); + int uch = ch & 0xFFFF; + + if ((uch & ~0x7F) != 0) { + int mask = ~0x3F; + int n = 0; + + do { + n++; + uch >>= 6; + mask >>= 1; + } while ((uch & mask) != 0); + + length += n + 1; + } else if (uch == 0) { + length += 2; + } else { + length++; + } + } + + return length; + } + + static void mutf8FromString(byte[] bytes, int offset, String s) { + int j = offset; + byte[] buffer = null; + int slen = s.length(); + + for (int i = 0; i < slen; i++) { + char ch = s.charAt(i); + int uch = ch & 0xFFFF; + + if ((uch & ~0x7F) != 0) { + if (buffer == null) { + buffer = new byte[8]; + } + int mask = ~0x3F; + int n = 0; + + do { + buffer[n++] = (byte)(0x80 | (uch & 0x3F)); + uch >>= 6; + mask >>= 1; + } while ((uch & mask) != 0); + + buffer[n] = (byte)((mask << 1) | uch); + + do { + bytes[j++] = buffer[n--]; + } while (0 <= n); + } else if (uch == 0) { + bytes[j++] = (byte)0xC0; + bytes[j++] = (byte)0x80; + } else { + bytes[j++] = (byte)uch; + } + } + } + + public static byte[] mutf8FromString(String string) { + int length = mutf8FromStringLength(string); + byte[] bytes = new byte[length]; + mutf8FromString(bytes, 0, string); + + return bytes; + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/NativeImageBuffer$1.class b/tests/test_data/std/jdk/internal/jimage/NativeImageBuffer$1.class new file mode 100644 index 0000000000000000000000000000000000000000..94116fcfa0eb4d11d7377ef7d2bdfc823d1f7584 GIT binary patch literal 840 zcma)4U2oGc6g_UcrON^2(-3FJ)GCli;<1Ocb}dA*r`Zsn0Kz$d!2?EkzW?9uuWM(7B1k zdn%A&>%V5bbgiID->E3o8Fl@mu;)7V@Qh*qTJ`!6p!W<3;pldSP)#Tzk4Beg{v<*RV@=uRwOO MPu?ei26_7a0W#IQP5=M^ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/NativeImageBuffer.class b/tests/test_data/std/jdk/internal/jimage/NativeImageBuffer.class new file mode 100644 index 0000000000000000000000000000000000000000..887a627056e9bd8a5c1e99bb357308890f2baa8a GIT binary patch literal 669 zcma)4(M}XG6g_u$Vb)<31VsfUJV@B}feDFkOH5!B6Ov^mfna>>&R)i@rDHnXP53OH zFq-%Qew6WccLa9AM`$FN!#rVWq$Vmg%I4{Z!H6?Y znBUV@`*(zTt9=%sN!T6@zogoFc2=2mq%Ty?XkkUhl?;P>->IB*Mc4 zkFZGCm|jqFHg?)yru$jOW!WvPcZD(R2+6QGc6y=>=R735ZT0>=al5&nd0p5}dzNsg z=1zpigspp3NoaJ7ArlsR+H!wryP}-HW{=dUEzN zZ;sSgLc7v4E%(GbZS%hhtS-`nOJCV1N1J<@sl1O*im}W1z1Tun{m<*2;1OY=&!s=& zph0R(4y|R^HL5JR#3q*HsY9zvm&b-E6qL$LA@b%LbS0pM6&b@eu!ScwCbI-Q#VSBe zJi~K|Hu2(yq*YNTKM;Mo#)EH&KL#$Ea)mzzY|BU3k;~Tv*RYP4GB+e6!Ye`X6bS(S E06K}HWdHyG literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/NativeImageBuffer.java b/tests/test_data/std/jdk/internal/jimage/NativeImageBuffer.java new file mode 100644 index 00000000..8d228c05 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/NativeImageBuffer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage; + +import java.nio.ByteBuffer; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +@SuppressWarnings("removal") +class NativeImageBuffer { + static { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + System.loadLibrary("jimage"); + return null; + } + }); + } + + static native ByteBuffer getNativeMap(String imagePath); +} diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/CompressIndexes.class b/tests/test_data/std/jdk/internal/jimage/decompressor/CompressIndexes.class new file mode 100644 index 0000000000000000000000000000000000000000..97399040f92acd8b1b23cd8ee1a19c14fa24b1b0 GIT binary patch literal 2550 zcmb7G&sP&y7`>BBG9iQzkf4Mh_^XB>1O>4cNaaV6v_Y()SbsAlLl_JbPBKySSP$*7 ze}GHR>57e;p3`flun*u$J%Tro1X0{4h%nRZ-(Gtxb;!KdJW+*G#Bd~B>()E}hG zlI=x3G%uWJ^dW#I1>U`=#E9G&Pj)B0IDi%nK_6OiP(jmPup}wxjG_YVo}Moovr7tE zBgyX6TRVp9(T0$Qb|1p%*bzZ;5j4nB&t??_BQ-}WnGAPd7yLSX=)w^NjXA@fHuS7f zOc_?rURIz+#s$S=IIiJ@5AWfmf`gKPS%^*Qww|=s%68f=8v3dN4_{fKyA)q%oDc8gyn+_1yt-%&Cl13Vxc4m z$g&J$M8l{LaeTNVsr1#1E`)KenwA1rB+0!LZen)k@|8q7otV5cl^VOKK;de`M8PWA zx@F6howVr&vz<DnbiOF`Y?0bbLCXNaG$!+nN^$Znuz;+d;3J46q6p7$}_Oz z#yB;}3$q0(E~`D+`X=QEYdf@0?Atq1a%%vri!E>e%~ zcd-3098DOMzzV|E%kZ|1hebgh8Q#0L3Y&LqVdl&7o=^rRu9nP)Wa4H!Dd!39-SuZl z1Es1o2jV1WcfauDA`K)3&N#f&j!3L~`a z+?s0J>J!%mM|iW`!d3|30>+?VoHGYIWC)Wr^91KpHS>$`a4#DkpVK@M<699{jJ|;D zdkK-`(=8WI;UkWHl@0h9DbDIJgG&q~4u8w=D&Mh}sK53C4JqenIQnW6UD5Cs{PCWS zEj0g#Lk?UGN5cbKIJ_|WeEavF?|4Lo2osVyoFS({w$8KcjYG_AkPYL!3?1dZR<_q! zX5b{}W4O$bLxjX9xWcywCy~Y+DSpbCpjug(=jf_jar_OhhBoCjj^Z<}IB<hL>+ufpwF%pgH{wrJ<@xrX9pCVbQ)Y3L zF~J7nVkNw+Ln9J6gp25)ND+?vD4h^;kUN^$yG0H{wtn2iExujo!EM|jV=r6pg3Pdy zI_NTMk;MTxwt3X0;h4fd;5FK@$PX$HWq6DomLpM<38p0q>JK$xT{^hJ+hU` z&el}c4}-xW<#NH{yC8V*hoTBNRRwGcZK3BG>O-D~?#IN`_G6}NFq_`QY?PS%g{WdC zs+fTarZ*Jm6p*3)kXLIU18+k530Wt8Z>x~MQVVe*&PCe?MrpspaXunLsygHfx;i$| z8B|$EQPXI9(6uliYdNGoaj}?x1l7IBm1^E3+-(L}U^O$Wrh!f@QRED(Xi8RbhHIv$ zL^Xwf&hfi&q!{J6#(seTSyu;f`ea@CKLQ;g>Z(e)TPk&RYgiU_m4!XR-6mG5Y5m10 z0{vF#Yc#w>>{|2b7Z~^@&_(5jvLo&81vTq_s4i$*_+T{rv*(g?$F{veH53l2Sv4E* zEI)iYSFvqa+eCA(^Ct7(2z%Byo^Cvy>lGKWV&y(wHozji0{kfP^4-I6JRs>uIE~Lq z{1J`)1v|l)yg*+`A%v}aYHWRrLW~iml{@cBA&&DpS8N^OCD$pFQ>Gt;>fh!`7gHA! ONM9dd=6N1>VD(>o`T2nW literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/CompressIndexes.java b/tests/test_data/std/jdk/internal/jimage/decompressor/CompressIndexes.java new file mode 100644 index 00000000..709b82a8 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/decompressor/CompressIndexes.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.io.DataInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * + * Index compressor. Use the minimal amount of bytes required to store + * an integer. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class CompressIndexes { + private static final int COMPRESSED_FLAG = 1 << (Byte.SIZE - 1); + private static final int HEADER_WIDTH = 3; + private static final int HEADER_SHIFT = Byte.SIZE - HEADER_WIDTH; + + public static List decompressFlow(byte[] values) { + List lst = new ArrayList<>(); + + for (int i = 0; i < values.length; i += getHeaderLength(values[i])) { + int decompressed = decompress(values, i); + lst.add(decompressed); + } + + return lst; + } + + public static int readInt(DataInputStream cr) throws IOException { + // Get header byte. + byte header = cr.readByte(); + // Determine size. + int size = getHeaderLength(header); + // Prepare result. + int result = getHeaderValue(header); + + // For each value byte + for (int i = 1; i < size; i++) { + // Merge byte value. + result <<= Byte.SIZE; + result |= cr.readByte() & 0xFF; + } + + return result; + } + + private static boolean isCompressed(byte b) { + return (b & COMPRESSED_FLAG) != 0; + } + + private static int getHeaderLength(byte b) { + return isCompressed(b) ? (b >> HEADER_SHIFT) & 3 : Integer.BYTES; + } + + private static int getHeaderValue(byte b) { + return isCompressed(b) ? b & (1 << HEADER_SHIFT) - 1 : b; + } + + public static int decompress(byte[] value, int offset) { + // Get header byte. + byte header = value[offset]; + // Determine size. + int size = getHeaderLength(header); + // Prepare result. + int result = getHeaderValue(header); + + // For each value byte + for (int i = 1; i < size; i++) { + // Merge byte value. + result <<= Byte.SIZE; + result |= value[offset + i] & 0xFF; + } + + return result; + } + + public static byte[] compress(int value) { + // Only positive values are supported. + if (value < 0) { + throw new IllegalArgumentException("value < 0"); + } + + // Determine number of significant digits. + int width = 32 - Integer.numberOfLeadingZeros(value); + // Determine number of byte to represent. Allow for header if + // compressed. + int size = Math.min(((width + HEADER_WIDTH - 1) >> 3) + 1, Integer.BYTES); + + // Allocate result buffer. + byte[] result = new byte[size]; + + // Insert significant bytes in result. + for (int i = 0; i < size; i++) { + result[i] = (byte)(value >> ((size - i - 1) * Byte.SIZE)); + } + + // If compressed, mark and insert size. + if (size < Integer.BYTES) { + result[0] |= (byte)(COMPRESSED_FLAG | (size << HEADER_SHIFT)); + } + + return result; + } + +} diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/CompressedResourceHeader.class b/tests/test_data/std/jdk/internal/jimage/decompressor/CompressedResourceHeader.class new file mode 100644 index 0000000000000000000000000000000000000000..5bfcd50745c78f44e01d203faa391d66bb059046 GIT binary patch literal 2656 zcmbVOTT>Hf7=FH-iHpV%D1ub!!6qR!TCG;GD1m@UbFc}5f-PN=1s9VIZW5K=^=I^| z9dCNm&e)lPOgrNb@K^MAI8*KO?QS&C*b5nEzr%Za-s6|&FaLZ7U64t=VXs745pFRy9-LaED8)mi6y70g;v34=Xq#RfpQf zeg;WAsvwL3fuU|21+}gf*VmgG!HSGz8&oia_XL7^b3rrfI>C{&9KPCzpa~Epz=r|@mW-h{lBw;M zmTIrBOOFF;t=6chE&4hf%{W^2GfhfGA1gS8PXxRT(~8uDgQ3G(l-C^;olD!ur2F~H z7cZoexPl1@#kbXNWsH`*`c%PbBnAAu$~BA)2_yS<7-toHhI7n2*(Gc0?W~_GxPXg9 zteU2}E#Qg9R#HJ`;*x^Pn54-Ktz~DKRg{rnzEm)Ut7Ls>s#^l1(Unx@e_}GNAcYya zLq&8)n#kCS(hBA z56`AMq+)5cFr80#iADs%neysFx|GiprgL4C<3u^rsIqpB1o~7S<#cZckWT zr6)McrgE|N4q*gE46p`o@Z`eRoNcA9bCmRQ*Li{Gn_cHco|n4Lw|KtYbzbIqrR#i$ zgO_uew!(7sTPsJgwQ|;S4G;_4ir;T|`T=hExsJx4Lc~w(z#kvqL4SPEyMs`C(6@ug z?k)ID8V2 zkMtp|IdGC(CBHZR2O__6V;h!C;P{Y6Y=vIOh(HCCJ%mFCg|j_{tI%ExyIx!F|LuU~ zLQmoKp2Gfv!ljVR$JtwukrgiHTi&w3G-(cM)4kFc|(_B&VA%K!Otsc_05%wSAw;| z$Hnn>l&k!6hsI=zgoV(~Zk6`P4?d-&opyyD3O#rJR}pNLy= zqSM!=#=_B`BrU;M&0h2*LW*2{iBN>p3xP!F_%5zr==%$S+e4lq-(X;{&-1erw5Q0u ziPvQoHt4aJ-UjJ!nEpm!@YhI#KO43X#eF`|CeEORi)gbM9$+4i7^iJ3ekJx8aa&R2 zhP(UZ7L?C9@r$x~nrs6%<Rcanjay9;pvGftjy5A9BR&sLOe z!c5Ogf##8QE3^>Tu^lZMb{N=+T~$7m94!cJb>-cn<;s*}r;53pz`>4^l0ZE1&NoFm z+OS(g)W9C>6*yhf@kBWWnHiG>r|72TurxE$C4Md+hFoW{vLP^DcEYxt*uVo%j=DS< zpBbPdwE%jX9fHw@cMZIUeFD*}^nysH%tbjmH&>9%9aEOnu^;bi_`tvcd{_a_M4i&geLXQ>t1{E3E-Cm34Mb>WHIX!x;l-aZcderotJMd8c4` zj{88M&6f8z!cE}HMh?{G)kew)#s!-4!SLBpif5o`<%p(^^QddUMS+$IDiuKb+STTe zflC->w=na0X=hme8@smFUaHiS(C2a4z!i)LGs?J?l)lue>y7Y#oxki5$;+KH0~$W9aMVxB8b=ioKT|~fTwr$)fQfn6xo6Ji zWV~}ypmE&F+NM`@>G(_u6u)z`r}hUhs#N;soR6Q43xpF+#&6t~EmOtCS?NwFFG!gY zCvD~?P1jQIWntKxx7f2|wG9Sa1H<<}0{R+?!e zZHHAt2y@c5rJKl^g@WYy=8~4RvA_}2#48WL6smg)e@(uHFw1{piwM^=B?GAA6R@po z1)}R2wCNQz{sH}W|8$1yR-OQ22&0#JjzIFwD1C!DWcemA4~u%KPy9m78fDAfPqA&P zM=iZ->E_zn7mkMi!4F+ephv^Yc;_kFS8*_eztP=SAFY3ZnI2!hirx_VBGJeTY@7IYhbk6R|VUIq8~l0j)%BFK?Cm zagjI=;sl0pnsXt6Vg4mC#s)uu5lrJMZX<<*!mi*3`;t>M9;m)J3(;nquX pluginsCache = new HashMap<>(); + + public Decompressor() { + } + + /** + * Decompress a resource. + * @param order Byte order. + * @param provider Strings provider + * @param content The resource content to uncompress. + * @return A fully uncompressed resource. + * @throws IOException + */ + public byte[] decompressResource(ByteOrder order, StringsProvider provider, + byte[] content) throws IOException { + Objects.requireNonNull(order); + Objects.requireNonNull(provider); + Objects.requireNonNull(content); + CompressedResourceHeader header; + do { + header = CompressedResourceHeader.readFromResource(order, content); + if (header != null) { + ResourceDecompressor decompressor = + pluginsCache.get(header.getDecompressorNameOffset()); + if (decompressor == null) { + String pluginName = + provider.getString(header.getDecompressorNameOffset()); + if (pluginName == null) { + throw new IOException("Plugin name not found"); + } + decompressor = ResourceDecompressorRepository. + newResourceDecompressor(pluginName); + if (decompressor == null) { + throw new IOException("Plugin not found: " + pluginName); + } + + pluginsCache.put(header.getDecompressorNameOffset(), decompressor); + } + try { + content = decompressor.decompress(provider, content, + CompressedResourceHeader.getSize(), header.getUncompressedSize()); + } catch (Exception ex) { + throw new IOException(ex); + } + } + } while (header != null); + return content; + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressor$StringsProvider.class b/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressor$StringsProvider.class new file mode 100644 index 0000000000000000000000000000000000000000..49504acdac22d6f7e623a8d780c28ef826e8d5b9 GIT binary patch literal 341 zcmbVIu}%U(5Pbu9#~mOv6!aF*xD}NpVk9AAhZ<{}WXio;n-7*AKT^|$0q-w^WcY5kpPm@xV4+VydY z(0yPD_fA5J9%243|`ASmYbS))pqXXIng)kgvXh zE}DdHsk=ma zl9$k#YRzVxDQnph{2zrJ0%1>n324Zm_u-%#xQhe9TY@%a_e9aD6gb4uC+6c=PM)y7 ItP`j82BhhcV*mgE literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressor.java b/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressor.java new file mode 100644 index 00000000..3e4e32d2 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressor.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +/** + * + * JLink Image Decompressor. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public interface ResourceDecompressor { + + public interface StringsProvider { + public String getString(int offset); + } + /** + * Decompressor unique name. + * @return The decompressor name. + */ + public String getName(); + + /** + * Decompress a resource. + * @param strings The String provider + * @param content The resource content + * @param offset Resource content offset + * @param originalSize Uncompressed size + * @return Uncompressed resource + * @throws Exception + */ + public byte[] decompress(StringsProvider strings, byte[] content, int offset, + long originalSize) throws Exception; +} diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.class b/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.class new file mode 100644 index 0000000000000000000000000000000000000000..7638bde200e0ea121b653d7ef3b14cda91c2fc9a GIT binary patch literal 693 zcmbtR%TB^T6g>llO09r`Zx_1bVeG<{k+4BYOb8@m*bilbgYA^G#m8T1qA_vd2l!FO z+d`Ct#DzAQ&fI&?J#*)rkI%Pv01fOJNFb?0Gm%1?AwS}`+;X@YTAlt#*dar@CY229 z49QZtm%$P;It&xbFd1s2!Hp$VD15~oYb0Gh6xKl4o;&tM5O}_IDFSce+v034+2nTU z`40@5;;vv=YyI5X4SlJGrwr?*#ca7pJq>R_J-L=tqCIi@!oT8uCuZ?%?)11Xqj;9o z!fP2Y)LZ`O?&jafa1sIkA`e|>oZs7G97<0GI<^@Ku|U$Z zE;`>8LUm(ln=*R-{x3=&MeW)Fd6yv9N$|)$Iwhfz?JJbYQq-hsR5vQGV3q0%^e2iE z$k9JbSfE1qDl#}ko}!H@8mq(?eMZd6h^>I)jMJi>Q7u(@hW<#0DP1~F9>+B16fmXH T$ao@V*d(k*`xdR8xNr9h)%K`h literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java b/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java new file mode 100644 index 00000000..7c6e3265 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.io.IOException; + +/** + * + * JLink Resource Decompressor factory + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public abstract class ResourceDecompressorFactory { + private final String name; + + protected ResourceDecompressorFactory(String name) { + this.name = name; + } + + /** + * The Factory name. + * @return The name. + */ + public String getName() { + return name; + } + + /** + * To build a new decompressor. + * @return A new decompressor. + * @throws IOException + */ + public abstract ResourceDecompressor newDecompressor() throws IOException; + +} + diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.class b/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.class new file mode 100644 index 0000000000000000000000000000000000000000..6cff9f9a45a932555a0dbdd3443ce8ffcb15a077 GIT binary patch literal 1735 zcmbtUX>$@m5Pbva0s)C663@h22EUYFRw~l}D9Vsw_YG z!QW(AzFCm0N>!@x%l1sqZ1?LoulxJY&tCwPQH~>ouz^Sdo3L46vS~fH%$8+0%=;@% zS@Q%o7nQBNl0Z0{TaF=$n1Of#6G#YLZq}cf%J!sdTP?Gx+EzoFby;)T9ana{j%zN- zuG4dC@_N9zBs)%5d5-%^AokR%aiwHeAXV|R_dL}y?^>P01hyb$U^0QNNDCzYI3=Ej zB)r4f{$Byih1|a`1JeS{k|suSd3NYg=tE+w)gt-5p{xXyD$D{z(A$6;)csE}JW zaFk&-4AN(>x@u_>M?%gcOet1X!?wJhOZu%oiNB>-3~)Mli~qx3DhNc%PMxVz6=lnN zz4nT9A6hFddeRlAX0?_HSMLYTh_|ZPBUi`EyWVn4JVW)4>Pvw;K{*Wy9aq;Z(DtRA z{+B$S>An{zjaSZZ32-P>J*)PN${o-YzwxprJDzgvt^p3MDPQ8sF>l`=p0Lk!c7Ogv zi?!BZzQwElq*_$^4GxSVXr0C5IxJ37<{{2eft`9D(jMn71QQW{IZ)|2LCEu%1M6p>;;bU@-dv^N(bO2UOz({!&#i;4ISVqt-ibcEsXh3NQUqgQl z?X`H#voPTRX+{G|Na8Z5<`rac&5xbw|Bv&y!1E;GUc@ElD{vQu_<@YUIaK5>Lhk~x zv3a@D*%ugFBTMP*@3Dgj_Jr~1??M(iu5ShkNfE*&Km3&;6J;L;Ft>(%k3ZnRI~Z#? j$kpMGII@O3SI4;0p+%q`lXy;Hn#|0S8+HNDL%8+}6|~%d literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java b/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java new file mode 100644 index 00000000..859f7a03 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * + * JLink Decompressors. All decompressors must be registered in the static + * initializer of this class. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public final class ResourceDecompressorRepository { + + private ResourceDecompressorRepository() { + } + + private static final Map factories = new HashMap<>(); + + static { + registerReaderProvider(new ZipDecompressorFactory()); + registerReaderProvider(new StringSharingDecompressorFactory()); + } + + /** + * Build a new decompressor for the passed name. + * @param name The plugin name to build. + * @return A decompressor or null if not found + * @throws IOException + */ + public static ResourceDecompressor newResourceDecompressor(String name) throws IOException { + + ResourceDecompressorFactory fact = factories.get(name); + if (fact != null) { + return fact.newDecompressor(); + } + return null; + } + + private static void registerReaderProvider(ResourceDecompressorFactory factory) { + factories.put(factory.getName(), factory); + } + + +} diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser$ParseResult.class b/tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser$ParseResult.class new file mode 100644 index 0000000000000000000000000000000000000000..96cf535358ca1192247127cf7f57600100583156 GIT binary patch literal 672 zcmbtST}vB56g`vOWX)zZR;~6Utu6Rq13G;-1ZqH9Sklr+z{g24-A>%hhM8HxpXEal zTIdhxj}q^0f-U+aeYtne{g`vlo%wU~^EZGV-h`;Y3*bknqQB{UH}Z=xR+_!ieU&y(iMZ-6=hD(l@n61z>WHC!*T}GUFWp(- zQp3O*rIVv>(ef=bGvS<^Fl;<5Veos|L^3pErDZ>#jifmhqm&{WaW)p|P#9InYha ossK2A9MF9n+k~P;4|ed3kca1FD|msIrElRi`H*TFXki!iTYDF*0RR91 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser.class b/tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser.class new file mode 100644 index 0000000000000000000000000000000000000000..a6e16f622d9dfcf0a8f4614d684a2b4aa09c1699 GIT binary patch literal 2638 zcmbtVTW?fV6#n+y&Y9`7)WVbwpp=Vt+A<7sDKJwCbO0Hg4yCPBT5hK^r^9LImNRDv zpg}|M#UJ1UFD5+LL`~GFCD?@cgoz1>Ccg7#j4|=a5DBq<`^>boOpPI=-DmH!&suA* z^?l#k^W#6?-2)KEv=0tA6}bFx!z0i1)6NTie=;?Nu$iHomrjFKq#>^M75-t zEMmPM8}PD#Vw8{OOBPdQd1Eq0-WQ>g96Lj0_vuf@W1reNZ#Yy1CV! zhV*hJXZg?}u~X6Q$2NoseoiY}i9$xda&l5uzd{8G6%heQuh;$9iCqHTa%G}iqpvlT zSO!_O0vobD(!8e*)S88tx$N^}KcWI|>uO0aQy$gx7iqCs>-FORq@1)2NnVy?ji1gj z8SIcBhtbdMCW~fXvn-v~E%gN{I3lp)c~PV?pEB#q8wzf+5)_1!*=R_Z;Iib`~o++&WU#;-1&*auy7bMn4|HffU zOHU7ICEHEG2(wufuE2@^FM7qmD+1A0l8vw!{fJ&pn?}hhngT;BoWmF|&|<7jovh?? zDJ@TJsJxi$_L2bSv}@OhEs5om%_`9MqDQ%8;|TbMixo4iA2XyL*DO|Ay#Th$tB$Hl z>1As`m%`=A{zRdmn{l>(Stio3+%rrF+9&ta0Fbs8J=T%wpXwGzVRB^-9YoK1OdkM9}rr zs^K#I7mhJlmxcGKpDyqq}8)hV9APQ&~3 z9OSIv9SmcH2sOjRTl9Bfl$KRArTyEqKf|34xaS$xqd-*<5DLZ=G!mXC{AqZCc5eTT zw#PhhoW>5EB?aejp3bDek>LRi+8dRd*mhDkrKy`eKwxHq+sI%A+^#zrH>bf|K-BEA% zH`p8W-9^lSQG4yJt`|fgQZtB#e?V(ZE~$kNGuRTY>SP8%8ZWVjm*UY@wiR+Nu9-K!~TJ$_zP)FVvTic;|>^U09pM*ME;$ia$!gU(8v ztm`3_Clw|2qro?i^)>x;ROPdvpnYPVz0hDwYsn{yOqGNGz&zGMsk5L`TfI$>;gQO7 X5)`SuEP;`_5frV#mCs(qF$M3xNlj!+ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser.java b/tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser.java new file mode 100644 index 00000000..9b65995f --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/decompressor/SignatureParser.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * A descriptor parser used to extract java type strings from + * UTF_8 descriptors. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class SignatureParser { + + public static class ParseResult { + + public final List types = new ArrayList<>(); + public String formatted; + private ParseResult() {} + } + + private SignatureParser() {} + + public static String reconstruct(String formatted, List arguments) { + int arg_index = 0; + char[] chars = formatted.toCharArray(); + StringBuilder out = new StringBuilder(); + + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + out.append(c); + switch (c) { + case 'L': { + String pkg = arguments.get(arg_index); + if(!pkg.isEmpty()) { + out.append(pkg).append("/"); + } + arg_index+=1; + out.append(arguments.get(arg_index)); + arg_index+=1; + break; + } + default: { + break; + } + } + } + return out.toString(); + } + + public static ParseResult parseSignatureDescriptor(String str) { + ParseResult res = new ParseResult(); + char[] chars = str.toCharArray(); + StringBuilder type = null; + StringBuilder formatted = new StringBuilder(); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + switch (c) { + case ';': + case ':': + case '<': { + if(type != null) { + String fullName = type.toString(); + int endIndex = fullName.lastIndexOf("/"); + String clazz = fullName; + String pkg = ""; + if(endIndex != -1) { + pkg = fullName.substring(0, endIndex); + clazz = fullName.substring(endIndex+1); + } + res.types.add(pkg); + res.types.add(clazz); + } + formatted.append(c); + + type = null; + break; + } + case 'L': { + if(type == null) { + type = new StringBuilder(); + formatted.append(c); + } else { + type.append(c); + } + break; + } + default: { + if(type == null) { + formatted.append(c); + } else { + type.append(c); + } + break; + } + } + } + res.formatted = formatted.toString(); + return res; + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressor.class b/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressor.class new file mode 100644 index 0000000000000000000000000000000000000000..d5858899ecc6518cd0629c75ac021b9e554da76f GIT binary patch literal 6780 zcmb_g3wRt?b^h-@G_$)Sc`bP@k1aov*r2CnNV1`llhk@8>&TL^WIKw}I-}i@wDxLO z?8AN%KW)y-Wi5vPy6nqB~Vdw~Hs4);mgfq!Z zE^8~SYHk@kWF4_OGgfx8b9nraoh){1s8wimhSRyuKC5UYvNNS3H?pm14J#CyDw93O ziuR6t-a6*t2%`=w4b-DSp=NtJn=W3Zpfw-pNhDhKg<&8jldBchG`o9q6VLMQmVFx5 zD6BtckKt0Wszw-%SSxbYDFm7+Si^cstgI2Gm$Eluqp)vMFc-J=vT$Ef?qUO%V6#Gq zhfNKXGMQtv7L}LTCcMGG8)Y_lG@mZo!rx+`6>SPDg@13hkenNFIg_$v@b~t{QKG`j!JdVP=aP3>?6XL>Fz+pH1dc zc1mIO`P?r2SK?O<9K=lub&F|aAd@>Pup-P|)l0>6rgJb|C=yoVNNPwKurZ;~;6zxK zAuFo%lqM#`9lDjt!R1mQPX{bXDbgAMyqYAP}^IHDT{a(OMnLB$Sye z)>tMZf+IMp;bsHJa0~6|oTO?o`i+h_2bR^``fJP;&I%_Y8A0}>oe$$y{JMd62t0JA z`+ZiXM0DJacWU?z19#wEOcRT%D$v)`h5qT8B2yGo%?%pfQ_0(&XzwYdGc;}(@5XV- zfTQyEJ_Emn-)4TcW@hZH#{!;(-RDMCSys1>-&IhZBIyGL?v(7L7jv#wV&UHt3*W7< z_560N!fcsg1#2HP@cRPxpe1ERM(#22VaF~rxk9>_&ShorUIQP+$GELj1UK8RX&!kk zpO53?22SFB+KK!M>)dLz6kt_^)Zr6isLc|4$HVv}KBeK)1|Gs^Do${m?bJPH!bmbV zb8L8G4=X6~ue+ip)W-2y1ApK|eBPe6SP8R}GWw{2$D9Kttr;tsE;^_DoGAEtsZOtD z9Sw5|J1&^ITrZrb9~iKb#a#ZFjwhHaq=6vak(>$RG>&UHQ#qT102i&|$^`>oz!#ac zvbp@Ul}X>iGY-+MuS*7HPrxLm;SUuq|9?qjLh8SMw13agjzP9MeFsNI_auf`XH-I= zwpVh#RSqUU+p9)}4d-D$*w;VOyC<=Gba;<&nX+_vXk>K9(CERv#fi7bprU!IgXN%= zaX;g~I?gm|6=gKw6)~90PRd|VVMUd-FIQszmti(}ixPS>R-quHnwQyisSN8(9#t6w zX*-k3+Y>SoVn(e_?6QkfxynqKaIemY=J^RLX)j@kFxggFhOB9OM>aKjY{pT~U?!{1 zxvQ?VvME=0wt@}ICM)ZrtU=YOMD|GTu-$hoYfYz&qyjRXo^U6n*wR$hpRIzuXd#w@y{HlDZ@ztx6?q1 z^o(^2i>FHRpT@0`=2o`#CHWId*@a}8Ga&CYQdwG`L)AGhvkM0^c6PGJUMV=vc0}4z zPNb9a7IjZqt;=$@@p8WsbLW=igAZR@JKB+X@$@vkXvPjc8xG zjJRKlKL%16gIkuVwB4n>jX?KR)YH$qor2+NP?60Gi6}&m@|0|6i?(=2OP2C^=S_`E zlD3b!WsEZn7>Q*9x;T}lLAcw6k~a4`|6P(wg%{gJh2ht+0_&HR_UF%Ng|uI^G=c#h^%n=tM>|A#DaGk z3SUA4O#BhP%=bTL{_){YNdKvaej01>6%YLk>92a|uaW+`hyDiXKl9LkPWmrA^fyWW zrHB3&>A&*O&yxPOhyH8Q-|^7jCHc-ld+7_BpbBNAi)zE1)j*^_U*hPGXM3o$*jC^pL2;E}BJ{|Dxfg<@ek9lvBvF zk^ejSZ}R^TWrb$(W=goME5cnOvv|uX9PF6K_IRW<7I^|aK6DvoFhDNO8_xXItz@`X z7LwF>D5B@m7=a z_KGR}jw$cNX1mOX4ZxYeoL6d6})6!g*5tb2-oqVwHFy)4zqYaX7EA04fi6C z2iTjR!cjbon=!{L%u~39j=h!eeh0pR+wd(K<2k$&FR;6R5y$a;ychq0_u@Et7Hn&CO=~5_A*`EhZmKPD>Uj4v_pTDTkwlmuciV@gQ1~OLz56(_;Y>~ zS-o+!?<_7l%f3xO6JQHiL%sMx!G*5Bm17OmWVnr(xU#j$LBtUKKh_nHp?EMB6ri@b zK&_d_uXJf@{D z-iPC+9;=R!DpZB0a)&>Fk3s_A_A*B;sQSO#@fL_P_Zsgh@Vg+|uufhael>0+4Y!DmO zHin_VyIozPVrn%s#FeQU)fxs)kE&HB`9eI=Zb#EFbsJD?IUC`LV)&U_2ZQGdt0wMS z%hUPQdhS-obA!RE%5pcB!{!PEC2VRXY`9Rv?N0QlfQBO)#@P!x;qwa8N+y4bZD*nX zWJv^tkSiBwu)gc~ zrlZ9sms@S7<>jwVZK3bkI`Z}>{_`=h@PkQN`rT#eaT?*_wuO^u=F1~(3pY8LV^@1Q z$izk`{QUWl1XlZXt+dzU`&*aW=UMvy+qBJhumRs?%sj_$(a+;DB3N)Nnyu#N_BT*7 z(K%k#G45!l9IN=Dwle>{k@dwjKnI_+9{lz5i>G$$`}Z8Vf*nq)X4S$cFJ2hsuh_1W zPniq0&f&>N`Qn<)UHp<~aj>#jwW>C9$>K4pE9F{iYhOQ)r%L5I}cN66uchTTWReHiXzMUBH5bvf(Z!3LLF6&x1BxLwl#u?qB4|dvcHF1Bb*)O?_S)1eX#i9cna6^bLkj->P?j6Q*Tz%`-CaI L7hh7B)r5Wl@Q{JY literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressor.java b/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressor.java new file mode 100644 index 00000000..6fc90319 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressor.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.List; + +/** + * + * A Decompressor that reconstructs the constant pool of classes. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class StringSharingDecompressor implements ResourceDecompressor { + + public static final int EXTERNALIZED_STRING = 23; + public static final int EXTERNALIZED_STRING_DESCRIPTOR = 25; + + private static final int CONSTANT_Utf8 = 1; + private static final int CONSTANT_Integer = 3; + private static final int CONSTANT_Float = 4; + private static final int CONSTANT_Long = 5; + private static final int CONSTANT_Double = 6; + private static final int CONSTANT_Class = 7; + private static final int CONSTANT_String = 8; + private static final int CONSTANT_Fieldref = 9; + private static final int CONSTANT_Methodref = 10; + private static final int CONSTANT_InterfaceMethodref = 11; + private static final int CONSTANT_NameAndType = 12; + private static final int CONSTANT_MethodHandle = 15; + private static final int CONSTANT_MethodType = 16; + private static final int CONSTANT_InvokeDynamic = 18; + private static final int CONSTANT_Module = 19; + private static final int CONSTANT_Package = 20; + + private static final int[] SIZES = new int[21]; + + static { + + //SIZES[CONSTANT_Utf8] = XXX; + SIZES[CONSTANT_Integer] = 4; + SIZES[CONSTANT_Float] = 4; + SIZES[CONSTANT_Long] = 8; + SIZES[CONSTANT_Double] = 8; + SIZES[CONSTANT_Class] = 2; + SIZES[CONSTANT_String] = 2; + SIZES[CONSTANT_Fieldref] = 4; + SIZES[CONSTANT_Methodref] = 4; + SIZES[CONSTANT_InterfaceMethodref] = 4; + SIZES[CONSTANT_NameAndType] = 4; + SIZES[CONSTANT_MethodHandle] = 3; + SIZES[CONSTANT_MethodType] = 2; + SIZES[CONSTANT_InvokeDynamic] = 4; + SIZES[CONSTANT_Module] = 2; + SIZES[CONSTANT_Package] = 2; + } + + public static int[] getSizes() { + return SIZES.clone(); + } + + @SuppressWarnings("fallthrough") + public static byte[] normalize(StringsProvider provider, byte[] transformed, + int offset) throws IOException { + DataInputStream stream = new DataInputStream(new ByteArrayInputStream(transformed, + offset, transformed.length - offset)); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(transformed.length); + DataOutputStream out = new DataOutputStream(outStream); + byte[] header = new byte[8]; //maginc/4, minor/2, major/2 + stream.readFully(header); + out.write(header); + int count = stream.readUnsignedShort(); + out.writeShort(count); + for (int i = 1; i < count; i++) { + int tag = stream.readUnsignedByte(); + byte[] arr; + switch (tag) { + case CONSTANT_Utf8: { + out.write(tag); + String utf = stream.readUTF(); + out.writeUTF(utf); + break; + } + + case EXTERNALIZED_STRING: { + int index = CompressIndexes.readInt(stream); + String orig = provider.getString(index); + out.write(CONSTANT_Utf8); + out.writeUTF(orig); + break; + } + + case EXTERNALIZED_STRING_DESCRIPTOR: { + String orig = reconstruct(provider, stream); + out.write(CONSTANT_Utf8); + out.writeUTF(orig); + break; + } + case CONSTANT_Long: + case CONSTANT_Double: { + i++; + } + default: { + out.write(tag); + int size = SIZES[tag]; + arr = new byte[size]; + stream.readFully(arr); + out.write(arr); + } + } + } + out.write(transformed, transformed.length - stream.available(), + stream.available()); + out.flush(); + + return outStream.toByteArray(); + } + + private static String reconstruct(StringsProvider reader, DataInputStream cr) + throws IOException { + int descIndex = CompressIndexes.readInt(cr); + String desc = reader.getString(descIndex); + byte[] encodedDesc = getEncoded(desc); + int indexes_length = CompressIndexes.readInt(cr); + byte[] bytes = new byte[indexes_length]; + cr.readFully(bytes); + List indices = CompressIndexes.decompressFlow(bytes); + ByteBuffer buffer = ByteBuffer.allocate(encodedDesc.length * 2); + buffer.order(ByteOrder.BIG_ENDIAN); + int argIndex = 0; + for (byte c : encodedDesc) { + if (c == 'L') { + buffer = safeAdd(buffer, c); + int index = indices.get(argIndex); + argIndex += 1; + String pkg = reader.getString(index); + if (!pkg.isEmpty()) { + pkg = pkg + "/"; + byte[] encoded = getEncoded(pkg); + buffer = safeAdd(buffer, encoded); + } + int classIndex = indices.get(argIndex); + argIndex += 1; + String clazz = reader.getString(classIndex); + byte[] encoded = getEncoded(clazz); + buffer = safeAdd(buffer, encoded); + } else { + buffer = safeAdd(buffer, c); + } + } + + byte[] encoded = buffer.array(); + ByteBuffer result = ByteBuffer.allocate(encoded.length + 2); + result.order(ByteOrder.BIG_ENDIAN); + result.putShort((short) buffer.position()); + result.put(encoded, 0, buffer.position()); + ByteArrayInputStream stream = new ByteArrayInputStream(result.array()); + DataInputStream inStream = new DataInputStream(stream); + String str = inStream.readUTF(); + return str; + } + + public static byte[] getEncoded(String pre) throws IOException { + ByteArrayOutputStream resultStream = new ByteArrayOutputStream(); + DataOutputStream resultOut = new DataOutputStream(resultStream); + resultOut.writeUTF(pre); + byte[] content = resultStream.toByteArray(); + // first 2 items are length; + if (content.length <= 2) { + return new byte[0]; + } + return Arrays.copyOfRange(content, 2, content.length); + } + + private static ByteBuffer safeAdd(ByteBuffer current, byte b) { + byte[] bytes = {b}; + return safeAdd(current, bytes); + } + + private static ByteBuffer safeAdd(ByteBuffer current, byte[] bytes) { + if (current.remaining() < bytes.length) { + ByteBuffer newBuffer = ByteBuffer.allocate((current.capacity() + + bytes.length) * 2); + newBuffer.order(ByteOrder.BIG_ENDIAN); + newBuffer.put(current.array(), 0, current.position()); + current = newBuffer; + } + current.put(bytes); + return current; + } + + @Override + public String getName() { + return StringSharingDecompressorFactory.NAME; + } + + public StringSharingDecompressor() {} + + @Override + public byte[] decompress(StringsProvider reader, byte[] content, + int offset, long originalSize) throws Exception { + return normalize(reader, content, offset); + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.class b/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.class new file mode 100644 index 0000000000000000000000000000000000000000..4bbe1c60f907567169729fd35fe19cf0764649b5 GIT binary patch literal 801 zcmbVKTT22_5dMyuYpZ72{Z0>oc3TR1=t3Z-5ST%R(BpAE*s=Aj?5mQ%rz0C&3)k*BrWnA@5I>bl zdS?u?xk{TqaKqxN70z^$uWLv#9FJ@CHxD)HDa z7{gI6Kbm=v*2Jclo=nm8B(0}mg<(37TH40N)h|L>wcwq~(qD0NsHWkNdp-v?KyOI@ z8^aMKA>%7qi+~{4U%T))(HT%iDU<}^p&ClO2ZuH$ucYu paU`HP2q_XDNZ!67{X%#IK1V#L+3%}Qg!M~=#t2=evl`^D{Qz0y*2w?> literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.java b/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.java new file mode 100644 index 00000000..ecdf15fc --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.io.IOException; + +/** + * + * Constant Pool strings sharing Decompressor factory. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class StringSharingDecompressorFactory extends ResourceDecompressorFactory { + + public static final String NAME = "compact-cp"; + public StringSharingDecompressorFactory() { + super(NAME); + } + + @Override + public ResourceDecompressor newDecompressor() + throws IOException { + return new StringSharingDecompressor(); + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressor.class b/tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressor.class new file mode 100644 index 0000000000000000000000000000000000000000..51b214f086717ff3268fa4fd29c93dd7c4e34350 GIT binary patch literal 1829 zcmb_dUsD@Z96dMLWJ6{d+B8H0rKYvkfV4}|Qiakg6zU?73YC%a;d*|NkQO+zYd^Nly6x4>%GR!QB7yWR*K?!W0?G2ox{i#%&E4uF)Ab@5cy`^~bsKg~ znpNrejbq}Ev)xBotW}diijeT#;o+fwwwGmtHRglB4>HIJ46n*>T5ce#B|8Z0y;A5tk)_D@OLaS_$t?PiSETv{`pZk* zT5D0@dbMdq3i>}W-9-6Ss4^0wIgUbwe+cl38E#j!&7qs7rrL$ArN6|Lu=Jw%b0k zQ4AMHHfMEwC~)J{YX2fU-f{tL&aX;=z9rX_E3L+s3?A59by{*uzGK(d?Z8#{9itZQ zxS_zr(y327FqW$e{_ESJu0)`*BHJ5|D z#`&RXk^JLu4js3h?gat^?aHss3IU`XzvVHycP+A=N6U6ICZ%JB!X9-q)WO>AKF0^_ z$RkkUgr0V${!8V{?P(702mWKXDud}x8NzD+d#`C{YU4em@{g|dw9 zL;TK70+U>o8$3rhxf<;Ne1wmACoqL+t}6K|uPQE?>-mkB>qVyfun zBXs68OL_D@{RO=*(6^C0yN`1(OF#UXnbKaMu(6MUsZ=pFIy8DPRDFhGaxz^^J;U%% zxYVEizV!5G4EEDf)VOK~{b|Nr{CYC|>*3!j?A6X5FRUCOz|vOJjjKeb92Ra9+nf9R+cvfX`^uSj6K0IzDfUggR|XBx7v2pgqUc zsdO>j6FR&9s_1{#8!P Integer.MAX_VALUE) { + throw new OutOfMemoryError("Required array size too large"); + } + byte[] bytesOut = new byte[(int) originalSize]; + + Inflater inflater = new Inflater(); + inflater.setInput(bytesIn, offset, bytesIn.length - offset); + + int count = 0; + while (!inflater.finished() && count < originalSize) { + count += inflater.inflate(bytesOut, count, bytesOut.length - count); + } + + inflater.end(); + + if (count != originalSize) { + throw new IOException("Resource content size mismatch"); + } + + return bytesOut; + } + + @Override + public byte[] decompress(StringsProvider reader, byte[] content, int offset, + long originalSize) throws Exception { + byte[] decompressed = decompress(content, offset, originalSize); + return decompressed; + } +} diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressorFactory.class b/tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressorFactory.class new file mode 100644 index 0000000000000000000000000000000000000000..132be2f39cf45f15acda3b856d9c6185099cd8b3 GIT binary patch literal 754 zcmb7CT}uK%6g{Kn+Gbgnec8vW8nhNfgc5`)1ZGen)Z4fYHnz^n?%LO{s;8i!AJC7A z?k-D63DU#NoqO-O=iWIppI>hu04mtj5MkKwwr>roJmDyA8C}`q9bvSEY4`e$a9!Im zu4Vst$ggqJvz^BTVhqtI+1C+=rXi8UBy@)ISiW=N+5^WFBS;zIWvQfh$dJj^yZnwD z7FQkP!gHkRl=4jtNrvLs7QaT;F@+g_z7&m|%QqQfjib{lL;7zIhUto}T#qZS$*qAP zY{hPqN!6tijX|#^oJ-!aD3Y$*Cbyd0k-i@WW8RH)84l|I9WvClM4gnl9~Ot$a{2Lm zqjV)Uz4~B^z9;EY8rB%*16ieQoSgk+2z3#>Nlp3}%l^_Y9BtdL#180{=mRmVU>0*^ z)8s`ErNw-WX`iRaUf=^-Asv0i#7h8Lpk1c~P#}^mWayNn0)k-?OJo_Ai8vBa?1mJH icT8QqV)~i#5%?VOpr$xfp9t$$DI23~mezWJ-}naG;ltAa literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java b/tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java new file mode 100644 index 00000000..b57ddc42 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.io.IOException; + +/** + * + * ZIP decompressor factory + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public final class ZipDecompressorFactory extends ResourceDecompressorFactory { + public static final String NAME = "zip"; + public ZipDecompressorFactory() { + super(NAME); + } + + @Override + public ResourceDecompressor newDecompressor() + throws IOException { + return new ZipDecompressor(); + } +} diff --git a/tests/test_data/std/jdk/internal/jmod/JmodFile$Entry.class b/tests/test_data/std/jdk/internal/jmod/JmodFile$Entry.class new file mode 100644 index 0000000000000000000000000000000000000000..a0e5dba0292307f4f4248ce04a5f66ab36d8095c GIT binary patch literal 3403 zcma)9Yj@OC6y3L-Hq#-{Qr=*p)E1_tFo2*)u~JHbfj*Ea$U}s5CX}?9WSq$$1s{k{ zd{)H=_(DOKA9O8WlmcsspIxryKT`KiGSf_3kPn?CH}{;q&pG>?oBsLFt=|E3;=2gS zP_7`Pq5_oyHAC7dEoN%gV61OoNKZNfm0JwUaM}gRqs<2*2%}0tM8yoK0`uMNdB-qg zXN*kju#xGqoa~5zGN?PfT3Q#F8*T2MaGG$khBeq0!7NlOs8KN+wI!(D20AdTlzzJJ zgg_`7Z;mUNE3kON&%V6n7-_xhbW+bahHWXBFR)oHiCI54`UI@7}hDx zG*b0LX**S~ORk&iGj^)e@6$M(=8n1cqH z*9QgWP3P`F6`HU@!AccTGz-)ZrG{gM<>*;UGh>osY&U;)7^dFn=QYeU`?m`{f>V<3 zCU=#JR;(7N%H;=gZq8Y(XgoeO1a5CaOvPHPW7cylInybyX*$B)_aKm<0>g_6yr7ujd3-Mw^e^U$v7+DbQ7%z+j>CT@80+v)TwfRZ_3ImKInOrN?53 zrF>iqZ)1$z#{F%z9B77$Aq)#tu#HV-Z&_jZxcg7!Emz&K9sUhVkp^dnts*1MmQ0jl z%3e0Mkz#HQXC#6wata(3d7LV-@)>p7tcMgI!>Mp=x2y;K?; z45u-o;Eam1c&;!6gIm4)P_#*pmcZH|m&u$9Xn{k3eOHw*1})9WXW2D717sQ7mOzz= zCFlG7D50HRmjsCfPms1|3Ov+lrwCWwZCHA5K0Tmk`?Ud+E4AHrQZo-|SwlYiiy`Nv z!F)H|3)>x?#1(WR4F1L0e+frR4l@ql&kCuTyAR^RoFl!QJ3|(iXsjd%YGzB)^pDR- z!p>)tx}4?&Ee!TGQgYnatLL0ucFs}ozC7seiqDqWX4?*nre%6`=cJv=)!=A#1-94V zV{dHV)wZ#~eVS9Cx)Ps8a0!@TJ=U$I2T~egwG)~@TW6$$Pk#j` zh;QVv+@)D5Q_nSa+xBoiLxB_s|D~JaS6T{?P8a1%^0c4Y778{Y{DeI759_P8M#bbh(@d}^F39m9D4iuguGL|x0 zx8pUuPTz0v{TzsY=_sV2NkLe_EWt&NEL`w|i}5PgDq4QS`k#1H=5nfZ7tgwws<*+% z6vUA$=eRd$ylJxW`Du;$LE#&(=T#zyiQG7bEk8^GzYwqw7s21;XSN5vo>T+&TYsEn zKRT^_6mR+VLGq20$zKc@R}{hdMd};x@xhn-rI*NHQ=#IDTa2ftUm&EcUHH%l^8tHzE zmH0k@xxtkQTyc~`tmKE>+mO{hM}x;)GoWr9Pmg2Z7ES`=Fvs!CO*|_h_Wp`JQn7g}kph$TQ$D6tBNrb0uSwxQd!vLza^#!b4Et((o57e4!E z{Ek6|(b3_vKZ@}=H(>};hwjYox#!$-p7VCk-G5&E@i%}1oEXM5%pdOmkoAJD+YTH* zd)RF4XYcT{=J{^Qb{k!<6~v(-Y#@TDhFHPM+jh~`kh0!xnG;jpKwM0th3)cMXd#@ zek*V_oJwb`L+6o`^_}1#yIntI!Eys;rI4k9g{j3 zX~cIA9AAg2Bd;OUbOIeyI##*%y}FLmI@Y_U#<6 znE1+!Tp9o=ZvaI(_KI@K73EAT$|+WqQ%g%zPArg|m1!j(rM-ns;%?cv> z93Z5?Hb}#wyl`pmDbfpzzv1#PQ^R8MkO zUOu~g$7rrmrNXadnKGWHj=YN(Hp zT@Clyt7@drgHVn3F=1C@eI)Iw-p5J1nxtsj7DumFRA)M04`F|1U*-AnPlB2sh0LX= z_~Z#fioG5-KUHi@v7bfE&lQ_c>~hrnLa`Hyy%jT86q{7+ZQU#=_M~Eq$*8%e_~~cZ zc!C+J^dPKx=v-U;U2O4gE@P4HUS>5m*}iXB+e5Cx!-7^Rk;2}`w~FqeMk?2fhCO`0 GGV?FjB6TSM literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jmod/JmodFile.class b/tests/test_data/std/jdk/internal/jmod/JmodFile.class new file mode 100644 index 0000000000000000000000000000000000000000..d1052e0726042576623017b84bba09e8375ddac2 GIT binary patch literal 4612 zcmbVPX>=3U8NE-EJ+eGl#;gVchCt#C1aU$Qa#?IlV%M@$Y}6Xs(m@*AgXI}j8bP4x zzVG|q2HLcxdm#iFZ~|$XLX-BKuBU(dFa6V={%+5q?R_&Nd2HDZr*N#9dGFir{l0ng z%71R$1ki)uC*nJ2`!_U<1xl-nB(0ABa_y15iG|_6|1mX zpt{R24SSzJu(>4}##)-|Gf!(7Bi+=W7&_D>tF*UCYOGVS9vi5kWm&Yez;-WppMz3* zz9r8mQ(TUX(!{2DnnNc~=_&g)G&if*g8K!+w&kWGu(H{!rOz3?M6pe#_JF{uh2l%r zpcyR+T2-{6U0~g*^kmF1Z9Qjdnb@f*D;?|SkHlMGxh%nn#KA}VdQJ=;O?3Aj5eOXb zuEh>)RuB_ts02TZU9@`C%onm*D`)HJCTX{St$uvMipR$f=|`V#z(fsu)vbw)dx(Ie=>eia9BP+*ysP7gDf zoSx6?gl(aLnTy!EV+F=!s;xW=NHKC^_6WX|uBE=Tue~VM) zeid)P0E3qtB3|>F!s!$Rg9OTPSFnvt?3|H}9W%1B{IbfAt9T<=^lIC35vebM&gPIS z1U!Ke3HVXMsITtP;lX$j|!SOk+WWw9)Q^`7}kTXGJ(LqKgZExT#VDwt`> z+63|{Y!o;I8KZA_3B(pRwaB!a#2FP&fLVr#ikI-Z61J5gN%!wm@g&|wF66!0yMB(m zyDA4A2XnlEBmX@r-i!AUC=RR)U2U2pKUOduIAVvrn|LigfDbD8kctoEBc`HxyvU?SLyyU`Z-Gc?&>XAJy+n0mIn>_tPM@}Srj|}$>u}?%F zySc|Q^R{N%Ni9>*gG^JDrTYeFrR5ITdp%Z~=Ar|JsSg&WPU^W4&%uC|(lSXcXUJ!7 zv1-cg>VQF(u38W~Mlft^vj4M=k|Kv_r2O9Dn<->Z7`$v4Se%V=-o{9pk0Gi@VysNh{lFaW%KG*sb|e-)>z>-0N;e6Ed|a z31Ou_a#44iJ8+H?Yh8&-x-0nMoFPn7^X;wR$E-octn|7k@&DIAo`_goZw%m{RO z@|9rT1IeP*cs_!gxTW9)6~DlX@h0s z{*XN-H>JlkGtKks)&a|!EMymG1RquBD2|-X>VENi-*jCrt?N<8pJb1g$qe)LN;K6z z)6{c48I8vl!laa6pH&Wf6xTcH_FTl8 z1n=wJ`J_MD&ySdxR1Nk1FIQC*EcMoG9 z#&|3}hi-hERlbB?YVXGHxbp>SG*LgwoiDPg()Mk9314RYSv#-7U*UZ_YVKmEf{22z zuG+NX-*}{7LDzp#i=cuX&UzOFm#Y3n-LFw2#A}p)t4f$4#kBx;HnmQpyX_i!TidRp zuXP5A(YEUt5}3yDRU|J{B;cg9njivKsP-(vxXKT;A~sS=hP~P~g|Fiqe4xf?2#HJ7bwR7+6?l=KCcnfs!YMO* z*tK2Gtdrn;$BC*FPvg6ccRlXI_jnhi&I){=@q{2jiXw0qyA}LE!H*6oJa`J89)IGM z;AINQpp*9)^c`&TF<7S6kmV2a>YMErnPp?Bh}>*SE@*#Xkbh)&e?lw%%s%~#FSTSj zwPZQ9WI45XIkjE*X*so8h`ShYQ=5Z|jh}f59^h5dOO-(plG9#TE|;pE3jWo{9km>W zN|!(9z8`I#dp)~{c$MwYAng`$?grisT*vzZY^4%YT^wI!3;vDY+^_nW)Zlq>WiQhb zKPElP{d|&^qtfziL|g|SmE`o(vl8|oM4d18FrJ|Ym#Mo5y8PFu zJQp4f*7uK$hUya|qgA1i(dyvH6+9??38&fI0_~*26|M!?a#wk+=G`Q}w~D-%t??Ya fO*8u&BrG_KgWPMzO9vV$)r?;`^W)ce1&#j$GH0$k literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jmod/JmodFile.java b/tests/test_data/std/jdk/internal/jmod/JmodFile.java new file mode 100644 index 00000000..987d68f0 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jmod/JmodFile.java @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jmod; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * Helper class to read JMOD file + */ +public class JmodFile implements AutoCloseable { + // jmod magic number and version number + private static final int JMOD_MAJOR_VERSION = 0x01; + private static final int JMOD_MINOR_VERSION = 0x00; + private static final byte[] JMOD_MAGIC_NUMBER = { + 0x4A, 0x4D, /* JM */ + JMOD_MAJOR_VERSION, JMOD_MINOR_VERSION, /* version 1.0 */ + }; + + public static void checkMagic(Path file) throws IOException { + try (InputStream in = Files.newInputStream(file)) { + // validate the header + byte[] magic = in.readNBytes(4); + if (magic.length != 4) { + throw new IOException("Invalid JMOD file: " + file); + } + if (magic[0] != JMOD_MAGIC_NUMBER[0] || + magic[1] != JMOD_MAGIC_NUMBER[1]) { + throw new IOException("Invalid JMOD file: " + file.toString()); + } + if (magic[2] > JMOD_MAJOR_VERSION || + (magic[2] == JMOD_MAJOR_VERSION && magic[3] > JMOD_MINOR_VERSION)) { + throw new IOException("Unsupported jmod version: " + + magic[2] + "." + magic[3] + " in " + file.toString()); + } + } + } + + /** + * JMOD sections + */ + public static enum Section { + CLASSES("classes"), + CONFIG("conf"), + HEADER_FILES("include"), + LEGAL_NOTICES("legal"), + MAN_PAGES("man"), + NATIVE_LIBS("lib"), + NATIVE_CMDS("bin"); + + private final String jmodDir; + private Section(String jmodDir) { + this.jmodDir = jmodDir; + } + + /** + * Returns the directory name in the JMOD file corresponding to + * this section + */ + public String jmodDir() { return jmodDir; } + } + + /** + * JMOD file entry. + * + * Each entry corresponds to a ZipEntry whose name is: + * Section::jmodDir + '/' + name + */ + public static class Entry { + private final ZipEntry zipEntry; + private final Section section; + private final String name; + + private Entry(ZipEntry e) { + String name = e.getName(); + int i = name.indexOf('/'); + if (i <= 1) { + throw new RuntimeException("invalid jmod entry: " + name); + } + + this.zipEntry = e; + this.section = section(name.substring(0, i)); + this.name = name.substring(i+1); + } + + /** + * Returns the section of this entry. + */ + public Section section() { + return section; + } + + /** + * Returns the name of this entry. + */ + public String name() { + return name; + } + + /** + * Returns true if the entry is a directory in the JMOD file. + */ + public boolean isDirectory() { + return zipEntry.isDirectory(); + } + + /** + * Returns the size of this entry. + */ + public long size() { + return zipEntry.getSize(); + } + + public ZipEntry zipEntry() { + return zipEntry; + } + + @Override + public String toString() { + return section.jmodDir() + "/" + name; + } + + /* + * A map from the jmodDir name to Section + */ + static final Map NAME_TO_SECTION = + Arrays.stream(Section.values()) + .collect(Collectors.toMap(Section::jmodDir, Function.identity())); + + static Section section(String name) { + if (!NAME_TO_SECTION.containsKey(name)) { + throw new IllegalArgumentException("invalid section: " + name); + + } + return NAME_TO_SECTION.get(name); + } + + } + + private final Path file; + private final ZipFile zipfile; + + /** + * Constructs a {@code JmodFile} from a given path. + */ + public JmodFile(Path file) throws IOException { + checkMagic(file); + this.file = file; + this.zipfile = new ZipFile(file.toFile()); + } + + public static void writeMagicNumber(OutputStream os) throws IOException { + os.write(JMOD_MAGIC_NUMBER); + } + + /** + * Returns the {@code Entry} for a resource in a JMOD file section + * or {@code null} if not found. + */ + public Entry getEntry(Section section, String name) { + String entry = section.jmodDir() + "/" + name; + ZipEntry ze = zipfile.getEntry(entry); + return (ze != null) ? new Entry(ze) : null; + } + + /** + * Opens an {@code InputStream} for reading the named entry of the given + * section in this JMOD file. + * + * @throws IOException if the named entry is not found, or I/O error + * occurs when reading it + */ + public InputStream getInputStream(Section section, String name) + throws IOException + { + String entry = section.jmodDir() + "/" + name; + ZipEntry e = zipfile.getEntry(entry); + if (e == null) { + throw new IOException(name + " not found: " + file); + } + return zipfile.getInputStream(e); + } + + /** + * Opens an {@code InputStream} for reading an entry in the JMOD file. + * + * @throws IOException if an I/O error occurs + */ + public InputStream getInputStream(Entry entry) throws IOException { + return zipfile.getInputStream(entry.zipEntry()); + } + + /** + * Returns a stream of entries in this JMOD file. + */ + public Stream stream() { + return zipfile.stream() + .map(Entry::new); + } + + @Override + public void close() throws IOException { + if (zipfile != null) { + zipfile.close(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/jrtfs/ExplodedImage$PathNode.class b/tests/test_data/std/jdk/internal/jrtfs/ExplodedImage$PathNode.class new file mode 100644 index 0000000000000000000000000000000000000000..842362b3cd67641cf1052a2680787d4cf5c6c694 GIT binary patch literal 4932 zcmbVP{d*ME6@KsTCX! z&$)L#{``Xv0rcQs8UhN92cieVmhGC3ZN$O{9Csuc-ZYVj#iM4lcib2?OA$hmhGHEW zN)%ddq~Em7aK{F?T%p(5#3QhS7EI|_X@N74YsOdEM z9yVCE<=(B(-Q0J;IAnxlhCLb{bREkc?MzE-D;^%PVrJNIDIQL_X1Lo(T9M6^b!9}! z&X!%W(JCDaQLPY4a1#nO1tw%`9?}{ex1d&G;i&268&U{2w-hY9zGv~fSVui>rQeuk zA5>_&VZ5?Y?kt7ES9C1JGKB@>@n|Y$ChxHv*;-Pe{r`s2sAD;9Qz(gyS+S^N+6q-^ zBPrL4h5M|e%MgT6Q;yrQLc>ZO&1fNJFa9?dZH016K$;OZ?o28Kn_Gs&W}A*xVyoCn z_AwA5TCF1tQmEW9lkwOgQ{)P(n}-^}5s7|^j5+Y}bf4GQ_BJ1oDhSgd=}HTk&Mx0Fr0S0ODA zbW03KjzQM`Y}9&VF>}<2bvdJ{anp9Q(JjGFmXg3X8lxFjbTo>M-8%NjJ}Ue;W;U}O zy&4|Kp!As8>N*E7WH4?}6?0#VhNGS7yjvq>UD2l}5Nj9AqGtBj1?-+C9hmB#W+~fGMj+gK< z8BddgsYHT(FKNGaV=K3h9#cvQ#&JmhRK=bDkpJ zu4rSY9T_tt2YCU=HTEiAm;UjKSt$AL2!&}Kv__e}ltW6~S#WG@DCpSNi1po_3KPVc zmzTNs690J5&3i%ZdSok*UH>SS9fW$kyUPL|H0D5ReAsk$NNQLOeesA9+hsVGJp00s zTydlty&hjZmy67~_@qu%zv+&}quUIJx-5T+_I=51=7r`OVU)eBD2U=UR2A<1l0f9j zHG3@(m$ms(noMLO)$dbpZo;w#ZkizCsAAAHA_x18grA90-X>B`l8r+_4Y51%#OPt` z;6cOuH1kZNEL$54ez_=Q?>N7;*tG!!tap!bu+YJx2x ztyNGd1Qhf7#`^0UVL&9pc}=`i>Z4;0+MAA@cSqqRAYc++%iMd^H91l?7*9D7Q*K8r zhP-ct)dG{fcEC)!TjJ6X^7=PV%CWN+jhm0kXnH$PofB_Ai8i*^NmNxffjHi96EI99i|oky^BRek6JN?Y5{ zW5GL=2JmZnN9(|L>J3824*J=NHz;ZKACodcWg*AZ-OZ;#&i2GnpI3A??eRRJci+F>YbzhTpUz2rTBcBUg z{WfjrObH;8)0E5u=oDWE@CT~#n}NRqY(Ga?*4TOu4Odaiq3$XcwNB%!GiXvgzqHU4 zLcufCNrSB92t=>|Q8aKAfN9r_KESh-6eDLNzWg2u*>)9nIu~;6a(RvbdMclFX z0`8=^a~j{O?%~fgHeJA$ON6oDecWG&#AN_eB>kbBy|2yLdl0G>=jloup5Xs9E~G)I zPbt&*=0EiIZO{MqjQ{E#bWHKCjQ_pjpGki6B8CX?!M-${ef_Iuzy>nVK7&!o_#RGT z3YU@S2)zrZJ~V^F0d$1?eN{gqcF!RwFCG&xkEcC!6nWC3X*|_YTwiQHI={`U*?XA5 zA33hW6@0`fguId&V37ciFb0qEGxIUB?Qv=x;i@OF8&8s-PvIz@#*4g=p5W|t-X%}t z7%d*5o#$xj7(T|c_yo`6-*~}Gz!q9N%DR4^J*S8(E9vO}eNpJSt5n{?Z&mmLgcbIkb^Ts=8Q^f1^+F zzJ{ZCFK%7JvJ;l4+kCpR@6Ta(v2RSeR1vLLNooGwTW|$ey;0#G9II(USpN}cWsLSG Hq0;{Wmt*Rz literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/ExplodedImage.class b/tests/test_data/std/jdk/internal/jrtfs/ExplodedImage.class new file mode 100644 index 0000000000000000000000000000000000000000..36826f7882626a0d22ef4e08fad488a34213c406 GIT binary patch literal 9393 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/ExplodedImage.java b/tests/test_data/std/jdk/internal/jrtfs/ExplodedImage.java new file mode 100644 index 00000000..e2c17f8c --- /dev/null +++ b/tests/test_data/std/jdk/internal/jrtfs/ExplodedImage.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import jdk.internal.jimage.ImageReader.Node; + +/** + * A jrt file system built on $JAVA_HOME/modules directory ('exploded modules + * build') + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +class ExplodedImage extends SystemImage { + + private static final String MODULES = "/modules/"; + private static final String PACKAGES = "/packages/"; + private static final int PACKAGES_LEN = PACKAGES.length(); + + private final FileSystem defaultFS; + private final String separator; + private final Map nodes = Collections.synchronizedMap(new HashMap<>()); + private final BasicFileAttributes modulesDirAttrs; + + ExplodedImage(Path modulesDir) throws IOException { + defaultFS = FileSystems.getDefault(); + String str = defaultFS.getSeparator(); + separator = str.equals("/") ? null : str; + modulesDirAttrs = Files.readAttributes(modulesDir, BasicFileAttributes.class); + initNodes(); + } + + // A Node that is backed by actual default file system Path + private final class PathNode extends Node { + + // Path in underlying default file system + private Path path; + private PathNode link; + private List children; + + PathNode(String name, Path path, BasicFileAttributes attrs) { // path + super(name, attrs); + this.path = path; + } + + PathNode(String name, Node link) { // link + super(name, link.getFileAttributes()); + this.link = (PathNode)link; + } + + PathNode(String name, List children) { // dir + super(name, modulesDirAttrs); + this.children = children; + } + + @Override + public boolean isDirectory() { + return children != null || + (link == null && getFileAttributes().isDirectory()); + } + + @Override + public boolean isLink() { + return link != null; + } + + @Override + public PathNode resolveLink(boolean recursive) { + if (link == null) + return this; + return recursive && link.isLink() ? link.resolveLink(true) : link; + } + + byte[] getContent() throws IOException { + if (!getFileAttributes().isRegularFile()) + throw new FileSystemException(getName() + " is not file"); + return Files.readAllBytes(path); + } + + @Override + public List getChildren() { + if (!isDirectory()) + throw new IllegalArgumentException("not a directory: " + getNameString()); + if (children == null) { + List list = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(path)) { + for (Path p : stream) { + p = explodedModulesDir.relativize(p); + String pName = MODULES + nativeSlashToFrontSlash(p.toString()); + Node node = findNode(pName); + if (node != null) { // findNode may choose to hide certain files! + list.add(node); + } + } + } catch (IOException x) { + return null; + } + children = list; + } + return children; + } + + @Override + public long size() { + try { + return isDirectory() ? 0 : Files.size(path); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + } + + @Override + public void close() throws IOException { + nodes.clear(); + } + + @Override + public byte[] getResource(Node node) throws IOException { + return ((PathNode)node).getContent(); + } + + // find Node for the given Path + @Override + public synchronized Node findNode(String str) { + Node node = findModulesNode(str); + if (node != null) { + return node; + } + // lazily created for paths like /packages///xyz + // For example /packages/java.lang/java.base/java/lang/ + if (str.startsWith(PACKAGES)) { + // pkgEndIdx marks end of part + int pkgEndIdx = str.indexOf('/', PACKAGES_LEN); + if (pkgEndIdx != -1) { + // modEndIdx marks end of part + int modEndIdx = str.indexOf('/', pkgEndIdx + 1); + if (modEndIdx != -1) { + // make sure we have such module link! + // ie., /packages// is valid + Node linkNode = nodes.get(str.substring(0, modEndIdx)); + if (linkNode == null || !linkNode.isLink()) { + return null; + } + // map to "/modules/zyz" path and return that node + // For example, "/modules/java.base/java/lang" for + // "/packages/java.lang/java.base/java/lang". + String mod = MODULES + str.substring(pkgEndIdx + 1); + return findModulesNode(mod); + } + } + } + return null; + } + + // find a Node for a path that starts like "/modules/..." + Node findModulesNode(String str) { + PathNode node = nodes.get(str); + if (node != null) { + return node; + } + // lazily created "/modules/xyz/abc/" Node + // This is mapped to default file system path "/xyz/abc" + Path p = underlyingPath(str); + if (p != null) { + try { + BasicFileAttributes attrs = Files.readAttributes(p, BasicFileAttributes.class); + if (attrs.isRegularFile()) { + Path f = p.getFileName(); + if (f.toString().startsWith("_the.")) + return null; + } + node = new PathNode(str, p, attrs); + nodes.put(str, node); + return node; + } catch (IOException x) { + // does not exists or unable to determine + } + } + return null; + } + + Path underlyingPath(String str) { + if (str.startsWith(MODULES)) { + str = frontSlashToNativeSlash(str.substring("/modules".length())); + return defaultFS.getPath(explodedModulesDir.toString(), str); + } + return null; + } + + // convert "/" to platform path separator + private String frontSlashToNativeSlash(String str) { + return separator == null ? str : str.replace("/", separator); + } + + // convert platform path separator to "/" + private String nativeSlashToFrontSlash(String str) { + return separator == null ? str : str.replace(separator, "/"); + } + + // convert "/"s to "."s + private String slashesToDots(String str) { + return str.replace(separator != null ? separator : "/", "."); + } + + // initialize file system Nodes + private void initNodes() throws IOException { + // same package prefix may exist in multiple modules. This Map + // is filled by walking "jdk modules" directory recursively! + Map> packageToModules = new HashMap<>(); + try (DirectoryStream stream = Files.newDirectoryStream(explodedModulesDir)) { + for (Path module : stream) { + if (Files.isDirectory(module)) { + String moduleName = module.getFileName().toString(); + // make sure "/modules/" is created + findModulesNode(MODULES + moduleName); + try (Stream contentsStream = Files.walk(module)) { + contentsStream.filter(Files::isDirectory).forEach((p) -> { + p = module.relativize(p); + String pkgName = slashesToDots(p.toString()); + // skip META-INF and empty strings + if (!pkgName.isEmpty() && !pkgName.startsWith("META-INF")) { + List moduleNames = packageToModules.get(pkgName); + if (moduleNames == null) { + moduleNames = new ArrayList<>(); + packageToModules.put(pkgName, moduleNames); + } + moduleNames.add(moduleName); + } + }); + } + } + } + } + // create "/modules" directory + // "nodes" map contains only /modules/ nodes only so far and so add all as children of /modules + PathNode modulesDir = new PathNode("/modules", new ArrayList<>(nodes.values())); + nodes.put(modulesDir.getName(), modulesDir); + + // create children under "/packages" + List packagesChildren = new ArrayList<>(packageToModules.size()); + for (Map.Entry> entry : packageToModules.entrySet()) { + String pkgName = entry.getKey(); + List moduleNameList = entry.getValue(); + List moduleLinkNodes = new ArrayList<>(moduleNameList.size()); + for (String moduleName : moduleNameList) { + Node moduleNode = findModulesNode(MODULES + moduleName); + PathNode linkNode = new PathNode(PACKAGES + pkgName + "/" + moduleName, moduleNode); + nodes.put(linkNode.getName(), linkNode); + moduleLinkNodes.add(linkNode); + } + PathNode pkgDir = new PathNode(PACKAGES + pkgName, moduleLinkNodes); + nodes.put(pkgDir.getName(), pkgDir); + packagesChildren.add(pkgDir); + } + // "/packages" dir + PathNode packagesDir = new PathNode("/packages", packagesChildren); + nodes.put(packagesDir.getName(), packagesDir); + + // finally "/" dir! + List rootChildren = new ArrayList<>(); + rootChildren.add(packagesDir); + rootChildren.add(modulesDir); + PathNode root = new PathNode("/", rootChildren); + nodes.put(root.getName(), root); + } +} diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtDirectoryStream$1.class b/tests/test_data/std/jdk/internal/jrtfs/JrtDirectoryStream$1.class new file mode 100644 index 0000000000000000000000000000000000000000..fa5fd82b54f095b204b4d3f0729e53564038aed5 GIT binary patch literal 1394 zcma)+TTc@~6vzM53)_}eD;5+LMJ>_`vUtA~Nep5{OF?T;@M$OmU08O>?$*njA3#5V z-@yk>RH7zobro)+lv>!z0-p-Z_fpHd15BsHXTbV3(M zugFKzu%x|gOfRf3Izx_{w&{-vM05GsBz9wuhO~~o=n@!cYZHNl>5W^Crxpdod=Mj} zqZ>VpY5J}}rW|hD@J-8@Jye)Q?@_xq^8z=)3Hw1x8pWNNuZExvk3WFQj9x`N?=dfv{j|CwxHa5a>3%8uCh~;)~s~R zVBUHe3+gOD;`Ta&H0dej*PX=~>B=?5B-4FY)t9x^DY+g-)o?~&-`@tfS9hJqO@?IE zT(+g(aLF^eGfV#|UrV(;C1b=$Rh@=gQ#Y7Nf&DwXcsKxH9wzJ>JI1t^o7g%o<4Vv- zt@hZG_U&y$O+|VBO~+$b=##ds+;K~Kp7PMoq9q_$dXY{CH;b1o#(yXBTq$rgMjN3` z6^id53LDVga27$4&klM5w=u+LPg8|c80L)nFq(kDah$SeX^Ppldk3z8zPSw?{qhH|U*IdU#m(1E z!U*>+ge*m7A;{2Hvin?pK(aaXVxFrHw~&qeOU7%SxI?n^wctj!$PC&b-lR?2m5yy#=`F`y zucT)k_o?Y{YuVW=xQ;ZoxwT|E0@w5Bo4+*N&1?jh(4nDI$9sqg^fosYX!Rlq^fht# z%(P@-uj0z>Y!qGS*3hHl3a$#o&v$#WL7>g7)brG|>r1=Bwi<&JBX?I;0W*Kq?M2!!1-sWI&hfv%xM{)BXYmRVmzTuE|Epqm-gMX9a( zLfqETk2_R|K`DX2fNxpPqmIMZp`S2mN2qvGchYuR=FZe0)kjl0>fvq_^S<` zPJv3IMftm{BaM4h+H{#nm!HV4Yg*|XLmDiGtcDK-Zk}MtS(e-|tb%K}vhFa9`_%P# zPkhs;#0`r@RN9NLNomI&>FzqVEJZPjxDxjh9S`wHAZpg)EUXJGU#Qxpve(S<)Q68rRlFjfm z?DAqv3*0!XVS|-Gq+o8?2APxsvkY*OF#^)=Pz%y#D_*G!sOz6Fz?Y6*rHP!~5v_jiy1o;D0Yd{C~*N zBServH?p{eaSUJrd9K8Lx0u5`M-1SlDZHLaG=K&6btb0P`n`l-vLA!^hmLrEhc#T% z@QQNJ zG@?@tpS}Y;*vH5(XwNH~R25@KhnQR;6QBOdXmLCswhVD7yaPlDJb}h9j1CgtgK1jK z&}Noa&uN$A$_o#B5A(^;{tGO7`0_Ot6ut<89i7V>GLagX6@pnMnLe2NY!xM;WN;q? zitd0HUVYO5YgDf2h46_B)f}G?6s&pu60g0zU*T)Eio8jD!(NPjUNQY|LlMq+zkdM= CacoHd literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtDirectoryStream.java b/tests/test_data/std/jdk/internal/jrtfs/JrtDirectoryStream.java new file mode 100644 index 00000000..f2f2aa68 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jrtfs/JrtDirectoryStream.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.nio.file.DirectoryStream; +import java.nio.file.ClosedDirectoryStreamException; +import java.nio.file.DirectoryIteratorException; +import java.nio.file.NotDirectoryException; +import java.nio.file.Path; +import java.util.Iterator; +import java.util.Objects; +import java.util.NoSuchElementException; +import java.io.IOException; + +/** + * DirectoryStream implementation for jrt file system implementations. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +final class JrtDirectoryStream implements DirectoryStream { + + private final JrtPath dir; + private final DirectoryStream.Filter filter; + private boolean isClosed; + private Iterator itr; + + JrtDirectoryStream(JrtPath dir, + DirectoryStream.Filter filter) + throws IOException + { + this.dir = dir; + if (!dir.jrtfs.isDirectory(dir, true)) { // sanity check + throw new NotDirectoryException(dir.toString()); + } + this.filter = filter; + } + + @Override + public synchronized Iterator iterator() { + if (isClosed) + throw new ClosedDirectoryStreamException(); + if (itr != null) + throw new IllegalStateException("Iterator has already been returned"); + try { + itr = dir.jrtfs.iteratorOf(dir, filter); + } catch (IOException e) { + throw new IllegalStateException(e); + } + return new Iterator() { + @Override + public boolean hasNext() { + synchronized (JrtDirectoryStream.this) { + if (isClosed) + return false; + return itr.hasNext(); + } + } + + @Override + public Path next() { + synchronized (JrtDirectoryStream.this) { + if (isClosed) + throw new NoSuchElementException(); + return itr.next(); + } + } + }; + } + + @Override + public synchronized void close() throws IOException { + isClosed = true; + } +} diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributeView$AttrID.class b/tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributeView$AttrID.class new file mode 100644 index 0000000000000000000000000000000000000000..9dcc27a5a119381b760dd8b2a9bd21eb6f7051f6 GIT binary patch literal 1857 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 CK4g#p literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributeView.java b/tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributeView.java new file mode 100644 index 00000000..874da943 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributeView.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.nio.file.LinkOption; +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +/** + * File attribute view for jrt file system. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +final class JrtFileAttributeView implements BasicFileAttributeView { + + private static enum AttrID { + size, + creationTime, + lastAccessTime, + lastModifiedTime, + isDirectory, + isRegularFile, + isSymbolicLink, + isOther, + fileKey, + compressedSize, + extension + }; + + private final JrtPath path; + private final boolean isJrtView; + private final LinkOption[] options; + + private JrtFileAttributeView(JrtPath path, boolean isJrtView, LinkOption... options) { + this.path = path; + this.isJrtView = isJrtView; + this.options = options; + } + + @SuppressWarnings("unchecked") // Cast to V + static V get(JrtPath path, Class type, LinkOption... options) { + Objects.requireNonNull(type); + if (type == BasicFileAttributeView.class) { + return (V) new JrtFileAttributeView(path, false, options); + } + if (type == JrtFileAttributeView.class) { + return (V) new JrtFileAttributeView(path, true, options); + } + return null; + } + + static JrtFileAttributeView get(JrtPath path, String type, LinkOption... options) { + Objects.requireNonNull(type); + if (type.equals("basic")) { + return new JrtFileAttributeView(path, false, options); + } + if (type.equals("jrt")) { + return new JrtFileAttributeView(path, true, options); + } + return null; + } + + @Override + public String name() { + return isJrtView ? "jrt" : "basic"; + } + + @Override + public JrtFileAttributes readAttributes() throws IOException { + return path.getAttributes(options); + } + + @Override + public void setTimes(FileTime lastModifiedTime, + FileTime lastAccessTime, + FileTime createTime) throws IOException { + path.setTimes(lastModifiedTime, lastAccessTime, createTime); + } + + static void setAttribute(JrtPath path, String attribute, Object value) + throws IOException { + int colonPos = attribute.indexOf(':'); + if (colonPos != -1) { // type = "basic", if no ":" + String type = attribute.substring(0, colonPos++); + if (!type.equals("basic") && !type.equals("jrt")) { + throw new UnsupportedOperationException( + "view <" + type + "> is not supported"); + } + attribute = attribute.substring(colonPos); + } + try { + AttrID id = AttrID.valueOf(attribute); + if (id == AttrID.lastModifiedTime) { + path.setTimes((FileTime) value, null, null); + } else if (id == AttrID.lastAccessTime) { + path.setTimes(null, (FileTime) value, null); + } else if (id == AttrID.creationTime) { + path.setTimes(null, null, (FileTime) value); + } + return; + } catch (IllegalArgumentException x) {} + throw new UnsupportedOperationException("'" + attribute + + "' is unknown or read-only attribute"); + } + + static Map readAttributes(JrtPath path, String attributes, + LinkOption... options) + throws IOException { + int colonPos = attributes.indexOf(':'); + boolean isJrtView = false; + if (colonPos != -1) { // type = "basic", if no ":" + String type = attributes.substring(0, colonPos++); + if (!type.equals("basic") && !type.equals("jrt")) { + throw new UnsupportedOperationException("view <" + type + + "> is not supported"); + } + isJrtView = true; + attributes = attributes.substring(colonPos); + } + JrtFileAttributes jrtfas = path.getAttributes(); + LinkedHashMap map = new LinkedHashMap<>(); + if ("*".equals(attributes)) { + for (AttrID id : AttrID.values()) { + map.put(id.name(), attribute(id, jrtfas, isJrtView)); + } + } else { + String[] as = attributes.split(","); + for (String a : as) { + //throw IllegalArgumentException + map.put(a, attribute(AttrID.valueOf(a), jrtfas, isJrtView)); + } + } + return map; + } + + static Object attribute(AttrID id, JrtFileAttributes jrtfas, boolean isJrtView) { + switch (id) { + case size: + return jrtfas.size(); + case creationTime: + return jrtfas.creationTime(); + case lastAccessTime: + return jrtfas.lastAccessTime(); + case lastModifiedTime: + return jrtfas.lastModifiedTime(); + case isDirectory: + return jrtfas.isDirectory(); + case isRegularFile: + return jrtfas.isRegularFile(); + case isSymbolicLink: + return jrtfas.isSymbolicLink(); + case isOther: + return jrtfas.isOther(); + case fileKey: + return jrtfas.fileKey(); + case compressedSize: + if (isJrtView) { + return jrtfas.compressedSize(); + } + break; + case extension: + if (isJrtView) { + return jrtfas.extension(); + } + break; + } + return null; + } +} diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributes.class b/tests/test_data/std/jdk/internal/jrtfs/JrtFileAttributes.class new file mode 100644 index 0000000000000000000000000000000000000000..565ba3f0de89033aab7021bf2c5365281f8e9a25 GIT binary patch literal 3347 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 V getFileStoreAttributeView(Class type) { + Objects.requireNonNull(type, "type"); + return (V) null; + } + + @Override + public long getTotalSpace() throws IOException { + throw new UnsupportedOperationException("getTotalSpace"); + } + + @Override + public long getUsableSpace() throws IOException { + throw new UnsupportedOperationException("getUsableSpace"); + } + + @Override + public long getUnallocatedSpace() throws IOException { + throw new UnsupportedOperationException("getUnallocatedSpace"); + } + + @Override + public Object getAttribute(String attribute) throws IOException { + throw new UnsupportedOperationException("does not support " + attribute); + } + + @Override + public boolean supportsFileAttributeView(Class type) { + return type == BasicFileAttributeView.class || + type == JrtFileAttributeView.class; + } +} diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem$1.class b/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem$1.class new file mode 100644 index 0000000000000000000000000000000000000000..5b582c9b28adac20126c397c40102fdce71261d3 GIT binary patch literal 2060 zcma)7TW=dh7(L@l)^;4nN!n6^0k^m`b}!qM0tNR%6H*$Jn=k~G^1#@hB%3(9W_R4u z3JD(I0e%F(03MKts#2-E^P3Rj%-Xfx)FF-J{dVVazH`p^&E)TY|9k>q9!p6?5Va6X zBaRV)liQ6Q+i|t>UD>p^eZ3Lb6<^2BJq zwQW_`0wY%(*U{GmqBF&HgEN`Nl);JlOf-t4IA-CcG>+qCfm1I;hoDZd+EQ)^`h|s8 zsHC6yGdF0rTAr^}gNuBr9nW3(rmkA%C535>nXIoF8m|i+pXqyGB+s=sHk4m3E?PJt zaPE0RE1vtg?`UID*Pa3Jd=WAf$9f7H^7HrkU)!vLi zX{J&f;>QqgNg>J{d^Q3$=F$GHfx5G)NkA+Lj8(O)?<~t!*P4X(+iqQIQjK-mKYovW zz|Uyl^DL#RUfZuLbJS?=Gl%ZHVa^&XxTYT*ceCS!g_{ET!>XOeEs##eRrdytq`fl`h}ui`^hWTWak)wYFBa;d|rhSNX-QOsuFt-|~!;=|$cg{(Msg zfeMi48BastO+gDFOlkhe@~a=*F<2dKOLoVpKs>P%)+dpb50^Sc8uZ-ndz9lJiX znAZMc{tyCoI$>BbdEa-9zf5}uy6O#qeiNq*Y4H=1;^zUpr=8WO6~i3GMfe~7L&g{u S@DVEE$O1lQG-WsP`S&0AQKTOL literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem.class b/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem.class new file mode 100644 index 0000000000000000000000000000000000000000..bdb8efa97571c392bd17cd4581e7a6034574b5ef GIT binary patch literal 16620 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem.java b/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem.java new file mode 100644 index 00000000..9a8d9d22 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystem.java @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.NonWritableChannelException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.ClosedFileSystemException; +import java.nio.file.CopyOption; +import java.nio.file.DirectoryStream; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemException; +import java.nio.file.InvalidPathException; +import java.nio.file.LinkOption; +import java.nio.file.NoSuchFileException; +import java.nio.file.NotDirectoryException; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.ReadOnlyFileSystemException; +import java.nio.file.StandardOpenOption; +import java.nio.file.WatchService; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileTime; +import java.nio.file.attribute.UserPrincipalLookupService; +import java.nio.file.spi.FileSystemProvider; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.regex.Pattern; +import jdk.internal.jimage.ImageReader.Node; +import static java.util.stream.Collectors.toList; + +/** + * jrt file system implementation built on System jimage files. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +class JrtFileSystem extends FileSystem { + + private final JrtFileSystemProvider provider; + private final JrtPath rootPath = new JrtPath(this, "/"); + private volatile boolean isOpen; + private volatile boolean isClosable; + private SystemImage image; + + JrtFileSystem(JrtFileSystemProvider provider, Map env) + throws IOException + { + this.provider = provider; + this.image = SystemImage.open(); // open image file + this.isOpen = true; + this.isClosable = env != null; + } + + // FileSystem method implementations + @Override + public boolean isOpen() { + return isOpen; + } + + @Override + public void close() throws IOException { + if (!isClosable) + throw new UnsupportedOperationException(); + cleanup(); + } + + @Override + public FileSystemProvider provider() { + return provider; + } + + @Override + public Iterable getRootDirectories() { + return Collections.singleton(getRootPath()); + } + + @Override + public JrtPath getPath(String first, String... more) { + if (more.length == 0) { + return new JrtPath(this, first); + } + StringBuilder sb = new StringBuilder(); + sb.append(first); + for (String path : more) { + if (!path.isEmpty()) { + if (sb.length() > 0) { + sb.append('/'); + } + sb.append(path); + } + } + return new JrtPath(this, sb.toString()); + } + + @Override + public final boolean isReadOnly() { + return true; + } + + @Override + public final UserPrincipalLookupService getUserPrincipalLookupService() { + throw new UnsupportedOperationException(); + } + + @Override + public final WatchService newWatchService() { + throw new UnsupportedOperationException(); + } + + @Override + public final Iterable getFileStores() { + return Collections.singleton(getFileStore(getRootPath())); + } + + private static final Set supportedFileAttributeViews + = Collections.unmodifiableSet( + new HashSet(Arrays.asList("basic", "jrt"))); + + @Override + public final Set supportedFileAttributeViews() { + return supportedFileAttributeViews; + } + + @Override + public final String toString() { + return "jrt:/"; + } + + @Override + public final String getSeparator() { + return "/"; + } + + @Override + public PathMatcher getPathMatcher(String syntaxAndInput) { + int pos = syntaxAndInput.indexOf(':'); + if (pos <= 0) { + throw new IllegalArgumentException(); + } + String syntax = syntaxAndInput.substring(0, pos); + String input = syntaxAndInput.substring(pos + 1); + String expr; + if (syntax.equalsIgnoreCase("glob")) { + expr = JrtUtils.toRegexPattern(input); + } else if (syntax.equalsIgnoreCase("regex")) { + expr = input; + } else { + throw new UnsupportedOperationException("Syntax '" + syntax + + "' not recognized"); + } + // return matcher + final Pattern pattern = Pattern.compile(expr); + return (Path path) -> pattern.matcher(path.toString()).matches(); + } + + JrtPath resolveLink(JrtPath path) throws IOException { + Node node = checkNode(path); + if (node.isLink()) { + node = node.resolveLink(); + return new JrtPath(this, node.getName()); // TBD, normalized? + } + return path; + } + + JrtFileAttributes getFileAttributes(JrtPath path, LinkOption... options) + throws IOException { + Node node = checkNode(path); + if (node.isLink() && followLinks(options)) { + return new JrtFileAttributes(node.resolveLink(true)); + } + return new JrtFileAttributes(node); + } + + /** + * returns the list of child paths of the given directory "path" + * + * @param path name of the directory whose content is listed + * @return iterator for child paths of the given directory path + */ + Iterator iteratorOf(JrtPath path, DirectoryStream.Filter filter) + throws IOException { + Node node = checkNode(path).resolveLink(true); + if (!node.isDirectory()) { + throw new NotDirectoryException(path.getName()); + } + if (filter == null) { + return node.getChildren() + .stream() + .map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName()))) + .iterator(); + } + return node.getChildren() + .stream() + .map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName()))) + .filter(p -> { try { return filter.accept(p); + } catch (IOException x) {} + return false; + }) + .iterator(); + } + + // returns the content of the file resource specified by the path + byte[] getFileContent(JrtPath path) throws IOException { + Node node = checkNode(path); + if (node.isDirectory()) { + throw new FileSystemException(path + " is a directory"); + } + //assert node.isResource() : "resource node expected here"; + return image.getResource(node); + } + + /////////////// Implementation details below this point ////////// + + // static utility methods + static ReadOnlyFileSystemException readOnly() { + return new ReadOnlyFileSystemException(); + } + + // do the supplied options imply that we have to chase symlinks? + static boolean followLinks(LinkOption... options) { + if (options != null) { + for (LinkOption lo : options) { + Objects.requireNonNull(lo); + if (lo == LinkOption.NOFOLLOW_LINKS) { + return false; + } else { + throw new AssertionError("should not reach here"); + } + } + } + return true; + } + + // check that the options passed are supported by (read-only) jrt file system + static void checkOptions(Set options) { + // check for options of null type and option is an instance of StandardOpenOption + for (OpenOption option : options) { + Objects.requireNonNull(option); + if (!(option instanceof StandardOpenOption)) { + throw new IllegalArgumentException( + "option class: " + option.getClass()); + } + } + if (options.contains(StandardOpenOption.WRITE) || + options.contains(StandardOpenOption.APPEND)) { + throw readOnly(); + } + } + + // clean up this file system - called from finalize and close + synchronized void cleanup() throws IOException { + if (isOpen) { + isOpen = false; + image.close(); + image = null; + } + } + + // These methods throw read only file system exception + final void setTimes(JrtPath jrtPath, FileTime mtime, FileTime atime, FileTime ctime) + throws IOException { + throw readOnly(); + } + + // These methods throw read only file system exception + final void createDirectory(JrtPath jrtPath, FileAttribute... attrs) throws IOException { + throw readOnly(); + } + + final void deleteFile(JrtPath jrtPath, boolean failIfNotExists) + throws IOException { + throw readOnly(); + } + + final OutputStream newOutputStream(JrtPath jrtPath, OpenOption... options) + throws IOException { + throw readOnly(); + } + + final void copyFile(boolean deletesrc, JrtPath srcPath, JrtPath dstPath, CopyOption... options) + throws IOException { + throw readOnly(); + } + + final FileChannel newFileChannel(JrtPath path, + Set options, + FileAttribute... attrs) + throws IOException { + throw new UnsupportedOperationException("newFileChannel"); + } + + final InputStream newInputStream(JrtPath path) throws IOException { + return new ByteArrayInputStream(getFileContent(path)); + } + + final SeekableByteChannel newByteChannel(JrtPath path, + Set options, + FileAttribute... attrs) + throws IOException { + checkOptions(options); + + byte[] buf = getFileContent(path); + final ReadableByteChannel rbc + = Channels.newChannel(new ByteArrayInputStream(buf)); + final long size = buf.length; + return new SeekableByteChannel() { + long read = 0; + + @Override + public boolean isOpen() { + return rbc.isOpen(); + } + + @Override + public long position() throws IOException { + return read; + } + + @Override + public SeekableByteChannel position(long pos) + throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public int read(ByteBuffer dst) throws IOException { + int n = rbc.read(dst); + if (n > 0) { + read += n; + } + return n; + } + + @Override + public SeekableByteChannel truncate(long size) + throws IOException { + throw new NonWritableChannelException(); + } + + @Override + public int write(ByteBuffer src) throws IOException { + throw new NonWritableChannelException(); + } + + @Override + public long size() throws IOException { + return size; + } + + @Override + public void close() throws IOException { + rbc.close(); + } + }; + } + + final JrtFileStore getFileStore(JrtPath path) { + return new JrtFileStore(path); + } + + final void ensureOpen() throws IOException { + if (!isOpen()) { + throw new ClosedFileSystemException(); + } + } + + final JrtPath getRootPath() { + return rootPath; + } + + boolean isSameFile(JrtPath path1, JrtPath path2) throws IOException { + return checkNode(path1) == checkNode(path2); + } + + boolean isLink(JrtPath path) throws IOException { + return checkNode(path).isLink(); + } + + boolean exists(JrtPath path) throws IOException { + try { + checkNode(path); + } catch (NoSuchFileException exp) { + return false; + } + return true; + } + + boolean isDirectory(JrtPath path, boolean resolveLinks) + throws IOException { + Node node = checkNode(path); + return resolveLinks && node.isLink() + ? node.resolveLink(true).isDirectory() + : node.isDirectory(); + } + + JrtPath toRealPath(JrtPath path, LinkOption... options) + throws IOException { + Node node = checkNode(path); + if (followLinks(options) && node.isLink()) { + node = node.resolveLink(); + } + // image node holds the real/absolute path name + return new JrtPath(this, node.getName(), true); + } + + private Node lookup(String path) { + try { + return image.findNode(path); + } catch (RuntimeException | IOException ex) { + throw new InvalidPathException(path, ex.toString()); + } + } + + private Node lookupSymbolic(String path) { + int i = 1; + while (i < path.length()) { + i = path.indexOf('/', i); + if (i == -1) { + break; + } + String prefix = path.substring(0, i); + Node node = lookup(prefix); + if (node == null) { + break; + } + if (node.isLink()) { + Node link = node.resolveLink(true); + // resolved symbolic path concatenated to the rest of the path + String resPath = link.getName() + path.substring(i); + node = lookup(resPath); + return node != null ? node : lookupSymbolic(resPath); + } + i++; + } + return null; + } + + Node checkNode(JrtPath path) throws IOException { + ensureOpen(); + String p = path.getResolvedPath(); + Node node = lookup(p); + if (node == null) { + node = lookupSymbolic(p); + if (node == null) { + throw new NoSuchFileException(p); + } + } + return node; + } +} diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystemProvider$1.class b/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystemProvider$1.class new file mode 100644 index 0000000000000000000000000000000000000000..3306b4cad0218a07cf5710fe43593814943a4e5b GIT binary patch literal 1033 zcma)4Yikoh6g`vICfiLLV|}$+AB~!%;!-GnNhy?|sHAN$8W2BCHq&I{b{1wQk^Ut? zP*4jB{s4cJcz3g6EC#YLduQ&QIdjh3^YhoY9{`%zDjtG`LLRYpK@)Pb?#@Y`VR^GHme8OENjQi?Et6?LLf(6^b z5*&t7T=cmbxJSK_@C-w4S1M`t7}C{R*TOQx&cb&`jKWsHiHD6MO3^JB7|PXiENWew zIic55n9xI0RYV9AYO`nGeR>Q&-hK-nOD7>+j=G1L#IU)4}(ckxs3L124??+n> zrZQ%e)687zyK{x_5uV)%#@Z86s~Oh*+w_Og(~$DV%JYLzs=_qIXOQ~gFHi(t2Eo8n4)Ocx4wYY&tQF`RSMVWpQDq&d#usliRU)fah+B-Xr$sC z*^4R>(j!8S_B-EEd|m$xc7~OY@xH%UA7-$eDOPEpEV_|kxD+FdZ2c?B=MT>k$tFay j36+~9HKKGIcPM7CiMy!AnN8FvmZ=uWjJ_gO>#%SrV%up`$*UGaa9A@mXM~|K@*wR;C8LWXLZ}uXN~nRv(7%>nPiTgt zT85%0)+}emPRv-&q^7IcE!$By<}GtmBi3$i-H#An(TuzsF7HNW=!tldbj4UrWF1R0 zR+CYm$%Q2a)a?oP0mq7(P9a3pqMj$$z)%_CQjeiYK(mAvv@+DYnfTlo1WPUGN={{H ziKJ5gaAgIYvQ0uePEb{pLP0h14Dr86^?b{sk|CTV-@Y6#FsC~$p%Z5qLXPPH8JZ$T zh7RGZgl_aONW5GNs%;i6F1G8>0?O@7@;0555aB(l=H71o_youjVmMD$ow{8ve(w>4 zOMXpW^*L#ugaj^-B#Y$en`)V%$YTZ?qb+R<3&77hy zDwf8-%f^87P_r2Z(*HA5Ns3mqbn*`$8d?TcWT-nh$qW@agX=gv6~seh;pRq;OZ3k% zH27d%b~G{vQ`jo(rO|X4JS>k8Yi-t1a_h57!Od2{I4S)V++`IoNtN}VI0kXzQBEy5 znrYYqrWra9`D9FI(kvSJeHgVitF0P}Q?#hiQGa8~Q~i5uJ%wV{9WZ`)8QPCL#(g|G z4R1!Zohj3H1k5u;{mu zox6XDRzA(ZV?sW`WqNDzQ0T`M`XW3AaFsX$eBe>(a(yLq746N)u@Zz#{4)mS52(Gr zi*T&IuRc*iV+qF_J7_84R0&-}fwsUWNF3gqc?(gFb?hR#)3J?^94{dr-yyaDxSn2A z)B2R+J|k_##|m6sUAD~w{BuHe_0!W&m>KdF$>OncYJoAm6fp1}~3q?+4?ah-As zVw`F)N*UZBt3-RAs5@nC->Y6X+Sk>EyLbnQ>t z*3kAud?eCmC74Q^Be95m9#iq^nr=V&aj`pL2Pi4^8GqE<3Mb7-FEHJ@qzYA*{r5s3{n)pQ4FAuTef%B01#gsCdSB~QpX;Xy0B zC&N|5c1R|*z`@KzMS2+>Z_o)QRnv(~rXn4)?BLGMHl{Mc0ThQUrg_=wJF*36xh!A7 zw0d{no?s+qTZvdG8U)Jy$>8RMoo|%@t)x{3tv0EKYO~Q-G%;jdl?p|ZZ3D4*!fFjA z!Mq?Yy9}ylIw^xjTQq77grY5pfz*%{vp4JuTf?@3{uHKaXjI)7x02PdxLrLIvcrSb z_FyDgJ*?d&Ky@@PK+9;2NvA0=pnXfq9*m0{_~{JT*S)O{$A^aFF>t|pD~VrOd8SEc z$w~t&w}f5u6CN#O&3EQ<=s0I5irwqw6DUI{nP`G6&X$$j1O6}=u*1Opvz5q zpTJt45w0UN3_Zi~m>r75l3T3(GWAN6LZU=5^cR+4lllmrS01zWW}KL5i&y?GCkh<# z(~>xM3I=d$(n-V3RT*N)83Rn!#|oSP^;1Oh!)~T#aGznEHRZ~IG!msDgJLGd2?#i8 zq<~y7TL37mxB5e=s10vRM}C31O@2aZERIHc{e-Cj1b#z*@|4}7M1V$UuR;4HB=$2c zQur63z|>R#(n~!qp;68SQeprQUXw?=JrdiqO$B~{uA}!GbiGL*pc{~V^JRdpWyl8` z_C=C5u1`yQRl2e$CR!L*_zVLCq(L{ODPvLFHaF`SbPGaGv2==ya+Y(+Z*F386MC2YSyfD-BZ1V zXVx>>vy=jMBqSx#oh9ZU6BCakj=X^F7)-?XhI*qGQmZ)XvnEZ@b4(?6TqWQNH!El@ zrS3d$(j>j$OzLb$DbJqNj(B~E>3GM{v92Q&g}H{TzMY-z9+B#3%%H!>Zb#Y;dX=em zrs;3RngAW8zY@*9CeE9VVaLl<=kpEvra|8_>D%<3v`lW3)S|F#MU6T6o=Ent<<{^aJ`EL{oS$lxRUh z^{sBJY4y|JG8LV2ip=;slm4FmK}w;nUuZDAW^2X5F4SBLuBzIFA2Tgzi;aY$k-qBT ztWHE?^`|ENlN5srB>WwNR>l?m^ee@SD0`gbTPas{Y^ekGm6ubIyFYNWCA1a5Xg$Oia7Ay8o-k$h^U&6`X7`2m;Mix!j2=KIeEEor9c`fSe|7KGRhnDrb)l2x1{}$ zKHc#$IG^jD>AK@Q!45&fPZs{cq_@#3QbocF^>ytZ>WxPuVJSqi`dDna$mC-70qJmj z7{#~|_)aZnI#klKv|^1@PaRpf)MSIPnVJ)ZFt)WG{ax6OCqTF^Pmz#~64aZrEww>w zN#AKo0h4FRey+67idwc6;BuaA@Er7FTp@-kD5N;4OQ<_y?PW?$tB}WaoZOzPp|_yt zc=HtU3tKTLSDHMR=OH~v-z-~D0D&5@#7%r@6y1kv*#eUn@*+f7B)KWl*Js7l9(9*c zTx{|ZUW!5;Np_)*$vOm)jtIACD37X93ywGW1Z7+)zy_mIIv%b9V`nUx8Xk@(Y^!hE zu$9P3{#-2{{sylw`D9+{l7PHW1Egt$bvc36r*~R8yI^* z=}ZJySItY_OEo=|71vWuUc;w3T-##9DLbv&X?f8C6UEY@<~Sno^Q=+y&MG3vTdG7=Vr+<;3O+$aYy#|}-LY`nqECZEeVfhk9P zWN0w8=82jegfk$oz_`HV7G4K%B``dzlQ1+x4U9YC&)s5)h+_~e5ja^r4Zs~;MdzNcaff%|EX*uogP&9=U;A=%SfYl+i zwKX-=YbAC_Fv;q8I27#;B_eXK2Yqt3fqrRSEu0lge+zi+ZMlUg6nIiMRSz<6OzB2P@I*~Iq!y9>8-uDW2_!AV& z@~3v_RXiktQk`K|aDRb`KCB0fbJ9VocLm66IS!I*d{uVAC=v&w`3@sV(V1;Os2BAk zNnVX!ErXb2eS@z}pA{%@+&z|)A2UITz&(Z_nYmzCxEW0=mv-E&o)W%<-rfQTOQxCU zkt0pTX*@K37v!JI zD^uhIOSg2OGX*yC5Pb5A)KrU5LT5-{LM>B6vLpB%kPs=SXbSOUp6*6nt(-P_s30(o zVKOnF*W=}vNmuMC@KEhB{J}=*F5qDvf|BerVd5mC9o2aH(15JfUVX-cqMl9C_a&~ev-SDAs^sB9*>y5{vh$G`1?<>r@xglqo zN;Kl0xBuz-Ohwe=UQj1*U#nYSS2b6Z=rp3ZxnqV#E$HK(Oa;yFo&mc*tAk~WQ@91m zRo9bTG|Wis-tBgQ+T~eO;BZ30KO;6-n{cN1H2A&S(p+E@4~rG3yDh5jUfbLSPFIIlc3f{Lno^*7>WagH0M% z9PrEDC(sp7CBpj9aIw67%iHMVipc?l`|6w9Ma=#55js_(i$Ae7vZy@B3dVJByhEu zFXTmpsL`~$QW^Tuo=}h7d-ikYH zBk4pJhN|h5dr>F9`F`C;^ zS3gP%M4VzJ&H_kGv_rRMay3-su^^tugt;KKC4W*NvRcP2iyBD~v~O&8H3>Y@{92R{Glrc)tiBlXZm z+J&c=;qGz@(G@gES5ks{mGTQ5@wLiOgm>^xSLM=06&3RW zHE5?nVImu#rD!QW0a;CZ;n4eG^Q&RoYcTsdx{9u+efT8fX1alHrJEI){fNh_Xf9vQ z?<0IQLMC6qSHh)lr2vPx7h^!fh57)_-4O6^FrAkf52tElKLYBT8ex8b6OLCXzVY0xr*F2$Jq<=uq$ zV9`8N#-Iv5fY9;xly=5o?O{4BW;xRS7?pQO{K4H`p7b4|S9*%;x-fE7M*eb~zWxIJ z^&zEQ0CDr8P7sbeJ_O>AV)S9S<0A<5$Dz#=3c)j=X8?2KJdCxosf@4UghD2$@F2`y zq@PyP98R*W9nz$t4uf8Ni^>do1#8dZlp{RP2PzUt2PKH!Ndh@WW&o+R9rZ_PL4ENk zeXk;TKbiHFKOChW-J|o)KT7@p)1PRkuKZ`XG6GfH8D75<0U&|uq)sQhJOiLdktWCB z0f$i{o}~tQj?SPX_^xh}HXziu(M!lXFC&Csfp@;@3F3pUXC2f*yn`;ltLaS|p>ir+ zT2WE)7A=7jlmS${G}rch9k5I0Ua#`Z)AY0Ux>xD!+MbS=YW2+twJNzVl1oqfGxRf< zf9nMOQo`|HC+lB+i~^0m`j@MGlXZsx_F^Q)dVG{|9G#8gBn9ex_3NnWgxA-h>Nk)e zz6nS87G{2%7SMOF^1E331FZfYRR2DmNk2q|{E@3>16*Q+_bP*~*9w>61H^r(p-u%^ zM!vVP93R@k*+&fC4+p0k%hnrw&6}#EUB~a&YHtPz5_PlP^eWcMl*ieM&5t4IPax<| zl@LxQpY38jTVuUQUaxDqyFgXqdP!~Nzm3y>TwMDiy>TzinxNkxxBb^-?F;lq#_*LO zPxKms_~&r=UjT*I6(c9-E`b3pRC1kj7a-gGp09^RrABN4AMxxmWZ3_PWBo3-G58gd z&#ztVFwqseOwkn~%lHF)0|>gw9HPI?H)GEuxxFl25od)V{`KFg_nxszWA+=KLo? z!PBGi{OM?d#uEO7mhQqFV^`&pTC7M({hTTwJ}F+61^WrpI`6Vvn^vRrpXfoq+(mz; z&ig68M?3Eb^pV``pWy1AF+OP$*G?XFtX!k`Na4gBmydjtFD4=X&27kN$*3#S$o7eCIS{ihvjyat~$g6UNIqR4e%niqc;WmE4t2D^3<}phDMomQVrG;pjGkLDcjesgQ z0;=3RSCyCN%P!OFW-wU}UwiOWd4OPBTZq3a%eKZSii_@% literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystemProvider.java b/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystemProvider.java new file mode 100644 index 00000000..4d3e0ed9 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jrtfs/JrtFileSystemProvider.java @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.channels.*; +import java.nio.file.*; +import java.nio.file.DirectoryStream.Filter; +import java.nio.file.attribute.*; +import java.nio.file.spi.FileSystemProvider; +import java.net.URI; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ExecutorService; + +/** + * File system provider for jrt file systems. Conditionally creates jrt fs on + * .jimage file or exploded modules directory of underlying JDK. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public final class JrtFileSystemProvider extends FileSystemProvider { + + private volatile FileSystem theFileSystem; + + public JrtFileSystemProvider() { + } + + @Override + public String getScheme() { + return "jrt"; + } + + /** + * Need RuntimePermission "accessSystemModules" to create or get jrt:/ + */ + private void checkPermission() { + @SuppressWarnings("removal") + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + RuntimePermission perm = new RuntimePermission("accessSystemModules"); + sm.checkPermission(perm); + } + } + + private void checkUri(URI uri) { + if (!uri.getScheme().equalsIgnoreCase(getScheme())) { + throw new IllegalArgumentException("URI does not match this provider"); + } + if (uri.getAuthority() != null) { + throw new IllegalArgumentException("Authority component present"); + } + if (uri.getPath() == null) { + throw new IllegalArgumentException("Path component is undefined"); + } + if (!uri.getPath().equals("/")) { + throw new IllegalArgumentException("Path component should be '/'"); + } + if (uri.getQuery() != null) { + throw new IllegalArgumentException("Query component present"); + } + if (uri.getFragment() != null) { + throw new IllegalArgumentException("Fragment component present"); + } + } + + @Override + public FileSystem newFileSystem(URI uri, Map env) + throws IOException { + Objects.requireNonNull(env); + checkPermission(); + checkUri(uri); + if (env.containsKey("java.home")) { + return newFileSystem((String)env.get("java.home"), uri, env); + } else { + return new JrtFileSystem(this, env); + } + } + + private static final String JRT_FS_JAR = "jrt-fs.jar"; + private FileSystem newFileSystem(String targetHome, URI uri, Map env) + throws IOException { + Objects.requireNonNull(targetHome); + Path jrtfs = FileSystems.getDefault().getPath(targetHome, "lib", JRT_FS_JAR); + if (Files.notExists(jrtfs)) { + throw new IOException(jrtfs.toString() + " not exist"); + } + Map newEnv = new HashMap<>(env); + newEnv.remove("java.home"); + ClassLoader cl = newJrtFsLoader(jrtfs); + try { + Class c = Class.forName(JrtFileSystemProvider.class.getName(), false, cl); + @SuppressWarnings("deprecation") + Object tmp = c.newInstance(); + return ((FileSystemProvider)tmp).newFileSystem(uri, newEnv); + } catch (ClassNotFoundException | + IllegalAccessException | + InstantiationException e) { + throw new IOException(e); + } + } + + private static class JrtFsLoader extends URLClassLoader { + JrtFsLoader(URL[] urls) { + super(urls); + } + @Override + protected Class loadClass(String cn, boolean resolve) + throws ClassNotFoundException + { + Class c = findLoadedClass(cn); + if (c == null) { + URL u = findResource(cn.replace('.', '/') + ".class"); + if (u != null) { + c = findClass(cn); + } else { + return super.loadClass(cn, resolve); + } + } + if (resolve) + resolveClass(c); + return c; + } + } + + @SuppressWarnings("removal") + private static URLClassLoader newJrtFsLoader(Path jrtfs) { + final URL url; + try { + url = jrtfs.toUri().toURL(); + } catch (MalformedURLException mue) { + throw new IllegalArgumentException(mue); + } + + final URL[] urls = new URL[] { url }; + return AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public URLClassLoader run() { + return new JrtFsLoader(urls); + } + } + ); + } + + @Override + public Path getPath(URI uri) { + checkPermission(); + if (!uri.getScheme().equalsIgnoreCase(getScheme())) { + throw new IllegalArgumentException("URI does not match this provider"); + } + if (uri.getAuthority() != null) { + throw new IllegalArgumentException("Authority component present"); + } + if (uri.getQuery() != null) { + throw new IllegalArgumentException("Query component present"); + } + if (uri.getFragment() != null) { + throw new IllegalArgumentException("Fragment component present"); + } + String path = uri.getPath(); + if (path == null || path.charAt(0) != '/' || path.contains("..")) { + throw new IllegalArgumentException("Invalid path component"); + } + + return getTheFileSystem().getPath("/modules" + path); + } + + private FileSystem getTheFileSystem() { + checkPermission(); + FileSystem fs = this.theFileSystem; + if (fs == null) { + synchronized (this) { + fs = this.theFileSystem; + if (fs == null) { + try { + this.theFileSystem = fs = new JrtFileSystem(this, null); + } catch (IOException ioe) { + throw new InternalError(ioe); + } + } + } + } + return fs; + } + + @Override + public FileSystem getFileSystem(URI uri) { + checkPermission(); + checkUri(uri); + return getTheFileSystem(); + } + + // Checks that the given file is a JrtPath + static final JrtPath toJrtPath(Path path) { + Objects.requireNonNull(path, "path"); + if (!(path instanceof JrtPath)) { + throw new ProviderMismatchException(); + } + return (JrtPath) path; + } + + @Override + public void checkAccess(Path path, AccessMode... modes) throws IOException { + toJrtPath(path).checkAccess(modes); + } + + @Override + public Path readSymbolicLink(Path link) throws IOException { + return toJrtPath(link).readSymbolicLink(); + } + + @Override + public void copy(Path src, Path target, CopyOption... options) + throws IOException { + toJrtPath(src).copy(toJrtPath(target), options); + } + + @Override + public void createDirectory(Path path, FileAttribute... attrs) + throws IOException { + toJrtPath(path).createDirectory(attrs); + } + + @Override + public final void delete(Path path) throws IOException { + toJrtPath(path).delete(); + } + + @Override + @SuppressWarnings("unchecked") + public V + getFileAttributeView(Path path, Class type, LinkOption... options) { + return JrtFileAttributeView.get(toJrtPath(path), type, options); + } + + @Override + public FileStore getFileStore(Path path) throws IOException { + return toJrtPath(path).getFileStore(); + } + + @Override + public boolean isHidden(Path path) { + return toJrtPath(path).isHidden(); + } + + @Override + public boolean isSameFile(Path path, Path other) throws IOException { + return toJrtPath(path).isSameFile(other); + } + + @Override + public void move(Path src, Path target, CopyOption... options) + throws IOException { + toJrtPath(src).move(toJrtPath(target), options); + } + + @Override + public AsynchronousFileChannel newAsynchronousFileChannel(Path path, + Set options, + ExecutorService exec, + FileAttribute... attrs) + throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public SeekableByteChannel newByteChannel(Path path, + Set options, + FileAttribute... attrs) + throws IOException { + return toJrtPath(path).newByteChannel(options, attrs); + } + + @Override + public DirectoryStream newDirectoryStream( + Path path, Filter filter) throws IOException { + return toJrtPath(path).newDirectoryStream(filter); + } + + @Override + public FileChannel newFileChannel(Path path, + Set options, + FileAttribute... attrs) + throws IOException { + return toJrtPath(path).newFileChannel(options, attrs); + } + + @Override + public InputStream newInputStream(Path path, OpenOption... options) + throws IOException { + return toJrtPath(path).newInputStream(options); + } + + @Override + public OutputStream newOutputStream(Path path, OpenOption... options) + throws IOException { + return toJrtPath(path).newOutputStream(options); + } + + @Override + @SuppressWarnings("unchecked") // Cast to A + public A + readAttributes(Path path, Class type, LinkOption... options) + throws IOException { + if (type == BasicFileAttributes.class || type == JrtFileAttributes.class) { + return (A) toJrtPath(path).getAttributes(options); + } + return null; + } + + @Override + public Map + readAttributes(Path path, String attribute, LinkOption... options) + throws IOException { + return toJrtPath(path).readAttributes(attribute, options); + } + + @Override + public void setAttribute(Path path, String attribute, + Object value, LinkOption... options) + throws IOException { + toJrtPath(path).setAttribute(attribute, value, options); + } +} diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtPath$1.class b/tests/test_data/std/jdk/internal/jrtfs/JrtPath$1.class new file mode 100644 index 0000000000000000000000000000000000000000..7cdfd6f6a42bea2dcbd71189662690c9c7ee8f4d GIT binary patch literal 1391 zcmaJ>T~8B16g{(T*|siFYefY`)QW9UR{T~FH3Va^6k@RvAB;m8+O6ANvpY2!U;Hh; z_~L^miisxr?vFCw*?fZ=F+^OE@?G=!|3k07>uTnRo)Q`Zr34X0t~_r z8#sbd20c1vI9@0h_o`aQQHF`2)~>W{v+CBmjn<+qI>M2QFB{^yv|J~RF~#jTLosl5 zEZ5w!Y+*hSd~?OIU)`lm?UgS@r!Qt4sWh=XY2Xy{3~@)iq*_M`RFKl92cmSI)iKGC z{aZ+xy1}LEDGGZLDAoyi!QB)L!xhUB)oy1)cx!yaCQG*BHn?5qo~8DYF|OLlFun(B zerA?BxGZGL-CX4!2~E{djNamYHDE!CKV}%LN#1z2%%4Zl1D^1^Hj&Kzk0RXwPjuWD zR9Nnh2z?iXQl@HF)8Vq~k;_~N(eDsif2vK_ zKqjM}7rnRyjeR&n_5!W$2Ohw1Y3egr=?nBy>@x;G(vgNDeTNXEWf>`L2}3lO$TmV} z6oM(7rCF^MG{ZSsCm8T1Lz`)s^i?^^Z Md79G%s}!Q&ZxcKsqyPW_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtPath$2.class b/tests/test_data/std/jdk/internal/jrtfs/JrtPath$2.class new file mode 100644 index 0000000000000000000000000000000000000000..f3595108e2f4d49548489f02d560415d0cb75a70 GIT binary patch literal 737 zcmZ`%!EVz)5Ph3CabjHJmO?{mX`yaO0AZ;T;s8Rbf-3?^iki??>S<$dn@x?4)=v2Y zeuXn2A%sxRh>t?dS`pG-22%q0CSp^KMIG0`ahGP+A43%d=Bx9L9&&du*YAc^zts`U6o4gweHQ>XDrn%5b0v;W3 zB{iM~=lU5B&S(}>Z1t0g3dAnWgTbDT?UANssQGaaC8>;0yCNGUp^2tG*vx5@xSmL} zmq|)G?RFds)rxqUiqu)BD_f=Kz?{0iH0@Dj4eMm@5c-HBdBBtJU>85FuQ0#pZ|)oB zjlEAWUgvO$VCfPr6D;TOGnH4dh$UP{9UIspdk@=qOty%-)VQqM7k<${GPGP;^C%yh fl+pdS!N6voutnt{)S&%-9%BKd#MeQ(x;;P2PZ@6U(Kdvo8t z=brtXd+vSn?Nd)3Bcf_!q)Cct)FrK(%iB65p{~y6_VP=*A{)BP7j{LKHb*x3$wh9H zJQkVcWeQxw7&g?RbP6!}I>TKZ&FyWMg_tH3*2O1mh;+4eZk#cxf0N9bX;Bsp zV{&Z)*7!Pbui+MrkY3)dP_RT|nbZ8gJ1AnLdHHHmOWzTX#*zmdH-&S!mHD zDgwXTL!BFiL||Ae4@xX5r7}Ed+0@)s1&O!{YbRC9lgSoMp{c;Cy}3J5+u0i0v1Eh& zSPz_L(K%EBj(2Ze->sR;6vWv6tP?JsCn_)}_>yNyY$0gg=bEUFgXn+{`ztQx`le5T=rwWmXNfgoGUbngEO z*-5KRS_H+7>t1bpduU^GdsWxQtsSAxNX?Fx(3VJBxYMM?Oe5m`Y{AXj+ScA0>he<^ zxxKVhexOHoLs9RL(Qj5B%8|ZaMn!6(1 zjctP7fE2Ix(pG3^S(yymZqW|f30N)R&Pa1xCm`e`vZ)#t*$}#PYpAm&G-J|glRnOr zuDJ}NYM0b>b%nc3x`laJHwIu^`ZQ(&=z{|n!aqmCE4$jD=82sh z!8^Lp8H$txzV^?bvgp(F8F-79O`(>}wg9I(Lt`@10vJ>}B9ibTE_Ca#kst2L-vV*kI(@4c#ce6(6ou7Kb)!}y z=zP(lJ>pp{_?Y_Uj!<#T=&MW_n&z#Mwst4jLsCP#Kwn!|s6O0TzqP&H z4hJ#ab=cjH+ety&=_H&#Y|#<1PainHw7Cm9okma5QInpw=ovZ&|D{n#QZIN@CwMaz zolgG*qoh$#;m7G&A?&%7v|<1iNx<;y7ClejU>X7p;{lFo+-XC5ycg!oqZcjuCVk5e zV7AdzCyL3jH^xwdrlD#zo~&-@nTAKjJtBHLeB^alMBbAg}L(#({V6nS(bIQN=(v;z9IMZXdIvm@w|4T9Ql zE&83HmJS%p9n^%i^6dALMZNwvGBp1+sWX6-?i`G<&hcBR0($WW}p#`QdZOj%cadO^G&E1=- z!>u9dc%wXVTkK&|9DBH93yg3Df@6|Hjw)oWmwf=bUBn#f@^YGZ@NF>KZZ8kPc*N7T z4Q-*WZj;ladZIOYWoP%+EnC7}h*(Rugu0p~bBb}+&qJ}o;7q2m$(q%u)k)xwTkJrF zgn5|7K^_i5x{!2W_0Yw1S*mjDp$(y~ZEc9Vsd+>K+(pRC274ZzH|oD)DxzU53hkU> z@<@2-)4TX_Q~W%FM?oNr6n_j5J-tzjpz=7+;?X++ha`Fbgu6dC$=o#Ewa$Q~zp84IH!6O*hPimJIb-Qr4~0e9OO z+FskaWorZm5^C;XI(tz1oFFbTiVuPU&0-oquvWxaXHVegnLI}{X)aUEpi`w}&M9!l zfuFD&oet*lJd3Ltyz$$9M|cgE4hmi`=JNP_i!a~>$P=8{7!whk`r1JOq>5Vf?hL7Y zk`8pw@bf}mWOALwi@9E$&46Z=G-y>@Xgl01mYgv}nIsqwI8?mrjQ$Qgp(UC)tP)(7 zTD**x>k!=B8iNl;to|QPFgR;Odv!v#xOt1D7resamAnex5M-^uvH>$*_Yr1{IkM)c zS!p8^2oBNzT@Ss|;0rBolFEiBv;&?R3#~j}WAR0d*e$uXNT&gw0s1y)P@GSJ*~0GlU%d@-qOAX;nig(k~n)Ye-DB6GI}BA(^PVydf0YEGx}~*|nB-TO465 zo5f=atw?Tc%p(84FiV(KW3=7k9gL7%V5t^ai|8+Xlz1)#(by6 zU*fyq!eqJ?;T6qY@MTPcXH92>y5Hivr84TV!?2I<;d@QK&*J;J=d>wK95#)7q*PE0)*JTe+g9!Q_YgDMUO{ z3o9PA_%S|cua0A$0U@Zmp9hSO6G;vjaYb@*AdoEcA&Z|7rVO>2QoEr>2NIJ}ohVG! z{#cGvACBmndCUY%KHRUjo~s>MTkB36WURNJdl4e|DL!iQ(-uD?=2DzIRoo-aYwm7q zNyb}h+ubo_Og=8zojBN7gozJN8Y%QXC#mz-FkwIboo0|-(&OjF-o7CTXsVul1PkI9 z`I{zx%i?eIONk4Kc#?|zSy-i)nDbEX;+OfmCV$W3?=#8)AoJbgnL045*S2H5B zt8mhqYU~a1KP~ESFVM}fLS+!C#{y=rlq_JMG)Vn z(2n_S8`~n#8nvd{RH%hmwvyN-bFV^0#DyKuO26{cT2o_~7s?<;I! znkp-$_!3`b&>bphso_!$Gdh}g2&N;ktD>@*ruVb^WaS&s-)b!uC^?qOmCC-qE7XqK z%r$fxYYIN!I7G1sX{dg z!(fwAOqV){6z~QgRcxseDJV1!L)|E3w8oSRrGv;;ENNI(Sn6DL9xz1>aB*`tDmL!I>gq{ayDBX;L$u4RTRXq@ zg4z|*f0m_YOMmaCwv9;qx;Kkr&9zjObo4D)yK-q&-O>eB(pqh)`O@lNu(obVW32gn zOI@I$E?66DtF_cZ-L=kct6#ZTAk(POMYC5e!91mF%f?<=G_i1!ptMX#!0L6t zvY#eog{4*s99Ylds^yDhP@~YXTqbF<)N1{3fqp1W7g_3K(qz@GU0J`prlDr}s+#%o zV6COr=?5S*_Q0#Ki)dEPoiM9-T#58*wNyxYfp1Hz7gXt4Hd<b?3Vuu;vs)j&kS~erqcR(1}nuQyxm3Syy zPOxjeA?((>#c0*rssIw-UWL{~_f>&Fm%V_ri8R^1SE zwhbr2pG5bfFrieSg%wyZVpmFH7qGG~g#$aHq+saaWFTDt48fw>lyw+)0UVNuZPkLT zVBCp^ZXI92RDH#H1a#~$#lail_0X=wQzVWf)*?@uGO5@M@0Kcy)Os^w_#j1O)oRrj8u1F2&Nl1SLaD#M-VVqh@i51D2R{b~g zN7sI_bS(jJ(|-e4_%sO8o=8|?NP^8E$(0r`*Nfa18yR7!)$piA>B3yC(~dqR13s8J zkQIr%0+M4lICXl7-!e=0g0|LHu}rrlSkUQykv=)`s*2Y00I)b!Xs79Ft4rBOg{--T zlH=5V0|s1dBo@2HuC~CSN2Tx}Vc-DHEa9oCo`qGSst{XYMQiV}w~%C(DLrCE@4>r) zZJrIfJdSPR!MjEwGR^u(9cPxNbkn{{BrjF4kAVB>0HmsL3gxF&xOvXB366M%jfie> z9A2stC1#e;0$)t2prhC~-3oh|Jpkarz}S<<>e`4{F`&@+*8d8cL;c`1iV)l#5xu~| zam6HA#88P>$h9@<&h8d_P)^j;V?Ij!gf4Ca^g4$EP2vAVja9N1jdg4Wc%S5!nZ+q| zC0Lb^e^m;OgZEFBW-^niqE0Bq!46s{X1Xv1h5xD)E&O-N%%E;Z3h4h+>XN5+b?CG* z)#b(OyFibzG3AziQ1^bhTtZJ%{X$Z;@HQBk2Pf5Z;j!Ov@s8sp z*@eEy#Wd29SSR<4>9Cz7I04%0J-1sq#;V4m@p(k*a zO(L3%T^Seto}!Tykkj&5rDn?cbzJAkNoak=Np)ODNd-Y)H{;5x9rsFgpgo-O9R&p4 zZ%ax$N(j3B(v)`85Oh202KtIZfxcp)udi6s>nj%W`igbCzG7vruUL)CRmy7mJL+iq ziV7J~V5C&-@O>Hna26Ywci}EXiVR#w6dfj`sQ9boD=IlcL%vEGMf_C?K8{C9b>nk5 z$?CldY??XUYfh-G!Dh@hS86 zkXh1$zm%zsgsCsUpaqz^ma=gQdNeK4Qy1BwVpETaO+6+y^%%7slpAUXCM_k^2hqAr zVw3Vr9Ji7i?gIshZAw2cpnxi*k2!dkLqUWlchOfU;~;Kq#&~pNy~f6}J2=>6$WeJ` zaGf(aqo|ig?x8fm@byyeK^8zZnL{-f8^Ea*sMW1X0GMF|)C3sB>69T=H3#y;2=hvwjjN@1^pYISLI$2aggr2{zI%$F;7P&UPK9 zbK_{8g%iJo0k|7679n9|m=AwJk!IMf%KkL}coV^Z?vvORmWv zS!4&{^Bf`iV+cPC^ldf37~F3I2HO)P=Z~s_6i*!}{{Y#d{}F+ba|c;Dn)bV?_$V!G zI!bj-hp9euNiQwS>7|vK7ve^Dz?WWHeV8sjE?;xXX4&Iht@~*xS|Iz0vwO(W4_)iZ zW+w_ZH*a8$T@FmH0F76|I1*i*O~*9YeFHS~a_~un6>%t%yDK#B z=F&8ECGHf)1nqvBix#;uCZ42R@DW=~8B%q&IlyV)fOwOu9S&sVY69;eZ%*#rG%b-0 z%~3YA;09tJgdekQDEleh;YNk4M;qF#+_DN+A~*7au7TNcBiQjdxV4+;0=kvz>2_+Q zFH#Hbg*x4-*)bcauXETTLcBW0j;qxtG&`j2D$S01I$JZw!06$cF|H_MhEG0;y7oz& z9iy9N%K%Cw-gq`xENbKj1-_!wyi~#3;osA>KZWjT8u>;<9vt|FIqSX zw-L-1$5jG$!}lcEd{o)mY#oCNErW_B+rRCW?uT3If%knNLAgt8+BHpZOFm3`z1rnW z`ZyRRq^!iGo1vX`#hIPGv}F%j#hH;_+O~(rAEnEn?w3bZ9^@{|ywXPDFkN++u0F2E zOoU6S!$WvBPi9+P@e$e;H~i7Si|7$}m`Cx_*kgE`=@6YyPtanVEMH2!3EW!gNXko# z)pZC;wrBE_ags(M4vftLx_D#2MxVEWkK*@k6V1#mb975=EyK~SyjIaK`8F#T=9bs$ zLPN3cUE$7^n`6>F6L(^oL3e9~r$>L){qY?GJV95`vya@y!$yS}G=r`KG+yB61xxP zw`dc+1Wo)74xqnGpT!CF&(Zhk7W$#)(FVB9Jixpjn(G4h4E0Ied4vNo4Zn>ZLx2}e zx=owD!mOWHH=v(^IX5|DD`=hi6x!UF_gn|cW-3;nMw_X1C7Zk_DIeND1b<`kH!~dbiFzdx+k7SXyB`h_s$PP> zeKb1Jo$Q8s0opBbN19QO5gC=PY*(pP&&9Y*tZ-+$f^Ju<6E;Ug=aklHfVA&*Sj|p+ z9uJ|w;r0qQu(%y^b_YF2Xm5pSRCt5lpm~6X7nKCPy|jNXK`nf{yb$a==;dv#@CALI zO;8R$I(iOJcF-><0xeu-1-)ghu664w{9?O7|6#hfGA-!4iwd&S#IBY#W~cR1PtbpW z(z4Se&_B?)%h%V__l6BDCp%4mIglKUyQ2HtKPA?-K_SjmpTnICI6bL8uQl~~ zdP3cVI}h-C(AHF7*`sbon-{oUuXf|k2Mn)NU%;Io_^nd6s9PybYxF!CdQ!4UP797Y zMKj<|B(pq0WBZT+`*be(l$}vZJN^-6xj&?0?1Gcuq`J}W(ZCijwm8l+G1c^?gaGy@ zxL~(Ka)!Jy>kM8Fa>YpV9MjlK!{jcS1Dfz!E+g(ibpFce2|)8~pqer_shqiz1>w~e z$2A%-Z3%r>*mfD4#V_`z?a)>$I};T(wY!M=iWaYPt%KIqm)fn%8s+Nra4c>g`Acop zEw#rii>W89GetYgkns}_gRFxz0=kpUBf;Zr8qYa2n{(*`&ZCQXG_~*;YUg}Sr@d;p zBC0P)fgF87@@DJHY?`CxYp)stUVMOJNv*7Ig0?Kb$p&EW;KoNH+%FQPSEM;o~wr@NNYb-bKD%?&uzvV!i${e#>{FYtx*BW_HP)hjVs zy%Lkv*Bx19(R1o{wGEsejr{A2kdO;e;#RdMCacl-ZGlrXQOim^U_PfqPQyH$<1Mfy zhI1~CZPj43q>&j#P~Wc=8_!TdFTK!9-%j<4AJgdBiLtX@mSIQ(2lZZz!JuCpOa<9~29P-R<6yZNj$3${2Uh;Lu2@{d{fVoA z;^f31RT8MtrC5-6Ayez7bl#dUl@lZYa-_OLc&yFPOOR(eOb`>{?PO=-D;*(D5wmM7 zeoh=z!BKiGn)zq`OwzI^3C9Sdx!JFdi~EXuODAUn7KdNeOVlj~v*z@Gi#%><0O>UZfkH$TQQJWz5dYIY5)8A#ay~W2eR93B>

FN7H?$iECS9ItMJygcQL5N}c0H%k=X1j6$KwvHz5XuWh z*{-kBEUC5GN&O{==7cliI8_d=Uk3xe9tQkL8i~{5Q>vHEt73vzD?uh+dr7I;0MYSun+ci*xgBzi_q9wH3X1-=Q3Pz`Z zE^`^emDf~v$x`3wZBZ$YAQ>3tRQ>o ztvV@B28-i5q1S#46$X=i`~V#Om%*Zk;7=X_n;uKhjfswKxall-EMwI65kKNvh~zRK}G>Pyt&pF4{-lpldG{>Ul@#?SrB!SRLldXIfF7 ztJQ9tB|6aeqHacg?OqgU4Aizze>hkaCuKIKClp-WP&*$VrZj#MHun^M8s#XM_cTq! z!RJyw4v9YtX@3pUehR;c@jR{KZy>dOQIjf_nj9)}q?k@Kb^0oaNwZVRcGE?UJcl5R z?uU%+#3D%MNlf`68RCvduzT1CNHFzRX`a0psEJ^Be?Ig}Xk?NsFqr#Pw zdw?z|%Gt%*a>N2ILTCzX2e6VK z(%CrUT*W`8`TQ!?@@x35kJl0Meh$9<0%^z_2z|e#9sDa;$FDUXB^@b5a$(y5NOrh~ zJG-O_K3}EzsIVN`uI|P%z(7&DU31hf@gN;N1w@c3f}z8E5mrh7ibVc&# zlAvdohXds+d+5!e&%K{+NE&gO{mssS0O69L`wj|7I*JsjOsXmmC4w6!6YNQVd1KJC zhen{m)jCbwxfOdB^kHp$7q#0B_B2?D1Jji~eZLhrfjH!SlyzD_*{)q~mNoto2W0lZ zAfL@U|7i(|_AxR!ReL+vjF%)u-QbAM6VLH*{+!{g8VfrvG^Xn1KiQk3H|AsjD zcZ7!bp!ENMj{Ot4_P^lw{*B)rdLIh^0WE{q4e@_yJ9O|`?!$VP=wXEzs}zyun zy^<+{nk&?Oxbx_sat>wmp_1>FHJGXH$KPFg87&2*#h~wOJ|}NvUPijt_W|XdAa_>A zLdilhuyGN!xWq+u>i&%yttm>`zrktrXz70{!j=RsZHK)~DOs2*NEq*RXwHydRdLK+ z_SwYTM@#mzhenE8Nrr<~iNKPRp@sXUY|rP`rO;e4VaW)2z#f3A+}m3`{Q9Q`ig9%-9r}v4year1v+=+y00f zQm(!pGf4E$FV14Gtb9wd*e}=8EVkr&l!rDQ=D>0Eu`?U(vedccRp()8I~}=WrJmPb zkmtwd&1awbvSxTbrzzPn#4J2SJp?$ydRtKP>=EGdC|Z9SHH&K(KBl*8hi81Ga;j-o*;09Irh-SFT^@hn*HsG*lnb!#ZL`X_FBJgJ@n^W*y9 zS5GR`G2>V|{CS#g;!5?5!=HmrDpOy)xa8PuWG+Eh-T|sC3A(0My0hJfxb!}nAVPF@ zN3!^AEKjmg47nwX&%rG+ki&fL@m($?b}u;WJTJ~py;Q*hc$nHwxo}={a9@M$Il5Cm zjEdDUbsR2^s6M84_1MCJKhVw&0y!m_^K;Av4LOF@U`-BF&|R8)MJ zXUB1{75u8x@a=geg~mj_J+EFEfNw7%rM??0CtI)1bM(rVm8+Ml;->>_S?z+Xu1k=( zBdbLG<^90{;TZ$Ky8-Y%H7LBBO)h*+BX<8Bds%((C||4#!-siY zJU-a22qQEeY^MS(b(Ag>)2K3hq@>+rC#sQ5nd{d&*H?RvQQ1*CFP zL3$FY4BaQ?w<3gv)?VJA>!cDRu?(WIXMiHLgjv`BQNB5~~h0EyRt1b*bfmN(A@ACPC#?&4!ndG+$P#vZ!Xm{nX~ zdaS}_$O2R)raL+^es_k$)W-!waZRy@*`+ zn^dR1O-s~wXqkE$%kl5gI`sqWqP|F-5Ycvs;yU#cx>@~H^H2lB+_*&RLh>PD_LE1dtm+N@2Rcs@ey68ZxzbLMiO6ySDjO3r>=ksnjA`D45V zOl5OznIUOXiDXB|oI-$XOc!S3Xu{M=Z?^XkAGn{qE*w7^DqkMBpFFM#mp-iUs<_#Q zdijw`H%|ElAN;Cg6Mqu;C9zT?@Z^fP<;XVT9rUxztgEg2>gyqfJj9(3)Y zxmfbNE|eYNUp&jNSDKg~82<)u)8X>Aefa~^ll*5F4$fp$dO_H}9&!tyNyq3Vl&5}(;?U1<-Hp=dd$^v!FUBdncwfMCcpm5DC!rSbB92<#qg0IWgHsdg zLs-HoSVA97fG!ss_|*YJQ3cv&8Xh{|@XRjH2B}4&7wCs19%>YDmNAZVjPYDx zOyn}7kk2tDaV75O809?ADB}4>2`?~8d9hK(ON}X7As@zad^DDP$JB4&MV6u3*aRQu z!ErM~y`_E&o;1bU?x7sm_S@KVe*`{L&W`xOsfFtI>K%;TO_!@b!2C??XjvHhC)7g< zs8szKrYKd1Wl;mfonwHw(*}rhCQH;`F)y~UxlX-{I~RVuI8FUc{T-&ap8jfMr498r zG@=h>VW~Q3Kl+{&AMhcLbd;(7af1BtqO!@a{j9iJ>4M@cKE8sYs+$ADPN6HmX!6UZ z`qv4(YGv||`%pNEoh8@hIc4IDGhG$n9HMGw-pY|IUXq}Z} z@GP3;6xBmE}BJaGq zN-sg*%zp$U?BJ*m>l#Zy@=`L5WfU-$(@3L%#uzK$9+pvwVV^6Oy@HW6)Twd%kp{?7 z7g-mSsSg}tCTX+7JHs?l-G`&((L)GWoBG+sIlv#dcNLN5&eEaS_P)7|6I7WUQr$#yXmU@8=r!-mFbVc8rYD7#Y)J zWK4^ZF?Ap^CfH=)7XutJo&{MZ$e8A<8Wos>Gh4az3DA0RT#wL_R+GwbO4LxHsjW^mMfXy`3u*)K%Tcc4X5Y`Lhrl}Lyl97MYuv`8m z=#e4^XZVW=>OWdUqwuD|N!;1z9x~-T`)C|~fkebFoj`6VLWxrIO@|uj(x|{EKuusS z$N}4hqNML1ovLn76`@RHE1hL*qf%o#O~bX)*b%ds2?Zky$AikR6b%osP$A*Vqdk45D)& zEKr4ml*cfyC@_Nuc68}8Iww0L}2w*)XuM5GFlZ>2IPr&moF4A_8NJ~9wZ)H@iQ zI87x34OV)8`E;rm8%)&$4aOT6Ao0wD@vDsksOZ-|(qQ%=QMH+Owqr6_+&oK9^{P@S zOPp@@Xz@F)6XZ1vWIEbbc(aaU#I8*4Rg?ERTPsiSKLV2j(~qcgo>0>RRe{w<)XXQ; zoIrEnGJQAiki!2tS3jX@4yoxrTo?EbsTy1tWvTijYUvZILEo%;LS1-BEjXka@NCT? zwdjz#5O)_JQfsnQGdki+%OQ2K{;~>RHXKqdS*lGxK{BK^=r4G}eSyH!?j|EJd1aF; zFlA+vJ1})+lP7TY$|f@~ZDo@;aL&r6fG1FaPcv{XKD~kS@aYRo$EQC~h0nCWJbYS# zYJ3g}%*W@@Kn*_A1Lv=NLV4nqy@hbLL^BXduSYPtk;WNcpfcljIuCWOxyBu|z}SZc z!hTw9+(WI#z0_$uKoR51^l{@sy4rXM3xh}LR^u@`U_7oc-aj?XY8X;6k6YYjpa zQ~0^X5r)Lisc_#JhS%_Wd`23sLp(knfp+{eh8h7Q6YW_>&=}#uPc%wv!2ACI0a5K4 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtPath.java b/tests/test_data/std/jdk/internal/jrtfs/JrtPath.java new file mode 100644 index 00000000..5010b653 --- /dev/null +++ b/tests/test_data/std/jdk/internal/jrtfs/JrtPath.java @@ -0,0 +1,949 @@ +/* + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.io.File; +import java.io.IOError; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.channels.FileChannel; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.*; +import java.nio.file.DirectoryStream.Filter; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.BasicFileAttributeView; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileTime; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Set; +import static java.nio.file.StandardOpenOption.*; +import static java.nio.file.StandardCopyOption.*; + +/** + * Base class for Path implementation of jrt file systems. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +final class JrtPath implements Path { + + final JrtFileSystem jrtfs; + private final String path; + private volatile int[] offsets; + + JrtPath(JrtFileSystem jrtfs, String path) { + this.jrtfs = jrtfs; + this.path = normalize(path); + this.resolved = null; + } + + JrtPath(JrtFileSystem jrtfs, String path, boolean normalized) { + this.jrtfs = jrtfs; + this.path = normalized ? path : normalize(path); + this.resolved = null; + } + + final String getName() { + return path; + } + + @Override + public final JrtPath getRoot() { + if (this.isAbsolute()) { + return jrtfs.getRootPath(); + } else { + return null; + } + } + + @Override + public final JrtPath getFileName() { + if (path.isEmpty()) + return this; + if (path.length() == 1 && path.charAt(0) == '/') + return null; + int off = path.lastIndexOf('/'); + if (off == -1) + return this; + return new JrtPath(jrtfs, path.substring(off + 1), true); + } + + @Override + public final JrtPath getParent() { + initOffsets(); + int count = offsets.length; + if (count == 0) { // no elements so no parent + return null; + } + int off = offsets[count - 1] - 1; + if (off <= 0) { // parent is root only (may be null) + return getRoot(); + } + return new JrtPath(jrtfs, path.substring(0, off)); + } + + @Override + public final int getNameCount() { + initOffsets(); + return offsets.length; + } + + @Override + public final JrtPath getName(int index) { + initOffsets(); + if (index < 0 || index >= offsets.length) { + throw new IllegalArgumentException("index: " + + index + ", offsets length: " + offsets.length); + } + int begin = offsets[index]; + int end; + if (index == (offsets.length - 1)) { + end = path.length(); + } else { + end = offsets[index + 1]; + } + return new JrtPath(jrtfs, path.substring(begin, end)); + } + + @Override + public final JrtPath subpath(int beginIndex, int endIndex) { + initOffsets(); + if (beginIndex < 0 || endIndex > offsets.length || + beginIndex >= endIndex) { + throw new IllegalArgumentException( + "beginIndex: " + beginIndex + ", endIndex: " + endIndex + + ", offsets length: " + offsets.length); + } + // starting/ending offsets + int begin = offsets[beginIndex]; + int end; + if (endIndex == offsets.length) { + end = path.length(); + } else { + end = offsets[endIndex]; + } + return new JrtPath(jrtfs, path.substring(begin, end)); + } + + @Override + public final JrtPath toRealPath(LinkOption... options) throws IOException { + return jrtfs.toRealPath(this, options); + } + + @Override + public final JrtPath toAbsolutePath() { + if (isAbsolute()) + return this; + return new JrtPath(jrtfs, "/" + path, true); + } + + @Override + public final URI toUri() { + String p = toAbsolutePath().path; + if (!p.startsWith("/modules") || p.contains("..")) { + throw new IOError(new RuntimeException(p + " cannot be represented as URI")); + } + + p = p.substring("/modules".length()); + if (p.isEmpty()) { + p = "/"; + } + return toUri(p); + } + + private boolean equalsNameAt(JrtPath other, int index) { + int mbegin = offsets[index]; + int mlen; + if (index == (offsets.length - 1)) { + mlen = path.length() - mbegin; + } else { + mlen = offsets[index + 1] - mbegin - 1; + } + int obegin = other.offsets[index]; + int olen; + if (index == (other.offsets.length - 1)) { + olen = other.path.length() - obegin; + } else { + olen = other.offsets[index + 1] - obegin - 1; + } + if (mlen != olen) { + return false; + } + int n = 0; + while (n < mlen) { + if (path.charAt(mbegin + n) != other.path.charAt(obegin + n)) { + return false; + } + n++; + } + return true; + } + + @Override + public final JrtPath relativize(Path other) { + final JrtPath o = checkPath(other); + if (o.equals(this)) { + return new JrtPath(jrtfs, "", true); + } + if (path.isEmpty()) { + return o; + } + if (jrtfs != o.jrtfs || isAbsolute() != o.isAbsolute()) { + throw new IllegalArgumentException( + "Incorrect filesystem or path: " + other); + } + final String tp = this.path; + final String op = o.path; + if (op.startsWith(tp)) { // fast path + int off = tp.length(); + if (op.charAt(off - 1) == '/') + return new JrtPath(jrtfs, op.substring(off), true); + if (op.charAt(off) == '/') + return new JrtPath(jrtfs, op.substring(off + 1), true); + } + int mc = this.getNameCount(); + int oc = o.getNameCount(); + int n = Math.min(mc, oc); + int i = 0; + while (i < n) { + if (!equalsNameAt(o, i)) { + break; + } + i++; + } + int dotdots = mc - i; + int len = dotdots * 3 - 1; + if (i < oc) { + len += (o.path.length() - o.offsets[i] + 1); + } + StringBuilder sb = new StringBuilder(len); + while (dotdots > 0) { + sb.append(".."); + if (sb.length() < len) { // no tailing slash at the end + sb.append('/'); + } + dotdots--; + } + if (i < oc) { + sb.append(o.path, o.offsets[i], o.path.length()); + } + return new JrtPath(jrtfs, sb.toString(), true); + } + + @Override + public JrtFileSystem getFileSystem() { + return jrtfs; + } + + @Override + public final boolean isAbsolute() { + return !path.isEmpty() && path.charAt(0) == '/'; + } + + @Override + public final JrtPath resolve(Path other) { + final JrtPath o = checkPath(other); + if (this.path.isEmpty() || o.isAbsolute()) { + return o; + } + if (o.path.isEmpty()) { + return this; + } + StringBuilder sb = new StringBuilder(path.length() + o.path.length() + 1); + sb.append(path); + if (path.charAt(path.length() - 1) != '/') + sb.append('/'); + sb.append(o.path); + return new JrtPath(jrtfs, sb.toString(), true); + } + + @Override + public final Path resolveSibling(Path other) { + Objects.requireNonNull(other, "other"); + Path parent = getParent(); + return (parent == null) ? other : parent.resolve(other); + } + + @Override + public final boolean startsWith(Path other) { + if (!(Objects.requireNonNull(other) instanceof JrtPath)) + return false; + final JrtPath o = (JrtPath)other; + final String tp = this.path; + final String op = o.path; + if (isAbsolute() != o.isAbsolute() || !tp.startsWith(op)) { + return false; + } + int off = op.length(); + if (off == 0) { + return tp.isEmpty(); + } + // check match is on name boundary + return tp.length() == off || tp.charAt(off) == '/' || + off == 0 || op.charAt(off - 1) == '/'; + } + + @Override + public final boolean endsWith(Path other) { + if (!(Objects.requireNonNull(other) instanceof JrtPath)) + return false; + final JrtPath o = (JrtPath)other; + final JrtPath t = this; + int olast = o.path.length() - 1; + if (olast > 0 && o.path.charAt(olast) == '/') { + olast--; + } + int last = t.path.length() - 1; + if (last > 0 && t.path.charAt(last) == '/') { + last--; + } + if (olast == -1) { // o.path.length == 0 + return last == -1; + } + if ((o.isAbsolute() && (!t.isAbsolute() || olast != last)) + || last < olast) { + return false; + } + for (; olast >= 0; olast--, last--) { + if (o.path.charAt(olast) != t.path.charAt(last)) { + return false; + } + } + return o.path.charAt(olast + 1) == '/' || + last == -1 || t.path.charAt(last) == '/'; + } + + @Override + public final JrtPath resolve(String other) { + return resolve(getFileSystem().getPath(other)); + } + + @Override + public final Path resolveSibling(String other) { + return resolveSibling(getFileSystem().getPath(other)); + } + + @Override + public final boolean startsWith(String other) { + return startsWith(getFileSystem().getPath(other)); + } + + @Override + public final boolean endsWith(String other) { + return endsWith(getFileSystem().getPath(other)); + } + + @Override + public final JrtPath normalize() { + String res = getResolved(); + if (res == path) { // no change + return this; + } + return new JrtPath(jrtfs, res, true); + } + + private JrtPath checkPath(Path path) { + Objects.requireNonNull(path); + if (!(path instanceof JrtPath)) + throw new ProviderMismatchException("path class: " + + path.getClass()); + return (JrtPath) path; + } + + // create offset list if not already created + private void initOffsets() { + if (this.offsets == null) { + int len = path.length(); + // count names + int count = 0; + int off = 0; + while (off < len) { + char c = path.charAt(off++); + if (c != '/') { + count++; + off = path.indexOf('/', off); + if (off == -1) + break; + } + } + // populate offsets + int[] offsets = new int[count]; + count = 0; + off = 0; + while (off < len) { + char c = path.charAt(off); + if (c == '/') { + off++; + } else { + offsets[count++] = off++; + off = path.indexOf('/', off); + if (off == -1) + break; + } + } + this.offsets = offsets; + } + } + + private volatile String resolved; + + final String getResolvedPath() { + String r = resolved; + if (r == null) { + if (isAbsolute()) { + r = getResolved(); + } else { + r = toAbsolutePath().getResolvedPath(); + } + resolved = r; + } + return r; + } + + // removes redundant slashes, replace "\" to separator "/" + // and check for invalid characters + private static String normalize(String path) { + int len = path.length(); + if (len == 0) { + return path; + } + char prevC = 0; + for (int i = 0; i < len; i++) { + char c = path.charAt(i); + if (c == '\\' || c == '\u0000') { + return normalize(path, i); + } + if (c == '/' && prevC == '/') { + return normalize(path, i - 1); + } + prevC = c; + } + if (prevC == '/' && len > 1) { + return path.substring(0, len - 1); + } + return path; + } + + private static String normalize(String path, int off) { + int len = path.length(); + StringBuilder to = new StringBuilder(len); + to.append(path, 0, off); + char prevC = 0; + while (off < len) { + char c = path.charAt(off++); + if (c == '\\') { + c = '/'; + } + if (c == '/' && prevC == '/') { + continue; + } + if (c == '\u0000') { + throw new InvalidPathException(path, + "Path: NUL character not allowed"); + } + to.append(c); + prevC = c; + } + len = to.length(); + if (len > 1 && to.charAt(len - 1) == '/') { + to.deleteCharAt(len - 1); + } + return to.toString(); + } + + // Remove DotSlash(./) and resolve DotDot (..) components + private String getResolved() { + int length = path.length(); + if (length == 0 || (!path.contains("./") && path.charAt(length - 1) != '.')) { + return path; + } else { + return resolvePath(); + } + } + + private String resolvePath() { + int length = path.length(); + char[] to = new char[length]; + int nc = getNameCount(); + int[] lastM = new int[nc]; + int lastMOff = -1; + int m = 0; + for (int i = 0; i < nc; i++) { + int n = offsets[i]; + int len = (i == offsets.length - 1) ? length - n + : offsets[i + 1] - n - 1; + if (len == 1 && path.charAt(n) == '.') { + if (m == 0 && path.charAt(0) == '/') // absolute path + to[m++] = '/'; + continue; + } + if (len == 2 && path.charAt(n) == '.' && path.charAt(n + 1) == '.') { + if (lastMOff >= 0) { + m = lastM[lastMOff--]; // retreat + continue; + } + if (path.charAt(0) == '/') { // "/../xyz" skip + if (m == 0) + to[m++] = '/'; + } else { // "../xyz" -> "../xyz" + if (m != 0 && to[m-1] != '/') + to[m++] = '/'; + while (len-- > 0) + to[m++] = path.charAt(n++); + } + continue; + } + if (m == 0 && path.charAt(0) == '/' || // absolute path + m != 0 && to[m-1] != '/') { // not the first name + to[m++] = '/'; + } + lastM[++lastMOff] = m; + while (len-- > 0) + to[m++] = path.charAt(n++); + } + if (m > 1 && to[m - 1] == '/') + m--; + return (m == to.length) ? new String(to) : new String(to, 0, m); + } + + @Override + public final String toString() { + return path; + } + + @Override + public final int hashCode() { + return path.hashCode(); + } + + @Override + public final boolean equals(Object obj) { + return obj instanceof JrtPath && + this.path.equals(((JrtPath) obj).path); + } + + @Override + public final int compareTo(Path other) { + final JrtPath o = checkPath(other); + return path.compareTo(o.path); + } + + @Override + public final WatchKey register( + WatchService watcher, + WatchEvent.Kind[] events, + WatchEvent.Modifier... modifiers) { + Objects.requireNonNull(watcher, "watcher"); + Objects.requireNonNull(events, "events"); + Objects.requireNonNull(modifiers, "modifiers"); + throw new UnsupportedOperationException(); + } + + @Override + public final WatchKey register(WatchService watcher, WatchEvent.Kind... events) { + return register(watcher, events, new WatchEvent.Modifier[0]); + } + + @Override + public final File toFile() { + throw new UnsupportedOperationException(); + } + + @Override + public final Iterator iterator() { + return new Iterator() { + private int i = 0; + + @Override + public boolean hasNext() { + return (i < getNameCount()); + } + + @Override + public Path next() { + if (i < getNameCount()) { + Path result = getName(i); + i++; + return result; + } else { + throw new NoSuchElementException(); + } + } + + @Override + public void remove() { + throw new ReadOnlyFileSystemException(); + } + }; + } + + // Helpers for JrtFileSystemProvider and JrtFileSystem + + final JrtPath readSymbolicLink() throws IOException { + if (!jrtfs.isLink(this)) { + throw new IOException("not a symbolic link"); + } + return jrtfs.resolveLink(this); + } + + final boolean isHidden() { + return false; + } + + final void createDirectory(FileAttribute... attrs) + throws IOException { + jrtfs.createDirectory(this, attrs); + } + + final InputStream newInputStream(OpenOption... options) throws IOException { + for (OpenOption opt : options) { + if (opt != READ) { + throw new UnsupportedOperationException("'" + opt + "' not allowed"); + } + } + return jrtfs.newInputStream(this); + } + + final DirectoryStream newDirectoryStream(Filter filter) + throws IOException { + return new JrtDirectoryStream(this, filter); + } + + final void delete() throws IOException { + jrtfs.deleteFile(this, true); + } + + final void deleteIfExists() throws IOException { + jrtfs.deleteFile(this, false); + } + + final JrtFileAttributes getAttributes(LinkOption... options) throws IOException { + return jrtfs.getFileAttributes(this, options); + } + + final void setAttribute(String attribute, Object value, LinkOption... options) + throws IOException { + JrtFileAttributeView.setAttribute(this, attribute, value); + } + + final Map readAttributes(String attributes, LinkOption... options) + throws IOException { + return JrtFileAttributeView.readAttributes(this, attributes, options); + } + + final void setTimes(FileTime mtime, FileTime atime, FileTime ctime) + throws IOException { + jrtfs.setTimes(this, mtime, atime, ctime); + } + + final FileStore getFileStore() throws IOException { + // each JrtFileSystem only has one root (as requested for now) + if (exists()) { + return jrtfs.getFileStore(this); + } + throw new NoSuchFileException(path); + } + + final boolean isSameFile(Path other) throws IOException { + if (this == other || this.equals(other)) { + return true; + } + if (other == null || this.getFileSystem() != other.getFileSystem()) { + return false; + } + this.checkAccess(); + JrtPath o = (JrtPath) other; + o.checkAccess(); + return this.getResolvedPath().equals(o.getResolvedPath()) || + jrtfs.isSameFile(this, o); + } + + final SeekableByteChannel newByteChannel(Set options, + FileAttribute... attrs) + throws IOException + { + return jrtfs.newByteChannel(this, options, attrs); + } + + final FileChannel newFileChannel(Set options, + FileAttribute... attrs) + throws IOException { + return jrtfs.newFileChannel(this, options, attrs); + } + + final void checkAccess(AccessMode... modes) throws IOException { + if (modes.length == 0) { // check if the path exists + jrtfs.checkNode(this); // no need to follow link. the "link" node + // is built from real node under "/module" + } else { + boolean w = false; + for (AccessMode mode : modes) { + switch (mode) { + case READ: + break; + case WRITE: + w = true; + break; + case EXECUTE: + throw new AccessDeniedException(toString()); + default: + throw new UnsupportedOperationException(); + } + } + jrtfs.checkNode(this); + if (w && jrtfs.isReadOnly()) { + throw new AccessDeniedException(toString()); + } + } + } + + final boolean exists() { + try { + return jrtfs.exists(this); + } catch (IOException x) {} + return false; + } + + final OutputStream newOutputStream(OpenOption... options) throws IOException { + if (options.length == 0) { + return jrtfs.newOutputStream(this, CREATE_NEW, WRITE); + } + return jrtfs.newOutputStream(this, options); + } + + final void move(JrtPath target, CopyOption... options) throws IOException { + if (this.jrtfs == target.jrtfs) { + jrtfs.copyFile(true, this, target, options); + } else { + copyToTarget(target, options); + delete(); + } + } + + final void copy(JrtPath target, CopyOption... options) throws IOException { + if (this.jrtfs == target.jrtfs) { + jrtfs.copyFile(false, this, target, options); + } else { + copyToTarget(target, options); + } + } + + private void copyToTarget(JrtPath target, CopyOption... options) + throws IOException { + boolean replaceExisting = false; + boolean copyAttrs = false; + for (CopyOption opt : options) { + if (opt == REPLACE_EXISTING) { + replaceExisting = true; + } else if (opt == COPY_ATTRIBUTES) { + copyAttrs = true; + } + } + // attributes of source file + BasicFileAttributes jrtfas = getAttributes(); + // check if target exists + boolean exists; + if (replaceExisting) { + try { + target.deleteIfExists(); + exists = false; + } catch (DirectoryNotEmptyException x) { + exists = true; + } + } else { + exists = target.exists(); + } + if (exists) { + throw new FileAlreadyExistsException(target.toString()); + } + if (jrtfas.isDirectory()) { + // create directory or file + target.createDirectory(); + } else { + try (InputStream is = jrtfs.newInputStream(this); + OutputStream os = target.newOutputStream()) { + byte[] buf = new byte[8192]; + int n; + while ((n = is.read(buf)) != -1) { + os.write(buf, 0, n); + } + } + } + if (copyAttrs) { + BasicFileAttributeView view = + Files.getFileAttributeView(target, BasicFileAttributeView.class); + try { + view.setTimes(jrtfas.lastModifiedTime(), + jrtfas.lastAccessTime(), + jrtfas.creationTime()); + } catch (IOException x) { + try { + target.delete(); // rollback? + } catch (IOException ignore) {} + throw x; + } + } + } + + // adopted from sun.nio.fs.UnixUriUtils + private static URI toUri(String str) { + char[] path = str.toCharArray(); + assert path[0] == '/'; + StringBuilder sb = new StringBuilder(); + sb.append(path[0]); + for (int i = 1; i < path.length; i++) { + char c = (char)(path[i] & 0xff); + if (match(c, L_PATH, H_PATH)) { + sb.append(c); + } else { + sb.append('%'); + sb.append(hexDigits[(c >> 4) & 0x0f]); + sb.append(hexDigits[(c) & 0x0f]); + } + } + + try { + return new URI("jrt:" + sb.toString()); + } catch (URISyntaxException x) { + throw new AssertionError(x); // should not happen + } + } + + // The following is copied from java.net.URI + + // Compute the low-order mask for the characters in the given string + private static long lowMask(String chars) { + int n = chars.length(); + long m = 0; + for (int i = 0; i < n; i++) { + char c = chars.charAt(i); + if (c < 64) + m |= (1L << c); + } + return m; + } + + // Compute the high-order mask for the characters in the given string + private static long highMask(String chars) { + int n = chars.length(); + long m = 0; + for (int i = 0; i < n; i++) { + char c = chars.charAt(i); + if ((c >= 64) && (c < 128)) + m |= (1L << (c - 64)); + } + return m; + } + + // Compute a low-order mask for the characters + // between first and last, inclusive + private static long lowMask(char first, char last) { + long m = 0; + int f = Math.max(Math.min(first, 63), 0); + int l = Math.max(Math.min(last, 63), 0); + for (int i = f; i <= l; i++) + m |= 1L << i; + return m; + } + + // Compute a high-order mask for the characters + // between first and last, inclusive + private static long highMask(char first, char last) { + long m = 0; + int f = Math.max(Math.min(first, 127), 64) - 64; + int l = Math.max(Math.min(last, 127), 64) - 64; + for (int i = f; i <= l; i++) + m |= 1L << i; + return m; + } + + // Tell whether the given character is permitted by the given mask pair + private static boolean match(char c, long lowMask, long highMask) { + if (c < 64) + return ((1L << c) & lowMask) != 0; + if (c < 128) + return ((1L << (c - 64)) & highMask) != 0; + return false; + } + + // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | + // "8" | "9" + private static final long L_DIGIT = lowMask('0', '9'); + private static final long H_DIGIT = 0L; + + // upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | + // "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | + // "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" + private static final long L_UPALPHA = 0L; + private static final long H_UPALPHA = highMask('A', 'Z'); + + // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | + // "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | + // "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" + private static final long L_LOWALPHA = 0L; + private static final long H_LOWALPHA = highMask('a', 'z'); + + // alpha = lowalpha | upalpha + private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA; + private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA; + + // alphanum = alpha | digit + private static final long L_ALPHANUM = L_DIGIT | L_ALPHA; + private static final long H_ALPHANUM = H_DIGIT | H_ALPHA; + + // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | + // "(" | ")" + private static final long L_MARK = lowMask("-_.!~*'()"); + private static final long H_MARK = highMask("-_.!~*'()"); + + // unreserved = alphanum | mark + private static final long L_UNRESERVED = L_ALPHANUM | L_MARK; + private static final long H_UNRESERVED = H_ALPHANUM | H_MARK; + + // pchar = unreserved | escaped | + // ":" | "@" | "&" | "=" | "+" | "$" | "," + private static final long L_PCHAR + = L_UNRESERVED | lowMask(":@&=+$,"); + private static final long H_PCHAR + = H_UNRESERVED | highMask(":@&=+$,"); + + // All valid path characters + private static final long L_PATH = L_PCHAR | lowMask(";/"); + private static final long H_PATH = H_PCHAR | highMask(";/"); + + private static final char[] hexDigits = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; +} diff --git a/tests/test_data/std/jdk/internal/jrtfs/JrtUtils.class b/tests/test_data/std/jdk/internal/jrtfs/JrtUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..904834f2803ca7708567e3e8df21d74f888f34ba GIT binary patch literal 2803 zcmai0ZERcB8Gg>WH~xy_I&Per2Uw*f0H(8TLop$xptC{ zWUT7(Ip=-f^S;mfnfu3^?_39v!M6gC(7e!tsDeizJY~!n>6~FtqTO*RQPdMf&a@|-Nf$+z zVtgftt=L9JcG4&wAWro<go(6r%fs z*o%FHXq&T4Mg0Z}m>eHiMRIu5hX)0AcFY!XR@QRjdu-#3884Xy#?Q$Y_rxtbp3NC0 z*3vLL9eo(M)z&!`qHhE-h?9() zlV7Rdx~BE9*((roi$1N^R=4Z1d>!nK85Ys45L54RBL(Qa7>QkAcfg(#oFnBtX%VV{&v8s_{pi`xc zd2k~quytL)R!Wy?>CaCWv*tsVa=vC|__V5)#T_h2$#7}dh9L|yY$Lo$_<0|_YDML7qEw*@ z$C69f{4)H>*b=r}xdmm2Xu+}I!<`7>ZdY}E`3)=vQ~e8L3a6=2;npBRjC2lX$|m%4 z449AMe@5GP4Y9#U!!mB~(e^jE2IXVPh9@;an{9ejf1U5;J^Z0Ok~{~wr&#y@;GX7s znya1k7Vbk_KjBgk4s*>>?p^NZxPRnoUqJ0O>>P~jPB!S{%V>OW)mBxs>M9bKP_6cs ziwLB`!%Mj1L@HXPwng!~R8%jYuB9S(Eurm1vf(Q33y&@!oQgc42!y?e<}!K50%}s> zQT2l4GOfj>wNz+Yn@4N&mYv4(DiAsy9$A2A5tn&NuOMz;K}_QCJYw92=26G3aRGH@ z{XDI~cEOTOqsOA2OBKfttf+DA5&vMDei8Rku52?M)uY~**MvQ8lq#+h@#5!?=xv^; z-sWBWyi>iJugGRr6sIB`Di(`)K6bIf>s;e?DW1M>5i{g&N=1&SyT<#eRQQ}5UJR2{ zlZy0|wH!@_Q)T+0vXe5RW z#0NisAIf-UB`qu=b(5XTnR9;gKWAos|M~d~Kn;&gq_Chvv$2RY!^WWd(eZ@jp>Ta? z5Xz&-X?>0)AJ&I%kLN24=85a)JvC$4Y)t#dW+!$%;BJ?PRSO189hQv@Y=*UI|0JIw z{oE6t++|oO6x$Y-kkyg1aT&`D>(jwAn=u$ip6E7%E=hYoVE6z-5 z7_7Zd9X^s?AR--khLzaI3!M79vlSwUSlf1Dw>fnnYAY_?YftIVORQiK;{f?4_oRzAh0FJznqyo>>>WCP4IfJxFe3A#mAjrzOP)AgJKT}eXs=0NXZ zI{~HZI)*-_6_t^pl%C?+d8Sq@t_~e zJV1p6AHYW;#&%GWDu5;Lc+SqAnLRW9`Rm&c05v={kwMl#&cY048HznV;I_w=Yd2aw z;b?~0eW|2AV91s$rv>CuFko7^28&^{*FLwU(jrjYvwMN=gm&{H)S`dX=dNH_==<%+ z6N&dydW5XhlN3t&c837_gzIkAz&ykHM-PLemmBhE+dYkeoF-Jcq`U=sqQ=6JLQ3l{UMmsT}gUv)&Eyom6|nCRXPy_7n;&l zTt@-rcr_-%Fd#+#TJZkZi9fO(5Ubhrqreeq`-)>@v>OXR_j{on&kv4XjIJi%% zl?LDe9+Jo6M$#G|ewL5|^Pgd4zhmwa3zt~^NIT;!oiUdAl%;q`Eaf4~sDv-Lb@lMH h5@t|IQtaSSVjtrP*&O|fz;1%%>0W?I2{y>m^BcM<>OTMg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/jrtfs/SystemImage.class b/tests/test_data/std/jdk/internal/jrtfs/SystemImage.class new file mode 100644 index 0000000000000000000000000000000000000000..9a09958edc56237e8aaa10408ff23eba6420d1d5 GIT binary patch literal 4561 zcma)Ad0Z6d8GZ&<2i8H!q6VWeBqgbUaT{Vy3P!7lb?YurP*O0)4!Z*k%+9Q{vkFO? zq|MPLJ(Awl-uGo2#dbldF+J0!>3!e#egE&T?eopd-kVT=KXzum<2|1DdEfW@eCj{v z9|zEbe+N;6S{VTa%dlKRRMsyR(PBP;Q`f|><%J?CK;<0tif6dSCwkkg}SgSV^C8Qnk^w< zr8HB*O`EDoYl|+i-__TwU>&X?DifMBXj#r4-6kZKJuBh*O-qVs%`fkku|YyhsmgM& zT5kwqJvNF!TqU8EW|v@F;bFHIjjI)0BVY_^GbzJLXo;AIIF-w2mC#&@WmGq(`%{i? znL%8K=gQcmpbhO3no8G+NHA3Orsd?q)>#$FLuK$56m++Z%GfNStx~ebkv_}WYh}zt z?@U~CO zWDODDVAtBeDsEgBZhBfpJ=agN%e_j&*P_QW1yx=jm8Jaa6 zbtYe+1XiyXMd1+=x;TahCT;7uI%a6B${}{vHz;@`-bAzP%rhjsevIZ%Xo+2JX&|<5 z!CPg#O~Ko7q9WmU#p7B!-D8=KZ5f8>Zc4%$uyZmbZ1s)F=T~9US5QnZ9|qBd-=W~0 zco*dj9_%|1iS-`Y*B|R;>8;=lEqo8&E8~3%-j5HEj~-092#H{L<$@dtGCF&-aW!Kw zn)yX-|Z+|f0OzMQMrL6UrpA@>;1;=$W(dWwUs)E4M zXA`lPa)Nnkr)4~z%V`ER(x0F4vTaaH`@N-|3ZMOG(&|cYJG7g{ByL!uwz@s9WLFih zmbr%<30E(rfR;B5Icj`5rlx%CTtxP~HdH*{7Nbo{JlZOU)V~Q+Uk{ofOyFGyM${i@UI4?jDP0Z zjLV)9e0S=`>-CvSr8lh+VFW&ZIh2??L!TbNHtjI_@~ zI>VP5Wce$mfg3T;U&UL11)LM|aUP2t`7CDwd|u$lMLbb9@;O&RehrOVgU?g8Q27XI zU5Pz&kWZj_4h;*qY=3(em*2XG^&>Ro%F}absl9;bEa2J`Xj(+a2nWvLdWiXIK2348uE85!zq+V)I~s5c@1i?+S&Ly4`fxM)^NuuNCBA?!a^II+2Wr-DD7b>4 zNE#YPGo@{Gua;{b4b^4QoyD&G?N6dU^r8hsPSe=_Xh#+YL!(*Tb`l#GF*dS@#K=6x zIXn@X&LWvbY92=~^4ng(v2(afLTvLn+$#}BdJ?)XiwCM~eWuil^v%GbMZtPgA2ns}+Gu;)*|T2^}(qFQH4umjCiU8frMk z0Z1}!s>9dw>^j3Y!OEfYcof**zJNDBfx~BUasls-cFf`AvI{soQX9H&Xe1E&;7}GH zK8pr19`MHfp_WCQBD9}!w?CG}nX`}uSBpb`h^lU*Be!EUo!!i9#ZI0D2YKoi99~N^ zmebj9;G6tfO>%q--=f&L80?_&I*h jk#;81A4s)75vcY27XMCp5B!/modules directory Path + static final Path explodedModulesDir; + + static { + PrivilegedAction pa = SystemImage::findHome; + RUNTIME_HOME = AccessController.doPrivileged(pa); + + FileSystem fs = FileSystems.getDefault(); + moduleImageFile = fs.getPath(RUNTIME_HOME, "lib", "modules"); + explodedModulesDir = fs.getPath(RUNTIME_HOME, "modules"); + + modulesImageExists = AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Boolean run() { + return Files.isRegularFile(moduleImageFile); + } + }); + } + + /** + * Returns the appropriate JDK home for this usage of the FileSystemProvider. + * When the CodeSource is null (null loader) then jrt:/ is the current runtime, + * otherwise the JDK home is located relative to jrt-fs.jar. + */ + private static String findHome() { + CodeSource cs = SystemImage.class.getProtectionDomain().getCodeSource(); + if (cs == null) + return System.getProperty("java.home"); + + // assume loaded from $TARGETJDK/lib/jrt-fs.jar + URL url = cs.getLocation(); + if (!url.getProtocol().equalsIgnoreCase("file")) + throw new InternalError(url + " loaded in unexpected way"); + try { + Path lib = Paths.get(url.toURI()).getParent(); + if (!lib.getFileName().toString().equals("lib")) + throw new InternalError(url + " unexpected path"); + + return lib.getParent().toString(); + } catch (URISyntaxException e) { + throw new InternalError(e); + } + } +} diff --git a/tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue$Memoizer$RecursiveInvocationException.class b/tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue$Memoizer$RecursiveInvocationException.class new file mode 100644 index 0000000000000000000000000000000000000000..0aedf370599da71138b1a87d7e340475a6e54aef GIT binary patch literal 751 zcmb_aK~Gab5dNkueWez}Dk=!l0|zjKcjAO0Ays3|lLN(f-@Z=j!m>+tw+-Q6c_QK9 z5Aa73=DjF-(S*c3>^Jl6?0mB``{VZJJAgiVEz}5$$6QQ(&@=88%9u79m`l*?AVG_; zajIr2HOfxXfiXN$W*AlE_m>4G_ELi5eMUx|v9rTuDyxf0B*( zRR_XJ_WvKSPiPO_)EE3gm-_2}>&I@{RYL2CL;UDMOt4DWc}PKo&cIssRi`;5SSRc~ zB*Fbiq>NwFA*}stKImayzLInvt9XQt;DUHHEQ$sBTuXva#M%?CV%~J=8uf2gP*?W0 s9Do#>G{RHy%M|6sXIK`j#(%5bqJElegb?t1^O*iYX zUZ*WWNIif!aX{iwE{F@2xD+I!0F?+(iAdb}XAmIfJv+8T(uil7d%(C8_)R&9KyShzq6->gBME$S^ z+YxcbfgoDZ#%C7HRl=FXe$J5_bOdn_hX}39+RBPyEl!rLf@2gd!pX|9Wydfhx2xL7 zn6YIby*qZrbvq+kU0f1wM>DJ0hLEdDk8{W12Dr4ZFlx=tiFIz@^})*4&ZGZt%cumeie3JB zs7a%}!T3+*5rDZDb)FB0`gZAWo(1;_Eonz9+)ZjLRm}Xg?qlS2OfeN)D`&A~b%j?enN4#J z*D%8}$4S5QDGFOZQNQH}YT#FR2fk*uD;e6vJvEp5Md)*hO}s6%x#TA1ndyFnz*F?( z*74GY>RCg#%F1^B6#iPiN3R>-LCq!Ba9DNo@?)GF_NZN+TyhOvRZYvVS8`q6jqtO_ z@DDeIpLI2DR6+>-jB}6R3;l$18_b`t@aH$4;$kkej=>EsTnsmHi%Th}%_-c%lB6~q zNsr=vJY@Ytd?2YuLT+){K$qdA7y@*K|2|yhe*mNWj*mg5I6o)j7@|qUXbLkljajBQ zDT%izg^U%OQ0R^tV5LR%OncGZm@Yg)fKYyUf t8weo9mLB%#sTTb@OO^7^;s&p|Fo(3H8DyDuu*QcB-oP>T@iC&le*l08mwx~N literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue$Sub.class b/tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue$Sub.class new file mode 100644 index 0000000000000000000000000000000000000000..897084363679b3d6515b71f48f810cbe88acc84e GIT binary patch literal 2421 zcmb7GO;a3I6g_WxV1P6*Kn7z%OjJzfOD4n!3L^%|7cziVP-9hAK4#iXL#K!I^rR}~ zCROUja_J^n#ElwLMMbSLgmPi&*572MJhyuS2*aWmJ@4b*cka38-S^)7^Wu*`0nDM) zjTnps;wC!Ksc>Pvx>2xQ-|}4T6r8%QT3%sxt>JsR;?Fs{(I^FTW$iSr(Us1H##!68ZPxqh;-3j!VI0jQ8A7wG47H!w|XB3QdrYuSHndnE7;|=Sc!eD7#-_-?2 zySECaH z!{!BUOiYC%bedP_Ua@bv+HZQYW_4j&VJ>1uZAg_B;vtRxlI>bc&D(31x2o411{o~X zE7~b*&z5m(GA`Ava50jWaxlnu`2T?SHeZ6yMnWsD&Xvm3tL5pLG2#{}#SFodiDM$*&ll0SMDuQ={q9a=C8ckQ3sZ;nnu!)An)eZ$NTz3{ z-t;QgHCyWW^ilWrm~1c4 zqw!=?-U{~RJBEue@D6)-=xMO+&*q*%WuGIF%|Ao$Z=5o4iNAefR$ro9eT6>tHQwdi z*>DLaFv$@Y2hb|$NzfSHV}F>f*e38kTj})&^rqPFrs;k%m=5_(lPRxPE)iC<90^=U z_IIdX*$KIH%B1=>;9!OhEe;ZIZ${#Uutj?HJ)iAkBevI4g zq!HS#(k5w`h$p)K#b^RCCZpu>X(jO~J){tZl4peRHZnEgx`Ver6Giuz=u?*GFBnu$ n_wD0Qi_~6u$czw(w+iGMu5%Q_4a^5^7d~d&!=Q4G7BKK1Ckius literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue.class b/tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue.class new file mode 100644 index 0000000000000000000000000000000000000000..3e34a71902dbccb66f6797204191063e62dbcdf7 GIT binary patch literal 5623 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue.java b/tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue.java new file mode 100644 index 00000000..739f9c0d --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/AbstractClassLoaderValue.java @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Iterator; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; +import java.util.function.Supplier; + +/** + * AbstractClassLoaderValue is a superclass of root-{@link ClassLoaderValue} + * and {@link Sub sub}-ClassLoaderValue. + * + * @param the type of concrete ClassLoaderValue (this type) + * @param the type of values associated with ClassLoaderValue + */ +public abstract class AbstractClassLoaderValue, V> { + + /** + * Sole constructor. + */ + AbstractClassLoaderValue() {} + + /** + * Returns the key component of this ClassLoaderValue. The key component of + * the root-{@link ClassLoaderValue} is the ClassLoaderValue itself, + * while the key component of a {@link #sub(Object) sub}-ClassLoaderValue + * is what was given to construct it. + * + * @return the key component of this ClassLoaderValue. + */ + public abstract Object key(); + + /** + * Constructs new sub-ClassLoaderValue of this ClassLoaderValue with given + * key component. + * + * @param key the key component of the sub-ClassLoaderValue. + * @param the type of the key component. + * @return a sub-ClassLoaderValue of this ClassLoaderValue for given key + */ + public Sub sub(K key) { + return new Sub<>(key); + } + + /** + * Returns {@code true} if this ClassLoaderValue is equal to given {@code clv} + * or if this ClassLoaderValue was derived from given {@code clv} by a chain + * of {@link #sub(Object)} invocations. + * + * @param clv the ClassLoaderValue to test this against + * @return if this ClassLoaderValue is equal to given {@code clv} or + * its descendant + */ + public abstract boolean isEqualOrDescendantOf(AbstractClassLoaderValue clv); + + /** + * Returns the value associated with this ClassLoaderValue and given ClassLoader + * or {@code null} if there is none. + * + * @param cl the ClassLoader for the associated value + * @return the value associated with this ClassLoaderValue and given ClassLoader + * or {@code null} if there is none. + */ + public V get(ClassLoader cl) { + Object val = AbstractClassLoaderValue.map(cl).get(this); + try { + return extractValue(val); + } catch (Memoizer.RecursiveInvocationException e) { + // propagate recursive get() for the same key that is just + // being calculated in computeIfAbsent() + throw e; + } catch (Throwable t) { + // don't propagate exceptions thrown from Memoizer - pretend + // that there was no entry + // (computeIfAbsent invocation will try to remove it anyway) + return null; + } + } + + /** + * Associates given value {@code v} with this ClassLoaderValue and given + * ClassLoader and returns {@code null} if there was no previously associated + * value or does nothing and returns previously associated value if there + * was one. + * + * @param cl the ClassLoader for the associated value + * @param v the value to associate + * @return previously associated value or null if there was none + */ + public V putIfAbsent(ClassLoader cl, V v) { + ConcurrentHashMap map = map(cl); + @SuppressWarnings("unchecked") + CLV clv = (CLV) this; + while (true) { + try { + Object val = map.putIfAbsent(clv, v); + return extractValue(val); + } catch (Memoizer.RecursiveInvocationException e) { + // propagate RecursiveInvocationException for the same key that + // is just being calculated in computeIfAbsent + throw e; + } catch (Throwable t) { + // don't propagate exceptions thrown from foreign Memoizer - + // pretend that there was no entry and retry + // (foreign computeIfAbsent invocation will try to remove it anyway) + } + // TODO: + // Thread.onSpinLoop(); // when available + } + } + + /** + * Removes the value associated with this ClassLoaderValue and given + * ClassLoader if the associated value is equal to given value {@code v} and + * returns {@code true} or does nothing and returns {@code false} if there is + * no currently associated value or it is not equal to given value {@code v}. + * + * @param cl the ClassLoader for the associated value + * @param v the value to compare with currently associated value + * @return {@code true} if the association was removed or {@code false} if not + */ + public boolean remove(ClassLoader cl, Object v) { + return AbstractClassLoaderValue.map(cl).remove(this, v); + } + + /** + * Returns the value associated with this ClassLoaderValue and given + * ClassLoader if there is one or computes the value by invoking given + * {@code mappingFunction}, associates it and returns it. + *

+ * Computation and association of the computed value is performed atomically + * by the 1st thread that requests a particular association while holding a + * lock associated with this ClassLoaderValue and given ClassLoader. + * Nested calls from the {@code mappingFunction} to {@link #get}, + * {@link #putIfAbsent} or {@link #computeIfAbsent} for the same association + * are not allowed and throw {@link IllegalStateException}. Nested call to + * {@link #remove} for the same association is allowed but will always return + * {@code false} regardless of passed-in comparison value. Nested calls for + * other association(s) are allowed, but care should be taken to avoid + * deadlocks. When two threads perform nested computations of the overlapping + * set of associations they should always request them in the same order. + * + * @param cl the ClassLoader for the associated value + * @param mappingFunction the function to compute the value + * @return the value associated with this ClassLoaderValue and given + * ClassLoader. + * @throws IllegalStateException if a direct or indirect invocation from + * within given {@code mappingFunction} that + * computes the value of a particular association + * to {@link #get}, {@link #putIfAbsent} or + * {@link #computeIfAbsent} + * for the same association is attempted. + */ + public V computeIfAbsent(ClassLoader cl, + BiFunction< + ? super ClassLoader, + ? super CLV, + ? extends V + > mappingFunction) throws IllegalStateException { + ConcurrentHashMap map = map(cl); + @SuppressWarnings("unchecked") + CLV clv = (CLV) this; + Memoizer mv = null; + while (true) { + Object val = (mv == null) ? map.get(clv) : map.putIfAbsent(clv, mv); + if (val == null) { + if (mv == null) { + // create Memoizer lazily when 1st needed and restart loop + mv = new Memoizer<>(cl, clv, mappingFunction); + continue; + } + // mv != null, therefore sv == null was a result of successful + // putIfAbsent + try { + // trigger Memoizer to compute the value + V v = mv.get(); + // attempt to replace our Memoizer with the value + map.replace(clv, mv, v); + // return computed value + return v; + } catch (Throwable t) { + // our Memoizer has thrown, attempt to remove it + map.remove(clv, mv); + // propagate exception because it's from our Memoizer + throw t; + } + } else { + try { + return extractValue(val); + } catch (Memoizer.RecursiveInvocationException e) { + // propagate recursive attempts to calculate the same + // value as being calculated at the moment + throw e; + } catch (Throwable t) { + // don't propagate exceptions thrown from foreign Memoizer - + // pretend that there was no entry and retry + // (foreign computeIfAbsent invocation will try to remove it anyway) + } + } + // TODO: + // Thread.onSpinLoop(); // when available + } + } + + /** + * Removes all values associated with given ClassLoader {@code cl} and + * {@link #isEqualOrDescendantOf(AbstractClassLoaderValue) this or descendants} + * of this ClassLoaderValue. + * This is not an atomic operation. Other threads may see some associations + * be already removed and others still present while this method is executing. + *

+ * The sole intention of this method is to cleanup after a unit test that + * tests ClassLoaderValue directly. It is not intended for use in + * actual algorithms. + * + * @param cl the associated ClassLoader of the values to be removed + */ + public void removeAll(ClassLoader cl) { + ConcurrentHashMap map = map(cl); + for (Iterator i = map.keySet().iterator(); i.hasNext(); ) { + if (i.next().isEqualOrDescendantOf(this)) { + i.remove(); + } + } + } + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + /** + * @return a ConcurrentHashMap for given ClassLoader + */ + @SuppressWarnings("unchecked") + private static > + ConcurrentHashMap map(ClassLoader cl) { + return (ConcurrentHashMap) + (cl == null ? BootLoader.getClassLoaderValueMap() + : JLA.createOrGetClassLoaderValueMap(cl)); + } + + /** + * @return value extracted from the {@link Memoizer} if given + * {@code memoizerOrValue} parameter is a {@code Memoizer} or + * just return given parameter. + */ + @SuppressWarnings("unchecked") + private V extractValue(Object memoizerOrValue) { + if (memoizerOrValue instanceof Memoizer) { + return ((Memoizer) memoizerOrValue).get(); + } else { + return (V) memoizerOrValue; + } + } + + /** + * A memoized supplier that invokes given {@code mappingFunction} just once + * and remembers the result or thrown exception for subsequent calls. + * If given mappingFunction returns null, it is converted to NullPointerException, + * thrown from the Memoizer's {@link #get()} method and remembered. + * If the Memoizer is invoked recursively from the given {@code mappingFunction}, + * {@link RecursiveInvocationException} is thrown, but it is not remembered. + * The in-flight call to the {@link #get()} can still complete successfully if + * such exception is handled by the mappingFunction. + */ + private static final class Memoizer, V> + implements Supplier { + + private final ClassLoader cl; + private final CLV clv; + private final BiFunction + mappingFunction; + + private volatile V v; + private volatile Throwable t; + private boolean inCall; + + Memoizer(ClassLoader cl, + CLV clv, + BiFunction + mappingFunction + ) { + this.cl = cl; + this.clv = clv; + this.mappingFunction = mappingFunction; + } + + @Override + public V get() throws RecursiveInvocationException { + V v = this.v; + if (v != null) return v; + Throwable t = this.t; + if (t == null) { + synchronized (this) { + if ((v = this.v) == null && (t = this.t) == null) { + if (inCall) { + throw new RecursiveInvocationException(); + } + inCall = true; + try { + this.v = v = Objects.requireNonNull( + mappingFunction.apply(cl, clv)); + } catch (Throwable x) { + this.t = t = x; + } finally { + inCall = false; + } + } + } + } + if (v != null) return v; + if (t instanceof Error) { + throw (Error) t; + } else if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } else { + throw new UndeclaredThrowableException(t); + } + } + + static class RecursiveInvocationException extends IllegalStateException { + @java.io.Serial + private static final long serialVersionUID = 1L; + + RecursiveInvocationException() { + super("Recursive call"); + } + } + } + + /** + * sub-ClassLoaderValue is an inner class of {@link AbstractClassLoaderValue} + * and also a subclass of it. It can therefore be instantiated as an inner + * class of either an instance of root-{@link ClassLoaderValue} or another + * instance of itself. This enables composing type-safe compound keys of + * arbitrary length: + *

{@code
+     * ClassLoaderValue clv = new ClassLoaderValue<>();
+     * ClassLoaderValue.Sub.Sub.Sub clv_k123 =
+     *     clv.sub(k1).sub(k2).sub(k3);
+     * }
+ * From which individual components are accessible in a type-safe way: + *
{@code
+     * K1 k1 = clv_k123.parent().parent().key();
+     * K2 k2 = clv_k123.parent().key();
+     * K3 k3 = clv_k123.key();
+     * }
+ * This allows specifying non-capturing lambdas for the mapping function of + * {@link #computeIfAbsent(ClassLoader, BiFunction)} operation that can + * access individual key components from passed-in + * sub-[sub-...]ClassLoaderValue instance in a type-safe way. + * + * @param the type of {@link #key()} component contained in the + * sub-ClassLoaderValue. + */ + public final class Sub extends AbstractClassLoaderValue, V> { + + private final K key; + + Sub(K key) { + this.key = key; + } + + /** + * @return the parent ClassLoaderValue this sub-ClassLoaderValue + * has been {@link #sub(Object) derived} from. + */ + public AbstractClassLoaderValue parent() { + return AbstractClassLoaderValue.this; + } + + /** + * @return the key component of this sub-ClassLoaderValue. + */ + @Override + public K key() { + return key; + } + + /** + * sub-ClassLoaderValue is a descendant of given {@code clv} if it is + * either equal to it or if its {@link #parent() parent} is a + * descendant of given {@code clv}. + */ + @Override + public boolean isEqualOrDescendantOf(AbstractClassLoaderValue clv) { + return equals(Objects.requireNonNull(clv)) || + parent().isEqualOrDescendantOf(clv); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Sub)) return false; + @SuppressWarnings("unchecked") + Sub that = (Sub) o; + return this.parent().equals(that.parent()) && + Objects.equals(this.key, that.key); + } + + @Override + public int hashCode() { + return 31 * parent().hashCode() + + Objects.hashCode(key); + } + } +} diff --git a/tests/test_data/std/jdk/internal/loader/ArchivedClassLoaders.class b/tests/test_data/std/jdk/internal/loader/ArchivedClassLoaders.class new file mode 100644 index 0000000000000000000000000000000000000000..41934abe869652931aedbb07d2bf237c056b537f GIT binary patch literal 2011 zcmZ`)U31$+6g}%NC9YyOZsRmy(xfe^g~P@x!)kk`+m^OrJF;QA zM#YxhZq=W61=0tO;{}#LskmH?f^7FJ+q2q3$nqpI$Z9yRB25bvqhR;k`b+D`Yz*NT zaklza#L!MzalfGBB4z|GbZqJU;JB?J2Z1?7Z;*hYEuYP-j!TM4<`f&KQpdih<9&5( zMs_+wFs0!G9rFq`$*lmOVL{;Ph@O_y=-H-GGunIB3nx;1vL}06UhUl?coq2uL7 z{z^8@7tXG)USRq({XNgJja}LC)BdqK_!IgEEC+iUZnD;I%k?;H!w0VGxM{2*o@V~y zDv7sse2UKmF3QM;DUIeaT-quNBq~mW-r1_vHlOuc2d4W% z9@t#TRh_!D_oZtoJ6ue7FD-UVcC3kbxdX8RQ#Fs}V9rCt(s(V-BBF&k<@>PM^aTOw0n1qpWYIjoYefjKf-WS6euCVT1@9$^D} zxQ+Yt)B`?v;Hv{MGa*-lqvEP!O&xO*<0Gz8p%(89fs+I9rATmo9K00?o{t0<#=+Z> z;2ji0+CPz}D%tuC#rqeeIV{H4j+L1Y%|u`pLNmE`{03`Zzs9Y92#otO=b>@F!w2^v zvdq{l9`kX1f+aj packageToModule; + + private ArchivedClassLoaders() { + bootLoader = ClassLoaders.bootLoader(); + platformLoader = ClassLoaders.platformClassLoader(); + appLoader = ClassLoaders.appClassLoader(); + + servicesCatalogs = new ServicesCatalog[3]; + servicesCatalogs[0] = ServicesCatalog.getServicesCatalog(bootLoader); + servicesCatalogs[1] = ServicesCatalog.getServicesCatalog(platformLoader); + servicesCatalogs[2] = ServicesCatalog.getServicesCatalog(appLoader); + + packageToModule = BuiltinClassLoader.packageToModule(); + } + + ClassLoader bootLoader() { + return bootLoader; + } + + ClassLoader platformLoader() { + return platformLoader; + } + + ClassLoader appLoader() { + return appLoader; + } + + ServicesCatalog servicesCatalog(ClassLoader loader) { + if (loader == bootLoader) { + return servicesCatalogs[0]; + } else if (loader == platformLoader) { + return servicesCatalogs[1]; + } else if (loader == appLoader) { + return servicesCatalogs[2]; + } else { + throw new InternalError(); + } + } + + Map packageToModule() { + return packageToModule; + } + + static void archive() { + archivedClassLoaders = new ArchivedClassLoaders(); + } + + static ArchivedClassLoaders get() { + return archivedClassLoaders; + } + + static { + CDS.initializeFromArchive(ArchivedClassLoaders.class); + } +} diff --git a/tests/test_data/std/jdk/internal/loader/BootLoader$1.class b/tests/test_data/std/jdk/internal/loader/BootLoader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..c997a00e8c2d50fe9e28a04c0ec5332879fcaaa9 GIT binary patch literal 1018 zcma)5ZEq4m5Pp`ogX3tiw!Yh9ix#N%Vq)S4nkJRlXoA!PgP)gULl>`m$=yQ2FERQn zG|_7O;1BRe8D|e7DEM;8-Rw?go_Xe(xo_XUdO!(k}S0#3RE z;c14U9Fyt6SJK z5*TMBykRKy*nJ+#k@Q7h^o~3&14`UjMxn!yY6Lx+$!b$7(Hfq0Mfieu{dh`&$Ndh8 zW$sgFN}o!SZhNV4^8>Fltp7rFGDmXf+On^>9)?uoc&?Xez{K;%Mh+G;4hht52gA@4 z$J8_RG9$8YWFgOE<@rHGoAylT)1YTYxkWqK5|MrqM6_PcQ>8@M@Oc!82qn@z3x=Cu z#iChp+WI8Dd2ErlM5hN7ksxc=_CA8uKEZlVw*+p{H$ySNYi!fkiO)86P^KF*qnskt zDcZypKBG|k0CtXxFWEbCOhC-&fj3n0?Ho{H0#rOApxaX*m#hIw*UoWu2C&E?J!O%` eow&>{DzUAiMm9zN)E@4}o)z39YZI&?LC+5$gYl05 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BootLoader$PackageHelper$1.class b/tests/test_data/std/jdk/internal/loader/BootLoader$PackageHelper$1.class new file mode 100644 index 0000000000000000000000000000000000000000..c8db826a0c368a753c45005148d6f9dccba6a7ee GIT binary patch literal 1461 zcmb7E>r&HD5dKa}36ub}T)hKU?L``HUJEE72s0@#ApFo@hxSkcAz{)}MjydP@GWpg z5uMQo@S)T_NdP;5Gj!VS$!7Q4Z!c$m{r>(FzzkkBBZ8=g1|2apGUT_*JBH;*;W^wk zY?qgXXH2`UH2q_0nU{8WMa&C(Pk50`n|8fz;HRMY|7 z(U8({7x$nifS>&bw8q;ic;Ce{Vg_*Mj2+Z^q`;sz2p*YXE(; zLz+O$!4e6zM`*P~>DPihX$?A!kwt`LJe&Ihmi-Ft6Fo&RME{Ls1D3-uopp6a93vPd z$r2p`B=VWzU5!Jc{N%nWe&*I^FUyJS2oiYD)52r)55v>u1F43dg+ xEPIH|0Ua*NDHh_#@Wi)zif6toV4P$FCh#27zGeoqB$I?RK?{10Dyu3-pT9HJV=4du literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BootLoader$PackageHelper$2.class b/tests/test_data/std/jdk/internal/loader/BootLoader$PackageHelper$2.class new file mode 100644 index 0000000000000000000000000000000000000000..428e8070837e3e3c036f13233e51e81c804bfb08 GIT binary patch literal 2028 zcmb7F-&Y$&6#gdJbRb!3q)lyVfvVV&5ZD%DRYI|lf`CatL(%F39g-m|-R|aWHdJ5z z8~h*oisvZp(W8Cy!9Pm8v%7(8TRf*ZXZOzD`R3j`-~Ew){{8(g0A)NFL=15bO-BOf z7^e4|j||iHq-zVyupH5puCeGiUd3OIZ-~Yt(UL3DYD;%~hCx3N*0|*~gl9T7!*FF^ z90}!95ub(miBsET`q~s z$Z}lK@h+}1T!`Y9DUJ@qd0ReNwcA~f!j|GO!*Uo;)KeJIiSpD-DU6J+)@O%88)dla zyX<ZW3op>)Dg#2Z^JKy%{|w7B6ch~R)C@7CT=kdiDt9j zZMR+7>BuJW-k-RW6D3s;AN8y$H|tA3G-Q~N7(UiGurxDrz)L?M(45KtT(Ey~@1DETJef|` zovz!Es+A}ar&DKIg-DtuTNNM8l&bXhoF>Ot423sIfGYetoq1geoD~?uK#dw?#p!q) zR41eV?~o?qs%=ZRYzeAs%JfiVWa1jl+W|0q0+vpznM-3hPEQJ-k#?3=MMA_#Ci9cO zf#sip|3Y6el<0kqFkthTqqVNqNa7CWNix+3fd%$6G~ez{{#UU0pBQ>hWj#rY%yYa` z{R1Np3h`$ct4$r@{aKCP*9(7x7mkq2YKMX1DfHPyR?8-iFrC$2)Ce%F08f!3KvpC5 z)Qc)R1jiWpEmC9Ors(gG%piwVl0|weS;N=3Pg2J%Y-5J>+rEtZH@c2N3jQvQmIY+k zBF0#m`uQGBh%$<#+ottHw&dTqNPLaa?0-1Ax63Hi{mg(WN# zBVQ0ZKVjgQ+$T6<9BGa`#|Xy?a7>4^ek~YB;h0kN61L!PkQM*$GPDwcQxOvZk{^?6 zf+?he&7>EIp|v1GFi5KGCGtlo9@65h^d`dVB=Dt=s-Wu28rDf_*dTH@ea(G*Lvolb OZ4lkx(hXD*(eFQe`sgG8 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BootLoader$PackageHelper.class b/tests/test_data/std/jdk/internal/loader/BootLoader$PackageHelper.class new file mode 100644 index 0000000000000000000000000000000000000000..3812494914db8edda0a9c1ddce61d50ede7506a5 GIT binary patch literal 4163 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BootLoader.java b/tests/test_data/std/jdk/internal/loader/BootLoader.java new file mode 100644 index 00000000..98ff60a7 --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/BootLoader.java @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.loader; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.ModuleReference; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.concurrent.ConcurrentHashMap; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; +import java.util.stream.Stream; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.module.Modules; +import jdk.internal.module.ServicesCatalog; +import jdk.internal.util.StaticProperty; + +/** + * Find resources and packages in modules defined to the boot class loader or + * resources and packages on the "boot class path" specified via -Xbootclasspath/a. + */ + +public class BootLoader { + private BootLoader() { } + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + // The unnamed module for the boot loader + private static final Module UNNAMED_MODULE; + private static final String JAVA_HOME = StaticProperty.javaHome(); + + static { + JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + UNNAMED_MODULE = jla.defineUnnamedModule(null); + jla.addEnableNativeAccess(UNNAMED_MODULE); + setBootLoaderUnnamedModule0(UNNAMED_MODULE); + } + + // ClassLoaderValue map for the boot class loader + private static final ConcurrentHashMap CLASS_LOADER_VALUE_MAP + = new ConcurrentHashMap<>(); + + // native libraries loaded by the boot class loader + private static final NativeLibraries NATIVE_LIBS + = NativeLibraries.newInstance(null); + + /** + * Returns the unnamed module for the boot loader. + */ + public static Module getUnnamedModule() { + return UNNAMED_MODULE; + } + + /** + * Returns the ServiceCatalog for modules defined to the boot class loader. + */ + public static ServicesCatalog getServicesCatalog() { + return ServicesCatalog.getServicesCatalog(ClassLoaders.bootLoader()); + } + + /** + * Returns the ClassLoaderValue map for the boot class loader. + */ + public static ConcurrentHashMap getClassLoaderValueMap() { + return CLASS_LOADER_VALUE_MAP; + } + + /** + * Returns NativeLibraries for the boot class loader. + */ + public static NativeLibraries getNativeLibraries() { + return NATIVE_LIBS; + } + + /** + * Returns {@code true} if there is a class path associated with the + * BootLoader. + */ + public static boolean hasClassPath() { + return ClassLoaders.bootLoader().hasClassPath(); + } + + /** + * Registers a module with this class loader so that its classes + * (and resources) become visible via this class loader. + */ + public static void loadModule(ModuleReference mref) { + ClassLoaders.bootLoader().loadModule(mref); + } + + /** + * Loads the Class object with the given name defined to the boot loader. + */ + public static Class loadClassOrNull(String name) { + return JLA.findBootstrapClassOrNull(name); + } + + /** + * Loads the Class object with the given name in the given module + * defined to the boot loader. Returns {@code null} if not found. + */ + public static Class loadClass(Module module, String name) { + Class c = loadClassOrNull(name); + if (c != null && c.getModule() == module) { + return c; + } else { + return null; + } + } + + /** + * Loads a native library from the system library path. + */ + @SuppressWarnings("removal") + public static void loadLibrary(String name) { + if (System.getSecurityManager() == null) { + BootLoader.getNativeLibraries().loadLibrary(name); + } else { + AccessController.doPrivileged(new java.security.PrivilegedAction<>() { + public Void run() { + BootLoader.getNativeLibraries().loadLibrary(name); + return null; + } + }); + } + } + + /** + * Returns a URL to a resource in a module defined to the boot loader. + */ + public static URL findResource(String mn, String name) throws IOException { + return ClassLoaders.bootLoader().findResource(mn, name); + } + + /** + * Returns an input stream to a resource in a module defined to the + * boot loader. + */ + public static InputStream findResourceAsStream(String mn, String name) + throws IOException + { + return ClassLoaders.bootLoader().findResourceAsStream(mn, name); + } + + /** + * Returns the URL to the given resource in any of the modules + * defined to the boot loader and the boot class path. + */ + public static URL findResource(String name) { + return ClassLoaders.bootLoader().findResource(name); + } + + /** + * Returns an Iterator to iterate over the resources of the given name + * in any of the modules defined to the boot loader. + */ + public static Enumeration findResources(String name) throws IOException { + return ClassLoaders.bootLoader().findResources(name); + } + + /** + * Define a package for the given class to the boot loader, if not already + * defined. + */ + public static Package definePackage(Class c) { + return getDefinedPackage(c.getPackageName()); + } + + /** + * Returns the Package of the given name defined to the boot loader or null + * if the package has not been defined. + */ + public static Package getDefinedPackage(String pn) { + Package pkg = ClassLoaders.bootLoader().getDefinedPackage(pn); + if (pkg == null) { + String location = getSystemPackageLocation(pn.replace('.', '/')); + if (location != null) { + pkg = PackageHelper.definePackage(pn.intern(), location); + } + } + return pkg; + } + + /** + * Returns a stream of the packages defined to the boot loader. + */ + public static Stream packages() { + return Arrays.stream(getSystemPackageNames()) + .map(name -> getDefinedPackage(name.replace('/', '.'))); + } + + /** + * Helper class to define {@code Package} objects for packages in modules + * defined to the boot loader. + */ + static class PackageHelper { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + /** + * Define the {@code Package} with the given name. The specified + * location is a jrt URL to a named module in the run-time image, + * a file URL to a module in an exploded run-time image, or a file + * path to an entry on the boot class path (java agent Boot-Class-Path + * or -Xbootclasspath/a. + * + *

If the given location is a JAR file containing a manifest, + * the defined Package contains the versioning information from + * the manifest, if present. + * + * @param name package name + * @param location location where the package is (jrt URL or file URL + * for a named module in the run-time or exploded image; + * a file path for a package from -Xbootclasspath/a) + */ + static Package definePackage(String name, String location) { + Module module = findModule(location); + if (module != null) { + // named module from runtime image or exploded module + if (name.isEmpty()) + throw new InternalError("empty package in " + location); + return JLA.definePackage(ClassLoaders.bootLoader(), name, module); + } + + // package in unnamed module (-Xbootclasspath/a) + URL url = toFileURL(location); + Manifest man = url != null ? getManifest(location) : null; + + return ClassLoaders.bootLoader().defineOrCheckPackage(name, man, url); + } + + /** + * Finds the module at the given location defined to the boot loader. + * The module is either in runtime image or exploded image. + * Otherwise this method returns null. + */ + private static Module findModule(String location) { + String mn = null; + if (location.startsWith("jrt:/")) { + // named module in runtime image ("jrt:/".length() == 5) + mn = location.substring(5, location.length()); + } else if (location.startsWith("file:/")) { + // named module in exploded image + Path path = Path.of(URI.create(location)); + Path modulesDir = Path.of(JAVA_HOME, "modules"); + if (path.startsWith(modulesDir)) { + mn = path.getFileName().toString(); + } + } + + // return the Module object for the module name. The Module may + // in the boot layer or a child layer for the case that the module + // is loaded into a running VM + if (mn != null) { + String name = mn; + return Modules.findLoadedModule(mn) + .orElseThrow(() -> new InternalError(name + " not loaded")); + } else { + return null; + } + } + + /** + * Returns URL if the given location is a regular file path. + */ + @SuppressWarnings("removal") + private static URL toFileURL(String location) { + return AccessController.doPrivileged(new PrivilegedAction<>() { + public URL run() { + Path path = Path.of(location); + if (Files.isRegularFile(path)) { + try { + return path.toUri().toURL(); + } catch (MalformedURLException e) {} + } + return null; + } + }); + } + + /** + * Returns the Manifest if the given location is a JAR file + * containing a manifest. + */ + @SuppressWarnings("removal") + private static Manifest getManifest(String location) { + return AccessController.doPrivileged(new PrivilegedAction<>() { + public Manifest run() { + Path jar = Path.of(location); + try (InputStream in = Files.newInputStream(jar); + JarInputStream jis = new JarInputStream(in, false)) { + return jis.getManifest(); + } catch (IOException e) { + return null; + } + } + }); + } + } + + /** + * Returns an array of the binary name of the packages defined by + * the boot loader, in VM internal form (forward slashes instead of dot). + */ + private static native String[] getSystemPackageNames(); + + /** + * Returns the location of the package of the given name, if + * defined by the boot loader; otherwise {@code null} is returned. + * + * The location may be a module from the runtime image or exploded image, + * or from the boot class append path (i.e. -Xbootclasspath/a or + * BOOT-CLASS-PATH attribute specified in java agent). + */ + private static native String getSystemPackageLocation(String name); + private static native void setBootLoaderUnnamedModule0(Module module); +} diff --git a/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$1.class b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..eefd4f8e3f65cd7dc990aa98b71b8aaf4ab9e074 GIT binary patch literal 1876 zcma)6TXPd-7=GU7uuZZ}VoO`0f&~MlDG-V$AhiM|NHGny!HzoP#WwkDw%zVByBmf} z|A5YTnz7@J7fQz&E?~xr)fx2)XZ#8N80CF88@k0h)68VQ!+Ut1_wc=c{qxIj0A_J3 zg+9bI#C0T)BotR$Yh}~+m1`ST*>a4Qa?4jbrsbRVtYvs!Ex0O75i)lStI%w#=9+2| z^0igtj#2LTrd6()o?j8i{W?-e6B44T2%{0Ds@+*vuHl=GT}ea7fQGD&9P;cdaAg_x zO8MsUs%rX#CZFQF^WV?E{^2_fo)+!mih;a=^bsWP>guxvWJrsi0HoSUZ%(Ooc zi{s++1cUZ?MWU=|C=&F*QHYX336mO5={PMQ!#g06^bvB5Gw-;nYN>T)`<|GUb(|HX zjIa*{X`I8$8eY-yDqbU;*k7?Zp+T8BYQmA??lgqy?PVp+Rp+c+AdK&DtviiQvmJ7% z-fgPeQuQ>>V?gw$h3Oky_FhhU&IqZ7xndiB$K~cJ>`|xb-DGAegheK}uO6;M`~@8w zIY+WvnONc$m~~oAAy+ePRqw1XEBBVMZ1K%t&1o9elHr7c^|IuH;WiRpCC)0VvN^W zz8hhgU|mI(SJ_>|Tg>A+?*~}@<9q-vMEYb*ut2A)LfF8t z;PatC_yZ@ma43*!+n5mPxS0HjgQCQDX9A_4F~xeD|Nbq)$I#-Nh{x_TKrCQ>4E@af zGidZVQuGCe=}R1^uW*vS#zoq|0(}!iBiUq9VKj5R??)naxR|~~Ea3sfU!h;-RWuW& zpYXcCbQ6@6OZqnADiOLOdEcRNo3$lrV`994oKUWni1|-G_!Z~he}s#_v$)HAL@Gw# zG4t=C(><=qCWh#Tr@7am;RaV)*o;MZ$3R2*%QF8$)F|c3gJ&prYuSyyM>!Gp(%Yy7 Z+ViOM8t3_W6N|ykIW%}pGk}D{zbEE2t{DIT literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$2.class b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$2.class new file mode 100644 index 0000000000000000000000000000000000000000..8ca8a449c1cc0c45a6d160b200148d7ef98ba5f2 GIT binary patch literal 2474 zcma)7`)^c56#mY3+o9WAx|Z@%!CF>Ywk?bJW(&B~R*JhVZlMSYI^CVNx7@wA-bbZA z68{bV0)B-Aiq*vM6DFGYh>sZkOEf_}Gy9}qY?F4T=brh_Ip6ut%r}33@fCn^eA0;+ z+63Yj+R;H6S}tGB*lwtNS2`KTlV#;+PDQp8+U~d`gCK8AsiTB#tI|oivZ4sR`DM8( zGmdl@Gqa&@yNg+kyUju;5`>O$$qrIS7(Kr=_-q0ex&^jd=s}W@Y{JjXFRN0>m}9nU zhbIVaLx<)%(Tg1deHM0N7vbR6q7W>d{yDGUl_Q7C=&6BL0ZOt%a@pRnrz zq^X*naZ-3j;Gl&;3^CnJoVp7^EXiP6U1MsPkxTkS+QKkK2yxe#`|8-HO;sMV0*49x zO?oSaicFP}qFPYCa!V?~{2sCJEV%7GRhOdD(wNjqk8@ia?SC{twnmT%y~#!6aD~s~ z1%VeWyo8qt`~DM9dvi$(wp(UBwMMQ9ueB93E4mHRVLcrK*E(k5I9M|+1lC=+ot{78 z1T2Gtt*AAgTJvvE_bMyMBrf^2!4GVb`2-}-r8i#u;%Ut))M`d_PV1}^2kx)T83!Yz5WsWp) zt)vVW0&fxqjF0KX6l--+Iyrwaswg*X_$4rla{}ir%;5qDZ06BaE-SxNRaQb%B9mIL z#ni6TW!hu7XyKBEX!9di;2pxC!3tC<^6hXfbJn+4ZB9a!8^LpCdI-n4%q?9<*%krT zWiZDo8TZO&tZi3KN0oWypOf=?(0lV0EGzGOuW8V&61(CzOPFB5}bn^Z1VB%{l_2m0E z`Hr<_kk6iA-0s;>mag)>X6hAi>smEJXpm1xH1>hO`*knd%S_EQzHsYj?L}9Hk7Qu zEUe)}CR^Vq1v@AeRbX%ksn#j0%W4zP9CzEa3c}N#o=$7Zb(L@4Nfn@<)o+3DHe$)7 zeqI4y`9$aG5=>n0J^TVQoo|+y6E6(#x|3-pI6J`_Uoa%5Dwp0N_MCRNoKHxRZuj@5@WGub-m{;9S-DLjx7b$FuBme*a literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$3.class b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$3.class new file mode 100644 index 0000000000000000000000000000000000000000..b3ebc7dea09bd25447dd210c553615e0dfe38b99 GIT binary patch literal 1609 zcma)6TTc^F5dID=ER;nmAb0^qtWcKAqIfT&P})E&mlWmIEZajlxZO3oTcU6NBuxOL z55{MIkBM)_*|S?*F%50f&gq<)Z)U!kGe3TR{RSY9Vi($wP>@v7jt++GLFJ7uY@fTf zVd<7*RJf}z*M;Q^J8v1DSCXpCJVWQ9VP$GA-(wgn9Tv#r1V5%6yNz z+%|bGh|{T}3#rJ{Hfo%qFXp-JyTYzYOI1Y=E--ZX`@+l2QC_9i63eBK#zh5vD*7?N zkp7$4=I#MEeZpK2w(u7j64}X}6b3P*;IfJ!fu*@a8^ah;a9za>j53Tg1q`eil6%6g5I6D25s6Wxx-Tq!^Q|u&YA10shFc0UDsE$( zxR>z%m=HUTTd+Lp%y=9%Ev;6nJKW4I#tA1RZ;R5EBS&SYjjM;xqkf8VKW87|E|JumW4ofhgT zc*M{z2@#IIwt0HPFwh`RzOGZ&2{N>o>X?1kwy4^MUw0|{7qMz1&rowd>kFY_qhpH{ zFSYH|U6U87OAJH*FNN74e2$E$0FtzRq@?9S>n}mye&}R5N2gVi zNs literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$4.class b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$4.class new file mode 100644 index 0000000000000000000000000000000000000000..7849717b044213bd59583643fee8081af9bd446c GIT binary patch literal 1627 zcma)7O;giQ6g{sgL`slapeP~&R;8^PKk&1NBI@8wp^PXCcOiY2U`&`KWpwA(e}glC zGcH`Z@JFfVr9~@5hfb51-rRG}efQpX`~An4uK?!pxCbd{I?@KZ&@C{vQGa7PUL*t0 za!uE_>M}4NH61r{ym{9O!)k0QObZ;_vfRR^6|D>8svFjpWxAHvFju0$@fsDyd(1$O zBJEb5wx>+J1`PDk6sSTlCPwx0c{R?#GB?e5PGeNZ83SWDD=?lU&UDkkdggQz)#2?LWjN4C0r?RYW{NMJsJ?f+bq`Yj)mRCJsd7>KQo zZ$7I%d1uSb$nm`l3wP1L6pGAG(Ddjvl>{#fjK%O!+Rea;-kZyTv*oz5A?tItViKqw zx!@h~wR`HYrMN1Pp7-m_XMdI1SZcmqlfesX&7~z*^=->twE{=|ZX468@dQeV$w_MT z3VUr)M(cik*$S+;l1GDhEs(sAC9?c3mq6c2WZ7>Pt<6|n$8CYpq(<3?2=uHt4bO_2 z0XL98oaLF)ECU++>qV>oXpAXqsObK&_q1YDsNW79Rly;EWq23OJ zwug~w`5R6s8!x@Qhw<%2u}$P4H#30(F)DyOHv=t&tfpa5>%xTAjY%!j5m2EWP?pFW zm?pzb;s%iVNt%?dzPBKBGU5(jq;NMo$MEjaQRTtp$~~g1w1*4ZvBSZQ8!d;nPFI_z cf|=O+K4!V5IffqKQEVCFp9qj4N+pb+UvH_D$^ZZW literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$5.class b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$5.class new file mode 100644 index 0000000000000000000000000000000000000000..e8ece0649ddaf8aa2e56923d3b67f5384057c0bd GIT binary patch literal 1484 zcma)6ZBG+H5Pp`nT<<7w1pyUb3RWxyIZzRk5)y47khEaLkoa-AE^u(&Yp!=hzxk6e zQAji~e)cyRb@qBd70`ZYXLfF8o@ZWmzyJLF6+ju!baWx1A(=r6-3*2O+JWWBK=_io zmh17F@U0i2;|7i_yS&+~M5g>aL;8@r`MNK57{)96{E%BNm%CQotA(zxs*!jlc7!ja zElLK`&@~tt^dQ4vo(F7f?+ZI%=w5WB6D%<#3X@v~`p~bz%pi*ahTOUP<@p(sUPDNR zvBKolWK=aJ4c8b3qlAuUt!*s7wM8RvJgH%rVWGnYtcR|9TBAy9UZ z59`~)f6cdDvJ6x_o4Z@wchosHCWAev$x!T&Lw>$Q^HwqWS=zY{qbSC#ieS&Hz2rWx z3tCdbWW;HxRnwp2B=`Q-vYc%pL+@t5?Sm?B#Kb4sr_`ESlKEe5I zEsPynmdl5;*yeuu_Wolg(aJ7SEyku7`nFhc)DT84Udb7?9#rzOv|X?1$lX?}G(2LM z=xjAIc%nANV+>X4a$>e)JRw>c08+JwT4`KpG6Uz)Vv;D)i1I z=+}cg^yMyTOX|rXX%weFffY}neV|hpMS{E;x&Ocz>BD3rFO1_JNu}j+pT19!uG6RY zCO{BO-8cGIsSo1R+2TjAWAq+XzhLOi2}X`oUTDN@kg#*4_bCpEUq~k@TQU(L=E$a# z&jS=9?CcqK7LyUTB1IC%RSkpYa{`_sKLz}lq++WVr@o=@7}t;JaIvIJL_?3$szOr4 mi|R;WItqA*nMhigC7Hw=WuA{Lb9hQ}AjTn;9-KKW!1xVzwthMQ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$LoadedModule.class b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$LoadedModule.class new file mode 100644 index 0000000000000000000000000000000000000000..0dc5214d793d92245f43ead34fa2490e74c0773d GIT binary patch literal 2191 zcma)8ZBrXn6n<_9YzRwBL!qrGrY%KCXxB>dEfuAdS~Lk73flTMOLC!0H@mpmbbR@u zqt=%hb^PF{{R4ijGZJU~;P|PX@i#fv=iUt=Y3s!08M05Fet zl8B+pK-@$(dISbG?d!JX+TMn>w6-bBp+L`B$8*A2fv$*|NwI@%8)=Fuy7sEJY;IN4!ct~J+vvSRHyif)V!E$}O zA_MDO-El+5n|JM6Ew7Kpw5UW`k%D^Q2<(eOXgba%@G!q@24NC|7&Y-I(gM93GF&cS zl~u-ka3^ma;c^%_-UhQihT{gtOq{@Y2l0^tbC&PcZMP;c^q`!tB$?2JiAiLLRt}^c z%9T=HV6>^d6JC>@Xq(R|9;Qs3#3>>~c?-~FPjqPO$4#8Z69VySAlC(swH4&SO`xsL zn3%zn0{vybBA5MoP>#awATv)|5_sCgGk8`YS&_AJ;B19{AaJ6C#15eIEj5~-#d8K` zO+2rvaP&X=bJv1tcy?8)(#@GThk1eS(APu`>>%z?XJCQ!wwkJ7yX$^Xl@)3)yjPaG zpAEc7N_JrvT~}_{?p&}@uSzd$=?NSu)xFTE%2lW4thsW|^ZZZ`3M+oRvmV#0mfiYn zEr&Msa{`4um+k*cG`UJ9=2;qn{dvce#d>v32A32PM>5YDc317dQTyg$JiO{K)S1pu z_cloko}=Wl8<!Z#;YGj3o77zNJQ?WQMUpwQ{cb^;a~b2E97jqG zCs!#oW?J&bqKv5lg1|+tdngyR1TXHFxO>t5q8A85>rqiH-t zsX+ROY&Gyy1G#%$eAVWnuZ2HDJ|cXNd8(?W>0&ycy@SJw?%Oz!+2Q?io@DF1BDPbS z!LM1>Z!mywF^carM${eYCPp_#G>byBn1J{jql&tidJme|pHr%C=of`-11}VQM!Yz6 ziz+ej1!rj@d7)Y6VL}4m^YjOP|A`tu@{zx(!PC^CqgI0b>Jg>;7&TNeV>%3mc$a4U jJHcWOs&IsX*Hs%`p>+&z;7u({c#ASg`(c#uHj@7WfR6hU literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$NullModuleReader.class b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader$NullModuleReader.class new file mode 100644 index 0000000000000000000000000000000000000000..3043ddc00f34ab8c893e7bbf8e03da002f7c8754 GIT binary patch literal 1153 zcmbVLU2hUW6g^XxF5RNgt);eFMXeR8vT97Mq3MG}BMH)^D2a~?j4*YWZFXl({8#!^ zqlv!zql|Zl)zS}>#+SWw=bm%!*UryhU%vxr;E{tFWNcV@WHHN7-1k5Dp7hnw+wJZ1 zzGj%+7E0(HhD@c}b&$iH4JVIz4Ivuai<01++ ziiyMm!}1X%(joW9UdI@QE64c9f^{2RvDh`58itsRrF-w4|wQ3i-pueHKZR!EpxTr zj-`AR3}VUmc!IHUm0|5@f@2f&rXdVgBN%XoLQ5##j>kP7zV>^PZroPT_hr`)MdGKI zmL7?S;c4qXOR7`CcR~#qDrfb3)_#bg{IMzMsFid;409bZRKAWw0&JaAa(j|SaqYd? zYu0y?qNIrE-}3&w;*>PKo`jg~%OIlMPA7=NK7S#S(Jh}|PA#dOA=l=Sei=mChR3jR zz9}-~n@aJ}?3&Z~izhdYGFIr}&_7DA$f6TH9`e@6^T;x?+08?+&vclNC&B>6gS6Klhu@6f4&g;cFZ9%W6` zE}T>=O;uv0Y7>nraW?<9^B5VU;e3Pp*1dFy(vK5$txhR9sZs`a4eB258(YHzvJNS& JpoWKVegixa50U@? literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader.class b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader.class new file mode 100644 index 0000000000000000000000000000000000000000..7913316dc54b996ca729a8968b57304c918b2b6f GIT binary patch literal 22077 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̳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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader.java b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader.java new file mode 100644 index 00000000..1f7df790 --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/BuiltinClassLoader.java @@ -0,0 +1,1088 @@ +/* + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReference; +import java.lang.module.ModuleReader; +import java.lang.ref.SoftReference; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.ByteBuffer; +import java.security.AccessController; +import java.security.CodeSigner; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.SecureClassLoader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import java.util.stream.Stream; + +import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.VM; +import jdk.internal.module.ModulePatcher.PatchedModuleReader; +import jdk.internal.module.Resources; +import jdk.internal.vm.annotation.Stable; +import sun.security.util.LazyCodeSourcePermissionCollection; + + +/** + * The platform or application class loader. Resources loaded from modules + * defined to the boot class loader are also loaded via an instance of this + * ClassLoader type. + * + *

This ClassLoader supports loading of classes and resources from modules. + * Modules are defined to the ClassLoader by invoking the {@link #loadModule} + * method. Defining a module to this ClassLoader has the effect of making the + * types in the module visible.

+ * + *

This ClassLoader also supports loading of classes and resources from a + * class path of URLs that are specified to the ClassLoader at construction + * time. The class path may expand at runtime (the Class-Path attribute in JAR + * files or via instrumentation agents).

+ * + *

The delegation model used by this ClassLoader differs to the regular + * delegation model. When requested to load a class then this ClassLoader first + * maps the class name to its package name. If there is a module defined to a + * BuiltinClassLoader containing this package then the class loader delegates + * directly to that class loader. If there isn't a module containing the + * package then it delegates the search to the parent class loader and if not + * found in the parent then it searches the class path. The main difference + * between this and the usual delegation model is that it allows the platform + * class loader to delegate to the application class loader, important with + * upgraded modules defined to the platform class loader. + */ + +public class BuiltinClassLoader + extends SecureClassLoader +{ + static { + if (!ClassLoader.registerAsParallelCapable()) + throw new InternalError("Unable to register as parallel capable"); + } + + // parent ClassLoader + private final BuiltinClassLoader parent; + + // the URL class path, or null if there is no class path + private @Stable URLClassPath ucp; + + /** + * A module defined/loaded by a built-in class loader. + * + * A LoadedModule encapsulates a ModuleReference along with its CodeSource + * URL to avoid needing to create this URL when defining classes. + */ + private static class LoadedModule { + private final BuiltinClassLoader loader; + private final ModuleReference mref; + private final URI uri; // may be null + private @Stable URL codeSourceURL; // may be null + + LoadedModule(BuiltinClassLoader loader, ModuleReference mref) { + URL url = null; + this.uri = mref.location().orElse(null); + + // for non-jrt schemes we need to resolve the codeSourceURL + // eagerly during bootstrap since the handler might be + // overridden + if (uri != null && !"jrt".equals(uri.getScheme())) { + url = createURL(uri); + } + this.loader = loader; + this.mref = mref; + this.codeSourceURL = url; + } + + BuiltinClassLoader loader() { return loader; } + ModuleReference mref() { return mref; } + String name() { return mref.descriptor().name(); } + + URL codeSourceURL() { + URL url = codeSourceURL; + if (url == null && uri != null) { + codeSourceURL = url = createURL(uri); + } + return url; + } + + private URL createURL(URI uri) { + URL url = null; + try { + url = uri.toURL(); + } catch (MalformedURLException | IllegalArgumentException e) { + } + return url; + } + } + + // maps package name to loaded module for modules in the boot layer + private static final Map packageToModule; + static { + ArchivedClassLoaders archivedClassLoaders = ArchivedClassLoaders.get(); + if (archivedClassLoaders != null) { + @SuppressWarnings("unchecked") + Map map + = (Map) archivedClassLoaders.packageToModule(); + packageToModule = map; + } else { + packageToModule = new ConcurrentHashMap<>(1024); + } + } + + /** + * Invoked by ArchivedClassLoaders to archive the package-to-module map. + */ + static Map packageToModule() { + return packageToModule; + } + + // maps a module name to a module reference + private final Map nameToModule; + + // maps a module reference to a module reader + private final Map moduleToReader; + + // cache of resource name -> list of URLs. + // used only for resources that are not in module packages + private volatile SoftReference>> resourceCache; + + /** + * Create a new instance. + */ + BuiltinClassLoader(String name, BuiltinClassLoader parent, URLClassPath ucp) { + // ensure getParent() returns null when the parent is the boot loader + super(name, parent == null || parent == ClassLoaders.bootLoader() ? null : parent); + + this.parent = parent; + this.ucp = ucp; + + this.nameToModule = new ConcurrentHashMap<>(32); + this.moduleToReader = new ConcurrentHashMap<>(); + } + + /** + * Appends to the given file path to the class path. + */ + void appendClassPath(String path) { + // assert ucp != null; + ucp.addFile(path); + } + + /** + * Sets the class path, called to reset the class path during -Xshare:dump + */ + void setClassPath(URLClassPath ucp) { + this.ucp = ucp; + } + + /** + * Returns {@code true} if there is a class path associated with this + * class loader. + */ + boolean hasClassPath() { + return ucp != null; + } + + /** + * Register a module this class loader. This has the effect of making the + * types in the module visible. + */ + public void loadModule(ModuleReference mref) { + ModuleDescriptor descriptor = mref.descriptor(); + String mn = descriptor.name(); + if (nameToModule.putIfAbsent(mn, mref) != null) { + throw new InternalError(mn + " already defined to this loader"); + } + + LoadedModule loadedModule = new LoadedModule(this, mref); + for (String pn : descriptor.packages()) { + LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule); + if (other != null) { + throw new InternalError(pn + " in modules " + mn + " and " + + other.name()); + } + } + + // clear resources cache if VM is already initialized + if (resourceCache != null && VM.isModuleSystemInited()) { + resourceCache = null; + } + } + + /** + * Returns the {@code ModuleReference} for the named module defined to + * this class loader; or {@code null} if not defined. + * + * @param name The name of the module to find + */ + protected ModuleReference findModule(String name) { + return nameToModule.get(name); + } + + + // -- finding resources + + /** + * Returns a URL to a resource of the given name in a module defined to + * this class loader. + */ + @Override + public URL findResource(String mn, String name) throws IOException { + URL url = null; + + if (mn != null) { + // find in module + ModuleReference mref = nameToModule.get(mn); + if (mref != null) { + url = findResource(mref, name); + } + } else { + // find on class path + url = findResourceOnClassPath(name); + } + + return checkURL(url); // check access before returning + } + + /** + * Returns an input stream to a resource of the given name in a module + * defined to this class loader. + */ + @SuppressWarnings("removal") + public InputStream findResourceAsStream(String mn, String name) + throws IOException + { + // Need URL to resource when running with a security manager so that + // the right permission check is done. + if (System.getSecurityManager() != null || mn == null) { + URL url = findResource(mn, name); + return (url != null) ? url.openStream() : null; + } + + // find in module defined to this loader, no security manager + ModuleReference mref = nameToModule.get(mn); + if (mref != null) { + return moduleReaderFor(mref).open(name).orElse(null); + } else { + return null; + } + } + + /** + * Finds a resource with the given name in the modules defined to this + * class loader or its class path. + */ + @Override + public URL findResource(String name) { + String pn = Resources.toPackageName(name); + LoadedModule module = packageToModule.get(pn); + if (module != null) { + + // resource is in a package of a module defined to this loader + if (module.loader() == this) { + URL url; + try { + url = findResource(module.name(), name); // checks URL + } catch (IOException ioe) { + return null; + } + if (url != null + && (name.endsWith(".class") + || url.toString().endsWith("/") + || isOpen(module.mref(), pn))) { + return url; + } + } + + } else { + + // not in a module package but may be in module defined to this loader + try { + List urls = findMiscResource(name); + if (!urls.isEmpty()) { + URL url = urls.get(0); + if (url != null) { + return checkURL(url); // check access before returning + } + } + } catch (IOException ioe) { + return null; + } + + } + + // search class path + URL url = findResourceOnClassPath(name); + return checkURL(url); + } + + /** + * Returns an enumeration of URL objects to all the resources with the + * given name in modules defined to this class loader or on the class + * path of this loader. + */ + @Override + public Enumeration findResources(String name) throws IOException { + List checked = new ArrayList<>(); // list of checked URLs + + String pn = Resources.toPackageName(name); + LoadedModule module = packageToModule.get(pn); + if (module != null) { + + // resource is in a package of a module defined to this loader + if (module.loader() == this) { + URL url = findResource(module.name(), name); // checks URL + if (url != null + && (name.endsWith(".class") + || url.toString().endsWith("/") + || isOpen(module.mref(), pn))) { + checked.add(url); + } + } + + } else { + // not in a package of a module defined to this loader + for (URL url : findMiscResource(name)) { + url = checkURL(url); + if (url != null) { + checked.add(url); + } + } + } + + // class path (not checked) + Enumeration e = findResourcesOnClassPath(name); + + // concat the checked URLs and the (not checked) class path + return new Enumeration<>() { + final Iterator iterator = checked.iterator(); + URL next; + private boolean hasNext() { + if (next != null) { + return true; + } else if (iterator.hasNext()) { + next = iterator.next(); + return true; + } else { + // need to check each URL + while (e.hasMoreElements() && next == null) { + next = checkURL(e.nextElement()); + } + return next != null; + } + } + @Override + public boolean hasMoreElements() { + return hasNext(); + } + @Override + public URL nextElement() { + if (hasNext()) { + URL result = next; + next = null; + return result; + } else { + throw new NoSuchElementException(); + } + } + }; + + } + + /** + * Returns the list of URLs to a "miscellaneous" resource in modules + * defined to this loader. A miscellaneous resource is not in a module + * package, e.g. META-INF/services/p.S. + * + * The cache used by this method avoids repeated searching of all modules. + */ + @SuppressWarnings("removal") + private List findMiscResource(String name) throws IOException { + SoftReference>> ref = this.resourceCache; + Map> map = (ref != null) ? ref.get() : null; + if (map == null) { + // only cache resources after VM is fully initialized + if (VM.isModuleSystemInited()) { + map = new ConcurrentHashMap<>(); + this.resourceCache = new SoftReference<>(map); + } + } else { + List urls = map.get(name); + if (urls != null) + return urls; + } + + // search all modules for the resource + List urls; + try { + urls = AccessController.doPrivileged( + new PrivilegedExceptionAction<>() { + @Override + public List run() throws IOException { + List result = null; + for (ModuleReference mref : nameToModule.values()) { + URI u = moduleReaderFor(mref).find(name).orElse(null); + if (u != null) { + try { + if (result == null) + result = new ArrayList<>(); + result.add(u.toURL()); + } catch (MalformedURLException | + IllegalArgumentException e) { + } + } + } + return (result != null) ? result : Collections.emptyList(); + } + }); + } catch (PrivilegedActionException pae) { + throw (IOException) pae.getCause(); + } + + // only cache resources after VM is fully initialized + if (map != null) { + map.putIfAbsent(name, urls); + } + + return urls; + } + + /** + * Returns the URL to a resource in a module or {@code null} if not found. + */ + @SuppressWarnings("removal") + private URL findResource(ModuleReference mref, String name) throws IOException { + URI u; + if (System.getSecurityManager() == null) { + u = moduleReaderFor(mref).find(name).orElse(null); + } else { + try { + u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () { + @Override + public URI run() throws IOException { + return moduleReaderFor(mref).find(name).orElse(null); + } + }); + } catch (PrivilegedActionException pae) { + throw (IOException) pae.getCause(); + } + } + if (u != null) { + try { + return u.toURL(); + } catch (MalformedURLException | IllegalArgumentException e) { } + } + return null; + } + + /** + * Returns the URL to a resource in a module. Returns {@code null} if not found + * or an I/O error occurs. + */ + private URL findResourceOrNull(ModuleReference mref, String name) { + try { + return findResource(mref, name); + } catch (IOException ignore) { + return null; + } + } + + /** + * Returns a URL to a resource on the class path. + */ + @SuppressWarnings("removal") + private URL findResourceOnClassPath(String name) { + if (hasClassPath()) { + if (System.getSecurityManager() == null) { + return ucp.findResource(name, false); + } else { + PrivilegedAction pa = () -> ucp.findResource(name, false); + return AccessController.doPrivileged(pa); + } + } else { + // no class path + return null; + } + } + + /** + * Returns the URLs of all resources of the given name on the class path. + */ + @SuppressWarnings("removal") + private Enumeration findResourcesOnClassPath(String name) { + if (hasClassPath()) { + if (System.getSecurityManager() == null) { + return ucp.findResources(name, false); + } else { + PrivilegedAction> pa; + pa = () -> ucp.findResources(name, false); + return AccessController.doPrivileged(pa); + } + } else { + // no class path + return Collections.emptyEnumeration(); + } + } + + // -- finding/loading classes + + /** + * Finds the class with the specified binary name. + */ + @Override + protected Class findClass(String cn) throws ClassNotFoundException { + // no class loading until VM is fully initialized + if (!VM.isModuleSystemInited()) + throw new ClassNotFoundException(cn); + + // find the candidate module for this class + LoadedModule loadedModule = findLoadedModule(cn); + + Class c = null; + if (loadedModule != null) { + + // attempt to load class in module defined to this loader + if (loadedModule.loader() == this) { + c = findClassInModuleOrNull(loadedModule, cn); + } + + } else { + + // search class path + if (hasClassPath()) { + c = findClassOnClassPathOrNull(cn); + } + + } + + // not found + if (c == null) + throw new ClassNotFoundException(cn); + + return c; + } + + /** + * Finds the class with the specified binary name in a module. + * This method returns {@code null} if the class cannot be found + * or not defined in the specified module. + */ + @Override + protected Class findClass(String mn, String cn) { + if (mn != null) { + // find the candidate module for this class + LoadedModule loadedModule = findLoadedModule(mn, cn); + if (loadedModule == null) { + return null; + } + + // attempt to load class in module defined to this loader + assert loadedModule.loader() == this; + return findClassInModuleOrNull(loadedModule, cn); + } + + // search class path + if (hasClassPath()) { + return findClassOnClassPathOrNull(cn); + } + + return null; + } + + /** + * Loads the class with the specified binary name. + */ + @Override + protected Class loadClass(String cn, boolean resolve) + throws ClassNotFoundException + { + Class c = loadClassOrNull(cn, resolve); + if (c == null) + throw new ClassNotFoundException(cn); + return c; + } + + /** + * A variation of {@code loadClass} to load a class with the specified + * binary name. This method returns {@code null} when the class is not + * found. + */ + protected Class loadClassOrNull(String cn, boolean resolve) { + synchronized (getClassLoadingLock(cn)) { + // check if already loaded + Class c = findLoadedClass(cn); + + if (c == null) { + + // find the candidate module for this class + LoadedModule loadedModule = findLoadedModule(cn); + if (loadedModule != null) { + + // package is in a module + BuiltinClassLoader loader = loadedModule.loader(); + if (loader == this) { + if (VM.isModuleSystemInited()) { + c = findClassInModuleOrNull(loadedModule, cn); + } + } else { + // delegate to the other loader + c = loader.loadClassOrNull(cn); + } + + } else { + + // check parent + if (parent != null) { + c = parent.loadClassOrNull(cn); + } + + // check class path + if (c == null && hasClassPath() && VM.isModuleSystemInited()) { + c = findClassOnClassPathOrNull(cn); + } + } + + } + + if (resolve && c != null) + resolveClass(c); + + return c; + } + } + + /** + * A variation of {@code loadClass} to load a class with the specified + * binary name. This method returns {@code null} when the class is not + * found. + */ + protected final Class loadClassOrNull(String cn) { + return loadClassOrNull(cn, false); + } + + /** + * Finds the candidate loaded module for the given class name. + * Returns {@code null} if none of the modules defined to this + * class loader contain the API package for the class. + */ + private LoadedModule findLoadedModule(String cn) { + int pos = cn.lastIndexOf('.'); + if (pos < 0) + return null; // unnamed package + + String pn = cn.substring(0, pos); + return packageToModule.get(pn); + } + + /** + * Finds the candidate loaded module for the given class name + * in the named module. Returns {@code null} if the named module + * is not defined to this class loader or does not contain + * the API package for the class. + */ + private LoadedModule findLoadedModule(String mn, String cn) { + LoadedModule loadedModule = findLoadedModule(cn); + if (loadedModule != null && mn.equals(loadedModule.name())) { + return loadedModule; + } else { + return null; + } + } + + /** + * Finds the class with the specified binary name if in a module + * defined to this ClassLoader. + * + * @return the resulting Class or {@code null} if not found + */ + @SuppressWarnings("removal") + private Class findClassInModuleOrNull(LoadedModule loadedModule, String cn) { + if (System.getSecurityManager() == null) { + return defineClass(cn, loadedModule); + } else { + PrivilegedAction> pa = () -> defineClass(cn, loadedModule); + return AccessController.doPrivileged(pa); + } + } + + /** + * Finds the class with the specified binary name on the class path. + * + * @return the resulting Class or {@code null} if not found + */ + @SuppressWarnings("removal") + private Class findClassOnClassPathOrNull(String cn) { + String path = cn.replace('.', '/').concat(".class"); + if (System.getSecurityManager() == null) { + Resource res = ucp.getResource(path, false); + if (res != null) { + try { + return defineClass(cn, res); + } catch (IOException ioe) { + // TBD on how I/O errors should be propagated + } + } + return null; + } else { + // avoid use of lambda here + PrivilegedAction> pa = new PrivilegedAction<>() { + public Class run() { + Resource res = ucp.getResource(path, false); + if (res != null) { + try { + return defineClass(cn, res); + } catch (IOException ioe) { + // TBD on how I/O errors should be propagated + } + } + return null; + } + }; + return AccessController.doPrivileged(pa); + } + } + + /** + * Defines the given binary class name to the VM, loading the class + * bytes from the given module. + * + * @return the resulting Class or {@code null} if an I/O error occurs + */ + private Class defineClass(String cn, LoadedModule loadedModule) { + ModuleReference mref = loadedModule.mref(); + ModuleReader reader = moduleReaderFor(mref); + + try { + ByteBuffer bb = null; + URL csURL = null; + + // locate class file, special handling for patched modules to + // avoid locating the resource twice + String rn = cn.replace('.', '/').concat(".class"); + if (reader instanceof PatchedModuleReader) { + Resource r = ((PatchedModuleReader)reader).findResource(rn); + if (r != null) { + bb = r.getByteBuffer(); + csURL = r.getCodeSourceURL(); + } + } else { + bb = reader.read(rn).orElse(null); + csURL = loadedModule.codeSourceURL(); + } + + if (bb == null) { + // class not found + return null; + } + + CodeSource cs = new CodeSource(csURL, (CodeSigner[]) null); + try { + // define class to VM + return defineClass(cn, bb, cs); + + } finally { + reader.release(bb); + } + + } catch (IOException ioe) { + // TBD on how I/O errors should be propagated + return null; + } + } + + /** + * Defines the given binary class name to the VM, loading the class + * bytes via the given Resource object. + * + * @return the resulting Class + * @throws IOException if reading the resource fails + * @throws SecurityException if there is a sealing violation (JAR spec) + */ + private Class defineClass(String cn, Resource res) throws IOException { + URL url = res.getCodeSourceURL(); + + // if class is in a named package then ensure that the package is defined + int pos = cn.lastIndexOf('.'); + if (pos != -1) { + String pn = cn.substring(0, pos); + Manifest man = res.getManifest(); + defineOrCheckPackage(pn, man, url); + } + + // defines the class to the runtime + ByteBuffer bb = res.getByteBuffer(); + if (bb != null) { + CodeSigner[] signers = res.getCodeSigners(); + CodeSource cs = new CodeSource(url, signers); + return defineClass(cn, bb, cs); + } else { + byte[] b = res.getBytes(); + CodeSigner[] signers = res.getCodeSigners(); + CodeSource cs = new CodeSource(url, signers); + return defineClass(cn, b, 0, b.length, cs); + } + } + + + // -- packages + + /** + * Defines a package in this ClassLoader. If the package is already defined + * then its sealing needs to be checked if sealed by the legacy sealing + * mechanism. + * + * @throws SecurityException if there is a sealing violation (JAR spec) + */ + protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { + Package pkg = getAndVerifyPackage(pn, man, url); + if (pkg == null) { + try { + if (man != null) { + pkg = definePackage(pn, man, url); + } else { + pkg = definePackage(pn, null, null, null, null, null, null, null); + } + } catch (IllegalArgumentException iae) { + // defined by another thread so need to re-verify + pkg = getAndVerifyPackage(pn, man, url); + if (pkg == null) + throw new InternalError("Cannot find package: " + pn); + } + } + return pkg; + } + + /** + * Gets the Package with the specified package name. If defined + * then verifies it against the manifest and code source. + * + * @throws SecurityException if there is a sealing violation (JAR spec) + */ + private Package getAndVerifyPackage(String pn, Manifest man, URL url) { + Package pkg = getDefinedPackage(pn); + if (pkg != null) { + if (pkg.isSealed()) { + if (!pkg.isSealed(url)) { + throw new SecurityException( + "sealing violation: package " + pn + " is sealed"); + } + } else { + // can't seal package if already defined without sealing + if ((man != null) && isSealed(pn, man)) { + throw new SecurityException( + "sealing violation: can't seal package " + pn + + ": already defined"); + } + } + } + return pkg; + } + + /** + * Defines a new package in this ClassLoader. The attributes in the specified + * Manifest are used to get the package version and sealing information. + * + * @throws IllegalArgumentException if the package name duplicates an + * existing package either in this class loader or one of its ancestors + * @throws SecurityException if the package name is untrusted in the manifest + */ + private Package definePackage(String pn, Manifest man, URL url) { + String specTitle = null; + String specVersion = null; + String specVendor = null; + String implTitle = null; + String implVersion = null; + String implVendor = null; + String sealed = null; + URL sealBase = null; + + if (man != null) { + Attributes attr = SharedSecrets.javaUtilJarAccess() + .getTrustedAttributes(man, pn.replace('.', '/').concat("/")); + if (attr != null) { + specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); + specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); + specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); + implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); + implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); + implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); + sealed = attr.getValue(Attributes.Name.SEALED); + } + + attr = man.getMainAttributes(); + if (attr != null) { + if (specTitle == null) + specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); + if (specVersion == null) + specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); + if (specVendor == null) + specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); + if (implTitle == null) + implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); + if (implVersion == null) + implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); + if (implVendor == null) + implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); + if (sealed == null) + sealed = attr.getValue(Attributes.Name.SEALED); + } + + // package is sealed + if ("true".equalsIgnoreCase(sealed)) + sealBase = url; + } + return definePackage(pn, + specTitle, + specVersion, + specVendor, + implTitle, + implVersion, + implVendor, + sealBase); + } + + /** + * Returns {@code true} if the specified package name is sealed according to + * the given manifest. + * + * @throws SecurityException if the package name is untrusted in the manifest + */ + private boolean isSealed(String pn, Manifest man) { + Attributes attr = SharedSecrets.javaUtilJarAccess() + .getTrustedAttributes(man, pn.replace('.', '/').concat("/")); + String sealed = null; + if (attr != null) + sealed = attr.getValue(Attributes.Name.SEALED); + if (sealed == null && (attr = man.getMainAttributes()) != null) + sealed = attr.getValue(Attributes.Name.SEALED); + return "true".equalsIgnoreCase(sealed); + } + + // -- permissions + + /** + * Returns the permissions for the given CodeSource. + */ + @Override + protected PermissionCollection getPermissions(CodeSource cs) { + return new LazyCodeSourcePermissionCollection(super.getPermissions(cs), cs); + } + + // -- miscellaneous supporting methods + + /** + * Returns the ModuleReader for the given module, creating it if needed. + */ + private ModuleReader moduleReaderFor(ModuleReference mref) { + ModuleReader reader = moduleToReader.get(mref); + if (reader == null) { + // avoid method reference during startup + Function create = new Function<>() { + public ModuleReader apply(ModuleReference moduleReference) { + try { + return mref.open(); + } catch (IOException e) { + // Return a null module reader to avoid a future class + // load attempting to open the module again. + return new NullModuleReader(); + } + } + }; + reader = moduleToReader.computeIfAbsent(mref, create); + } + return reader; + } + + /** + * A ModuleReader that doesn't read any resources. + */ + private static class NullModuleReader implements ModuleReader { + @Override + public Optional find(String name) { + return Optional.empty(); + } + @Override + public Stream list() { + return Stream.empty(); + } + @Override + public void close() { + throw new InternalError("Should not get here"); + } + }; + + /** + * Returns true if the given module opens the given package + * unconditionally. + * + * @implNote This method currently iterates over each of the open + * packages. This will be replaced once the ModuleDescriptor.Opens + * API is updated. + */ + private boolean isOpen(ModuleReference mref, String pn) { + ModuleDescriptor descriptor = mref.descriptor(); + if (descriptor.isOpen() || descriptor.isAutomatic()) + return true; + for (ModuleDescriptor.Opens opens : descriptor.opens()) { + String source = opens.source(); + if (!opens.isQualified() && source.equals(pn)) { + return true; + } + } + return false; + } + + /** + * Checks access to the given URL. We use URLClassPath for consistent + * checking with java.net.URLClassLoader. + */ + private static URL checkURL(URL url) { + return URLClassPath.checkURL(url); + } + + // Called from VM only, during -Xshare:dump + private void resetArchivedStates() { + ucp = null; + resourceCache = null; + } +} diff --git a/tests/test_data/std/jdk/internal/loader/ClassLoaderHelper.class b/tests/test_data/std/jdk/internal/loader/ClassLoaderHelper.class new file mode 100644 index 0000000000000000000000000000000000000000..8522e56e5c548584664840c0d07130011045625c GIT binary patch literal 2162 zcmaJ?T~`xV6y2B1Fc5|q5%3d53m6cRYAvk=0gYPIh7ZMJ(YAV%jAU?_q?5r_`X~Bc z`_va-`e5x^p{uNR^|`;Gf2PuXXC{&e?OIuL?>+b2bM`)G-qC%5u;&5t7;vb<#CJzQpLyHO%tam;mKk^$1n??V$;@DbZDOQh8T zC6vh2D7)B;X%kmLnY25WyXKbzz2sDYITP2^hE}t`wUi-i;s$Oqsb2{Y38YdFo2u0a zdw|Wr$7IyJ@kR+bd}82J6M4)FoNN(hKz?y~#qw%)#bx5+rsr8M#eGJps#(LWt`t}f zi>eDt0zqX~l;y68W!$4Sij@tP+`3m07-WzBC(vk)1;|!P6!oFJ?OF?)8wJa|CksmE zJ^4yeIxEt%)jBe2e%Y=GoNo>LUw3Ru;F#LW+XYX0TZ^u)X$)1-U^irz5RJcW^4wY-7o`QlSEguwQ#-jki0X^7h3dGCfci z1;rwCvS2l9iE<^kgLHjBbCsw{;gPl~YoaT)bL$mmWK8sQFEGBXy^g zx7hvu)@pB68x@bJwuYN-5@w{e8K&r%E;`Y>7+0I;8rR6iOG8~1nj%`Ey%t;$o_*L7$dEDpM3?1+}R=MiH13aXqahN8UuV8!+ zLwf-&_7m65F)rf^T9`CGNA&m-Uqy$%W0DxRE{)aEoxhMw*Ky?PsUM(=mpe$T?%??9 zHcnoMovMSs!JZ+0>KNI^`IkHu3t;v$FfhaKEMd+e$s6CpzZV62FpQ2zc+8cK2}l%} z+r$WpC=sLr)(PD(b8WUozN~sRP@B@z?Vz2&z^}NygWPH|o=k3Ip^iJxBX#`(V^5@s Ypu= 0; + + private ClassLoaderHelper() {} + + /** + * Returns true if loading a native library only if + * it's present on the file system. + * + * @implNote + * On macOS 11.x or later which supports dynamic linker cache, + * the dynamic library is not present on the filesystem. The + * library cannot determine if a dynamic library exists on a + * given path or not and so this method returns false. + */ + static boolean loadLibraryOnlyIfPresent() { + return !hasDynamicLoaderCache; + } + + /** + * Returns an alternate path name for the given file + * such that if the original pathname did not exist, then the + * file may be located at the alternate location. + * For mac, this replaces the final .dylib suffix with .jnilib + */ + static File mapAlternativeName(File lib) { + String name = lib.toString(); + int index = name.lastIndexOf('.'); + if (index < 0) { + return null; + } + return new File(name.substring(0, index) + ".jnilib"); + } + + /** + * Parse a PATH env variable. + * + * Empty elements will be replaced by dot. + */ + static String[] parsePath(String ldPath) { + char ps = File.pathSeparatorChar; + ArrayList paths = new ArrayList<>(); + int pathStart = 0; + int pathEnd; + while ((pathEnd = ldPath.indexOf(ps, pathStart)) >= 0) { + paths.add((pathStart < pathEnd) ? + ldPath.substring(pathStart, pathEnd) : "."); + pathStart = pathEnd + 1; + } + int ldLen = ldPath.length(); + paths.add((pathStart < ldLen) ? + ldPath.substring(pathStart, ldLen) : "."); + return paths.toArray(new String[paths.size()]); + } +} diff --git a/tests/test_data/std/jdk/internal/loader/ClassLoaderValue.class b/tests/test_data/std/jdk/internal/loader/ClassLoaderValue.class new file mode 100644 index 0000000000000000000000000000000000000000..4d566fa0b47307b155c91381614e247102274720 GIT binary patch literal 1373 zcmb7@OK%e~5Xb-CBn?@XHZ4tf)6$lZN9n2(5)z3bMFCDxa%hP}#l_i};?(TIJ}UJ) zaezxf9QXiyD8x9~ioB4Li|rZD{QRHM`1hZmzW_9`Z^A$#jiiMXRv7jN{WDv-q3~U< zY~}I3@a;w~2z~B^O~r$tHS~44iUh+-O}a9yGbD z@*J+Z+?U#poyqWnB*leA>G?^>#iuJ!Wg$ZCxLd80$jp&Eb$J;1r0eN|wO!@rWbjHi zy5qkTfg{{Lcf-zmhC}N5oEH6Wa;l{hni)r(GaM|J$nb2bgjzYS`uTDS<2 + * ClassLoaderValue allows associating a + * {@link #computeIfAbsent(ClassLoader, BiFunction) computed} non-null value with + * a {@code (ClassLoader, keys...)} tuple. The associated value, as well as the + * keys are strongly reachable from the associated ClassLoader so care should be + * taken to use such keys and values that only reference types resolvable from + * the associated ClassLoader. Failing that, ClassLoader leaks are inevitable. + *

+ * Example usage: + *

{@code
+ * // create a root instance which represents a namespace and declares the type of
+ * // associated values (Class instances in this example)
+ * static final ClassLoaderValue> proxyClasses = new ClassLoaderValue<>();
+ *
+ * // create a compound key composed of a Module and a list of interfaces
+ * Module module = ...;
+ * List> interfaces = ...;
+ * ClassLoaderValue>.Sub.Sub>> key =
+ *     proxyClasses.sub(module).sub(interfaces);
+ *
+ * // use the compound key together with ClassLoader to lazily associate
+ * // the value with tuple (loader, module, interfaces) and return it
+ * ClassLoader loader = ...;
+ * Class proxyClass = key.computeIfAbsent(loader, (ld, ky) -> {
+ *     List> intfcs = ky.key();
+ *     Module m = ky.parent().key();
+ *     Class clazz = defineProxyClass(ld, m, intfcs);
+ *     return clazz;
+ * });
+ * }
+ *

+ * {@code classLoaderValue.(classLoader, ...)} represents an operation + * to {@link #get}, {@link #putIfAbsent}, {@link #computeIfAbsent} or {@link #remove} + * a value associated with a (classLoader, classLoaderValue) tuple. ClassLoader + * instances and root-{@link ClassLoaderValue} instances are compared using + * identity equality while {@link Sub sub}-ClassLoaderValue instances define + * {@link #equals(Object) equality} in terms of equality of its + * {@link Sub#parent() parent} ClassLoaderValue and its + * {@link #key() key} component. + * + * @param the type of value(s) associated with the root-ClassLoaderValue and + * all its {@link #sub(Object) descendants}. + * @author Peter Levart + * @since 9 + */ +public final class ClassLoaderValue + extends AbstractClassLoaderValue, V> { + + /** + * Constructs new root-ClassLoaderValue representing its own namespace. + */ + public ClassLoaderValue() {} + + /** + * @return the key component of this root-ClassLoaderValue (itself). + */ + @Override + public ClassLoaderValue key() { + return this; + } + + /** + * root-ClassLoaderValue can only be equal to itself and has no predecessors. + */ + @Override + public boolean isEqualOrDescendantOf(AbstractClassLoaderValue clv) { + return equals(Objects.requireNonNull(clv)); + } +} diff --git a/tests/test_data/std/jdk/internal/loader/ClassLoaders$AppClassLoader.class b/tests/test_data/std/jdk/internal/loader/ClassLoaders$AppClassLoader.class new file mode 100644 index 0000000000000000000000000000000000000000..aaa0c04dc7b3501f167455b0f827bf5ef6e5bc78 GIT binary patch literal 2680 zcma)7U2_vv7=BI?vSC?TD5QL2fdXmL648oiYo$agfwWW#Rf>w+&1t&rW_R7)RQM~7 zGhQh(dZRPibi~n7XS{Iq$~*llj^lgIF3G0dak$9to|ET1@AH11-~RpX2LKg(ltYRk zt-G#@40b8VYEY14IJZ_`FPnD2JzKZRmZR6XSH9XZt-!P^mhSsCxy6v3G;K4OVt7!f zt?3(j+0yMsc_HvjyD?FFHkM@E-P<*3XLrbsv!@IRc@@$>&7~XpEeBc z`waPnz>08WFr?uWPLl|c9~mo3TmpJ2u1ey_@eGDFoW(hYK8o8s_nM~fn~qHuuS6Vv zq_13Y>U_azc?O?|s5*aj4^|w@;zmFe6AB6p$GVQ*ZrOp^f!Z@V}Ns?bhoe%VClez_N74@sff|8eSF|C?{2Atf>9rY1fUd z8TzR~xE+RAl%t5=D;i$K1jE5PUomZd%d5n4$1t0ahfrfHFs<^M?v<%V%@ytkRQ{rI zY#x-U=ATAb_EA&{l&*2SreO-NGiW{!q&lI5;VcdO|VNEb$y6uilBsC&2?O^9or=Xfe+P!);1A;F7b5E8WQ zoFmUP0jT{%AyPVO6!5uLbD4X0LTv*z$Iz`s-802H+ROy2CROvr#Q4PA-kxttYSz^~ zZU+p>!A)?0Ty7aI6>Xxmo@_8MlYUi(lwniT$LCWxG8hz(`;N6i&ax%K`83{+#c{op zgB0&w2xx4~>Tcw`dhMaXUD1ucf)5ymx=E9+&pE-2)3WOw7>$tyvtjE&%Ok5J3FW(U zj7%1%$aKn}C?5^gbs8`>G8lHbG+qcaybaVH2(jV8a3*ZGJ5Hy}XB@9;)0}NJDJ#10 zii*LN^`CO-JKfajc{rrs*Fwz((wgsr~bS%V?!^bFn2pgt16 zn_#HX*G<|@(|dPufR#quNPkU>6lUqE(i`{!IedvZ`Wgy>xP^II(Gk3b+e9P27I25q z8F6nAN)UfSt6lUiY+?7@*snNV+IL|S{g*QNOzKngjg`{*%qH@iI8rPfZ{xYI2%DC6 zk0MLo-_ZGQ$@V7Qifs&Hi@3j+I>w2Yu2WpGfY{bkF}13sSx#DGvj6qRpZo94mAZXy9aIXo}WiCtD=y7q^H0cXIR($vPOK zI;>f&N=Gx|u86qiNwf$@u2>o!YvXcPXO z8xi|BtprQ9$Tl&#UFlz>^l!2dBeuS#ksYTe$Ku_B_GNy*94@*rf`?`5A@k gbM)b{%vc&sY`bJRg%9D$w~rRRRkAb=9~)5r1MbbG(f|Me literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/ClassLoaders$BootClassLoader.class b/tests/test_data/std/jdk/internal/loader/ClassLoaders$BootClassLoader.class new file mode 100644 index 0000000000000000000000000000000000000000..93b6ae95116185ded7cbd0001f5d4e940686cd91 GIT binary patch literal 1074 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 b?*+5?J>NR`Hp_utV@wX$b*{@?H=zC>2&XeE literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/ClassLoaders.java b/tests/test_data/std/jdk/internal/loader/ClassLoaders.java new file mode 100644 index 00000000..7b0f4d13 --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/ClassLoaders.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.util.jar.Manifest; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.VM; +import jdk.internal.module.ServicesCatalog; + +/** + * Creates and provides access to the built-in platform and application class + * loaders. It also creates the class loader that is used to locate resources + * in modules defined to the boot class loader. + */ + +public class ClassLoaders { + + private ClassLoaders() { } + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + // the built-in class loaders + private static final BootClassLoader BOOT_LOADER; + private static final PlatformClassLoader PLATFORM_LOADER; + private static final AppClassLoader APP_LOADER; + + // Sets the ServicesCatalog for the specified loader using archived objects. + private static void setArchivedServicesCatalog(ClassLoader loader) { + ServicesCatalog catalog = ArchivedClassLoaders.get().servicesCatalog(loader); + ServicesCatalog.putServicesCatalog(loader, catalog); + } + + // Creates the built-in class loaders. + static { + ArchivedClassLoaders archivedClassLoaders = ArchivedClassLoaders.get(); + // -Xbootclasspath/a or -javaagent with Boot-Class-Path attribute + String append = VM.getSavedProperty("jdk.boot.class.path.append"); + URLClassPath bootUcp = (append != null && !append.isEmpty()) + ? new URLClassPath(append, true) + : null; + if (archivedClassLoaders != null) { + BOOT_LOADER = (BootClassLoader) archivedClassLoaders.bootLoader(); + BOOT_LOADER.setClassPath(bootUcp); + setArchivedServicesCatalog(BOOT_LOADER); + PLATFORM_LOADER = (PlatformClassLoader) archivedClassLoaders.platformLoader(); + setArchivedServicesCatalog(PLATFORM_LOADER); + } else { + BOOT_LOADER = new BootClassLoader(bootUcp); + PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER); + } + // A class path is required when no initial module is specified. + // In this case the class path defaults to "", meaning the current + // working directory. When an initial module is specified, on the + // contrary, we drop this historic interpretation of the empty + // string and instead treat it as unspecified. + String cp = System.getProperty("java.class.path"); + if (cp == null || cp.isEmpty()) { + String initialModuleName = System.getProperty("jdk.module.main"); + cp = (initialModuleName == null) ? "" : null; + } + URLClassPath ucp = new URLClassPath(cp, false); + if (archivedClassLoaders != null) { + APP_LOADER = (AppClassLoader) archivedClassLoaders.appLoader(); + setArchivedServicesCatalog(APP_LOADER); + APP_LOADER.setClassPath(ucp); + } else { + APP_LOADER = new AppClassLoader(PLATFORM_LOADER, ucp); + ArchivedClassLoaders.archive(); + } + } + + /** + * Returns the class loader that is used to find resources in modules + * defined to the boot class loader. + * + * @apiNote This method is not public, it should instead be used via + * the BootLoader class that provides a restricted API to this class + * loader. + */ + static BuiltinClassLoader bootLoader() { + return BOOT_LOADER; + } + + /** + * Returns the platform class loader. + */ + public static ClassLoader platformClassLoader() { + return PLATFORM_LOADER; + } + + /** + * Returns the application class loader. + */ + public static ClassLoader appClassLoader() { + return APP_LOADER; + } + + /** + * The class loader that is used to find resources in modules defined to + * the boot class loader. It is not used for class loading. + */ + private static class BootClassLoader extends BuiltinClassLoader { + BootClassLoader(URLClassPath bcp) { + super(null, null, bcp); + } + + @Override + protected Class loadClassOrNull(String cn, boolean resolve) { + return JLA.findBootstrapClassOrNull(cn); + } + }; + + /** + * The platform class loader, a unique type to make it easier to distinguish + * from the application class loader. + */ + private static class PlatformClassLoader extends BuiltinClassLoader { + static { + if (!ClassLoader.registerAsParallelCapable()) + throw new InternalError(); + } + + PlatformClassLoader(BootClassLoader parent) { + super("platform", parent, null); + } + } + + /** + * The application class loader that is a {@code BuiltinClassLoader} with + * customizations to be compatible with long standing behavior. + */ + private static class AppClassLoader extends BuiltinClassLoader { + static { + if (!ClassLoader.registerAsParallelCapable()) + throw new InternalError(); + } + + AppClassLoader(BuiltinClassLoader parent, URLClassPath ucp) { + super("app", parent, ucp); + } + + @Override + protected Class loadClass(String cn, boolean resolve) + throws ClassNotFoundException + { + // for compatibility reasons, say where restricted package list has + // been updated to list API packages in the unnamed module. + @SuppressWarnings("removal") + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + int i = cn.lastIndexOf('.'); + if (i != -1) { + sm.checkPackageAccess(cn.substring(0, i)); + } + } + + return super.loadClass(cn, resolve); + } + + @Override + protected PermissionCollection getPermissions(CodeSource cs) { + PermissionCollection perms = super.getPermissions(cs); + perms.add(new RuntimePermission("exitVM")); + return perms; + } + + /** + * Called by the VM to support dynamic additions to the class path + * + * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch + */ + void appendToClassPathForInstrumentation(String path) { + appendClassPath(path); + } + + /** + * Called by the VM to support define package for AppCDS + */ + protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { + return super.defineOrCheckPackage(pn, man, url); + } + + /** + * Called by the VM, during -Xshare:dump + */ + private void resetArchivedStates() { + setClassPath(null); + } + } + + /** + * Attempts to convert the given string to a file URL. + * + * @apiNote This is called by the VM + */ + @Deprecated + private static URL toFileURL(String s) { + try { + // Use an intermediate File object to construct a URI/URL without + // authority component as URLClassPath can't handle URLs with a UNC + // server name in the authority component. + return Path.of(s).toRealPath().toFile().toURI().toURL(); + } catch (InvalidPathException | IOException ignore) { + // malformed path string or class path element does not exist + return null; + } + } +} diff --git a/tests/test_data/std/jdk/internal/loader/FileURLMapper.class b/tests/test_data/std/jdk/internal/loader/FileURLMapper.class new file mode 100644 index 0000000000000000000000000000000000000000..7610faf6febfe3464c8f42228f65c6a8bb69d472 GIT binary patch literal 1161 zcmah|TTc^F5dID=-FDe>DFvx0f++TaEElhoi&7<`3lfng^0u_cvasyd-L2?P(HH*! z51L3Zn)rx`zlj*Z}O7I5ScP8!<%6Ur8C7CqKHY56|_KM7}zXtsfOio$I?yJwDmG~)Oo|?t1q-g zy;|iCrPUmhp;hydE$*rGmKQj!3fj=l5U%Rp21B9|;n!aA9K)*QWhBrkA*rAX-3-b} z2nMOby(hLy6qD)9dC5IUNw}z>7ne?T)<7o!!+pG6_1^oftwqtt5HszPZf+2&j2`qW z7{FD^u-2GSBT3bM#iqFb|6A;Zqj zj=HQnE?@Nw5-3vUCA&<>L+2r%EhdwKHx-N=m0BhdC5#@aWZ3>3WT+Syvz_<{<)VnV zt>BK(D8kCy&9L}VZF`+NFZFek2q!e5Sy6WkaSkrS-iARy zgW7*LBu~&naEADbrV$aZJ*wyAh2%rsza@ z;xiyDCgu=eehM%P*{_HnAS(VolacD^&~gXp%++z>Bb3Bta;|(pD%*G*+(TTr@oyLs zu1KR2A)ibiB=RT8=BeN`l9)jnvzWjG^5#yED+J_{G}mcrnbEr-8d46?E1{>0ZfMv6 z*&5-CHdEO;hPB);G>3M7Kz)_l$JpX<9k+ImDRh%=zyjH)q{lPre357@`K9{_BuOu` dL`UeE3P?25?ZaadQLsa_5CZ||& literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/FileURLMapper.java b/tests/test_data/std/jdk/internal/loader/FileURLMapper.java new file mode 100644 index 00000000..6507b296 --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/FileURLMapper.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.net.URL; +import java.io.File; +import sun.net.www.ParseUtil; + +/** + * (Solaris) platform specific handling for file: URLs . + * urls must not contain a hostname in the authority field + * other than "localhost". + * + * This implementation could be updated to map such URLs + * on to /net/host/... + * + * @author Michael McMahon + */ + +public class FileURLMapper { + + URL url; + String path; + + public FileURLMapper (URL url) { + this.url = url; + } + + /** + * @return the platform specific path corresponding to the URL + * so long as the URL does not contain a hostname in the authority field. + */ + + public String getPath () { + if (path != null) { + return path; + } + String host = url.getHost(); + if (host == null || host.isEmpty() || "localhost".equalsIgnoreCase(host)) { + path = url.getFile(); + path = ParseUtil.decode(path); + } + return path; + } + + /** + * Checks whether the file identified by the URL exists. + */ + public boolean exists () { + String s = getPath (); + if (s == null) { + return false; + } else { + File f = new File (s); + return f.exists(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/loader/Loader$1.class b/tests/test_data/std/jdk/internal/loader/Loader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..f5423bf9c112c88509dab41d3d70e43235ed7dbc GIT binary patch literal 1816 zcmah~ZBrXn6n<_JSO|;60#Pfi6=MlY+ZC;^K@<^6>;^Cabn1*VOL9q^ojr8n}6u34J*@yziYsa3tj!C>AFd98}!qQvBVhsmV$)kW5HC)p%jTwQ$ zC77MVW7&+DXT|ZHXjLFvUOdR7h?g|Htm7427q~t=v%pl+PF zT~waR1mGLC=XUn$x17ABgZv&P9n$WsL01W-q29e z@g{DQ<2d~l7lCmn+zn(XJ+ebm9;ukJjzt*!-Ilb@ln2{Ln5<~HBcR6#JsFw%^=ckV zxTnJer!*4z`*n*G=!GUe7Q@~axY-Y@+3t}abYzR(8{ai$3|zx~Zqg+cRo9hm+g%IV z-40>){qo$T_jJ6k3TA_@r{P0^g*Yyh&2HdCPtD!HIdvE=Tm7)Lrea5+K^BMZb!GVA zdW$^Z(VM{mN3`y@xXx3S7Ks07lL0W-L0U8(%^q*uN49RHQXmd>=Y%J|7f zWH+DG?2{O@hAn~V%jxua70CDXP{YHXm*bn&o&FPnhXcf=%amCDe`r_0SuwbLgS|K9 zCWkCAkz7jm6gtje!)v;J$g3n_Psf+2b7|Efs>?8r6S)7J!!&@fH`+m3ERr&|EyHNb z4|zWHs^`gI-L=C|hPcJ8EI{A`WD5m#e*%=e?qbQyj8|-ypJ{wVS)sPYh#cjNapxSu zxO)!GSUSgq@iV4=qCJBZevdLI#2!ATUZjowSj8ulN>h0SKBYd%DRh~gyV3tDr1+QjcEnVRCA23C+@H_Z@_pBz)7%_+2Sio{B-yviL ztH>51zQU~d8gt?i7Q{Cwi*E;D8Y#?K%;Gcty9j*FIGr-FY*5>zWg3~kSRkXR_dJA# z2SAk%a&-8ju*L?Av;mVAvVjrf0`Hzt`8P!>KONHAy)+MKNf@zEi{rMjLz!bAyJ*Cg NBK9crj8`P{^)~~_zWx9J literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/Loader$2.class b/tests/test_data/std/jdk/internal/loader/Loader$2.class new file mode 100644 index 0000000000000000000000000000000000000000..d7d41883bab9c17cd1c3e637d688f4827fdf0b84 GIT binary patch literal 1172 zcmah|T~E_c7=8{6x|IqQ5ET(or)(1_B6lMsWWh+BumEy@=#E=QIW=uZ^v<88iC^); zAK;HNKJ5l>i(r%X{Wx!*=lwdre*gFhpn~-rhA?a(V_^iN0&}hUiR0;5gRV5f(^)D36vxTV}! zV06RNUc4zVTqquy7{`PG+ro8B3M~AKoUj#NMo~@1O@XYN@X{wRU+Cv9_M0XPo3?NR zGvo@}n%NWvLJZszSWI(_l-mxy_`OpLy)(~O4OQQM=c>1{7w9cF`3fwP@Y3#-``L>} z0+~usR{|4NPpjSb>9GnA<*`rCWHoT5eWWCl z*{@XG4C*x*%2UO85<7R`HMES|A#*S<%8Lv<5|~Qc;04ak-o=T)^m)sAW>_{*IFC== zJ@GF)UFePOc>dqtjs6C1vIO%WXos$P&Upxob+&LN$&*dp)~+8!o^Eu?G_WEtd--@Q ztm3JF^~TfneHEp+0_)usO7lI4L&A0E*y|bC8ZP0kisBbR#C5iIv{qrdpen)wcPTTj$b5dIE(sq7ZEA{S8vFDt?-R>k`wiU?}5pb;g;x5IJ*#nPI#Ykc%?;2-eC z2TeqS4{ChS=#Mgfr!86&bd&8&=gfTH%$%A2`1#=@fN9)nM;mem@+Jx>3Jk0*Kein& zQh_I3+x6wL3hYKKs^bE?o=Ugc3fxe@YOKkp(r!hLYd4%Qs%xZOCfZRFC}=+=(3f$V z@mlLDkdfni^%6{U80a)nfkmts%9Y-VeP?M+H6wxIgyT8Uq(E+Dbg_&s>@m=7q6fVK zoqsbkEr$uq$PWa1M@BQ8w^MtZ++H2tFVMY{LmB%qVBmm>K@16W{h`>#5HMC{IIo^D zJ0|t0j6*nV;E0K;j_COlk*QRm!k{@nP&2MtS6&oqqG1!qFd~rmVzlnk7G zF{q~^`@y}2COlzcOh=Y=WC~eg<85s}#ZGQRr7?AZ_629flTj<+eN=ZSeIl`K2TU?# zcBJv|IjCna;)~C`XDY9cF0#OBf0?wEhU2OE*7}kP?#m^Ymac~1lj)h1zAJ54rDdnXk`E28NE@y`> zl@|O~&{VUIE~uO=$w_@-EO^Fix_;<*D@h6lt_$q@cTY{+zznZ@MMd{i7{fBz-Y!gQ9J<7G(TZk>}7T84J8=kk}9G{)Uhxmw2 z@d^7W&(qe+GsfcrE>ddk5-yX!PQ8Qf&#jnTC&1~%5TBa(KBb@>BvaoO_6fW|g}SkY zg8~~c@-LCky`o1hrY>r4@g=6zr7|+5oSv$16gHz`X5)-C4m7j9Kff&c&j literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/Loader$LoadedModule.class b/tests/test_data/std/jdk/internal/loader/Loader$LoadedModule.class new file mode 100644 index 0000000000000000000000000000000000000000..6687059b6049f9114d6ae9e6cc217fa0b4c0855e GIT binary patch literal 1713 zcma)6U31e$6g}4;QDO@SCJ7WmnuLVJjzN@`LhAs903~4OlVqmlNs%{3L6$O-+-Vz$?rUGec)OyfMR%YI}E;$aWGseX#Fpbp zr6Y|lLhpw8jcGWhTQla@HiQ)tx~6T{4zCcBllj#Qy3wN{qazEQFx*P7d)0;`jEV|N zVqN&cwFIHt@hmg6J(n;rnJ+6qBeWf3epBw6PAP+fIHaLh$6@3MxxFcb9y?g@MIc-j z#5%r~m_8l-7~toc;N8BR;%(wf8jcZkRnQfov9dIq!BHI7aRP&cbm*-tmAUC1Xp~cC z*breThE+^w-Sg|B%Go!+wS*F`VVE$gaunmNt<1}Gn zqx#UW-B9@4y5V?cRrp3(g)tSX(F6&px-Zt5A{v?E*nh?)NinG-j{*;);X8zb5vbKq zk#J0D4TRP3?eIHe#;b~Dui;xl!&$ z*6|505E52EIKCf=62TN$~BIL{5G)yvj*$tH@U3m{z|pK)A-MxBQ&qc)9QjM3t!~v?dPxf&OT9 zMoQgel=EsPY3TbL;PiK(xO^af{M!Pvt27fjiUA&lVUcKnb9T<5Z<(Zm0b znBp7gY-h+~VBrI{ zzII17bZht$q+wR(kK^ukQwB%kopj+PMxOH`p~Q5l&8Lb?j}l@sHa_pjiCo|)!C47z z;?pKR-(BL@wi4O6L>7bFCEEEXc7uOw1E*tf8I^s&=XZmD-v^w;oN93%3o0&RnPY~_ Kjbah^kogx32#dA= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/Loader$NullModuleReader.class b/tests/test_data/std/jdk/internal/loader/Loader$NullModuleReader.class new file mode 100644 index 0000000000000000000000000000000000000000..07d3ba9056044bc432be50225fd66ee8244fa7bc GIT binary patch literal 1105 zcmb7DO>fgc5Ph3Cb?O9~rZlC6(f|dLmd1cMR7%xL1R_#Mr3NB#bmAr1uvu638i{`e zry>v^2M&lIg%~@Aq@|VM;+ff*_vY=4_s7ojn%Eu?*Lq=ly($&lgWBmIVgpWm*zwpF3l_6B~vrC-5hdbrVa!p|RMe(%h%+k9^I}V5x@G0* z@__5|ko(+15i8M6FEcDxCgNf^wG?VluXatWF>H_ASGGtPZRt5K_w80}Hrt_;Pdzu3 z{E$cICayB9Pp3AHbM|ZrgVFF@&aluDinqgYkNeM@o}`mv%j-L`>-ZvylS4xfMZmDr z`VSd(YVuMjm!Wdjz0TSLA(S(YMNH)GKOka8d^|m@*==b?!5sfQ1Swbz+%aCpJKtJ&UZNg?)JAYaX`KD6b zZ%8KyIE}V&dW$Gyl^z29bMz_<^5`*8v`&#tmXXbD9fQ3iCxvVDjnYVc!Up;INdb{u zr-Kd_KIL-EL zMv0NIO*pEA+4^&xhe*d9)<+ay6fYg4^yQSU?=wtR!j#5#Ty+;av8~}AS&NufQNw*$ FzW~|y{?7ma literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/Loader.class b/tests/test_data/std/jdk/internal/loader/Loader.class new file mode 100644 index 0000000000000000000000000000000000000000..d2ab8aee576f031445c6e004f35855e66bd9e73e GIT binary patch literal 20237 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/Loader.java b/tests/test_data/std/jdk/internal/loader/Loader.java new file mode 100644 index 00000000..fbd16467 --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/Loader.java @@ -0,0 +1,736 @@ +/* + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.io.File; +import java.io.FilePermission; +import java.io.IOException; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.lang.module.ResolvedModule; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.ByteBuffer; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.CodeSigner; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.SecureClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +import jdk.internal.access.SharedSecrets; +import jdk.internal.module.Resources; + +/** + * A class loader that loads classes and resources from a collection of + * modules, or from a single module where the class loader is a member + * of a pool of class loaders. + * + *

The delegation model used by this ClassLoader differs to the regular + * delegation model. When requested to load a class then this ClassLoader first + * maps the class name to its package name. If there a module defined to the + * Loader containing the package then the class loader attempts to load from + * that module. If the package is instead defined to a module in a "remote" + * ClassLoader then this class loader delegates directly to that class loader. + * The map of package name to remote class loader is created based on the + * modules read by modules defined to this class loader. If the package is not + * local or remote then this class loader will delegate to the parent class + * loader. This allows automatic modules (for example) to link to types in the + * unnamed module of the parent class loader. + * + * @see ModuleLayer#defineModulesWithOneLoader + * @see ModuleLayer#defineModulesWithManyLoaders + */ + +public final class Loader extends SecureClassLoader { + + static { + ClassLoader.registerAsParallelCapable(); + } + + // the pool this loader is a member of; can be null + private final LoaderPool pool; + + // parent ClassLoader, can be null + private final ClassLoader parent; + + // maps a module name to a module reference + private final Map nameToModule; + + // maps package name to a module loaded by this class loader + private final Map localPackageToModule; + + // maps package name to a remote class loader, populated post initialization + private final Map remotePackageToLoader + = new ConcurrentHashMap<>(); + + // maps a module reference to a module reader, populated lazily + private final Map moduleToReader + = new ConcurrentHashMap<>(); + + // ACC used when loading classes and resources + @SuppressWarnings("removal") + private final AccessControlContext acc; + + /** + * A module defined/loaded to a {@code Loader}. + */ + private static class LoadedModule { + private final ModuleReference mref; + private final URL url; // may be null + private final CodeSource cs; + + LoadedModule(ModuleReference mref) { + URL url = null; + if (mref.location().isPresent()) { + try { + url = mref.location().get().toURL(); + } catch (MalformedURLException | IllegalArgumentException e) { } + } + this.mref = mref; + this.url = url; + this.cs = new CodeSource(url, (CodeSigner[]) null); + } + + ModuleReference mref() { return mref; } + String name() { return mref.descriptor().name(); } + URL location() { return url; } + CodeSource codeSource() { return cs; } + } + + + /** + * Creates a {@code Loader} in a loader pool that loads classes/resources + * from one module. + */ + @SuppressWarnings("removal") + public Loader(ResolvedModule resolvedModule, + LoaderPool pool, + ClassLoader parent) + { + super("Loader-" + resolvedModule.name(), parent); + + this.pool = pool; + this.parent = parent; + + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + String mn = descriptor.name(); + this.nameToModule = Map.of(mn, mref); + + Map localPackageToModule = new HashMap<>(); + LoadedModule lm = new LoadedModule(mref); + descriptor.packages().forEach(pn -> localPackageToModule.put(pn, lm)); + this.localPackageToModule = localPackageToModule; + + this.acc = AccessController.getContext(); + } + + /** + * Creates a {@code Loader} that loads classes/resources from a collection + * of modules. + * + * @throws IllegalArgumentException + * If two or more modules have the same package + */ + @SuppressWarnings("removal") + public Loader(Collection modules, ClassLoader parent) { + super(parent); + + this.pool = null; + this.parent = parent; + + Map nameToModule = new HashMap<>(); + Map localPackageToModule = new HashMap<>(); + for (ResolvedModule resolvedModule : modules) { + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + nameToModule.put(descriptor.name(), mref); + descriptor.packages().forEach(pn -> { + LoadedModule lm = new LoadedModule(mref); + if (localPackageToModule.put(pn, lm) != null) + throw new IllegalArgumentException("Package " + + pn + " in more than one module"); + }); + } + this.nameToModule = nameToModule; + this.localPackageToModule = localPackageToModule; + + this.acc = AccessController.getContext(); + } + + /** + * Completes initialization of this Loader. This method populates + * remotePackageToLoader with the packages of the remote modules, where + * "remote modules" are the modules read by modules defined to this loader. + * + * @param cf the Configuration containing at least modules to be defined to + * this class loader + * + * @param parentModuleLayers the parent ModuleLayers + */ + public Loader initRemotePackageMap(Configuration cf, + List parentModuleLayers) + { + for (String name : nameToModule.keySet()) { + ResolvedModule resolvedModule = cf.findModule(name).get(); + assert resolvedModule.configuration() == cf; + + for (ResolvedModule other : resolvedModule.reads()) { + String mn = other.name(); + ClassLoader loader; + + if (other.configuration() == cf) { + + // The module reads another module in the newly created + // layer. If all modules are defined to the same class + // loader then the packages are local. + if (pool == null) { + assert nameToModule.containsKey(mn); + continue; + } + + loader = pool.loaderFor(mn); + assert loader != null; + + } else { + + // find the layer for the target module + ModuleLayer layer = parentModuleLayers.stream() + .map(parent -> findModuleLayer(parent, other.configuration())) + .flatMap(Optional::stream) + .findAny() + .orElseThrow(() -> + new InternalError("Unable to find parent layer")); + + // find the class loader for the module + // For now we use the platform loader for modules defined to the + // boot loader + assert layer.findModule(mn).isPresent(); + loader = layer.findLoader(mn); + if (loader == null) + loader = ClassLoaders.platformClassLoader(); + } + + // find the packages that are exported to the target module + ModuleDescriptor descriptor = other.reference().descriptor(); + if (descriptor.isAutomatic()) { + ClassLoader l = loader; + descriptor.packages().forEach(pn -> remotePackage(pn, l)); + } else { + String target = resolvedModule.name(); + for (ModuleDescriptor.Exports e : descriptor.exports()) { + boolean delegate; + if (e.isQualified()) { + // qualified export in same configuration + delegate = (other.configuration() == cf) + && e.targets().contains(target); + } else { + // unqualified + delegate = true; + } + + if (delegate) { + remotePackage(e.source(), loader); + } + } + } + } + + } + + return this; + } + + /** + * Adds to remotePackageToLoader so that an attempt to load a class in + * the package delegates to the given class loader. + * + * @throws IllegalStateException + * if the package is already mapped to a different class loader + */ + private void remotePackage(String pn, ClassLoader loader) { + ClassLoader l = remotePackageToLoader.putIfAbsent(pn, loader); + if (l != null && l != loader) { + throw new IllegalStateException("Package " + + pn + " cannot be imported from multiple loaders"); + } + } + + + /** + * Find the layer corresponding to the given configuration in the tree + * of layers rooted at the given parent. + */ + private Optional findModuleLayer(ModuleLayer parent, Configuration cf) { + return SharedSecrets.getJavaLangAccess().layers(parent) + .filter(l -> l.configuration() == cf) + .findAny(); + } + + + /** + * Returns the loader pool that this loader is in or {@code null} if this + * loader is not in a loader pool. + */ + public LoaderPool pool() { + return pool; + } + + + // -- resources -- + + /** + * Returns a URL to a resource of the given name in a module defined to + * this class loader. + */ + @SuppressWarnings("removal") + @Override + protected URL findResource(String mn, String name) throws IOException { + ModuleReference mref = (mn != null) ? nameToModule.get(mn) : null; + if (mref == null) + return null; // not defined to this class loader + + // locate resource + URL url = null; + try { + url = AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public URL run() throws IOException { + Optional ouri = moduleReaderFor(mref).find(name); + if (ouri.isPresent()) { + try { + return ouri.get().toURL(); + } catch (MalformedURLException | + IllegalArgumentException e) { } + } + return null; + } + }); + } catch (PrivilegedActionException pae) { + throw (IOException) pae.getCause(); + } + + // check access with permissions restricted by ACC + if (url != null && System.getSecurityManager() != null) { + try { + URL urlToCheck = url; + url = AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public URL run() throws IOException { + return URLClassPath.checkURL(urlToCheck); + } + }, acc); + } catch (PrivilegedActionException pae) { + url = null; + } + } + + return url; + } + + @Override + public URL findResource(String name) { + String pn = Resources.toPackageName(name); + LoadedModule module = localPackageToModule.get(pn); + + if (module != null) { + try { + URL url = findResource(module.name(), name); + if (url != null + && (name.endsWith(".class") + || url.toString().endsWith("/") + || isOpen(module.mref(), pn))) { + return url; + } + } catch (IOException ioe) { + // ignore + } + + } else { + for (ModuleReference mref : nameToModule.values()) { + try { + URL url = findResource(mref.descriptor().name(), name); + if (url != null) return url; + } catch (IOException ioe) { + // ignore + } + } + } + + return null; + } + + @Override + public Enumeration findResources(String name) throws IOException { + return Collections.enumeration(findResourcesAsList(name)); + } + + @Override + public URL getResource(String name) { + Objects.requireNonNull(name); + + // this loader + URL url = findResource(name); + if (url == null) { + // parent loader + if (parent != null) { + url = parent.getResource(name); + } else { + url = BootLoader.findResource(name); + } + } + return url; + } + + @Override + public Enumeration getResources(String name) throws IOException { + Objects.requireNonNull(name); + + // this loader + List urls = findResourcesAsList(name); + + // parent loader + Enumeration e; + if (parent != null) { + e = parent.getResources(name); + } else { + e = BootLoader.findResources(name); + } + + // concat the URLs with the URLs returned by the parent + return new Enumeration<>() { + final Iterator iterator = urls.iterator(); + @Override + public boolean hasMoreElements() { + return (iterator.hasNext() || e.hasMoreElements()); + } + @Override + public URL nextElement() { + if (iterator.hasNext()) { + return iterator.next(); + } else { + return e.nextElement(); + } + } + }; + } + + /** + * Finds the resources with the given name in this class loader. + */ + private List findResourcesAsList(String name) throws IOException { + String pn = Resources.toPackageName(name); + LoadedModule module = localPackageToModule.get(pn); + if (module != null) { + URL url = findResource(module.name(), name); + if (url != null + && (name.endsWith(".class") + || url.toString().endsWith("/") + || isOpen(module.mref(), pn))) { + return List.of(url); + } else { + return Collections.emptyList(); + } + } else { + List urls = new ArrayList<>(); + for (ModuleReference mref : nameToModule.values()) { + URL url = findResource(mref.descriptor().name(), name); + if (url != null) { + urls.add(url); + } + } + return urls; + } + } + + + // -- finding/loading classes + + /** + * Finds the class with the specified binary name. + */ + @Override + protected Class findClass(String cn) throws ClassNotFoundException { + Class c = null; + LoadedModule loadedModule = findLoadedModule(cn); + if (loadedModule != null) + c = findClassInModuleOrNull(loadedModule, cn); + if (c == null) + throw new ClassNotFoundException(cn); + return c; + } + + /** + * Finds the class with the specified binary name in the given module. + * This method returns {@code null} if the class cannot be found. + */ + @Override + protected Class findClass(String mn, String cn) { + Class c = null; + LoadedModule loadedModule = findLoadedModule(cn); + if (loadedModule != null && loadedModule.name().equals(mn)) + c = findClassInModuleOrNull(loadedModule, cn); + return c; + } + + /** + * Loads the class with the specified binary name. + */ + @Override + protected Class loadClass(String cn, boolean resolve) + throws ClassNotFoundException + { + @SuppressWarnings("removal") + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + String pn = packageName(cn); + if (!pn.isEmpty()) { + sm.checkPackageAccess(pn); + } + } + + synchronized (getClassLoadingLock(cn)) { + // check if already loaded + Class c = findLoadedClass(cn); + + if (c == null) { + + LoadedModule loadedModule = findLoadedModule(cn); + + if (loadedModule != null) { + + // class is in module defined to this class loader + c = findClassInModuleOrNull(loadedModule, cn); + + } else { + + // type in another module or visible via the parent loader + String pn = packageName(cn); + ClassLoader loader = remotePackageToLoader.get(pn); + if (loader == null) { + // type not in a module read by any of the modules + // defined to this loader, so delegate to parent + // class loader + loader = parent; + } + if (loader == null) { + c = BootLoader.loadClassOrNull(cn); + } else { + c = loader.loadClass(cn); + } + + } + } + + if (c == null) + throw new ClassNotFoundException(cn); + + if (resolve) + resolveClass(c); + + return c; + } + } + + + /** + * Finds the class with the specified binary name if in a module + * defined to this ClassLoader. + * + * @return the resulting Class or {@code null} if not found + */ + @SuppressWarnings("removal") + private Class findClassInModuleOrNull(LoadedModule loadedModule, String cn) { + PrivilegedAction> pa = () -> defineClass(cn, loadedModule); + return AccessController.doPrivileged(pa, acc); + } + + /** + * Defines the given binary class name to the VM, loading the class + * bytes from the given module. + * + * @return the resulting Class or {@code null} if an I/O error occurs + */ + private Class defineClass(String cn, LoadedModule loadedModule) { + ModuleReader reader = moduleReaderFor(loadedModule.mref()); + + try { + // read class file + String rn = cn.replace('.', '/').concat(".class"); + ByteBuffer bb = reader.read(rn).orElse(null); + if (bb == null) { + // class not found + return null; + } + + try { + return defineClass(cn, bb, loadedModule.codeSource()); + } finally { + reader.release(bb); + } + + } catch (IOException ioe) { + // TBD on how I/O errors should be propagated + return null; + } + } + + + // -- permissions + + /** + * Returns the permissions for the given CodeSource. + */ + @Override + protected PermissionCollection getPermissions(CodeSource cs) { + PermissionCollection perms = super.getPermissions(cs); + + URL url = cs.getLocation(); + if (url == null) + return perms; + + // add the permission to access the resource + try { + Permission p = url.openConnection().getPermission(); + if (p != null) { + // for directories then need recursive access + if (p instanceof FilePermission) { + String path = p.getName(); + if (path.endsWith(File.separator)) { + path += "-"; + p = new FilePermission(path, "read"); + } + } + perms.add(p); + } + } catch (IOException ioe) { } + + return perms; + } + + + // -- miscellaneous supporting methods + + /** + * Find the candidate module for the given class name. + * Returns {@code null} if none of the modules defined to this + * class loader contain the API package for the class. + */ + private LoadedModule findLoadedModule(String cn) { + String pn = packageName(cn); + return pn.isEmpty() ? null : localPackageToModule.get(pn); + } + + /** + * Returns the package name for the given class name + */ + private String packageName(String cn) { + int pos = cn.lastIndexOf('.'); + return (pos < 0) ? "" : cn.substring(0, pos); + } + + + /** + * Returns the ModuleReader for the given module. + */ + private ModuleReader moduleReaderFor(ModuleReference mref) { + return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref)); + } + + /** + * Creates a ModuleReader for the given module. + */ + private ModuleReader createModuleReader(ModuleReference mref) { + try { + return mref.open(); + } catch (IOException e) { + // Return a null module reader to avoid a future class load + // attempting to open the module again. + return new NullModuleReader(); + } + } + + /** + * A ModuleReader that doesn't read any resources. + */ + private static class NullModuleReader implements ModuleReader { + @Override + public Optional find(String name) { + return Optional.empty(); + } + @Override + public Stream list() { + return Stream.empty(); + } + @Override + public void close() { + throw new InternalError("Should not get here"); + } + } + + /** + * Returns true if the given module opens the given package + * unconditionally. + * + * @implNote This method currently iterates over each of the open + * packages. This will be replaced once the ModuleDescriptor.Opens + * API is updated. + */ + private boolean isOpen(ModuleReference mref, String pn) { + ModuleDescriptor descriptor = mref.descriptor(); + if (descriptor.isOpen() || descriptor.isAutomatic()) + return true; + for (ModuleDescriptor.Opens opens : descriptor.opens()) { + String source = opens.source(); + if (!opens.isQualified() && source.equals(pn)) { + return true; + } + } + return false; + } +} diff --git a/tests/test_data/std/jdk/internal/loader/LoaderPool.class b/tests/test_data/std/jdk/internal/loader/LoaderPool.class new file mode 100644 index 0000000000000000000000000000000000000000..64494efa2f4b9a459a0343b93374cc7296d8fee8 GIT binary patch literal 3506 zcmb7H`%@EF6#i}!vLP%4@kP`sQnUn+D794yRRN`<0hL&&+FF<70!uc#>Fx%l@Av!t zoca&=Yo9vkOxxc&u&P4CDJK0thMy zsi;Gkp?O|g(2|B`&L&S!&-1Ly5FXG?-95|@>`Y85h%l^^MkQA_k|#80ZcHmip&%GV z15^c#Dw+^u*j{l}uyQ4XCx0U#RhC- zXsnuLi0CdSH+1+n5072C0c zA!N$o4a>fLgrpSgWY}>ZxC!o9#sbfcNvsMUW!N&G%O`b{QZh9oX;@m0+sU;2ilQC6 z1n0XME_Qn0Wsove)!tI++Mdo>mO=9?Wg9j$$MJ%s5|dH1p;JWyT>_L=;0)EEGOn$g zvqV=9_9*C8k;L9AzNxyzPq9QS9rP#a$-^JHJW?*DpR#)N;c*4~RXl+wg)(aLBG6D_ zJg!I?F`q6d6Pf2h6^GDI!d%dd5+|e9_o|yhtcc z`%$c>%rYkFEUi0k$}i5Dk|}))F*~IKw<)Eg7*sH%Qac?ZdMiq+WI~W;Ec>{YonvS# z$Cv)^cbAwHwHQ(HG)@rlvz$`i?N51anop`Yg*3zZ4w3=41r5$I-O;8Eo?~Da6pRyL z6}b#9TOGG;%Z_3UK>_HjiV0+hHOIBNR$$m##j!VN{IOx6_c1E_+qn|;04R& zXS8fyo8?kK<9-AWN_tI|P{i{fC>K>cC%QXU!6W5QyF!jTy3KPd@G`FEmPjl08GY8I zN1Hm~NVT{Id|gy-i#7T#bvVUv@}Xh*VpMl3_2;maqpV_S-Q?q?!Zf$fiL%k=mA0~) zF{#+XnN}@3gId&VZn|l0k=x|C*-N6*eH9D2b24o9rRnF8s$NahVsV))e+P?}_Lq80 zZrC!stZ5@jC7UPJN}?5%h^b0Xi`5FQFl@X>bKaKAkbPK5)Xt>_&cr0i*sK1CI05(i zBbKX6fNOUT!=c*UOzG5KDKxJdT46e;b(s802OSj;zn!iXKwx8Z0z?L~M)}$i%~&Nn z%SUw43NepnA+cUj0Mg5lWx0-PYsE3{&RIF98ShYa{G2TBn3J(E-iy*%^uCH$@M<$Y zq=TFcYvWCbB_Bue2|iWunTpTx1w(tK^18WT<#{qK8KL;vjFzQa$s$8T!TQQsfxzJcfxni=}*;&n^d#P9?9#M3s0Khf47zK!vW@xOJ zE^M=yLzryx(8*r><>}ubu;QrzQ__-$g(89!?UJM?gcoUkQ+cico1VP6OO%yEbK4QP zi&lgc^eJdiKpWYDf*yq~zW9go_UOGzaTf6seO{(D3*;q8-|bz$Vqf%5bdfmDO^G7<{S5jNj!5FkfJ!5X7imQBnoKx?*QrdN&;4=+Sl7~b1J7QA61t91 x@E45U>pUTG)*+xCrQ03eAb$b8iMQxmWd0G2y^VMA0luV>D2;rDZ}1)B{{x#jxS{|6 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/LoaderPool.java b/tests/test_data/std/jdk/internal/loader/LoaderPool.java new file mode 100644 index 00000000..c0bdecf6 --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/LoaderPool.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.lang.module.Configuration; +import java.lang.module.ResolvedModule; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +/** + * A pool of class loaders. + * + * @see ModuleLayer#defineModulesWithManyLoaders + */ + +public final class LoaderPool { + + // maps module names to class loaders + private final Map loaders; + + + /** + * Creates a pool of class loaders. Each module in the given configuration + * is mapped to its own class loader in the pool. The class loader is + * created with the given parent class loader as its parent. + */ + public LoaderPool(Configuration cf, + List parentLayers, + ClassLoader parentLoader) + { + Map loaders = new HashMap<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + Loader loader = new Loader(resolvedModule, this, parentLoader); + String mn = resolvedModule.name(); + loaders.put(mn, loader); + } + this.loaders = loaders; + + // complete the initialization + loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayers)); + } + + + /** + * Returns the class loader for the named module + */ + public Loader loaderFor(String name) { + Loader loader = loaders.get(name); + assert loader != null; + return loader; + } + + /** + * Returns a stream of the loaders in this pool. + */ + public Stream loaders() { + return loaders.values().stream(); + } + +} diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibraries$1.class b/tests/test_data/std/jdk/internal/loader/NativeLibraries$1.class new file mode 100644 index 0000000000000000000000000000000000000000..00cba7d3368efc620f30f57b8d14873a963c9575 GIT binary patch literal 1300 zcma)6>rN9v6#j;`Y+Dvs%0(`MC`HG@ueJTM*CF@dWDv?}}@w;fxSxmDo)KEqHd-Ks5s zU-VsRSF;+X7zY0Y-P~C}DT`xYI(D2oIj!Tm3Knu}wuTvosld<^<(ez~hFNfBotjh? zm9?_+VOUP(FHv&#e2>$+4B?zpq3-wRr7gB=ML zEvk@NtSGBC_iHYN+UOWY+n{yx&-Si#c(lj2NHWnxerD)?aX|JIx@l?a4u|`-H+gMDJ$}o~S s#kD4F{;p7O8MGrsuoPI`!QDXK!+nxr`q(VvQE=0T$0XzArHZ8AZ$Q{JH2?qr literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibraries$2.class b/tests/test_data/std/jdk/internal/loader/NativeLibraries$2.class new file mode 100644 index 0000000000000000000000000000000000000000..3b13d47abc33ab76a2483a6184d65ec898bf6674 GIT binary patch literal 1366 zcmbVMT~8B16g|@xm$qA}6%;>E6p$7wtGs9eA<;&nNkNku5+A4A5eAl7oSh}%7x}6$ zkZ3|M(U|z7jCXdMxI##ZO?K|g?c8(jJ$Gh){r++cpoK>z{sDl;9w5hq4RTvJ|EAwb&KPIJo=|X~$@(HcP1Dii4Vqs~BaN8H8__rwoNw*b@vRZK=e1yxSG} zE$;^8sgY7V*dX!jy6-HQEg3P)4wTE{62U9Jn}D4WfT8TiT9f9sB@B-T!pthdQ0W-% z@2v5?etJ){LZ|12gg$kGtdgf))bllAw!+>Ut|?(UNmOOABR3T{v8Dn(o{dR8=PA3K z3HaZZUs#b9QoPg&W9^GoX`48D>J}{6%BkBglpll#LiKmVQvNZyB L$m@Era#y4N_ z1rr|(&nCtgqd&)ZXSazJLQ-t9b7xNHo_p`PGxO#5r_TUtc$`NHX$u(}0~ll|?(zff zcwDueSIu4Fh75zNQps?QAw5^w&LfMQg}jX+*bL5YtK&!&3az;3cs_3l?QHQ-9*DYZ zYObXSrfYsgJ6d($?J(rqB1`}sGj15hVH+bR`e39y+GU_iHcAG{wS=q1o=~BM@;~`C zLM>H0k1<@aFmB^2t})E?lh8850N>yD4jB&S>VGRv7+323aP$GrUeIcSW)4|qkok{bA83-oO&ZPLU|(^I=614y zNN&@LnafI}aqgH0h-|rf3@h^vIkE+IL}RgfM0h&p8l!Mv-;ibB>D~E(VfGUx_ABO| zO#Hjt#DqJTisO|rjTz#<8}qQ?;xh_7OMnUdgxpNv!u-MsE>};GJ;tbscwY8}ZiG47 rlS=_bvh)q05CFN literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibraries$CountedLock.class b/tests/test_data/std/jdk/internal/loader/NativeLibraries$CountedLock.class new file mode 100644 index 0000000000000000000000000000000000000000..8a129853bb94c6076456cd14522a23e95398978d GIT binary patch literal 918 zcmb7C&ubG=5dJ2cbdybL+qCsZYh$!g(;QsADHSh4F_7k9B+!H4%kCq-X0t1AcS~>n zD}o3j6)aQ=3VQdCGR|&78pMNMcIKNm^UXIi`}5b=?*N*pTgbpLku4#I1w#Em911&* zlxI7E@5EY5KeD~R8HV;V$-WkT)MiLnc&L08Jt7$Oon8TX6iiqp6j37B2ky{Tek8Ro zJT4cm)OJTi>QJ^-Ukj~dSZf9`XSfqK(@BvgP|L&x!b+;d6aK(%aoRv?e5cO$L*!R}6vkZlI8 zWbU@|WhWl>rG75@9!JWoPYcC*36!l<#Oc;$;#RyOD5)d*bz! zw&2Ryn>CQpWJkOeUUG|Ib%R(t@`*}xt^KjkJIPptd`E`S(;$pY+$3!OgFZs3<@-`M zJrRbIrz*~!26y?i8U9&_zkFQwvh4BS!jVgi?lU5`R^trRFuuS%VU)q;B*qr>4q1AS zD~wB%Ol)A25#j2LNFPG1-_M@@SvFyt!vyn2FSq10=3iOeW ze~c~qG}oar?XbmNn0J+_E3;M)rmcz-UiUAGKf|JvIlkgd@ikPLEScM8o6Ma{6d$uQ i897-C=ya|)H!U`BJ<}^dDL(l8@~bETEwFO literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibraries$LibraryPaths.class b/tests/test_data/std/jdk/internal/loader/NativeLibraries$LibraryPaths.class new file mode 100644 index 0000000000000000000000000000000000000000..794c7fbd07d276d322bd8d1db55814c1afad1527 GIT binary patch literal 824 zcmb7D&2AGh5dJ1fyUAi`NdtucKwG*gh(%mmAwdKR(keu3sf0KnC$UAuSh?MpK7tfE!^UZuS{_*qMcK{vS^HDeMQe$|RgvorJNKRuB6o+f&9K5bF6P zeUfE1(gP#SL0{TkLL+ELe~@Bpbh@+Q;~W+|EDD@Qov?Z=caq7GGGQl?c^(ydS0xNV zsO?FUt7+b~;AGnNo0Gm88o1!$qQE6I2@g(#>Tw_YYFf5d`N~WKIitp}WaWs$I^mpb>_K4zbOgo^)UtQmKrE_>s<+hvU))A3Pw;8qcYn{0(FiRIk-SJ3C;y2Yov27SOS z*2Odcx3SDt6)VRcvkOay@D6eIi&HKa$~BjY*OyQC0YD#7qfaPfl|3cg!CD~$tQQf? J3j*9l^%v$h%1QtL literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibraries$NativeLibraryContext$1.class b/tests/test_data/std/jdk/internal/loader/NativeLibraries$NativeLibraryContext$1.class new file mode 100644 index 0000000000000000000000000000000000000000..1bf7978d054547878cde53d15b647f8941160d3c GIT binary patch literal 1356 zcmbVMTTc@~6#k|cwp~{#7g50rO2GokipIoP(u7nAO)8o|NPIDwwj&HKvpBm;?2quj z=!+zp7@z$s#=l@Zv%AP5FQl7v&!uO+^PS7=&p%(k18Cx*jU4h83J!`GVyNu#L+*N9 z?YJ*Hd!idM46R5d!v;gXHotA5#4sKQMWOWERjqmdnRp)w8y0MXa)F^xYnjlCr|`CR zwctG)!>CvoaWIN8hNpYIcdk^S(29Gm=kuP>?gkI#p=isF=30uNnzj2)pQ1m6)n$ev zKREFE470WN3GF0JeLiu;Bx8Pc3zr$DPN=_)R5z5qa@SIYcsKo?U>I&oB{rh{j?i1Y z~T%It$^h3>a40gV#`JVASH#v-}y#n{r3-Fw&I&&3P&ufJkfqz^gZi z#auQ)GWp{cW|n~hD=$R2>-S!9&G!Y3jT-PV!#+KlY5tiu6U~1+mJTZu9?xp6>JR&oGj0P~Z44O?Na0 zN=BcEJpJg)K-L6lE=guQ3rAp|Ny*^~z0KcXzi^dwCkencOp-;rjWLQchZ_WzBWZtw z^}13zLirO}S%lv)!bB34B2YZ0aGj8D#L+h^tAu$g#e784V3rpaf57>IOaDV=NtIK` wX*y6O#uZaqf_fWwV)PkQNft1RyI6=li?~m6lDN-e5lf^ElWiWC>}8bx0s#SN3;+NC literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibraries$NativeLibraryContext.class b/tests/test_data/std/jdk/internal/loader/NativeLibraries$NativeLibraryContext.class new file mode 100644 index 0000000000000000000000000000000000000000..a5e227279bef8b39d1658c35c3b6b2661d849a98 GIT binary patch literal 2271 zcmbtVO;;OL7=G?d%7n?#ltNLFDlLeB+O%q0N)V~E2qmRz5Y*iy+`>RI6DJci$6w+v zaO1*{MN4~*$5j{o7oOurw=Q&1tIwU8gh|_l#L3Crk9j|y_j%v@-iMFx{RChUpP0~~ z8%S9=h8}?vyY{}FtJv;#?pA46mIHyFImdN^c>#TLYNHov^cpZNWMB!*>~8Jl95;}@ zYgcj=&)$-LZp{vyeOYiyzU@1*KAv1R7d=XUNwdRlLae#I<4b$1{V`hzaWn#_lDlcw z@+OWWYv6>1ew^$;87T_%l^eb<-JrD|oScemgt0`sc>{w2v)y7IzhGhjdIrzoc>^z4 z7{-fq+<{aeTlT88Mj%&iUoF)MNMLa?fh1xzpNQ{v!z~An=jN8;Nj`}@mN#&krVm|R zlb<)F$z;52VH9Tsj5vOQfmY-pd!b-HgAt5b7{@CDshX5~0-Xf4-MlJr@yGlaUQ;d_^&Npz&j@^KLkYfN;he&v*SwlqpSN%UZ!!v}e!W@?nqjehrkH-)!bMzS z75cL3?Ms1)XBmB(V5K`_;fm7Lw`E`;Pu)WT%bpuEmSfe$(`CE9!*Vk*3tgbM=xnn{ z8$P{O6A7clT*6^oTM2=XbBY}GY$zJ@^Zb#)MQ@94vjxYMYmI72`s;S7!kv=^uWVN~ zc(T+w-b@8MPMwu~beHjoqsPM2Wz&5K0#}r|t_WZpOmSDLQyWZn#VH9~?$QF8r#`vt ze=?t>XsDC>X065ljVFcw4|9FRz%K8x$l~N0EY+xGrsv9)xEGs6ui=;FlA~&3Fxg?* zanGqT7f7$kda&%(S^Mh(WB-9t0c*u|rN3CQ>vc&MIxHXd?*631rYc*UXD`xtr3jen zYT)<|R~qJF@Xfo0JMVHQ$5C)RHhl-;`%q+oZ}l1C7hL6BDN_LN@qPl$vA@xTQoe)~ z-@wohFz%x7J_bI$gHs0>((yA!zT+2x1-_3%=kzxo;@{E7F@kc9w#IRtGRoF?=!M?y z;-v$e6|^vMXd%M$2Q{X#6l=^7g+gXhWBLG-8V>QRYZT&7^oqX{F_?HC%SwaYu0_CC zv6VBlvPv_r3v6=834D!g6xRXX(y*zFr^0ZCNCw2;NQuYDh<`As35;rb+ffRqv4R_v zU*%uX7wr_dy2*bU;t@s-_E}T4**KgpVjyQ*PA_YU#ntHtuv&nO)Hg`!-_k~eBqUbr zfvy?IYUwtDEHB2j4g}Fo3qc0@Ba9G%zQDS~tu`BDiZ?!)`M;Xs-gEc+k1yWA2BcWfjt+_fUAcVOK)-+)1!>n>(Y8t=g8>7BCN5w|VESA#1mcd|R|12j zGXa}{r=2<#_F*KHH!3ik`|~_s4kIp^xQr`Qs}8jv_>tP}6t3aAfg2`n;+DX`8TND6 zwUu-PjHa|3YJEpwB)6UKKyOEoK87(9S==F}*Wi`m+~491+!MGSG5D(5@N{rwZFsuL z6xCI2u^MQXcjx#5=c)C4zRVmgxi#h}UDA$PYwTB)w8}> z=OfHc&C?C9RIuyTHl)Ym(4B;f@9>2L`dgW5dw`)sza^#R9d0K#b={Fc!{eP79ocOM zw08cPuZ4~qzv@vWYHHJMcvThJkIbEo!A6+~YrrfmJ5}5D>7dq2n0OlcV<_15+;_`| zRdo&pWVC(v4wHYM_N(1j|W^aK0*_i;5@;w z_ZbG$qkM+2>!b-`N57))P2m{g80k|Cm&Q+U@iVS|;8BYsbT>p9Y4N&)XSB_erg{sL zRKG~@sW!O9k(5XjPH_7Ss#C7n3TVS5@Gv5LgvZf1jVB!A{BX=*HrkoP0>?p$$zTr8 JNE@o>?CKbm01M06%52Q5Dg=y;Uj1aciyM3 z3%maqUT&*qFho}^b8Fh*w$0ErzrnY8#^7=-<8Eb@kq!-=h%*Ew-x3VnO_!D&OP6cz zt!@oxksv(Xo~rAHqe})>Qu;j_&f@~HU+1!F5CY4`XuDU#C-{^hwyMkOjC8EVb%vgS zd@Fn^AI3$7p%3x!ne;*zLm!eVw3isp542+DOQ~WQSLpD_<(wb=8Ot)QFg`za=((y~ zqr}9}k3a+i44qy`lZKb0q&i7!7{m}c%xg6vs|>>@5J)cM3g^)?t zp{fGDuHgo5GDIBHqr;FGXa&l~a2dCi^LH4|on*VH5-_UaF76S8vu>F`&b+LMnxmUC zw>rypDh#TzQVdy)g)y#S0$(y*`G5>iohZT#1v31el0LB{vn_$imP#qAq%0;iOsN{X zpe*=Zu^^2`ZgtTTwvbL3UoniH%549Q7G(cxr86HvW90UQkB--mN~giO8FFBi7x4Dk~?*a znm5su9(P8Jr6;n~#T!yD3d<&f)ZjUWYt41%4U;BKe{fI}QoT%@RRZpu*QF@bx5~m= z=4CY}y64RbH;UZS)w{nLbk=nmRimdYE*de%Q5&^4$mtfw%C&cqR#WR8-Ib>f^@6JM z+jFc#pVp;R-cZPbCQS#1_9cf`HXrkv?_j86m^OJITQcibMa)uRP}G|zH?_@($~BoO z2-}%6ZHMxklTui2poJRc%?b@~)JNV7MmLA+eI6bt3_H^G4x_+bm0KTJV4{3l6BFKgi zWy9!TBRI=4_@2(vo<4rS3wk3YpO0E8CW>Xk8#;<#D2{Oh!rh+~7Vw{^c!zyDmVFcj=II)aA-( zS76nLnt*E(i39YlC@u<;eqDR`>}^^PnrI~sQP*(K$9hRoQa+6 zvWKhP*LIOo21s-d(_2>`t@f0`^e(>G$Nkp?;3cGkB-ler#vFa89yJ*s_l>W+ zcPU?O>Koy+ctUE5Mepx;@Cu>e>jO-$Q08a$G4~G&yI4Fjq5iu8TSSB{H^KKFhmR1L z?uJPvZo+pme#o1g-N%wDBrk^^=nHf*-UJ%=K?B%uZ*IbHWfof`dx>;}#+{^RA4!ws IH0{&h|CLcd2mk;8 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibraries$Unloader.class b/tests/test_data/std/jdk/internal/loader/NativeLibraries$Unloader.class new file mode 100644 index 0000000000000000000000000000000000000000..648efdff730b455273da0e75384666653b0fed8d GIT binary patch literal 2088 zcmbVNT~`}b6y1j;Op*=-QYbVkofaw(DDi{RN>HJc+F(eud?;AONpc$|OeS$ML81?? zrOV~gr9S!8KhP&1TBV?@CGY+f|ATt&Bq`AFfIi$gH}{@8F}8$e z8fja%tD1CfSJ8n^hN72B!pah^4kezA9UE?1s$UnAA=B*jGW1 zOhzxE`=nb|0tn+d1<$K^0eytge0DQxSdOqQ-He(=oe4&hE{B9m!4TzvWvjM9@LGC7 z5JF90V=}I$;u0=1(ONzTG%uG2R9wM}gn&_&oE*dAowXo_FsvY=Vnm|tKLrp%ub%m& zV%Xv+!fK+J*$i;Bt18A2WppmuYz==k$%xB@_8R1hW0=uJ;l$41WxS%`RTbm7Mrd;% zq_N8sY*8p~G1X&PtcfZ%yr$qf;o{*V)`hg_=#F@*B0pXugjpPAO*d_!XRBIT2urKf z(wPln0zEQ8Qz~8uOVq!dOr&OR&D|wjPn;qj1IN-3FO*Ccz%*tQ+*G+bZV_($=P0v9 z7Q;3dj<-}PZxAL~MW>KRGm_yI`NFqVyoEcQ&l+j2suNVXHZPs0F|XonS;n4Hu_O;K zs7Oj}^xDD{db#=46}&^Z_P_A?!CCfYD}_Qeh!mD&(JT`NkHVWZ^>R7Zto1e7N#0|j z9SY!X#j^CY$$~kF;5?t;jLsIb?9iStERn1f(!yS<9SO05b#q0x4f(si=yf&>*6rA- z(%-1i7%Q1YnAu#=OKuzmA0KOrjqc&GE8OKWgmZ@+mNx9-r!_?Wsf=0go596m#mpY&jjzkS?CK{mWp=Dz|5S7;j%s&aSvjJw6> z_<(&Pd>7w@d-#y8oJoY_&LqYbcP3GK@e$8ELH}?g^ePA|Socatf{xZY^uO3mlF3JY z#f3c#KE|k={f3uX@Bo+gG0~tQmzhN9MuW-Z!DGbs@TT10(a+=J9_IECe~3VW&B%e= z+C$KbY<^*4ftRPvR_t`vMAmiSzUo#_4NJ(l?0Hw@A=;NU>dH zyG-BX9{qrIwmG&2{phAfb<>cqr$&-*gKwO>X4)6$PXK;opAsK*Ukqs9M{1Qq?|OEz t_zPn4G01%knIX_7V-vjAg8Rt1b_g46!@M5mW?^v96x%%8X||gP{|nzv5;gz; literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibraries.class b/tests/test_data/std/jdk/internal/loader/NativeLibraries.class new file mode 100644 index 0000000000000000000000000000000000000000..4b1d5d48548de16127897e7f428f1c864da7ffc4 GIT binary patch literal 8861 zcmbtZ33yc3b^ecLG;e0~5JE_T!7O64g%$+ZY!b%E0!6|?U<9%yJDA7J6B-!J$TK6b z>h5)#v?*Of8%Wb6)HdDR5-^g8YGXGwb`p0r`g zj@y|q1b!362nYh(;>mb+yP&?N^O$wQYD`$kqm8WzE0gKeo11SQZth#t6Gjjr17Ss^ zL{L`Px%bF1JDL^vYS#1^m?OAT&kbkeiN5Cz_3?lFcQkMV*0q6Af5P{R*TDiv+Hrz{c{qbasru2qYcQzeQ9&KK;JB<6V!$6CP`x&_~wT$spV_Q67Q@W#e zw#ypi+f-rP?J9hCnP|g%1f`10{loD@HlC!b7;e+?^Elh3VW2~>dM1UKE34Lr(T)dH zpmz#3k^0Q}<))0QPqRvwF6=e1&%}e+FIcM8&Dczacy^?*B^tFe8D>N_t)hXRHDjrL z>G%m6UL0cbYHbU!LZ{Kc9)uA@ro^0Qih*~SnO&gJ;Ue3vbUKwb zK!dl-))r9y|$Fl{0*G6ZQ88MR`e6@7d-p0>Sc zJ<^$q9#^0kCdPe;U))fOEyV5h62s%&W$=>GR1 z6~-z2tbw01@$>iv!Iqg~SLOQ@>#L;HsA#x_OE5ndtGXKPv>zX~X^~%2(EXuYuotEb z{IX!<_szFsa3~SRX?)nk85L3fBwZ0kH$GzGSC!EN!I8%V;p3i8l7^;cz_D zJ(9`VgF91$48Km@y$BZFqLVYzyrwUVQH&WFH*rM)RrM6QP8fMRAqI3Q;ll$@VNBrn z4ZL9DMO+mun?fLM_j9*xCGB*Z6=lU{S71b)ftw-EvzG9A8ZVpp1ALmfG@Nwg@Kk%9 zGy8{=N$W_$=IU2)&A_WBUc+aYaRsRK&?KR>eKbzvu((VCdN(OO1u{?BizgmhtF%s< zw*rFCnRs0Vq|b`Q6i)rIi9f-gD!&aA3$}QTe=DyXBzV}nLkg6>VB*hIH#UD2v)WFp zCMmNso>8o0AvO?inD`?8f&i4Uhb-L_wGLQRP+C={{H2L6<14BqOUCRc_VzQjYC6_* z82Bq9ZNW+{Ino+-!nm%AhTv~hjr^LR-K)UuGGaDGF@&$grb!<0n9QwSO6+f$_%^;nlc=_+jd#6K&w!Uwx|?RSI><6rS_2L9c|f2c;yb3|~ml*u$`4Y?|+N~3zh|58Bo-!}n~ ztDi?)cSJQ-g13~bzAM;yJ6GlVuo)3b^)ByV(!lpjyo(#R=@2~t&~7J&R8Eysm6n7) zbg7e;)4VQq1@iD$2dvyrhPa3+Me49qk@TFkaI$j1BQZSHHcH}l;ch7gMzXA`uosbSX4nCe@?5|%lp zlqwweCpch8*(^1>J1lb@jpmzDp)@LUHR|Z!m$oxJLn`W3rYum@0}3a}kcDG8|HvX! z?vTZ*INA1b!B$nXy+z|T3Fo!zh^|g-AZ4j3%T#TuirE>qXR$nFbZ4#XFi+F($Z}Iw zs3i*(VK=7tCKDrhVU@F2sYOe9(3Lw)xl3x8(nJ4AE7(Kb_Nctd+0qlY zPc|!9h#zJ245#VqJ|{OQWelMd!OX|t*IF4%w-#DcMT67vC{`swPAiU zoUKF;Z%@>3cW@5W-QH zp+wj`qoC7wlq^Hma5i;Nw@$={s1+TsV}`H_%`X)G0|V*QNyodL|BJ}F+j0#stJ5## z_L9q$su^`r8b9FOna{CXJuy4`8FaVfu%cvw&KuHqSjFm*F;ulaG@GuV;61M?W+y=j zCE%6gh*J;O&u9bXPj8CzCWOab)yHUKcn)7$7ClI_sl3&1hOtWlig!0 z$jKP;7|&DRx5VyQb=7)9NU(l3`<)cA(}qMDwzJvcm0nlKRqN@bjwBB`+8gS=V2X+( z`6KkaTlN~lgX6M7N=|#qAiCsF9AxDdSGTV%@kEOugM#&%nl6B|ETKe;LOrG5ayG$w z_Lf23tOt3xX5Hpnxw@HVAz#DyBB|v&Z=m%!FPHPdlB3B|8Vxv12`rSNpV#R}u^9tsK^!}IX{g+ywAqZXG)Xhx)?uD(lY410N|V>H z4QFIKWmQg_1AplxN)4=A`8HJ*b-Zyc{VE9*bIIoVQEVT_&aQ@BP;By7`p+UVf%e|o z`Z4St$DWta-PQ0aiseFWT|=dR6bDt<_;uJgazDX<7{PpA5H7@%sKNVDj}KriKB(os z$6=M1akIK-(jm54?vou9Er>=fw~sVdNelhq_xOYB=?_PzQuroOW}thAOk!~^h3+Q} zUPU{~`PPzO38O7r_o|M0gQo9o^3zB2BmQTwd;*X4PQYStML822gYD8jTAQpIQK*(aN#1JE62fC1W_J7>(nZNMIDdc@|~TWQ^l?G$G?c#6OPTJBzvMdHER^1~wU$ z#u>~T$EV1jyIvZ_A3nrA=TXuW;xiJu>L~nK8d+OL$^S<_JQN8~eq|ElLQ`13gs;+< zlf;A;+JBxj>t~C!swcMMK{?Ln!+2RgU*o}xzqu}^pT`NjYTk*gbBrV4!_0;=Sb($G zh>w!O$N3TE6WD`u`~q^FnSYMdo<)pTh)?kn?rDtiif zVi9Lm?E6qE{Tit}S)kVEv!D}Y!BztBBx>~E6$ZA{O{y=c>n5?)!0ETKj43~f)qJ17 zLn?L|(q`Piauh3U2CvS$HE{D!n~QVp3LvPhQ#_)SLZRb|i}?ImRMuU@pO4~8A3@0k zt}}7IdbO63uz>0F*M$-i);qpM4EVOTOqD|+r!iJ|u*nBms1fOFE+SndA}Q?O>M*Ro zmElGFZ5^}gn+l66$o-Bpm{WTZ|L6`DFsVx8&6||tyX5&cKZCwQ-27f1L&+pB)7G39 z7+a1PR$zgHs~!a6s=Vz(C|Wp)rL?$fxZPBfmt~F~vWi-SsmGzZCV#~L;-+HXra)z& zviKbKMEsS34Nb-b?(2;h4deKiG5lv!u(m!D9L1YWp-AW&0+G;#NN^l)Hw7cXYgF^* z$)^Hx{>DWqD7%3rgFa))D&ps1AJ#LtH%T#7G_XU0*d-x!G0?lE1U+2$sLa)dXlIDl z@cZxs1mGZhl-1J7U=6V>-Ya_;j;b6T%A4tsbm1EsvJYv4sn9s&K(@zBoTHhFbn#gX z|GOwLWUt7(XkfemYK3a-jtlW_6pygC)UT{%RJ0ZT_F)6+x0UutH z@Ti!o>KEyn!x})9Utp%ahAR1tR>!H_3*x^&hG?ovyu$r!yHd>-641Ui1Yj(wxJqQ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibraries.java b/tests/test_data/std/jdk/internal/loader/NativeLibraries.java new file mode 100644 index 00000000..64a3813a --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/NativeLibraries.java @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.loader; + +import jdk.internal.misc.VM; +import jdk.internal.ref.CleanerFactory; +import jdk.internal.util.StaticProperty; + +import java.io.File; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Native libraries are loaded via {@link System#loadLibrary(String)}, + * {@link System#load(String)}, {@link Runtime#loadLibrary(String)} and + * {@link Runtime#load(String)}. They are caller-sensitive. + * + * Each class loader has a NativeLibraries instance to register all of its + * loaded native libraries. System::loadLibrary (and other APIs) only + * allows a native library to be loaded by one class loader, i.e. one + * NativeLibraries instance. Any attempt to load a native library that + * has already been loaded by a class loader with another class loader + * will fail. + */ +public final class NativeLibraries { + private static final boolean loadLibraryOnlyIfPresent = ClassLoaderHelper.loadLibraryOnlyIfPresent(); + private final Map libraries = new ConcurrentHashMap<>(); + private final ClassLoader loader; + // caller, if non-null, is the fromClass parameter for NativeLibraries::loadLibrary + // unless specified + private final Class caller; // may be null + private final boolean searchJavaLibraryPath; + + /** + * Creates a NativeLibraries instance for loading JNI native libraries + * via for System::loadLibrary use. + * + * 1. Support of auto-unloading. The loaded native libraries are unloaded + * when the class loader is reclaimed. + * 2. Support of linking of native method. See JNI spec. + * 3. Restriction on a native library that can only be loaded by one class loader. + * Each class loader manages its own set of native libraries. + * The same JNI native library cannot be loaded into more than one class loader. + * + * This static factory method is intended only for System::loadLibrary use. + * + * @see + * JNI Specification: Library and Version Management + */ + public static NativeLibraries newInstance(ClassLoader loader) { + return new NativeLibraries(loader, loader != null ? null : NativeLibraries.class, loader != null); + } + + private NativeLibraries(ClassLoader loader, Class caller, boolean searchJavaLibraryPath) { + this.loader = loader; + this.caller = caller; + this.searchJavaLibraryPath = searchJavaLibraryPath; + } + + /* + * Find the address of the given symbol name from the native libraries + * loaded in this NativeLibraries instance. + */ + public long find(String name) { + if (libraries.isEmpty()) + return 0; + + // the native libraries map may be updated in another thread + // when a native library is being loaded. No symbol will be + // searched from it yet. + for (NativeLibrary lib : libraries.values()) { + long entry = lib.find(name); + if (entry != 0) return entry; + } + return 0; + } + + /* + * Load a native library from the given file. Returns null if the given + * library is determined to be non-loadable, which is system-dependent. + * + * @param fromClass the caller class calling System::loadLibrary + * @param file the path of the native library + * @throws UnsatisfiedLinkError if any error in loading the native library + */ + @SuppressWarnings("removal") + public NativeLibrary loadLibrary(Class fromClass, File file) { + // Check to see if we're attempting to access a static library + String name = findBuiltinLib(file.getName()); + boolean isBuiltin = (name != null); + if (!isBuiltin) { + name = AccessController.doPrivileged(new PrivilegedAction<>() { + public String run() { + try { + if (loadLibraryOnlyIfPresent && !file.exists()) { + return null; + } + return file.getCanonicalPath(); + } catch (IOException e) { + return null; + } + } + }); + if (name == null) { + return null; + } + } + return loadLibrary(fromClass, name, isBuiltin); + } + + /** + * Returns a NativeLibrary of the given name. + * + * @param fromClass the caller class calling System::loadLibrary + * @param name library name + * @param isBuiltin built-in library + * @throws UnsatisfiedLinkError if the native library has already been loaded + * and registered in another NativeLibraries + */ + private NativeLibrary loadLibrary(Class fromClass, String name, boolean isBuiltin) { + ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader(); + if (this.loader != loader) { + throw new InternalError(fromClass.getName() + " not allowed to load library"); + } + + acquireNativeLibraryLock(name); + try { + // find if this library has already been loaded and registered in this NativeLibraries + NativeLibrary cached = libraries.get(name); + if (cached != null) { + return cached; + } + + // cannot be loaded by other class loaders + if (loadedLibraryNames.contains(name)) { + throw new UnsatisfiedLinkError("Native Library " + name + + " already loaded in another classloader"); + } + + /* + * When a library is being loaded, JNI_OnLoad function can cause + * another loadLibrary invocation that should succeed. + * + * Each thread maintains its own stack to hold the list of + * libraries it is loading. + * + * If there is a pending load operation for the library, we + * immediately return success; if the pending load is from + * a different class loader, we raise UnsatisfiedLinkError. + */ + for (NativeLibraryImpl lib : NativeLibraryContext.current()) { + if (name.equals(lib.name())) { + if (loader == lib.fromClass.getClassLoader()) { + return lib; + } else { + throw new UnsatisfiedLinkError("Native Library " + + name + " is being loaded in another classloader"); + } + } + } + + NativeLibraryImpl lib = new NativeLibraryImpl(fromClass, name, isBuiltin); + // load the native library + NativeLibraryContext.push(lib); + try { + if (!lib.open()) { + return null; // fail to open the native library + } + // auto unloading is only supported for JNI native libraries + // loaded by custom class loaders that can be unloaded. + // built-in class loaders are never unloaded. + boolean autoUnload = !VM.isSystemDomainLoader(loader) && loader != ClassLoaders.appClassLoader(); + if (autoUnload) { + // register the loaded native library for auto unloading + // when the class loader is reclaimed, all native libraries + // loaded that class loader will be unloaded. + // The entries in the libraries map are not removed since + // the entire map will be reclaimed altogether. + CleanerFactory.cleaner().register(loader, lib.unloader()); + } + } finally { + NativeLibraryContext.pop(); + } + // register the loaded native library + loadedLibraryNames.add(name); + libraries.put(name, lib); + return lib; + } finally { + releaseNativeLibraryLock(name); + } + } + + /** + * Loads a native library from the system library path and java library path. + * + * @param name library name + * + * @throws UnsatisfiedLinkError if the native library has already been loaded + * and registered in another NativeLibraries + */ + public NativeLibrary loadLibrary(String name) { + assert name.indexOf(File.separatorChar) < 0; + return loadLibrary(caller, name); + } + + /** + * Loads a native library from the system library path and java library path. + * + * @param name library name + * @param fromClass the caller class calling System::loadLibrary + * + * @throws UnsatisfiedLinkError if the native library has already been loaded + * and registered in another NativeLibraries + */ + public NativeLibrary loadLibrary(Class fromClass, String name) { + assert name.indexOf(File.separatorChar) < 0; + + NativeLibrary lib = findFromPaths(LibraryPaths.SYS_PATHS, fromClass, name); + if (lib == null && searchJavaLibraryPath) { + lib = findFromPaths(LibraryPaths.USER_PATHS, fromClass, name); + } + return lib; + } + + private NativeLibrary findFromPaths(String[] paths, Class fromClass, String name) { + for (String path : paths) { + File libfile = new File(path, System.mapLibraryName(name)); + NativeLibrary nl = loadLibrary(fromClass, libfile); + if (nl != null) { + return nl; + } + libfile = ClassLoaderHelper.mapAlternativeName(libfile); + if (libfile != null) { + nl = loadLibrary(fromClass, libfile); + if (nl != null) { + return nl; + } + } + } + return null; + } + + /** + * NativeLibraryImpl denotes a loaded native library instance. + * Each NativeLibraries contains a map of loaded native libraries in the + * private field {@code libraries}. + * + * Every native library requires a particular version of JNI. This is + * denoted by the private {@code jniVersion} field. This field is set by + * the VM when it loads the library, and used by the VM to pass the correct + * version of JNI to the native methods. + */ + static class NativeLibraryImpl extends NativeLibrary { + // the class from which the library is loaded, also indicates + // the loader this native library belongs. + final Class fromClass; + // the canonicalized name of the native library. + // or static library name + final String name; + // Indicates if the native library is linked into the VM + final boolean isBuiltin; + + // opaque handle to native library, used in native code. + long handle; + // the version of JNI environment the native library requires. + int jniVersion; + + NativeLibraryImpl(Class fromClass, String name, boolean isBuiltin) { + this.fromClass = fromClass; + this.name = name; + this.isBuiltin = isBuiltin; + } + + @Override + public String name() { + return name; + } + + @Override + public long find(String name) { + return findEntry0(handle, name); + } + + /* + * Unloader::run method is invoked to unload the native library + * when this class loader becomes phantom reachable. + */ + private Runnable unloader() { + return new Unloader(name, handle, isBuiltin); + } + + /* + * Loads the named native library + */ + boolean open() { + if (handle != 0) { + throw new InternalError("Native library " + name + " has been loaded"); + } + + return load(this, name, isBuiltin, throwExceptionIfFail()); + } + + @SuppressWarnings("removal") + private boolean throwExceptionIfFail() { + if (loadLibraryOnlyIfPresent) return true; + + // If the file exists but fails to load, UnsatisfiedLinkException thrown by the VM + // will include the error message from dlopen to provide diagnostic information + return AccessController.doPrivileged(new PrivilegedAction<>() { + public Boolean run() { + File file = new File(name); + return file.exists(); + } + }); + } + + /* + * Close this native library. + */ + void close() { + unload(name, isBuiltin, handle); + } + } + + /* + * The run() method will be invoked when this class loader becomes + * phantom reachable to unload the native library. + */ + static class Unloader implements Runnable { + // This represents the context when a native library is unloaded + // and getFromClass() will return null, + static final NativeLibraryImpl UNLOADER = + new NativeLibraryImpl(null, "dummy", false); + + final String name; + final long handle; + final boolean isBuiltin; + + Unloader(String name, long handle, boolean isBuiltin) { + if (handle == 0) { + throw new IllegalArgumentException( + "Invalid handle for native library " + name); + } + + this.name = name; + this.handle = handle; + this.isBuiltin = isBuiltin; + } + + @Override + public void run() { + acquireNativeLibraryLock(name); + try { + /* remove the native library name */ + if (!loadedLibraryNames.remove(name)) { + throw new IllegalStateException(name + " has already been unloaded"); + } + NativeLibraryContext.push(UNLOADER); + try { + unload(name, isBuiltin, handle); + } finally { + NativeLibraryContext.pop(); + } + } finally { + releaseNativeLibraryLock(name); + } + } + } + + /* + * Holds system and user library paths derived from the + * {@code java.library.path} and {@code sun.boot.library.path} system + * properties. The system properties are eagerly read at bootstrap, then + * lazily parsed on first use to avoid initialization ordering issues. + */ + static class LibraryPaths { + // The paths searched for libraries + static final String[] SYS_PATHS = ClassLoaderHelper.parsePath(StaticProperty.sunBootLibraryPath()); + static final String[] USER_PATHS = ClassLoaderHelper.parsePath(StaticProperty.javaLibraryPath()); + } + + // All native libraries we've loaded. + private static final Set loadedLibraryNames = + ConcurrentHashMap.newKeySet(); + + // reentrant lock class that allows exact counting (with external synchronization) + @SuppressWarnings("serial") + private static final class CountedLock extends ReentrantLock { + + private int counter = 0; + + public void increment() { + if (counter == Integer.MAX_VALUE) { + // prevent overflow + throw new Error("Maximum lock count exceeded"); + } + ++counter; + } + + public void decrement() { + --counter; + } + + public int getCounter() { + return counter; + } + } + + // Maps native library name to the corresponding lock object + private static final Map nativeLibraryLockMap = + new ConcurrentHashMap<>(); + + private static void acquireNativeLibraryLock(String libraryName) { + nativeLibraryLockMap.compute(libraryName, + new BiFunction<>() { + public CountedLock apply(String name, CountedLock currentLock) { + if (currentLock == null) { + currentLock = new CountedLock(); + } + // safe as compute BiFunction<> is executed atomically + currentLock.increment(); + return currentLock; + } + } + ).lock(); + } + + private static void releaseNativeLibraryLock(String libraryName) { + CountedLock lock = nativeLibraryLockMap.computeIfPresent(libraryName, + new BiFunction<>() { + public CountedLock apply(String name, CountedLock currentLock) { + if (currentLock.getCounter() == 1) { + // unlock and release the object if no other threads are queued + currentLock.unlock(); + // remove the element + return null; + } else { + currentLock.decrement(); + return currentLock; + } + } + } + ); + if (lock != null) { + lock.unlock(); + } + } + + // native libraries being loaded + private static final class NativeLibraryContext { + + // Maps thread object to the native library context stack, maintained by each thread + private static Map> nativeLibraryThreadContext = + new ConcurrentHashMap<>(); + + // returns a context associated with the current thread + private static Deque current() { + return nativeLibraryThreadContext.computeIfAbsent( + Thread.currentThread(), + new Function<>() { + public Deque apply(Thread t) { + return new ArrayDeque<>(8); + } + }); + } + + private static NativeLibraryImpl peek() { + return current().peek(); + } + + private static void push(NativeLibraryImpl lib) { + current().push(lib); + } + + private static void pop() { + // this does not require synchronization since each + // thread has its own context + Deque libs = current(); + libs.pop(); + if (libs.isEmpty()) { + // context can be safely removed once empty + nativeLibraryThreadContext.remove(Thread.currentThread()); + } + } + + private static boolean isEmpty() { + Deque context = + nativeLibraryThreadContext.get(Thread.currentThread()); + return (context == null || context.isEmpty()); + } + } + + // Invoked in the VM to determine the context class in JNI_OnLoad + // and JNI_OnUnload + private static Class getFromClass() { + if (NativeLibraryContext.isEmpty()) { // only default library + return Object.class; + } + return NativeLibraryContext.peek().fromClass; + } + + /* + * Return true if the given library is successfully loaded. + * If the given library cannot be loaded for any reason, + * if throwExceptionIfFail is false, then this method returns false; + * otherwise, UnsatisfiedLinkError will be thrown. + * + * JNI FindClass expects the caller class if invoked from JNI_OnLoad + * and JNI_OnUnload is NativeLibrary class. + */ + private static native boolean load(NativeLibraryImpl impl, String name, + boolean isBuiltin, + boolean throwExceptionIfFail); + /* + * Unload the named library. JNI_OnUnload, if present, will be invoked + * before the native library is unloaded. + */ + private static native void unload(String name, boolean isBuiltin, long handle); + private static native String findBuiltinLib(String name); +} diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibrary.class b/tests/test_data/std/jdk/internal/loader/NativeLibrary.class new file mode 100644 index 0000000000000000000000000000000000000000..3dfa3c6e09c7f625584deaa5805b9f56d8b75832 GIT binary patch literal 916 zcmah{U2hUW6g>kgY}Z9vN?SjwEY=U8wzMUE!k8$j4}{_ahNO?f?pg+xS+ZRk`3=7M zx#!-w-+p}l0-%P9ff(XRXeO>9!LZunm%Qw8 zd0u|i>A7~uka#Mj2%j;;3&pkp9V7hT9Z6JmFs@psN=t-MMYraFI>4uPQ zb2R9c)-st1vIJ!_H_4PHxJ_*r&ZlXo~5CAJB>6kZcS`KLN<3%-H|{ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/NativeLibrary.java b/tests/test_data/std/jdk/internal/loader/NativeLibrary.java new file mode 100644 index 00000000..228356e0 --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/NativeLibrary.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +/** + * NativeLibrary represents a loaded native library instance. + */ +public abstract class NativeLibrary { + public abstract String name(); + + /** + * Finds the address of the entry of the given name. Returns 0 + * if not found. + * + * @param name the name of the symbol to be found + */ + public abstract long find(String name); + + /** + * Finds the address of the entry of the given name. + * + * @param name the name of the symbol to be found + * @throws NoSuchMethodException if the named entry is not found. + */ + public final long lookup(String name) throws NoSuchMethodException { + long addr = find(name); + if (0 == addr) { + throw new NoSuchMethodException("Cannot find symbol " + name + " in library " + name()); + } + return addr; + } + + /* + * Returns the address of the named symbol defined in the library of + * the given handle. Returns 0 if not found. + */ + static native long findEntry0(long handle, String name); +} diff --git a/tests/test_data/std/jdk/internal/loader/RawNativeLibraries$1.class b/tests/test_data/std/jdk/internal/loader/RawNativeLibraries$1.class new file mode 100644 index 0000000000000000000000000000000000000000..2e1d029b2e61c30b17bfce89d4732ba1f11e0331 GIT binary patch literal 1325 zcma)5>rN9v6#j-5wk-?PQVMv#RBS7<6tAQNLkL8YatSrn#9!0xPzIJ=vOBHv&qu<< zOEA#~@S%)nwi~5@2~E0Z=FE4_`OfXv@9#eWEMq>2KEw>fP4r`cp|IE7x1_6t?{dd- zJl+((wawpea3wpUDjPocr3mt6hD3)u`9rRD8M4(q-r<%jJ!?lg!rCHjC4~f%22v&l zVKSsch{N5Mwb|Gcwqh7qkgimV46#D7ZeW;UqSsGVy8D}lN_y@f(zs$EV`3CphDYX_N6+qwtU&4Dz!v&$=10syew2NSNF>vos=? zv?81Ix=_1bbBp`@K+sH4Oh%l>x>@vAj^INz#qIrdei+g0Eq!-t2$rnLmdjP!Cs(Uo zSEt4*D$#$dy>QAR>gFOjP1U@%Z;MrG48!>OiJ#Fuqyn$Fw&Mjf8Qs(jJZ6}>T=Psk z#WQM^-YSN9s^j^kp;^0N0Z(t=5s^)7h(Nva0@@*S&2@#p?C>BE0dCXyB|sAgmQL%9 zrX`Qje=vNxL#IW(?<7;D=`UcVZ!kX5tq*tUJ3y8|4fp7qBORfT$9WK(^tFRArozsD}4rw{lL%(M*47qF^1zRI}V*^Xn!Y(fDSht5~-8s4YGLq zH*A)?6j2KCxro3+!V|rkfywj|#hi{}S|l~;{?b=mJEp_=Ow2AIa@3DUA!-IzC}&Y7 V8OI!+;CZN-!wZrrveL=W?+>aHMBM-Y literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/RawNativeLibraries$RawNativeLibraryImpl.class b/tests/test_data/std/jdk/internal/loader/RawNativeLibraries$RawNativeLibraryImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..c0259c28c0c08d8f1d573a2c7cda682c1b1d545e GIT binary patch literal 1444 zcmbtUTTc@~6#k|cwq2Kt6p#2^qc`tFZ1p4o1s(vq0?uybb4ob#P;&Sii8`uZI}9(ff31Qmodgwes!zh2$Q z8p73W!Og5`@v3fT7r1L|=|!V#b9gU>te}!Qrr`{F z8Pw;7sLl%4-X3R&rwXkg>4JhdL*fX1-hb(=ZCkd2vwvMSLeJCosiQ4U0YOdZxU7*I+t8t*?7upK80|_v>f86E?ITEqR$zUY@#(| zW3nNs#tXXRKCv8^L7NvsxAP`<9GxD~d(6ih7bL0q12n|}^vL0(9pr$}8uq>v7;e#S zjx3~|n%M`-41a;LL#F_4)7pg~t*;Tn8$|II6Lg90YePZ~*Rnu1C~QF87aKEUaZ#{k|p@reH65%qZhlgRl{ zHDWG#Oh~Bc%U2jWMBnlu63hEI7dyX)i;^ITSdx}KT;0dekBrnEApLu*hfnhzMn1G)|1As%@$ PgU2LQ!i&&Y%pmd`R@FvM literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/RawNativeLibraries.class b/tests/test_data/std/jdk/internal/loader/RawNativeLibraries.class new file mode 100644 index 0000000000000000000000000000000000000000..82397688bf0df22b228754586e38fe6e0ffa90de GIT binary patch literal 3516 zcma)8`*Raj7(KTw-8L+xlv)IlMkvsx#ejf{!SaYj3T=55g2m@HxwK0+yLGc^sqgpu zg(wOt>VJSUTF}mjzd7UIn%Zr|AC9{s5 zExN9>y=1yPJZcmshmC20W?Rl4mvf_%2KRRN3@vY8SFj~x%Gp#iTCiF}tBy5jQ^>ig zq-lH7wGAt2IYv&p$yKa4cC+fB3qU5>Ig2Wq+)2tJsLW6ti!zmTPx0+ z_KY(nlf%-RbaF=xJ7>v4*O22(73s`M%O9jIqd5sv$Zjk0#Fv)>FMI^+PK$?7%@)XNLsti8@w7VRf}2tyVlCkch5W zA{|pb84X7Sx~t--9IIInUAtl!z)=MzP8*LhMDGlcYQp?k&Yf;OY8_Z8zF=TL1JbQUjHj>KLU=AYmHpr;=B}ySH9%(J}@T*}I6 z6`Us6bR%on+r4k6c4@I7h){x1vL#;#aih&&Aw4qx!Qsf zvyyaSy|SySEh2n zdbz=`or-r0(Q{rv3z*YNi%RL2z6*r-!F^DjjC2dtKyyM(E0AO~Z}SVc;LrwK9=`DBY*p7xDC)D0Z=<*YT2C zhgNmvgTPDv+sl0C#j5=N3N)_anaP<~x#A4p)V}t_Er`TzXun}qqIVu^f5ZA;d<(Df z*@gx_ck{WESJ^#Si@kWAGabQRyn#3QMk{y=Z_{!!-od*e!X@q!{Pt*K9`|2EEC1Hc zf z`z-XpzK;#O$Mp@UYu~`xGk8B_;c>2>Up6jaU@Xyl3s2t0vA=L~xbJVQ5H}Nj^Eka2 zX_VSML!@Wv=kq>NJg`yrcOyQ)heT+F>fs+z4TatW@h>_wob(x-4H>-5y^2BS0y1MH z@YFCd$FBS6zhYJ2?|7yT=lUunIv6G}NX>MxmWg!YW5O%pJMalU zjS^|oc(w|BhR;JHH$o}Wy|*!bEqsnMsuYg4JVU`maQN5e1>=YO(9GQF z{R libraries = ConcurrentHashMap.newKeySet(); + final Class caller; + + private RawNativeLibraries(MethodHandles.Lookup trustedCaller) { + this.caller = trustedCaller.lookupClass(); + } + + /** + * Creates a RawNativeLibraries instance that has no relationship with + * any class loaders and disabled auto unloading. + * + * This static factory method is restricted for JDK trusted class use. + */ + public static RawNativeLibraries newInstance(MethodHandles.Lookup trustedCaller) { + if (!trustedCaller.hasFullPrivilegeAccess() || + !VM.isSystemDomainLoader(trustedCaller.lookupClass().getClassLoader())) { + throw new InternalError(trustedCaller + " does not have access to raw native library loading"); + } + return new RawNativeLibraries(trustedCaller); + } + + /* + * Load a native library from the given path. Returns null if the given + * library is determined to be non-loadable, which is system-dependent. + * + * The library is opened with the platform-specific library loading + * mechanism. If this method is called with the same path multiple times, + * the library is opened the same number of times. To close the library + * of the given path, {@code #unload} must be called on all the + * {@code NativeLibrary} instances that load it. + * + * @param path the path of the native library + */ + @SuppressWarnings("removal") + public NativeLibrary load(Path path) { + String name = AccessController.doPrivileged(new PrivilegedAction<>() { + public String run() { + try { + return path.toRealPath().toString(); + } catch (IOException e) { + return null; + } + } + }); + if (name == null) { + return null; + } + return load(name); + } + + /** + * Load a native library of the given pathname, which is platform-specific. + * Returns null if it fails to load the given pathname. + * + * If the given pathname does not contain a name-separator character, + * for example on Unix a slash character, the library search strategy + * is system-dependent for example on Unix, see dlopen. + * + * @apiNote + * The {@code pathname} argument is platform-specific. + * {@link System#mapLibraryName} can be used to convert a name to + * a platform-specific pathname: + * {@snippet + * RawNativeLibraries libs = RawNativeLibraries.newInstance(MethodHandles.lookup()); + * NativeLibrary lib = libs.load(System.mapLibraryName("blas")); + * } + * + * The library is opened with the platform-specific library loading + * mechanism. If this method is called with the same pathname multiple times, + * the library is opened the same number of times. To close the library + * of the given path, {@code #unload} must be called on all the + * {@code NativeLibrary} instances that load it. + * + * @param pathname the pathname of the native library + * @see System#mapLibraryName(String) + */ + public NativeLibrary load(String pathname) { + RawNativeLibraryImpl lib = new RawNativeLibraryImpl(pathname); + if (!lib.open()) { + return null; + } + libraries.add(lib); + return lib; + } + + /* + * Unloads the given native library. Each {@code NativeLibrary} + * instance can be unloaded only once. + * + * The native library may remain opened after this method is called. + * Refer to the platform-specific library loading mechanism, for example, + * dlopen/dlclose on Unix or LoadLibrary/FreeLibrary on Windows. + * + * @throws IllegalArgumentException if the given library is not + * loaded by this RawNativeLibraries or has already been unloaded + */ + public void unload(NativeLibrary lib) { + Objects.requireNonNull(lib); + if (!libraries.remove(lib)) { + throw new IllegalArgumentException("can't unload " + lib.name() + " loaded from " + lib); + } + RawNativeLibraryImpl nl = (RawNativeLibraryImpl)lib; + nl.close(); + } + + static class RawNativeLibraryImpl extends NativeLibrary { + // the name of the raw native library. + final String name; + // opaque handle to raw native library, used in native code. + long handle; + + RawNativeLibraryImpl(String name) { + this.name = name; + } + + @Override + public String name() { + return name; + } + + @Override + public long find(String name) { + return findEntry0(handle, name); + } + + /* + * Loads the named native library. + */ + boolean open() { + if (handle != 0) { + throw new InternalError("Native library " + name + " has been loaded"); + } + return load0(this, name); + } + + /* + * Close this native library. + */ + void close() { + unload0(name, handle); + } + } + + private static native boolean load0(RawNativeLibraryImpl impl, String name); + private static native void unload0(String name, long handle); +} + diff --git a/tests/test_data/std/jdk/internal/loader/Resource.class b/tests/test_data/std/jdk/internal/loader/Resource.class new file mode 100644 index 0000000000000000000000000000000000000000..4f66e52e6a341567ec3b4c929b495e37a3d33baf GIT binary patch literal 2849 zcmai0X>1f_7=FI(OsAdBQmEZ>2*}~lb}Neqs}=+)S68-FDTjh6)7@!1Wjnjh&LZG} z2S#F|5j84Gf@k{27`zH1f*7L-e~B?B#+Vp?7=Mrue;7kppKoTjyNw`eI^Q?%`Ml@s znTy9y0$729ju2`zCc@Rh-JeNeWnE(e5`IE z=UIGXKwBh?s}0P=EGiJjiY%jXyrks}dPBZQLc=uzvnw$$+Q34hch#`q4xSgDpmdD!9$+^~u=@ndS4n=e%vBDvGR zQrSpqDwEAy8t$q_RLPetRhPjATqzJv6HX}f;BiW(9` zn=d#qhwat1+q1d~0|S<8r5n(VwFZ*tp##>n!mH}8iAs!1S&>b%ZyS@gW34NU^jq!* zvp+*hQ!<+}Gn-7;mhUB^;tk3Eo}K)^DWFx2{@0l!G&3=@QsP)s3T#}TWWCFwJC+wC zg~~xwrma4IrhF-Vyjt`g?(@vljvg~t0##QEmMo=}?ZF<-SnMysOewaVC5ky!vvsLv zrq_mk<}$w_yWSt0P%1?;xh!ppeu0p*8j?*Lw)3*nOY=bP77b|)!{wrvE0}#GNMi%R z^_Y%5VCA`4W|X7#8+_PwV`Ux@G*Wbh<$Csjoid3@qlA@m6 zC9;Zr_Ml_ARGal*wF;jK1{GGCp1I0(vu;&$_}IrYO+h^mi|!92Mj=|MW~B%a`~ zXz1Za?ybVp9N@wIzN~1hIHuVx*c!O0SxYbt6#0whr}P{{^HN@B#FbG@>Qwojh=i59T6p>rlTjPDA;}s^W(LV+C$KNV!Sp= z(OQz*lB3Y0Cn*@Ot%++LK79A6b=E;dk74;3R*hm_XMLHi2W*|}`hY#X{#5jc z{3bGOO_+@=_TX`zV>phlO6Rv&#sZDuEc5dNe!|bB%kwwV&+;beK^eZ`0tHj8VmmFS zY15+B0W@QfpR^&&fK5vym9O1*duc4zJ-1UMI?zi1h$* zzsd++#xLam%KPu+|3Usa9K?CN>9@`sMBd1l9>6yCMKjy{K|I8$l9CA#V_f^u&znjVp_1-ge1a5nBIr4w>9XHS?RlQGfU6RT#bF9DgMTu2gTyfl zKbEk_Ha?7&i)3n8D7rPwz5rbmIj*XPIt@dT%z?Rpkhp+0@ehm({N@xnP~?sa2+9a5 zYmv!+qkc7S{9i^fejq948}}vbBH#21iT*WKQR?~{^+h6`=z7A4@dHKyImrVIU9OmE za>SC+)95~kaP(_*e}TINj)=-MH!= b.length) { // Only expand when there's no room + bytesToRead = Math.min(len - pos, b.length + 1024); + if (bytesToRead < 0) { + // Can overflow only due to large b.length + bytesToRead = len - pos; + } + b = Arrays.copyOf(b, pos + bytesToRead); + } else { + bytesToRead = b.length - pos; + } + int cc = 0; + try { + cc = in.read(b, pos, bytesToRead); + } catch (InterruptedIOException iioe) { + Thread.interrupted(); + isInterrupted = true; + } + if (cc < 0) { + if (len != Integer.MAX_VALUE) { + throw new EOFException("Detect premature EOF"); + } else { + if (b.length != pos) { + b = Arrays.copyOf(b, pos); + } + break; + } + } + pos += cc; + } + } finally { + try { + in.close(); + } catch (InterruptedIOException iioe) { + isInterrupted = true; + } catch (IOException ignore) {} + + if (isInterrupted) { + Thread.currentThread().interrupt(); + } + } + return b; + } + + /** + * Returns the Resource data as a ByteBuffer, but only if the input stream + * was implemented on top of a ByteBuffer. Return {@code null} otherwise. + * @return Resource data or null. + */ + public ByteBuffer getByteBuffer() throws IOException { + InputStream in = cachedInputStream(); + if (in instanceof ByteBuffered) { + return ((ByteBuffered)in).getByteBuffer(); + } + return null; + } + + /** + * Returns the Manifest for the Resource, or null if none. + */ + public Manifest getManifest() throws IOException { + return null; + } + + /** + * Returns theCertificates for the Resource, or null if none. + */ + public java.security.cert.Certificate[] getCertificates() { + return null; + } + + /** + * Returns the code signers for the Resource, or null if none. + */ + public CodeSigner[] getCodeSigners() { + return null; + } + + /** + * Returns non-fatal reading error during data retrieval if there's any. + * For example, CRC error when reading a JAR entry. + */ + public Exception getDataError() { + return null; + } +} diff --git a/tests/test_data/std/jdk/internal/loader/URLClassPath$1.class b/tests/test_data/std/jdk/internal/loader/URLClassPath$1.class new file mode 100644 index 0000000000000000000000000000000000000000..d003c686e87ea38c474da1938ad9037d490f1ae1 GIT binary patch literal 1782 zcma)7T~ixn6n;)VSQ3^dd@8mew$Z{u8}O^eAX+iCXhJ(gQ5eT@32({5vfJ5gI$ZiI zyzn=0p)-Zf=#1X=!u$T4j{3a2E2PyiUTn_0?|b$<&w0*yPk#U7=U)M=Vm*fx(grdn zvgi|B-rqeaJ6@;)&vwhMZ||z0{KZCX)wSF0dv@3=EeiS{+HT3S50zlJwr@YQ%dYM1 zl^bE;czYEcvEM`vc|lHlHe0HBAdqc+VwxDl1wmifa@wT@BG!6AR`Muf$iT3P5sV6o z=a6@I_Ej@vv}MP0!WBV!W_DAw)>=+y~a!G)N+r$U_} zQKs;!foT)3;j&=57cFMDr@~q!kzjsiZMJ77rP!NLCA@Cn4HH)}Be>cND)~-e-e*1= zs_l1zCe^<(^H2G=Nkf<9JgpQg6LXjsWIT05wJ6fIf$KU)?b!((x4iB*I?YzqRfoz8 zt4B@sAar~$k82ppQ@KSGZ{jV%fR2!Ou@W;cfEjp4Fm@ib>U9oPVCztVn`GOgyDI;d z&nAhl`n$}xP;)%B-Z|V+!RPjl8}*;xwB1cRaP)h!nbEx^DD{LZEmoLBU4<=w_nsZF zquKcUvM+9Y!T&F*V6YL|&4arAAYoBx+3mU?s6;J>m5yNaZ^@!76ZbDkimCn){8U<+rO^b;T^xt<}%kjPX*DuP+H2k(L{`-hHP_Z6i;t8^u zV=e})tw$K!&U{PwQ%r8vp5T%-#{=PGoZ<=@MgD(2%^atX873WZn}R`Z8!)7SoNQuR zzQlrjg&VSkCHeY{=Oo#^j}=lNaKiWlt~tzd&rmivM+6_9aV+yqyJoFZ%xbh)i9Wq4 zb`;f&9g)yUq)C$t#~ WbqAkCJ5#994kzhwNtLEhNB%ER;fdS; literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/URLClassPath$2.class b/tests/test_data/std/jdk/internal/loader/URLClassPath$2.class new file mode 100644 index 0000000000000000000000000000000000000000..90ccaf9678cd72318bf592b69641e4e9d504a45e GIT binary patch literal 1844 zcmah~O>Y}j6g}5p6DJemd_rhrLNU~tq;*Jvwm1aZkWzyasv06C3&g~EiYIYqs`0qW z0uUhaA+ce>N8vYQL8T^@K!RNt?D;ncIB&*rUDe2o@qP2&oqNtb@80V_|M~TI0LxfQ zBZjzvgoz|lf-}3@dj-c0l<(U0Lfx~sm0x)OW_h`8HyStWpq5(@^xd}WIoIA-f|2sB zecLY7ZFi?o34F)hDe8!QCer8^q_tgk((!Cxff)y9~lfA z7%?%5F+t`bRVMo z&D*|V`)mOA3BOE5eIn?dZnqm33|0cWy0>cIYOxrq*^O1tS1t7zR(!#jmayGnQMr>u zy5j7(cF^>hQ|WPsXeYe54oMfgCfKfoCC2TqgtdRo(P9mE5ofPwNZY6)7C5xgpYBI=g27Z|M#!NVf>I`;vu&z z408JnhJ22+e1U2C67%vEF3Q)qEZ?+wPLbVfSRw@iw-~?9HAi9kZxjqp9l;xIjs?DH z*Q9lf8I2Yxkhg+Da^a;WX>FFcMC zn9!Fa-!XyjF(f~7sNcb){M07SFfE8Nrh0|fEYQT`kfF>KqF!yGc2b_#@jEF;7xpOS lB>(fY*PB=g?KQkbo1jqF@lLptMVWS_l@6CwDT`I~{|B*}r#t`v literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/URLClassPath$3.class b/tests/test_data/std/jdk/internal/loader/URLClassPath$3.class new file mode 100644 index 0000000000000000000000000000000000000000..35fd62c2957f97e483d3323cd2756a56fcefb42e GIT binary patch literal 2308 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/URLClassPath$JarLoader$2.class b/tests/test_data/std/jdk/internal/loader/URLClassPath$JarLoader$2.class new file mode 100644 index 0000000000000000000000000000000000000000..0076d076afb51edf20f3b24f06275003d388c3a1 GIT binary patch literal 2977 zcmb7GYgZFj6y29e7#@Q>L=oyER%{_4vCx;rst{4ZfJy`_^fe3@G7u(oGEt!~?PINe zZ@=_E^h3LrU|ZMf59ohtSNENnB-5C-mbEf>=H7GmId`8IzyJB`ZvfKxx)}}7bi@qA z(I_yyvAUVE9Z$NBnNQ^l=Bjj43-g(D-YgbxnqIDd#&k3OcK@hA(>*ia@0eRspewUs z-ZN8q(^*etJ=b>D#}#&yfo8M_=t{EW<^>J}f{yeQurFj7Xu|=4W+fyY&)pF?5{Q*N zJD=Jx-4yLksS{tJ!$2px1RA}ZUF<(gzcbJ8_;?GtaY)Bu13fq*aI~K4yet+6ufmTW|#qMQ%U!z>?dZU2y2?ah%YRFmO_FkgR8@ zKDo4J6-!G0l!1Pn<~KuWd z_L?kuN-1Qp5{2@aPh#4@WlRaQQzcejj2kA^n7}3 zv;}iGq#pAIvbfEnC~Y(Q8Q%E7@}#0+4vPlvsGLxsi)OwgRj%AMu%tE{)iqs9$Gc?% zDzR=8yJ>ztowJ1|ct3J7WdTcdCNG zyTn(5)N5Fti2C*jaVW&9jhrQaUtzsRL^A1~FyOhsVYLzn{9 zVpLw{ZyO)+sQ|}9z~%sH_?sWN8KvWD1gg2>5$8(i(X|ku?`MpLPW^&68xX$l<3iQB z7Ro}KM!Pl>LG7#KAV*N>V3aXlb+U>Ugljf}RAr0xenT)U`#9FOo7Yg!c>|Na7y3a51d literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/URLClassPath$JarLoader.class b/tests/test_data/std/jdk/internal/loader/URLClassPath$JarLoader.class new file mode 100644 index 0000000000000000000000000000000000000000..36bc9fa50b6b753f836877e8ca91f5d2c1a53e73 GIT binary patch literal 9451 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 C%~b*b literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/URLClassPath$Loader$1.class b/tests/test_data/std/jdk/internal/loader/URLClassPath$Loader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..115f51199f7164f834fe347d23ad91a2fbe0531d GIT binary patch literal 1563 zcma)5+fEZv6kP{Or<4)OMQ);?R%y$nAl{33As9(&C7?X`Hnb=0;4njGro>0T!b?p2 z0v|L1O?>bJ{3zo(rxZ$Ulu2gxnRC|KXYaN5{`LFEPXNn!)QL8<8;F?bKvW>TU3!(Z z-B9|j4Vm-g?SV6F6g_UGp?CVJ6FbXc*2 z-6h6To2@z!PFRsAAUiZ0r&9WDv9r_!697{xgQV9{lJhyH_*8}!ue4_QY&Nzg9T?2Ipj&UCu2Ez2 zv3vxuA|%((>pfSOtRy#dsWmFT^13K@RhI<@ZVL1t$^PuUkwr=A(i6X=bG6mjgndt+F%*+9d%t+(_ zU74u^^klxH|0_@1kl{B9!R1>_aXrXAvM`MqTD4N%1!lSKjR0>F`brgsdIhqW<5yjo zrKKZuWcDGxaM9@fo%U|l0EgZM=5ehB*=Q!eZ%JM_A}c5A<`{48*~dsT|3d>mc62$X zn<1*m8~I(|aG{z1u?7D+c@f@vgD)q$wWs9gCK*2c(^CYuH2ya3Xz!!Ai+g%!2@h!d Pc*`i3@Q@9l%Eadny+lwO literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/URLClassPath$Loader.class b/tests/test_data/std/jdk/internal/loader/URLClassPath$Loader.class new file mode 100644 index 0000000000000000000000000000000000000000..ef905c9b559841f9ecef6794932e0403348007c5 GIT binary patch literal 3196 zcmb7G+fx%)82_D<4GVDvK?NgLv0^14Mzj|TR*I-a4HrRB5yd4e5C|JgHe&6?ORLlA zL)+YN6eWMrAsWYASr4Rj^oZ8>n-6Vu$#x^tAv-^GD`OfeAeV5(8|M~5A0KIq+ zf)ZV2%Au= zqt3u)Y!TR+$=Xq6y}Y~}9Wv7yYt%_31wxh`Pfc6u2%>25yt=SQoOHsT?HZ4i%0k$P zdKGAcz#e~34oRtXWK2g`U}qj(znPp#r5CMfB0qUEZY?>9lpR7NcIbG;z)tKEXnGkT z0>Sv46<-jjU56ktrts}H@GAC@sML~W_oi%{Ip8q@+gtpIe8dGES=>u~9%rB9EU6si zH&86C#~T9mc_>9Nm}wq4%8e!|$PiM?xbohCw+tM?+YFlCPuojb zhe@=|MS+G~(1}!ZjiM`rE*#bIj)7yUYB#$F7TYMIlc|iQhm&?SflPH=H#-flnEBM zo9gv+=(x&O%+*h?su*)hrCIaJyC#;ft%2;~l$Ad3De7XWxS1R?(+TzL3pHmh!HO;q zM%C52f!M{y$)?pHV}!>!8fn9p%#~J-CAQ2=!k*4WQy5$2MqOc(ApWKT-(?3E5d`Pr zoDl*$3Z^BqgJx1iw$-yK?lGmz#s#(&92E5s_5Qx%)}vgr%|)WD^LDNcM?j1VY#edS z_(H$AG4S8}nua0jl9M1+?kKj<5swtnR9L$DIluwjm&))>Yn#56)D{IJ=Vlgjln{`( zMQH_fv(K>cl5)@%c#4`Q*m`N8Q+ouxQxhvY9zt(_itX*IXzJ9$+Mj5Ch}~iB4>WfM z!@;`OR?!j;u3~?!`057)#mXaW4Qqi_91Lr#cvIP|qO*NP`BE`r3mUMEujsRksv9vE zRyQ@*s2kuX2IM%l$SY`&ml2i|Xq4BmOPbgt=Ma$zbjW!ekqhXSNt}_3h{+TN<#mk8 zG$v#QrpzKPZ@`kvZum3gt&V{z?g9vtpakZj@%6R^3rJEk!T%y`UL)v43QN>luHALs zk)AcwrIB&zoaM)bLz_lM;Car{G6MaAj&0A?_uEGOIa+kWt$o2AnvO~xHw5M2rJKea zr+yx;G7BmXlm9CZJr7Z@^3c;6Y*i%pKE->F(eKl)(#LE(!?{bXZS7(02}V|kcP;+| zgyHdi3^nBaHhI5C-tUn2yX5^od4E9OKO^s-GmtOH`xFnRMbqj+vdMG?rlATlB*w5BDlfJWpj{xqt e_IGj5T^sQU*X=y2lJ)v2`=O8PeXi#y=kH$^X5VoD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/URLClassPath.class b/tests/test_data/std/jdk/internal/loader/URLClassPath.class new file mode 100644 index 0000000000000000000000000000000000000000..5b575c0b923af4bac6dfe3dea935b398203374ba GIT binary patch literal 12099 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 ZKXZ(ic>N2nFSzetcCW9v*WWwW{{lOX2I~L- literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/loader/URLClassPath.java b/tests/test_data/std/jdk/internal/loader/URLClassPath.java new file mode 100644 index 00000000..dbd76e07 --- /dev/null +++ b/tests/test_data/std/jdk/internal/loader/URLClassPath.java @@ -0,0 +1,1092 @@ +/* + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.security.AccessControlContext; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.CodeSigner; +import java.security.Permission; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.cert.Certificate; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.jar.JarFile; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.jar.JarEntry; +import java.util.jar.Manifest; +import java.util.jar.Attributes; +import java.util.jar.Attributes.Name; +import java.util.zip.ZipFile; + +import jdk.internal.access.JavaNetURLAccess; +import jdk.internal.access.JavaUtilZipFileAccess; +import jdk.internal.access.SharedSecrets; +import sun.net.util.URLUtil; +import sun.net.www.ParseUtil; +import sun.security.action.GetPropertyAction; + +/** + * This class is used to maintain a search path of URLs for loading classes + * and resources from both JAR files and directories. + * + * @author David Connelly + */ +public class URLClassPath { + private static final String USER_AGENT_JAVA_VERSION = "UA-Java-Version"; + private static final String JAVA_VERSION; + private static final boolean DEBUG; + private static final boolean DISABLE_JAR_CHECKING; + private static final boolean DISABLE_ACC_CHECKING; + private static final boolean DISABLE_CP_URL_CHECK; + private static final boolean DEBUG_CP_URL_CHECK; + + static { + Properties props = GetPropertyAction.privilegedGetProperties(); + JAVA_VERSION = props.getProperty("java.version"); + DEBUG = (props.getProperty("sun.misc.URLClassPath.debug") != null); + String p = props.getProperty("sun.misc.URLClassPath.disableJarChecking"); + DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.isEmpty() : false; + + p = props.getProperty("jdk.net.URLClassPath.disableRestrictedPermissions"); + DISABLE_ACC_CHECKING = p != null ? p.equals("true") || p.isEmpty() : false; + + // This property will be removed in a later release + p = props.getProperty("jdk.net.URLClassPath.disableClassPathURLCheck"); + DISABLE_CP_URL_CHECK = p != null ? p.equals("true") || p.isEmpty() : false; + + // Print a message for each Class-Path entry that is ignored (assuming + // the check is not disabled). + p = props.getProperty("jdk.net.URLClassPath.showIgnoredClassPathEntries"); + DEBUG_CP_URL_CHECK = p != null ? p.equals("true") || p.isEmpty() : false; + } + + /* The original search path of URLs. */ + private final ArrayList path; + + /* The deque of unopened URLs */ + private final ArrayDeque unopenedUrls; + + /* The resulting search path of Loaders */ + private final ArrayList loaders = new ArrayList<>(); + + /* Map of each URL opened to its corresponding Loader */ + private final HashMap lmap = new HashMap<>(); + + /* The jar protocol handler to use when creating new URLs */ + private final URLStreamHandler jarHandler; + + /* Whether this URLClassLoader has been closed yet */ + private boolean closed = false; + + /* The context to be used when loading classes and resources. If non-null + * this is the context that was captured during the creation of the + * URLClassLoader. null implies no additional security restrictions. */ + @SuppressWarnings("removal") + private final AccessControlContext acc; + + /** + * Creates a new URLClassPath for the given URLs. The URLs will be + * searched in the order specified for classes and resources. A URL + * ending with a '/' is assumed to refer to a directory. Otherwise, + * the URL is assumed to refer to a JAR file. + * + * @param urls the directory and JAR file URLs to search for classes + * and resources + * @param factory the URLStreamHandlerFactory to use when creating new URLs + * @param acc the context to be used when loading classes and resources, may + * be null + */ + public URLClassPath(URL[] urls, + URLStreamHandlerFactory factory, + @SuppressWarnings("removal") AccessControlContext acc) { + ArrayList path = new ArrayList<>(urls.length); + ArrayDeque unopenedUrls = new ArrayDeque<>(urls.length); + for (URL url : urls) { + path.add(url); + unopenedUrls.add(url); + } + this.path = path; + this.unopenedUrls = unopenedUrls; + + if (factory != null) { + jarHandler = factory.createURLStreamHandler("jar"); + } else { + jarHandler = null; + } + if (DISABLE_ACC_CHECKING) + this.acc = null; + else + this.acc = acc; + } + + public URLClassPath(URL[] urls, @SuppressWarnings("removal") AccessControlContext acc) { + this(urls, null, acc); + } + + /** + * Constructs a URLClassPath from a class path string. + * + * @param cp the class path string + * @param skipEmptyElements indicates if empty elements are ignored or + * treated as the current working directory + * + * @apiNote Used to create the application class path. + */ + URLClassPath(String cp, boolean skipEmptyElements) { + ArrayList path = new ArrayList<>(); + if (cp != null) { + // map each element of class path to a file URL + int off = 0, next; + do { + next = cp.indexOf(File.pathSeparator, off); + String element = (next == -1) + ? cp.substring(off) + : cp.substring(off, next); + if (!element.isEmpty() || !skipEmptyElements) { + URL url = toFileURL(element); + if (url != null) path.add(url); + } + off = next + 1; + } while (next != -1); + } + + // can't use ArrayDeque#addAll or new ArrayDeque(Collection); + // it's too early in the bootstrap to trigger use of lambdas + int size = path.size(); + ArrayDeque unopenedUrls = new ArrayDeque<>(size); + for (int i = 0; i < size; i++) + unopenedUrls.add(path.get(i)); + + this.unopenedUrls = unopenedUrls; + this.path = path; + // the application class loader uses the built-in protocol handler to avoid protocol + // handler lookup when opening JAR files on the class path. + this.jarHandler = new sun.net.www.protocol.jar.Handler(); + this.acc = null; + } + + public synchronized List closeLoaders() { + if (closed) { + return Collections.emptyList(); + } + List result = new ArrayList<>(); + for (Loader loader : loaders) { + try { + loader.close(); + } catch (IOException e) { + result.add(e); + } + } + closed = true; + return result; + } + + /** + * Appends the specified URL to the search path of directory and JAR + * file URLs from which to load classes and resources. + *

+ * If the URL specified is null or is already in the list of + * URLs, then invoking this method has no effect. + */ + public synchronized void addURL(URL url) { + if (closed || url == null) + return; + synchronized (unopenedUrls) { + if (! path.contains(url)) { + unopenedUrls.addLast(url); + path.add(url); + } + } + } + + /** + * Appends the specified file path as a file URL to the search path. + */ + public void addFile(String s) { + URL url = toFileURL(s); + if (url != null) { + addURL(url); + } + } + + /** + * Returns a file URL for the given file path. + */ + private static URL toFileURL(String s) { + try { + File f = new File(s).getCanonicalFile(); + return ParseUtil.fileToEncodedURL(f); + } catch (IOException e) { + return null; + } + } + + /** + * Returns the original search path of URLs. + */ + public URL[] getURLs() { + synchronized (unopenedUrls) { + return path.toArray(new URL[0]); + } + } + + /** + * Finds the resource with the specified name on the URL search path + * or null if not found or security check fails. + * + * @param name the name of the resource + * @param check whether to perform a security check + * @return a {@code URL} for the resource, or {@code null} + * if the resource could not be found. + */ + public URL findResource(String name, boolean check) { + Loader loader; + for (int i = 0; (loader = getLoader(i)) != null; i++) { + URL url = loader.findResource(name, check); + if (url != null) { + return url; + } + } + return null; + } + + /** + * Finds the first Resource on the URL search path which has the specified + * name. Returns null if no Resource could be found. + * + * @param name the name of the Resource + * @param check whether to perform a security check + * @return the Resource, or null if not found + */ + public Resource getResource(String name, boolean check) { + if (DEBUG) { + System.err.println("URLClassPath.getResource(\"" + name + "\")"); + } + + Loader loader; + for (int i = 0; (loader = getLoader(i)) != null; i++) { + Resource res = loader.getResource(name, check); + if (res != null) { + return res; + } + } + return null; + } + + /** + * Finds all resources on the URL search path with the given name. + * Returns an enumeration of the URL objects. + * + * @param name the resource name + * @return an Enumeration of all the urls having the specified name + */ + public Enumeration findResources(final String name, + final boolean check) { + return new Enumeration<>() { + private int index = 0; + private URL url = null; + + private boolean next() { + if (url != null) { + return true; + } else { + Loader loader; + while ((loader = getLoader(index++)) != null) { + url = loader.findResource(name, check); + if (url != null) { + return true; + } + } + return false; + } + } + + public boolean hasMoreElements() { + return next(); + } + + public URL nextElement() { + if (!next()) { + throw new NoSuchElementException(); + } + URL u = url; + url = null; + return u; + } + }; + } + + public Resource getResource(String name) { + return getResource(name, true); + } + + /** + * Finds all resources on the URL search path with the given name. + * Returns an enumeration of the Resource objects. + * + * @param name the resource name + * @return an Enumeration of all the resources having the specified name + */ + public Enumeration getResources(final String name, + final boolean check) { + return new Enumeration<>() { + private int index = 0; + private Resource res = null; + + private boolean next() { + if (res != null) { + return true; + } else { + Loader loader; + while ((loader = getLoader(index++)) != null) { + res = loader.getResource(name, check); + if (res != null) { + return true; + } + } + return false; + } + } + + public boolean hasMoreElements() { + return next(); + } + + public Resource nextElement() { + if (!next()) { + throw new NoSuchElementException(); + } + Resource r = res; + res = null; + return r; + } + }; + } + + public Enumeration getResources(final String name) { + return getResources(name, true); + } + + /* + * Returns the Loader at the specified position in the URL search + * path. The URLs are opened and expanded as needed. Returns null + * if the specified index is out of range. + */ + private synchronized Loader getLoader(int index) { + if (closed) { + return null; + } + // Expand URL search path until the request can be satisfied + // or unopenedUrls is exhausted. + while (loaders.size() < index + 1) { + final URL url; + synchronized (unopenedUrls) { + url = unopenedUrls.pollFirst(); + if (url == null) + return null; + } + // Skip this URL if it already has a Loader. + String urlNoFragString = URLUtil.urlNoFragString(url); + if (lmap.containsKey(urlNoFragString)) { + continue; + } + // Otherwise, create a new Loader for the URL. + Loader loader; + try { + loader = getLoader(url); + // If the loader defines a local class path then add the + // URLs as the next URLs to be opened. + URL[] urls = loader.getClassPath(); + if (urls != null) { + push(urls); + } + } catch (IOException e) { + // Silently ignore for now... + continue; + } catch (SecurityException se) { + // Always silently ignore. The context, if there is one, that + // this URLClassPath was given during construction will never + // have permission to access the URL. + if (DEBUG) { + System.err.println("Failed to access " + url + ", " + se ); + } + continue; + } + // Finally, add the Loader to the search path. + loaders.add(loader); + lmap.put(urlNoFragString, loader); + } + return loaders.get(index); + } + + /* + * Returns the Loader for the specified base URL. + */ + @SuppressWarnings("removal") + private Loader getLoader(final URL url) throws IOException { + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction<>() { + public Loader run() throws IOException { + String protocol = url.getProtocol(); // lower cased in URL + String file = url.getFile(); + if (file != null && file.endsWith("/")) { + if ("file".equals(protocol)) { + return new FileLoader(url); + } else if ("jar".equals(protocol) && + isDefaultJarHandler(url) && + file.endsWith("!/")) { + // extract the nested URL + @SuppressWarnings("deprecation") + URL nestedUrl = new URL(file.substring(0, file.length() - 2)); + return new JarLoader(nestedUrl, jarHandler, acc); + } else { + return new Loader(url); + } + } else { + return new JarLoader(url, jarHandler, acc); + } + } + }, acc); + } catch (PrivilegedActionException pae) { + throw (IOException)pae.getException(); + } + } + + private static final JavaNetURLAccess JNUA + = SharedSecrets.getJavaNetURLAccess(); + + private static boolean isDefaultJarHandler(URL u) { + URLStreamHandler h = JNUA.getHandler(u); + return h instanceof sun.net.www.protocol.jar.Handler; + } + + /* + * Pushes the specified URLs onto the head of unopened URLs. + */ + private void push(URL[] urls) { + synchronized (unopenedUrls) { + for (int i = urls.length - 1; i >= 0; --i) { + unopenedUrls.addFirst(urls[i]); + } + } + } + + /* + * Checks whether the resource URL should be returned. + * Returns null on security check failure. + * Called by java.net.URLClassLoader. + */ + public static URL checkURL(URL url) { + if (url != null) { + try { + check(url); + } catch (Exception e) { + return null; + } + } + return url; + } + + /* + * Checks whether the resource URL should be returned. + * Throws exception on failure. + * Called internally within this file. + */ + public static void check(URL url) throws IOException { + @SuppressWarnings("removal") + SecurityManager security = System.getSecurityManager(); + if (security != null) { + URLConnection urlConnection = url.openConnection(); + Permission perm = urlConnection.getPermission(); + if (perm != null) { + try { + security.checkPermission(perm); + } catch (SecurityException se) { + // fallback to checkRead/checkConnect for pre 1.2 + // security managers + if ((perm instanceof java.io.FilePermission) && + perm.getActions().contains("read")) { + security.checkRead(perm.getName()); + } else if ((perm instanceof + java.net.SocketPermission) && + perm.getActions().contains("connect")) { + URL locUrl = url; + if (urlConnection instanceof JarURLConnection) { + locUrl = ((JarURLConnection)urlConnection).getJarFileURL(); + } + security.checkConnect(locUrl.getHost(), + locUrl.getPort()); + } else { + throw se; + } + } + } + } + } + + /** + * Nested class used to represent a loader of resources and classes + * from a base URL. + */ + private static class Loader implements Closeable { + private final URL base; + private JarFile jarfile; // if this points to a jar file + + /* + * Creates a new Loader for the specified URL. + */ + Loader(URL url) { + base = url; + } + + /* + * Returns the base URL for this Loader. + */ + final URL getBaseURL() { + return base; + } + + URL findResource(final String name, boolean check) { + URL url; + try { + @SuppressWarnings("deprecation") + var _unused = url = new URL(base, ParseUtil.encodePath(name, false)); + } catch (MalformedURLException e) { + return null; + } + + try { + if (check) { + URLClassPath.check(url); + } + + /* + * For a HTTP connection we use the HEAD method to + * check if the resource exists. + */ + URLConnection uc = url.openConnection(); + if (uc instanceof HttpURLConnection) { + HttpURLConnection hconn = (HttpURLConnection)uc; + hconn.setRequestMethod("HEAD"); + if (hconn.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST) { + return null; + } + } else { + // our best guess for the other cases + uc.setUseCaches(false); + InputStream is = uc.getInputStream(); + is.close(); + } + return url; + } catch (Exception e) { + return null; + } + } + + Resource getResource(final String name, boolean check) { + final URL url; + try { + @SuppressWarnings("deprecation") + var _unused = url = new URL(base, ParseUtil.encodePath(name, false)); + } catch (MalformedURLException e) { + return null; + } + final URLConnection uc; + try { + if (check) { + URLClassPath.check(url); + } + uc = url.openConnection(); + + if (uc instanceof JarURLConnection) { + /* Need to remember the jar file so it can be closed + * in a hurry. + */ + JarURLConnection juc = (JarURLConnection)uc; + jarfile = JarLoader.checkJar(juc.getJarFile()); + } + + InputStream in = uc.getInputStream(); + } catch (Exception e) { + return null; + } + return new Resource() { + public String getName() { return name; } + public URL getURL() { return url; } + public URL getCodeSourceURL() { return base; } + public InputStream getInputStream() throws IOException { + return uc.getInputStream(); + } + public int getContentLength() throws IOException { + return uc.getContentLength(); + } + }; + } + + /* + * Returns the Resource for the specified name, or null if not + * found or the caller does not have the permission to get the + * resource. + */ + Resource getResource(final String name) { + return getResource(name, true); + } + + /* + * Closes this loader and release all resources. + * Method overridden in sub-classes. + */ + @Override + public void close() throws IOException { + if (jarfile != null) { + jarfile.close(); + } + } + + /* + * Returns the local class path for this loader, or null if none. + */ + URL[] getClassPath() throws IOException { + return null; + } + } + + /* + * Nested class used to represent a Loader of resources from a JAR URL. + */ + private static class JarLoader extends Loader { + private JarFile jar; + private final URL csu; + @SuppressWarnings("removal") + private final AccessControlContext acc; + private boolean closed = false; + private static final JavaUtilZipFileAccess zipAccess = + SharedSecrets.getJavaUtilZipFileAccess(); + + /* + * Creates a new JarLoader for the specified URL referring to + * a JAR file. + */ + private JarLoader(URL url, URLStreamHandler jarHandler, + @SuppressWarnings("removal") AccessControlContext acc) + throws IOException + { + super(newURL("jar", "", -1, url + "!/", jarHandler)); + csu = url; + this.acc = acc; + + ensureOpen(); + } + + @SuppressWarnings("deprecation") + private static URL newURL(String protocol, String host, int port, String file, URLStreamHandler handler) + throws MalformedURLException + { + return new URL(protocol, host, port, file, handler); + } + + @Override + public void close () throws IOException { + // closing is synchronized at higher level + if (!closed) { + closed = true; + // in case not already open. + ensureOpen(); + jar.close(); + } + } + + private boolean isOptimizable(URL url) { + return "file".equals(url.getProtocol()); + } + + @SuppressWarnings("removal") + private void ensureOpen() throws IOException { + if (jar == null) { + try { + AccessController.doPrivileged( + new PrivilegedExceptionAction<>() { + public Void run() throws IOException { + if (DEBUG) { + System.err.println("Opening " + csu); + Thread.dumpStack(); + } + jar = getJarFile(csu); + return null; + } + }, acc); + } catch (PrivilegedActionException pae) { + throw (IOException)pae.getException(); + } + } + } + + /* Throws if the given jar file is does not start with the correct LOC */ + @SuppressWarnings("removal") + static JarFile checkJar(JarFile jar) throws IOException { + if (System.getSecurityManager() != null && !DISABLE_JAR_CHECKING + && !zipAccess.startsWithLocHeader(jar)) { + IOException x = new IOException("Invalid Jar file"); + try { + jar.close(); + } catch (IOException ex) { + x.addSuppressed(ex); + } + throw x; + } + + return jar; + } + + private JarFile getJarFile(URL url) throws IOException { + // Optimize case where url refers to a local jar file + if (isOptimizable(url)) { + FileURLMapper p = new FileURLMapper(url); + if (!p.exists()) { + throw new FileNotFoundException(p.getPath()); + } + return checkJar(new JarFile(new File(p.getPath()), true, ZipFile.OPEN_READ, + JarFile.runtimeVersion())); + } + @SuppressWarnings("deprecation") + URLConnection uc = (new URL(getBaseURL(), "#runtime")).openConnection(); + uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION); + JarFile jarFile = ((JarURLConnection)uc).getJarFile(); + return checkJar(jarFile); + } + + /* + * Creates the resource and if the check flag is set to true, checks if + * is its okay to return the resource. + */ + Resource checkResource(final String name, boolean check, + final JarEntry entry) { + + final URL url; + try { + String nm; + if (jar.isMultiRelease()) { + nm = entry.getRealName(); + } else { + nm = name; + } + @SuppressWarnings("deprecation") + var _unused = url = new URL(getBaseURL(), ParseUtil.encodePath(nm, false)); + if (check) { + URLClassPath.check(url); + } + } catch (@SuppressWarnings("removal") AccessControlException | IOException e) { + return null; + } + + return new Resource() { + private Exception dataError = null; + public String getName() { return name; } + public URL getURL() { return url; } + public URL getCodeSourceURL() { return csu; } + public InputStream getInputStream() throws IOException + { return jar.getInputStream(entry); } + public int getContentLength() + { return (int)entry.getSize(); } + public Manifest getManifest() throws IOException { + SharedSecrets.javaUtilJarAccess().ensureInitialization(jar); + return jar.getManifest(); + } + public Certificate[] getCertificates() + { return entry.getCertificates(); }; + public CodeSigner[] getCodeSigners() + { return entry.getCodeSigners(); }; + public Exception getDataError() + { return dataError; } + public byte[] getBytes() throws IOException { + byte[] bytes = super.getBytes(); + CRC32 crc32 = new CRC32(); + crc32.update(bytes); + if (crc32.getValue() != entry.getCrc()) { + dataError = new IOException( + "CRC error while extracting entry from JAR file"); + } + return bytes; + } + }; + } + + /* + * Returns the URL for a resource with the specified name + */ + @Override + URL findResource(final String name, boolean check) { + Resource rsc = getResource(name, check); + if (rsc != null) { + return rsc.getURL(); + } + return null; + } + + /* + * Returns the JAR Resource for the specified name. + */ + @Override + Resource getResource(final String name, boolean check) { + try { + ensureOpen(); + } catch (IOException e) { + throw new InternalError(e); + } + final JarEntry entry = jar.getJarEntry(name); + if (entry != null) + return checkResource(name, check, entry); + + + return null; + } + + /* + * Returns the JAR file local class path, or null if none. + */ + @Override + URL[] getClassPath() throws IOException { + ensureOpen(); + + // Only get manifest when necessary + if (SharedSecrets.javaUtilJarAccess().jarFileHasClassPathAttribute(jar)) { + Manifest man = jar.getManifest(); + if (man != null) { + Attributes attr = man.getMainAttributes(); + if (attr != null) { + String value = attr.getValue(Name.CLASS_PATH); + if (value != null) { + return parseClassPath(csu, value); + } + } + } + } + return null; + } + + /* + * Parses value of the Class-Path manifest attribute and returns + * an array of URLs relative to the specified base URL. + */ + private static URL[] parseClassPath(URL base, String value) + throws MalformedURLException + { + StringTokenizer st = new StringTokenizer(value); + URL[] urls = new URL[st.countTokens()]; + int i = 0; + while (st.hasMoreTokens()) { + String path = st.nextToken(); + @SuppressWarnings("deprecation") + URL url = DISABLE_CP_URL_CHECK ? new URL(base, path) : tryResolve(base, path); + if (url != null) { + urls[i] = url; + i++; + } else { + if (DEBUG_CP_URL_CHECK) { + System.err.println("Class-Path entry: \"" + path + + "\" ignored in JAR file " + base); + } + } + } + if (i == 0) { + urls = null; + } else if (i != urls.length) { + // Truncate nulls from end of array + urls = Arrays.copyOf(urls, i); + } + return urls; + } + + static URL tryResolve(URL base, String input) throws MalformedURLException { + if ("file".equalsIgnoreCase(base.getProtocol())) { + return tryResolveFile(base, input); + } else { + return tryResolveNonFile(base, input); + } + } + + /** + * Attempt to return a file URL by resolving input against a base file + * URL. + * @return the resolved URL or null if the input is an absolute URL with + * a scheme other than file (ignoring case) + * @throws MalformedURLException + */ + static URL tryResolveFile(URL base, String input) throws MalformedURLException { + @SuppressWarnings("deprecation") + URL retVal = new URL(base, input); + if (input.indexOf(':') >= 0 && + !"file".equalsIgnoreCase(retVal.getProtocol())) { + // 'input' contains a ':', which might be a scheme, or might be + // a Windows drive letter. If the protocol for the resolved URL + // isn't "file:", it should be ignored. + return null; + } + return retVal; + } + + /** + * Attempt to return a URL by resolving input against a base URL. Returns + * null if the resolved URL is not contained by the base URL. + * + * @return the resolved URL or null + * @throws MalformedURLException + */ + static URL tryResolveNonFile(URL base, String input) throws MalformedURLException { + String child = input.replace(File.separatorChar, '/'); + if (isRelative(child)) { + @SuppressWarnings("deprecation") + URL url = new URL(base, child); + String bp = base.getPath(); + String urlp = url.getPath(); + int pos = bp.lastIndexOf('/'); + if (pos == -1) { + pos = bp.length() - 1; + } + if (urlp.regionMatches(0, bp, 0, pos + 1) + && urlp.indexOf("..", pos) == -1) { + return url; + } + } + return null; + } + + /** + * Returns true if the given input is a relative URI. + */ + static boolean isRelative(String child) { + try { + return !URI.create(child).isAbsolute(); + } catch (IllegalArgumentException e) { + return false; + } + } + } + + /* + * Nested class used to represent a loader of classes and resources + * from a file URL that refers to a directory. + */ + private static class FileLoader extends Loader { + /* Canonicalized File */ + private final File dir; + private final URL normalizedBase; + + /* + * Creates a new FileLoader for the specified URL with a file protocol. + */ + private FileLoader(URL url) throws IOException { + super(url); + String path = url.getFile().replace('/', File.separatorChar); + path = ParseUtil.decode(path); + dir = (new File(path)).getCanonicalFile(); + @SuppressWarnings("deprecation") + var _unused = normalizedBase = new URL(getBaseURL(), "."); + } + + /* + * Returns the URL for a resource with the specified name + */ + @Override + URL findResource(final String name, boolean check) { + Resource rsc = getResource(name, check); + if (rsc != null) { + return rsc.getURL(); + } + return null; + } + + @Override + Resource getResource(final String name, boolean check) { + final URL url; + try { + @SuppressWarnings("deprecation") + var _unused = url = new URL(getBaseURL(), ParseUtil.encodePath(name, false)); + + if (url.getFile().startsWith(normalizedBase.getFile()) == false) { + // requested resource had ../..'s in path + return null; + } + + if (check) + URLClassPath.check(url); + + final File file; + if (name.contains("..")) { + file = (new File(dir, name.replace('/', File.separatorChar))) + .getCanonicalFile(); + if ( !((file.getPath()).startsWith(dir.getPath())) ) { + /* outside of base dir */ + return null; + } + } else { + file = new File(dir, name.replace('/', File.separatorChar)); + } + + if (file.exists()) { + return new Resource() { + public String getName() { return name; }; + public URL getURL() { return url; }; + public URL getCodeSourceURL() { return getBaseURL(); }; + public InputStream getInputStream() throws IOException + { return new FileInputStream(file); }; + public int getContentLength() throws IOException + { return (int)file.length(); }; + }; + } + } catch (Exception e) { + return null; + } + return null; + } + } +} diff --git a/tests/test_data/std/jdk/internal/logger/AbstractLoggerWrapper.class b/tests/test_data/std/jdk/internal/logger/AbstractLoggerWrapper.class new file mode 100644 index 0000000000000000000000000000000000000000..ca5b15cfe66a62912424780ef9d84dc4e1be6c06 GIT binary patch literal 12162 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 ION8Km0RX*I=>Px# literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/AbstractLoggerWrapper.java b/tests/test_data/std/jdk/internal/logger/AbstractLoggerWrapper.java new file mode 100644 index 00000000..95d35ed4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/logger/AbstractLoggerWrapper.java @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.logger; + +import java.util.ResourceBundle; +import java.util.function.Supplier; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; +import sun.util.logging.PlatformLogger; + +/** + * An implementation of {@link System.Logger System.Logger} + * that redirects all calls to a wrapped instance of {@link + * System.Logger System.Logger} + * + * @param Type of the wrapped Logger: {@code Logger} or + * an extension of that interface. + * + */ +abstract class AbstractLoggerWrapper + implements Logger, PlatformLogger.Bridge, PlatformLogger.ConfigurableBridge { + + AbstractLoggerWrapper() { } + + abstract L wrapped(); + + abstract PlatformLogger.Bridge platformProxy(); + + L getWrapped() { + return wrapped(); + } + + @Override + public final String getName() { + return wrapped().getName(); + } + + // ----------------------------------------------------------------- + // Generic methods taking a Level as parameter + // ----------------------------------------------------------------- + + + @Override + public boolean isLoggable(Level level) { + return wrapped().isLoggable(level); + } + + @Override + public void log(Level level, String msg) { + wrapped().log(level, msg); + } + + @Override + public void log(Level level, + Supplier msgSupplier) { + wrapped().log(level, msgSupplier); + } + + @Override + public void log(Level level, Object obj) { + wrapped().log(level, obj); + } + + @Override + public void log(Level level, + String msg, Throwable thrown) { + wrapped().log(level, msg, thrown); + } + + @Override + public void log(Level level, Supplier msgSupplier, Throwable thrown) { + wrapped().log(level, msgSupplier, thrown); + } + + @Override + public void log(Level level, + String format, Object... params) { + wrapped().log(level, format, params); + } + + @Override + public void log(Level level, ResourceBundle bundle, + String key, Throwable thrown) { + wrapped().log(level, bundle, key, thrown); + } + + @Override + public void log(Level level, ResourceBundle bundle, + String format, Object... params) { + wrapped().log(level, bundle, format, params); + } + + // --------------------------------------------------------- + // Methods from PlatformLogger.Bridge + // --------------------------------------------------------- + + @Override + public boolean isLoggable(PlatformLogger.Level level) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) return isLoggable(level.systemLevel()); + else return platformProxy.isLoggable(level); + } + + @Override + public boolean isEnabled() { + final PlatformLogger.Bridge platformProxy = platformProxy(); + return platformProxy == null || platformProxy.isEnabled(); + } + + @Override + public void log(PlatformLogger.Level level, String msg) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { + wrapped().log(level.systemLevel(), msg); + } else { + platformProxy.log(level, msg); + } + } + + @Override + public void log(PlatformLogger.Level level, String msg, Throwable thrown) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { + wrapped().log(level.systemLevel(), msg, thrown); + } else { + platformProxy.log(level, msg, thrown); + } + } + + @Override + public void log(PlatformLogger.Level level, String msg, Object... params) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { + wrapped().log(level.systemLevel(), msg, params); + } else { + platformProxy.log(level, msg, params); + } + } + + @Override + public void log(PlatformLogger.Level level, Supplier msgSupplier) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { + wrapped().log(level.systemLevel(),msgSupplier); + } else { + platformProxy.log(level,msgSupplier); + } + } + + @Override + public void log(PlatformLogger.Level level, Throwable thrown, + Supplier msgSupplier) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { + wrapped().log(level.systemLevel(), msgSupplier, thrown); + } else { + platformProxy.log(level, thrown, msgSupplier); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, String msg) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { + if (sourceClass == null && sourceMethod == null) { // best effort + wrapped().log(level.systemLevel(), msg); + } else { + Level systemLevel = level.systemLevel(); + Logger wrapped = wrapped(); + if (wrapped.isLoggable(systemLevel)) { + sourceClass = sourceClass == null ? "" : sourceClass; + sourceMethod = sourceMethod == null ? "" : sourceMethod; + msg = msg == null ? "" : msg; + wrapped.log(systemLevel, String.format("[%s %s] %s", + sourceClass, sourceMethod, msg)); + } + } + } else { + platformProxy.logp(level, sourceClass, sourceMethod, msg); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, Supplier msgSupplier) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { // best effort + if (sourceClass == null && sourceMethod == null) { + wrapped().log(level.systemLevel(), msgSupplier); + } else { + Level systemLevel = level.systemLevel(); + Logger wrapped = wrapped(); + if (wrapped.isLoggable(systemLevel)) { + final String sClass = sourceClass == null ? "" : sourceClass; + final String sMethod = sourceMethod == null ? "" : sourceMethod; + wrapped.log(systemLevel, () -> String.format("[%s %s] %s", + sClass, sMethod, msgSupplier.get())); + } + } + } else { + platformProxy.logp(level, sourceClass, sourceMethod, msgSupplier); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, String msg, Object... params) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { // best effort + if (sourceClass == null && sourceMethod == null) { + wrapped().log(level.systemLevel(), msg, params); + } else { + Level systemLevel = level.systemLevel(); + Logger wrapped = wrapped(); + if (wrapped.isLoggable(systemLevel)) { + sourceClass = sourceClass == null ? "" : sourceClass; + sourceMethod = sourceMethod == null ? "" : sourceMethod; + msg = msg == null ? "" : msg; + wrapped.log(systemLevel, String.format("[%s %s] %s", + sourceClass, sourceMethod, msg), params); + } + } + } else { + platformProxy.logp(level, sourceClass, sourceMethod, msg, params); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, String msg, Throwable thrown) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { // best effort + if (sourceClass == null && sourceMethod == null) { + wrapped().log(level.systemLevel(), msg, thrown); + } else { + Level systemLevel = level.systemLevel(); + Logger wrapped = wrapped(); + if (wrapped.isLoggable(systemLevel)) { + sourceClass = sourceClass == null ? "" : sourceClass; + sourceMethod = sourceMethod == null ? "" : sourceMethod; + msg = msg == null ? "" : msg; + wrapped.log(systemLevel, String.format("[%s %s] %s", + sourceClass, sourceMethod, msg), thrown); + } + } + } else { + platformProxy.logp(level, sourceClass, sourceMethod, msg, thrown); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, Throwable thrown, + Supplier msgSupplier) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { // best effort + if (sourceClass == null && sourceMethod == null) { + wrapped().log(level.systemLevel(), msgSupplier, thrown); + } else { + Level systemLevel = level.systemLevel(); + Logger wrapped = wrapped(); + if (wrapped.isLoggable(systemLevel)) { + final String sClass = sourceClass == null ? "" : sourceClass; + final String sMethod = sourceMethod == null ? "" : sourceMethod; + wrapped.log(systemLevel, () -> String.format("[%s %s] %s", + sClass, sMethod, msgSupplier.get()), thrown); + } + } + } else { + platformProxy.logp(level, sourceClass, sourceMethod, + thrown, msgSupplier); + } + } + + @Override + public void logrb(PlatformLogger.Level level, String sourceClass, + String sourceMethod, ResourceBundle bundle, + String msg, Object... params) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { // best effort + if (bundle != null || sourceClass == null && sourceMethod == null) { + wrapped().log(level.systemLevel(), bundle, msg, params); + } else { + Level systemLevel = level.systemLevel(); + Logger wrapped = wrapped(); + if (wrapped.isLoggable(systemLevel)) { + sourceClass = sourceClass == null ? "" : sourceClass; + sourceMethod = sourceMethod == null ? "" : sourceMethod; + msg = msg == null ? "" : msg; + wrapped.log(systemLevel, bundle, String.format("[%s %s] %s", + sourceClass, sourceMethod, msg), params); + } + } + } else { + platformProxy.logrb(level, sourceClass, sourceMethod, + bundle, msg, params); + } + } + + @Override + public void logrb(PlatformLogger.Level level, String sourceClass, + String sourceMethod, ResourceBundle bundle, String msg, + Throwable thrown) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { // best effort + if (bundle != null || sourceClass == null && sourceMethod == null) { + wrapped().log(level.systemLevel(), bundle, msg, thrown); + } else { + Level systemLevel = level.systemLevel(); + Logger wrapped = wrapped(); + if (wrapped.isLoggable(systemLevel)) { + sourceClass = sourceClass == null ? "" : sourceClass; + sourceMethod = sourceMethod == null ? "" : sourceMethod; + msg = msg == null ? "" : msg; + wrapped.log(systemLevel, bundle, String.format("[%s %s] %s", + sourceClass, sourceMethod, msg), thrown); + } + } + } else { + platformProxy.logrb(level, sourceClass, sourceMethod, bundle, + msg, thrown); + } + } + + @Override + public void logrb(PlatformLogger.Level level, ResourceBundle bundle, + String msg, Throwable thrown) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { + wrapped().log(level.systemLevel(), bundle, msg, thrown); + } else { + platformProxy.logrb(level, bundle, msg, thrown); + } + } + + @Override + public void logrb(PlatformLogger.Level level, ResourceBundle bundle, + String msg, Object... params) { + final PlatformLogger.Bridge platformProxy = platformProxy(); + if (platformProxy == null) { + wrapped().log(level.systemLevel(), bundle, msg, params); + } else { + platformProxy.logrb(level, bundle, msg, params); + } + } + + + @Override + public LoggerConfiguration getLoggerConfiguration() { + final PlatformLogger.Bridge platformProxy = platformProxy(); + return platformProxy == null ? null + : PlatformLogger.ConfigurableBridge + .getLoggerConfiguration(platformProxy); + } + +} diff --git a/tests/test_data/std/jdk/internal/logger/BootstrapLogger$BootstrapExecutors$1.class b/tests/test_data/std/jdk/internal/logger/BootstrapLogger$BootstrapExecutors$1.class new file mode 100644 index 0000000000000000000000000000000000000000..244c455040f856654a043da3bcedf9879922a3be GIT binary patch literal 1900 zcmbtVZBG+H5Pr544(cJL_=>2gRZ9`i_qQSn2#OX&AtZiWuA6dj?2)}a)Ng(>QGbjk z3PuxufIrGOd)L+?nwZ+8w|8?p&-2X8&fNDOU%mmD#FH+h&}JcRqa7U#H&!cajwiKH zlKYMyRI5Tc6G5Out@uVce$F?Zr(Os*(t!%|7a6)Xxt|Z7OQ9IflvnvCcOvcijvGif zQc6he)b}q4wduK{WXL;hbRomgZrsUrU*hU>S#_R9Qu1YAlrpfU{}j#8 zQU(Wc$iiV8{W!vKVu#dqFLa$5DFZhOqHu9V30|S}O7XmYU#OAqOwv#jSF*EY;V8qw zU)fsF%9GWJ$nz^gWiWv5P7E>}`FqSGX4gp@r;w*4^NkH5Nz6#IfCRMEOuvJNs&@uw zEfj1Fp}3=Z^?g=myoXaRGGptg!CC|4+&&-zi+S zaRpcDfT&3R&eKTOb%tYcx3s<*+&U!bwjA_`$-XN6t~ zD)U@XeQBYxm-hMeUy^1zhT@pu`oyn-v)_BDw{PU9-x&5E=~V7`uE@ltvBOuK?-SODW3ZT zRvh^RtGJClAIOx#ExL9P4DcEyx*i~#aUR8OTFu=U?$GaXT^_1_Yu}M`aa`8dH5>^o^9h;?)Vl?3~%8yEnA?Q^TY3BD5GU> zEdCAp@Rp{+yCzLeO;aC@j0yU{vFtbz->VTjw3;Z|i(9z#3$8gdlP%g%gK4knpTcxZ kejg8LO=AX!@F=#FF-L1Z37SC}k14YzGV|*t%RDka0l5SQi~s-t literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/BootstrapLogger$BootstrapExecutors$BootstrapMessageLoggerTask.class b/tests/test_data/std/jdk/internal/logger/BootstrapLogger$BootstrapExecutors$BootstrapMessageLoggerTask.class new file mode 100644 index 0000000000000000000000000000000000000000..502d6dee5ce76b37f40a02889e3e386b75fe6954 GIT binary patch literal 1035 zcmb_b$!-%t5Pj_>6K`1@vzaYq!*&pJ<6_`|1p;Xj6l_`IMtjn7#-8*<-8~6^#5ocX zf&<+7C`9#)7bH0Nz@@sYx~kr*rGNhV_8mY6%_1_$I>?og#}dQZh@W#evW;fHfMpaM6w4@~%y2Y19=m}wLP;LFVKf{H<-Uj_qmANcUZU^J^p_un zADc+&x#>V?&4(iO>~TG2$VV4aD26>R;S!r5bp1&Bu~I@BcbcRt)Op~Gwq>+Z#wyl` zp^7C#Ee%YHco$2_2cc+}P{oFWn)ReQtMfXiE)35ai$VS?f3we!>qN(bVbu$yIE+sR zLiH>*p?Q(d!#-Dm)hEWBISDjF*Zc21Y%?%wV5MugKR)1R37~^}3>)*ZdnYQoNa+>3 zQLKFNDzIE@vvH+Ed2B-%mJfwCuOn?7Y%^>xz?q@^M$#lZA=g@H2YU=p7KocK$8^-x zrRt2;AIAF3_}3a?lhz^w3M2`;tR!K#grv3SagF44(%#!2VBcC_z*_rPa9WS9P`OMT zZ;-4aNAd$njsgZ)fsdPH*-XQ53w6?Latp(f+ie1}FtltFm{Za%m3r$lDqpeA&|-x3 z2_-MN?Ekn-VhdO&uPiKbouYvup$3FHqL+Z|BSIV}3{tfEguxy1b&xr7aMz&(_esqV Y$p^`~g&jI=H+HdwhbU5icF{obHx_jQcmMzZ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/BootstrapLogger$BootstrapExecutors.class b/tests/test_data/std/jdk/internal/logger/BootstrapLogger$BootstrapExecutors.class new file mode 100644 index 0000000000000000000000000000000000000000..6c7fe26963befb557f2c5d1d383f45b475e2ce96 GIT binary patch literal 5054 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 pVUZhAZtc^&l-GXnTIC1)sgon-q3 z*5a4UnqTwN?=5V{Z?Ffy&6ueE>+?0YS}NLAps4r;%4y5u&|WVV)b{l>1I03$qZruX zJKj1deAKfzBQw|(nS||G+OBMkoOcVRrrrf>{PMw8JjVfxc!ZNq5 zA<8KGQS5hH&%(`a-TFPH|G>ogBmV>RCkE}$tb2c9-TNzQ@Ha&8ck=Te^vpk54gTd? zx`w_hp-((ZBi!K}Z4PklmMrU=pxxwDKxH2U&A&-tYzKh1v7Cc^ZQTrd(RW&3(UC}@O_R%Xk#%8#jD(_ YfqnHGVE+fq#fzM|#PQ2`odjO?KXCUoegFUf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/BootstrapLogger$DetectBackend$1.class b/tests/test_data/std/jdk/internal/logger/BootstrapLogger$DetectBackend$1.class new file mode 100644 index 0000000000000000000000000000000000000000..304c3e3f8a1095330ab91860be548b1c69663875 GIT binary patch literal 2274 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/BootstrapLogger$LoggingBackend.class b/tests/test_data/std/jdk/internal/logger/BootstrapLogger$LoggingBackend.class new file mode 100644 index 0000000000000000000000000000000000000000..f8b2a684f040a13b9095447ecd526fe0768529d2 GIT binary patch literal 1564 zcmbVNT~8BH5IwiM{h%yR%aPVm#6~wu3u<9sGmA|SkQI30Bb&`-Qvws2^V1}lC!nB-d77WBXSNqp z>G}1{8poRzC>(F&__LL@RGzrwI?Ck1fn(}(dRGo@VOXUbDL^pP(VAKyoif|y^ zK*Jrc>`qm304vM zgpTj%d`BMrHqfV!b5e=${g{Nu#ZQps6~VBGouKDC1mit_;qOyKsi821Y4RS>>!oFH z8A_KKl1sKsR%UQ)xbGO(V*MX6_@4Y4T`OfFy@F4Ajb`Z$n6`^@O#aYqjlXeolDk0* z!9$egm!1T@9?XP-JP=e3cRT5B2lV^DLTpM^Ncl~<3V(jnTcwlS^i|Q4KP^B2k1$)O zD3O5tJpMuq;oFjYjK~K_t~V@8uIG2XJKkC@=z4d3HLv9aBOegrHft((F`=ZRRXRkU jA70Oc!0i-Q01VTVkN+~EzlaF-T=_F1jNb&tv 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 Qa`3}f;r(66FcJOvkH3GsqW}N^ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/BootstrapLogger.java b/tests/test_data/std/jdk/internal/logger/BootstrapLogger.java new file mode 100644 index 00000000..f351b529 --- /dev/null +++ b/tests/test_data/std/jdk/internal/logger/BootstrapLogger.java @@ -0,0 +1,1105 @@ +/* + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.logger; + +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.ServiceLoader; +import java.util.function.BooleanSupplier; +import java.util.function.Function; +import java.util.function.Supplier; +import java.lang.System.LoggerFinder; +import java.lang.System.Logger; +import java.lang.ref.WeakReference; +import java.util.Objects; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import jdk.internal.misc.InnocuousThread; +import jdk.internal.misc.VM; +import sun.util.logging.PlatformLogger; +import jdk.internal.logger.LazyLoggers.LazyLoggerAccessor; + +/** + * The BootstrapLogger class handles all the logic needed by Lazy Loggers + * to delay the creation of System.Logger instances until the VM is booted. + * By extension - it also contains the logic that will delay the creation + * of JUL Loggers until the LogManager is initialized by the application, in + * the common case where JUL is the default and there is no custom JUL + * configuration. + * + * A BootstrapLogger instance is both a Logger and a + * PlatformLogger.Bridge instance, which will put all Log messages in a queue + * until the VM is booted. + * Once the VM is booted, it obtain the real System.Logger instance from the + * LoggerFinder and flushes the message to the queue. + * + * There are a few caveat: + * - the queue may not be flush until the next message is logged after + * the VM is booted + * - while the BootstrapLogger is active, the default implementation + * for all convenience methods is used + * - PlatformLogger.setLevel calls are ignored + * + * + */ +public final class BootstrapLogger implements Logger, PlatformLogger.Bridge, + PlatformLogger.ConfigurableBridge { + + // We use the BootstrapExecutors class to submit delayed messages + // to an independent InnocuousThread which will ensure that + // delayed log events will be clearly identified as messages that have + // been delayed during the boot sequence. + private static class BootstrapExecutors implements ThreadFactory { + + // Maybe that should be made configurable with system properties. + static final long KEEP_EXECUTOR_ALIVE_SECONDS = 30; + + // The BootstrapMessageLoggerTask is a Runnable which keeps + // a hard ref to the ExecutorService that owns it. + // This ensure that the ExecutorService is not gc'ed until the thread + // has stopped running. + private static class BootstrapMessageLoggerTask implements Runnable { + ExecutorService owner; + Runnable run; + public BootstrapMessageLoggerTask(ExecutorService owner, Runnable r) { + this.owner = owner; + this.run = r; + } + @Override + public void run() { + try { + run.run(); + } finally { + owner = null; // allow the ExecutorService to be gced. + } + } + } + + private static volatile WeakReference executorRef; + private static ExecutorService getExecutor() { + WeakReference ref = executorRef; + ExecutorService executor = ref == null ? null : ref.get(); + if (executor != null) return executor; + synchronized (BootstrapExecutors.class) { + ref = executorRef; + executor = ref == null ? null : ref.get(); + if (executor == null) { + executor = new ThreadPoolExecutor(0, 1, + KEEP_EXECUTOR_ALIVE_SECONDS, TimeUnit.SECONDS, + new LinkedBlockingQueue<>(), new BootstrapExecutors()); + } + // The executor service will be elligible for gc + // KEEP_EXECUTOR_ALIVE_SECONDS seconds (30s) + // after the execution of its last pending task. + executorRef = new WeakReference<>(executor); + return executorRef.get(); + } + } + + @Override + public Thread newThread(Runnable r) { + ExecutorService owner = getExecutor(); + @SuppressWarnings("removal") + Thread thread = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Thread run() { + Thread t = InnocuousThread.newThread(new BootstrapMessageLoggerTask(owner, r)); + t.setName("BootstrapMessageLoggerTask-"+t.getName()); + return t; + } + }, null, new RuntimePermission("enableContextClassLoaderOverride")); + thread.setDaemon(true); + return thread; + } + + static void submit(Runnable r) { + getExecutor().execute(r); + } + + // This is used by tests. + static void join(Runnable r) { + try { + getExecutor().submit(r).get(); + } catch (InterruptedException | ExecutionException ex) { + // should not happen + throw new RuntimeException(ex); + } + } + + // This is used by tests. + static void awaitPendingTasks() { + WeakReference ref = executorRef; + ExecutorService executor = ref == null ? null : ref.get(); + if (ref == null) { + synchronized(BootstrapExecutors.class) { + ref = executorRef; + executor = ref == null ? null : ref.get(); + } + } + if (executor != null) { + // since our executor uses a FIFO and has a single thread + // then awaiting the execution of its pending tasks can be done + // simply by registering a new task and waiting until it + // completes. This of course would not work if we were using + // several threads, but we don't. + join(()->{}); + } + } + + // This is used by tests. + static boolean isAlive() { + WeakReference ref = executorRef; + if (ref != null && !ref.refersTo(null)) return true; + synchronized (BootstrapExecutors.class) { + ref = executorRef; + return ref != null && !ref.refersTo(null); + } + } + + // The pending log event queue. The first event is the head, and + // new events are added at the tail + static LogEvent head, tail; + + static void enqueue(LogEvent event) { + if (event.next != null) return; + synchronized (BootstrapExecutors.class) { + if (event.next != null) return; + event.next = event; + if (tail == null) { + head = tail = event; + } else { + tail.next = event; + tail = event; + } + } + } + + static void flush() { + LogEvent event; + // drain the whole queue + synchronized(BootstrapExecutors.class) { + event = head; + head = tail = null; + } + while(event != null) { + LogEvent.log(event); + synchronized(BootstrapExecutors.class) { + LogEvent prev = event; + event = (event.next == event ? null : event.next); + prev.next = null; + } + } + } + } + + // The accessor in which this logger is temporarily set. + final LazyLoggerAccessor holder; + // tests whether the logger is invoked by the loading thread before + // the LoggerFinder is loaded; can be null; + final BooleanSupplier isLoadingThread; + + // returns true if the logger is invoked by the loading thread before the + // LoggerFinder service is loaded + boolean isLoadingThread() { + return isLoadingThread != null && isLoadingThread.getAsBoolean(); + } + + BootstrapLogger(LazyLoggerAccessor holder, BooleanSupplier isLoadingThread) { + this.holder = holder; + this.isLoadingThread = isLoadingThread; + } + + // Temporary data object storing log events + // It would be nice to use a Consumer instead of a LogEvent. + // This way we could simply do things like: + // push((logger) -> logger.log(level, msg)); + // Unfortunately, if we come to here it means we are in the bootsraping + // phase where using lambdas is not safe yet - so we have to use + // a data object instead... + // + static final class LogEvent { + // only one of these two levels should be non null + final Level level; + final PlatformLogger.Level platformLevel; + final BootstrapLogger bootstrap; + + final ResourceBundle bundle; + final String msg; + final Throwable thrown; + final Object[] params; + final Supplier msgSupplier; + final String sourceClass; + final String sourceMethod; + final long timeMillis; + final long nanoAdjustment; + + // because logging a message may entail calling toString() on + // the parameters etc... we need to store the context of the + // caller who logged the message - so that we can reuse it when + // we finally log the message. + @SuppressWarnings("removal") + final AccessControlContext acc; + + // The next event in the queue + LogEvent next; + + @SuppressWarnings("removal") + private LogEvent(BootstrapLogger bootstrap, Level level, + ResourceBundle bundle, String msg, + Throwable thrown, Object[] params) { + this.acc = AccessController.getContext(); + this.timeMillis = System.currentTimeMillis(); + this.nanoAdjustment = VM.getNanoTimeAdjustment(timeMillis); + this.level = level; + this.platformLevel = null; + this.bundle = bundle; + this.msg = msg; + this.msgSupplier = null; + this.thrown = thrown; + this.params = params; + this.sourceClass = null; + this.sourceMethod = null; + this.bootstrap = bootstrap; + } + + @SuppressWarnings("removal") + private LogEvent(BootstrapLogger bootstrap, Level level, + Supplier msgSupplier, + Throwable thrown, Object[] params) { + this.acc = AccessController.getContext(); + this.timeMillis = System.currentTimeMillis(); + this.nanoAdjustment = VM.getNanoTimeAdjustment(timeMillis); + this.level = level; + this.platformLevel = null; + this.bundle = null; + this.msg = null; + this.msgSupplier = msgSupplier; + this.thrown = thrown; + this.params = params; + this.sourceClass = null; + this.sourceMethod = null; + this.bootstrap = bootstrap; + } + + @SuppressWarnings("removal") + private LogEvent(BootstrapLogger bootstrap, + PlatformLogger.Level platformLevel, + String sourceClass, String sourceMethod, + ResourceBundle bundle, String msg, + Throwable thrown, Object[] params) { + this.acc = AccessController.getContext(); + this.timeMillis = System.currentTimeMillis(); + this.nanoAdjustment = VM.getNanoTimeAdjustment(timeMillis); + this.level = null; + this.platformLevel = platformLevel; + this.bundle = bundle; + this.msg = msg; + this.msgSupplier = null; + this.thrown = thrown; + this.params = params; + this.sourceClass = sourceClass; + this.sourceMethod = sourceMethod; + this.bootstrap = bootstrap; + } + + @SuppressWarnings("removal") + private LogEvent(BootstrapLogger bootstrap, + PlatformLogger.Level platformLevel, + String sourceClass, String sourceMethod, + Supplier msgSupplier, + Throwable thrown, Object[] params) { + this.acc = AccessController.getContext(); + this.timeMillis = System.currentTimeMillis(); + this.nanoAdjustment = VM.getNanoTimeAdjustment(timeMillis); + this.level = null; + this.platformLevel = platformLevel; + this.bundle = null; + this.msg = null; + this.msgSupplier = msgSupplier; + this.thrown = thrown; + this.params = params; + this.sourceClass = sourceClass; + this.sourceMethod = sourceMethod; + this.bootstrap = bootstrap; + } + + // Log this message in the given logger. Do not call directly. + // Use LogEvent.log(LogEvent, logger) instead. + private void log(Logger logger) { + assert platformLevel == null && level != null; + //new Exception("logging delayed message").printStackTrace(); + if (msgSupplier != null) { + if (thrown != null) { + logger.log(level, msgSupplier, thrown); + } else { + logger.log(level, msgSupplier); + } + } else { + // BootstrapLoggers are never localized so we can safely + // use the method that takes a ResourceBundle parameter + // even when that resource bundle is null. + if (thrown != null) { + logger.log(level, bundle, msg, thrown); + } else { + logger.log(level, bundle, msg, params); + } + } + } + + // Log this message in the given logger. Do not call directly. + // Use LogEvent.doLog(LogEvent, logger) instead. + private void log(PlatformLogger.Bridge logger) { + assert platformLevel != null && level == null; + if (sourceClass == null) { + if (msgSupplier != null) { + if (thrown != null) { + logger.log(platformLevel, thrown, msgSupplier); + } else { + logger.log(platformLevel, msgSupplier); + } + } else { + // BootstrapLoggers are never localized so we can safely + // use the method that takes a ResourceBundle parameter + // even when that resource bundle is null. + if (thrown != null) { + logger.logrb(platformLevel, bundle, msg, thrown); + } else { + logger.logrb(platformLevel, bundle, msg, params); + } + } + } else { + if (msgSupplier != null) { + if (thrown != null) { + logger.logp(platformLevel, sourceClass, sourceMethod, thrown, msgSupplier); + } else { + logger.logp(platformLevel, sourceClass, sourceMethod, msgSupplier); + } + } else { + // BootstrapLoggers are never localized so we can safely + // use the method that takes a ResourceBundle parameter + // even when that resource bundle is null. + if (thrown != null) { + logger.logrb(platformLevel, sourceClass, sourceMethod, bundle, msg, thrown); + } else { + logger.logrb(platformLevel, sourceClass, sourceMethod, bundle, msg, params); + } + } + } + } + + // non default methods from Logger interface + static LogEvent valueOf(BootstrapLogger bootstrap, Level level, + ResourceBundle bundle, String key, Throwable thrown) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), bundle, key, + thrown, null); + } + static LogEvent valueOf(BootstrapLogger bootstrap, Level level, + ResourceBundle bundle, String format, Object[] params) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), bundle, format, + null, params); + } + static LogEvent valueOf(BootstrapLogger bootstrap, Level level, + Supplier msgSupplier, Throwable thrown) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), + Objects.requireNonNull(msgSupplier), thrown, null); + } + static LogEvent valueOf(BootstrapLogger bootstrap, Level level, + Supplier msgSupplier) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), + Objects.requireNonNull(msgSupplier), null, null); + } + @SuppressWarnings("removal") + static void log(LogEvent log, Logger logger) { + final SecurityManager sm = System.getSecurityManager(); + // not sure we can actually use lambda here. We may need to create + // an anonymous class. Although if we reach here, then it means + // the VM is booted. + if (sm == null || log.acc == null) { + BootstrapExecutors.submit(() -> log.log(logger)); + } else { + BootstrapExecutors.submit(() -> + AccessController.doPrivileged((PrivilegedAction) () -> { + log.log(logger); return null; + }, log.acc)); + } + } + + // non default methods from PlatformLogger.Bridge interface + static LogEvent valueOf(BootstrapLogger bootstrap, + PlatformLogger.Level level, String msg) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), null, null, null, + msg, null, null); + } + static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level, + String msg, Throwable thrown) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), null, null, null, msg, thrown, null); + } + static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level, + String msg, Object[] params) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), null, null, null, msg, null, params); + } + static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level, + Supplier msgSupplier) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), null, null, msgSupplier, null, null); + } + static LogEvent vaueOf(BootstrapLogger bootstrap, PlatformLogger.Level level, + Supplier msgSupplier, + Throwable thrown) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), null, null, + msgSupplier, thrown, null); + } + static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level, + String sourceClass, String sourceMethod, + ResourceBundle bundle, String msg, Object[] params) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), sourceClass, + sourceMethod, bundle, msg, null, params); + } + static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level, + String sourceClass, String sourceMethod, + ResourceBundle bundle, String msg, Throwable thrown) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), sourceClass, + sourceMethod, bundle, msg, thrown, null); + } + static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level, + String sourceClass, String sourceMethod, + Supplier msgSupplier, Throwable thrown) { + return new LogEvent(Objects.requireNonNull(bootstrap), + Objects.requireNonNull(level), sourceClass, + sourceMethod, msgSupplier, thrown, null); + } + @SuppressWarnings("removal") + static void log(LogEvent log, PlatformLogger.Bridge logger) { + final SecurityManager sm = System.getSecurityManager(); + if (sm == null || log.acc == null) { + BootstrapExecutors.submit(() -> log.log(logger)); + } else { + // not sure we can actually use lambda here. We may need to create + // an anonymous class. Although if we reach here, then it means + // the VM is booted. + BootstrapExecutors.submit(() -> + AccessController.doPrivileged((PrivilegedAction) () -> { + log.log(logger); return null; + }, log.acc)); + } + } + + static void log(LogEvent event) { + event.bootstrap.flush(event); + } + + } + + // Push a log event at the end of the pending LogEvent queue. + void push(LogEvent log) { + BootstrapExecutors.enqueue(log); + // if the queue has been flushed just before we entered + // the synchronized block we need to flush it again. + checkBootstrapping(); + } + + // Flushes the queue of pending LogEvents to the logger. + void flush(LogEvent event) { + assert event.bootstrap == this; + if (event.platformLevel != null) { + PlatformLogger.Bridge concrete = holder.getConcretePlatformLogger(this); + LogEvent.log(event, concrete); + } else { + Logger concrete = holder.getConcreteLogger(this); + LogEvent.log(event, concrete); + } + } + + /** + * The name of this logger. This is the name of the actual logger for which + * this logger acts as a temporary proxy. + * @return The logger name. + */ + @Override + public String getName() { + return holder.name; + } + + /** + * Check whether the VM is still bootstrapping, and if not, arranges + * for this logger's holder to create the real logger and flush the + * pending event queue. + * @return true if the VM is still bootstrapping. + */ + boolean checkBootstrapping() { + if (isBooted() && !isLoadingThread()) { + BootstrapExecutors.flush(); + holder.getConcreteLogger(this); + return false; + } + return true; + } + + // ---------------------------------- + // Methods from Logger + // ---------------------------------- + + @Override + public boolean isLoggable(Level level) { + if (checkBootstrapping()) { + return level.getSeverity() >= Level.INFO.getSeverity(); + } else { + final Logger spi = holder.wrapped(); + return spi.isLoggable(level); + } + } + + @Override + public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, bundle, key, thrown)); + } else { + final Logger spi = holder.wrapped(); + spi.log(level, bundle, key, thrown); + } + } + + @Override + public void log(Level level, ResourceBundle bundle, String format, Object... params) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, bundle, format, params)); + } else { + final Logger spi = holder.wrapped(); + spi.log(level, bundle, format, params); + } + } + + @Override + public void log(Level level, String msg, Throwable thrown) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, null, msg, thrown)); + } else { + final Logger spi = holder.wrapped(); + spi.log(level, msg, thrown); + } + } + + @Override + public void log(Level level, String format, Object... params) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, null, format, params)); + } else { + final Logger spi = holder.wrapped(); + spi.log(level, format, params); + } + } + + @Override + public void log(Level level, Supplier msgSupplier) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, msgSupplier)); + } else { + final Logger spi = holder.wrapped(); + spi.log(level, msgSupplier); + } + } + + @Override + public void log(Level level, Object obj) { + if (checkBootstrapping()) { + Logger.super.log(level, obj); + } else { + final Logger spi = holder.wrapped(); + spi.log(level, obj); + } + } + + @Override + public void log(Level level, String msg) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, null, msg, (Object[])null)); + } else { + final Logger spi = holder.wrapped(); + spi.log(level, msg); + } + } + + @Override + public void log(Level level, Supplier msgSupplier, Throwable thrown) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, msgSupplier, thrown)); + } else { + final Logger spi = holder.wrapped(); + spi.log(level, msgSupplier, thrown); + } + } + + // ---------------------------------- + // Methods from PlatformLogger.Bridge + // ---------------------------------- + + @Override + public boolean isLoggable(PlatformLogger.Level level) { + if (checkBootstrapping()) { + return level.intValue() >= PlatformLogger.Level.INFO.intValue(); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + return spi.isLoggable(level); + } + } + + @Override + public boolean isEnabled() { + if (checkBootstrapping()) { + return true; + } else { + final PlatformLogger.Bridge spi = holder.platform(); + return spi.isEnabled(); + } + } + + @Override + public void log(PlatformLogger.Level level, String msg) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, msg)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.log(level, msg); + } + } + + @Override + public void log(PlatformLogger.Level level, String msg, Throwable thrown) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, msg, thrown)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.log(level, msg, thrown); + } + } + + @Override + public void log(PlatformLogger.Level level, String msg, Object... params) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, msg, params)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.log(level, msg, params); + } + } + + @Override + public void log(PlatformLogger.Level level, Supplier msgSupplier) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, msgSupplier)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.log(level, msgSupplier); + } + } + + @Override + public void log(PlatformLogger.Level level, Throwable thrown, + Supplier msgSupplier) { + if (checkBootstrapping()) { + push(LogEvent.vaueOf(this, level, msgSupplier, thrown)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.log(level, thrown, msgSupplier); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, String msg) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, null, + msg, (Object[])null)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.logp(level, sourceClass, sourceMethod, msg); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, Supplier msgSupplier) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, msgSupplier, null)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.logp(level, sourceClass, sourceMethod, msgSupplier); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, String msg, Object... params) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, null, msg, params)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.logp(level, sourceClass, sourceMethod, msg, params); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, String msg, Throwable thrown) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, null, msg, thrown)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.logp(level, sourceClass, sourceMethod, msg, thrown); + } + } + + @Override + public void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, Throwable thrown, Supplier msgSupplier) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, msgSupplier, thrown)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.logp(level, sourceClass, sourceMethod, thrown, msgSupplier); + } + } + + @Override + public void logrb(PlatformLogger.Level level, String sourceClass, + String sourceMethod, ResourceBundle bundle, String msg, Object... params) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, bundle, msg, params)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.logrb(level, sourceClass, sourceMethod, bundle, msg, params); + } + } + + @Override + public void logrb(PlatformLogger.Level level, String sourceClass, + String sourceMethod, ResourceBundle bundle, String msg, Throwable thrown) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, sourceClass, sourceMethod, bundle, msg, thrown)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.logrb(level, sourceClass, sourceMethod, bundle, msg, thrown); + } + } + + @Override + public void logrb(PlatformLogger.Level level, ResourceBundle bundle, + String msg, Object... params) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, null, null, bundle, msg, params)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.logrb(level, bundle, msg, params); + } + } + + @Override + public void logrb(PlatformLogger.Level level, ResourceBundle bundle, String msg, Throwable thrown) { + if (checkBootstrapping()) { + push(LogEvent.valueOf(this, level, null, null, bundle, msg, thrown)); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + spi.logrb(level, bundle, msg, thrown); + } + } + + @Override + public LoggerConfiguration getLoggerConfiguration() { + if (checkBootstrapping()) { + // This practically means that PlatformLogger.setLevel() + // calls will be ignored if the VM is still bootstrapping. We could + // attempt to fix that but is it worth it? + return PlatformLogger.ConfigurableBridge.super.getLoggerConfiguration(); + } else { + final PlatformLogger.Bridge spi = holder.platform(); + return PlatformLogger.ConfigurableBridge.getLoggerConfiguration(spi); + } + } + + // This BooleanSupplier is a hook for tests - so that we can simulate + // what would happen before the VM is booted. + private static volatile BooleanSupplier isBooted; + public static boolean isBooted() { + if (isBooted != null) return isBooted.getAsBoolean(); + else return VM.isBooted(); + } + + // A bit of magic. We try to find out the nature of the logging + // backend without actually loading it. + private static enum LoggingBackend { + // There is no LoggerFinder and JUL is not present + NONE(true), + + // There is no LoggerFinder, but we have found a + // JdkLoggerFinder installed (which means JUL is present), + // and we haven't found any custom configuration for JUL. + // Until LogManager is initialized we can use a simple console + // logger. + JUL_DEFAULT(false), + + // Same as above, except that we have found a custom configuration + // for JUL. We cannot use the simple console logger in this case. + JUL_WITH_CONFIG(true), + + // We have found a custom LoggerFinder. + CUSTOM(true); + + final boolean useLoggerFinder; + private LoggingBackend(boolean useLoggerFinder) { + this.useLoggerFinder = useLoggerFinder; + } + }; + + // The purpose of this class is to delay the initialization of + // the detectedBackend field until it is actually read. + // We do not want this field to get initialized if VM.isBooted() is false. + @SuppressWarnings("removal") + private static final class DetectBackend { + static final LoggingBackend detectedBackend; + static { + detectedBackend = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public LoggingBackend run() { + final Iterator iterator = + ServiceLoader.load(LoggerFinder.class, ClassLoader.getSystemClassLoader()) + .iterator(); + if (iterator.hasNext()) { + return LoggingBackend.CUSTOM; // Custom Logger Provider is registered + } + // No custom logger provider: we will be using the default + // backend. + final Iterator iterator2 = + ServiceLoader.loadInstalled(DefaultLoggerFinder.class) + .iterator(); + if (iterator2.hasNext()) { + // LoggingProviderImpl is registered. The default + // implementation is java.util.logging + String cname = System.getProperty("java.util.logging.config.class"); + String fname = System.getProperty("java.util.logging.config.file"); + return (cname != null || fname != null) + ? LoggingBackend.JUL_WITH_CONFIG + : LoggingBackend.JUL_DEFAULT; + } else { + // SimpleConsoleLogger is used + return LoggingBackend.NONE; + } + } + }); + + } + } + + // We will use a temporary SurrogateLogger if + // the logging backend is JUL, there is no custom config, + // and the LogManager has not been initialized yet. + private static boolean useSurrogateLoggers() { + // being paranoid: this should already have been checked + if (!isBooted()) return true; + return DetectBackend.detectedBackend == LoggingBackend.JUL_DEFAULT + && !logManagerConfigured; + } + + // We will use lazy loggers if: + // - the VM is not yet booted + // - the logging backend is a custom backend + // - the logging backend is JUL, there is no custom config, + // and the LogManager has not been initialized yet. + public static boolean useLazyLoggers() { + // Note: avoid triggering the initialization of the DetectBackend class + // while holding the BootstrapLogger class monitor + if (!BootstrapLogger.isBooted() || + DetectBackend.detectedBackend == LoggingBackend.CUSTOM) { + return true; + } + synchronized (BootstrapLogger.class) { + return useSurrogateLoggers(); + } + } + + // Called by LazyLoggerAccessor. This method will determine whether + // to create a BootstrapLogger (if the VM is not yet booted), + // a SurrogateLogger (if JUL is the default backend and there + // is no custom JUL configuration and LogManager is not yet initialized), + // or a logger returned by the loaded LoggerFinder (all other cases). + static Logger getLogger(LazyLoggerAccessor accessor, BooleanSupplier isLoading) { + if (!BootstrapLogger.isBooted() || isLoading != null && isLoading.getAsBoolean()) { + return new BootstrapLogger(accessor, isLoading); + } else { + if (useSurrogateLoggers()) { + // JUL is the default backend, there is no custom configuration, + // LogManager has not been used. + synchronized(BootstrapLogger.class) { + if (useSurrogateLoggers()) { + return createSurrogateLogger(accessor); + } + } + } + // Already booted. Return the real logger. + return accessor.createLogger(); + } + } + + // trigger class initialization outside of holding lock + static void ensureBackendDetected() { + assert VM.isBooted() : "VM is not booted"; + // triggers detection of the backend + var backend = DetectBackend.detectedBackend; + } + + // If the backend is JUL, and there is no custom configuration, and + // nobody has attempted to call LogManager.getLogManager() yet, then + // we can temporarily substitute JUL Logger with SurrogateLoggers, + // which avoids the cost of actually loading up the LogManager... + // The RedirectedLoggers class has the logic to create such surrogate + // loggers, and to possibly replace them with real JUL loggers if + // someone calls LogManager.getLogManager(). + static final class RedirectedLoggers implements + Function { + + // all accesses must be synchronized on the outer BootstrapLogger.class + final Map redirectedLoggers = + new HashMap<>(); + + // all accesses must be synchronized on the outer BootstrapLogger.class + // The redirectLoggers map will be cleared when LogManager is initialized. + boolean cleared; + + @Override + // all accesses must be synchronized on the outer BootstrapLogger.class + public SurrogateLogger apply(LazyLoggerAccessor t) { + if (cleared) throw new IllegalStateException("LoggerFinder already initialized"); + return SurrogateLogger.makeSurrogateLogger(t.getLoggerName()); + } + + // all accesses must be synchronized on the outer BootstrapLogger.class + SurrogateLogger get(LazyLoggerAccessor a) { + if (cleared) throw new IllegalStateException("LoggerFinder already initialized"); + return redirectedLoggers.computeIfAbsent(a, this); + } + + // all accesses must be synchronized on the outer BootstrapLogger.class + Map drainLoggersMap() { + if (redirectedLoggers.isEmpty()) return null; + if (cleared) throw new IllegalStateException("LoggerFinder already initialized"); + final Map accessors = new HashMap<>(redirectedLoggers); + redirectedLoggers.clear(); + cleared = true; + return accessors; + } + + static void replaceSurrogateLoggers(Map accessors) { + // When the backend is JUL we want to force the creation of + // JUL loggers here: some tests are expecting that the + // PlatformLogger will create JUL loggers as soon as the + // LogManager is initialized. + // + // If the backend is not JUL then we can delay the re-creation + // of the wrapped logger until they are next accessed. + // + final LoggingBackend detectedBackend = DetectBackend.detectedBackend; + final boolean lazy = detectedBackend != LoggingBackend.JUL_DEFAULT + && detectedBackend != LoggingBackend.JUL_WITH_CONFIG; + for (Map.Entry a : accessors.entrySet()) { + a.getKey().release(a.getValue(), !lazy); + } + } + + // all accesses must be synchronized on the outer BootstrapLogger.class + static final RedirectedLoggers INSTANCE = new RedirectedLoggers(); + } + + static synchronized Logger createSurrogateLogger(LazyLoggerAccessor a) { + // accesses to RedirectedLoggers is synchronized on BootstrapLogger.class + return RedirectedLoggers.INSTANCE.get(a); + } + + private static volatile boolean logManagerConfigured; + + private static synchronized Map + releaseSurrogateLoggers() { + // first check whether there's a chance that we have used + // surrogate loggers; Will be false if logManagerConfigured is already + // true. + final boolean releaseSurrogateLoggers = useSurrogateLoggers(); + + // then sets the flag that tells that the log manager is configured + logManagerConfigured = true; + + // finally retrieves all surrogate loggers that should be replaced + // by real JUL loggers, and return them in the form of a redirected + // loggers map. + if (releaseSurrogateLoggers) { + // accesses to RedirectedLoggers is synchronized on BootstrapLogger.class + return RedirectedLoggers.INSTANCE.drainLoggersMap(); + } else { + return null; + } + } + + public static void redirectTemporaryLoggers() { + // This call is synchronized on BootstrapLogger.class. + final Map accessors = + releaseSurrogateLoggers(); + + // We will now reset the logger accessors, triggering the + // (possibly lazy) replacement of any temporary surrogate logger by the + // real logger returned from the loaded LoggerFinder. + if (accessors != null) { + RedirectedLoggers.replaceSurrogateLoggers(accessors); + } + + BootstrapExecutors.flush(); + } + + // Hook for tests which need to wait until pending messages + // are processed. + static void awaitPendingTasks() { + BootstrapExecutors.awaitPendingTasks(); + } + static boolean isAlive() { + return BootstrapExecutors.isAlive(); + } + +} diff --git a/tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder$1.class b/tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder$1.class new file mode 100644 index 0000000000000000000000000000000000000000..b925016932bbb333af163d85ee61b499c26898d6 GIT binary patch literal 1124 zcma)5T~8B16g^W~7M8V?3J9o(iqaNkMNvs0BnYA=Etp{X(6?bbEQ8ybWIssw7ryvE zG*Kiz_yhb=#=F~X*cvfzvU_Llo;mlPd++@G_5BBcEvybBhXDh53k3`^RFB*5ZK*=x zEAH8zc3t7y+v1Q%URY0dJ5sfUKflaSIN{!WhoM|Q<|o|txN_}=ZbzP2Gckl=1Ez%$ zSPZ2Lz}~^Ja6*Q`b*W^y!7xy%Hcb>UYM^9c4COv}mye<7ig3&0K~UG6!ZS=)s+q8v zUle;B69y(NT*DN@c%Pz<3>>@JAh!(mPlHf&wsnU~)uWxMT*6vynV7+K12-((#4N+u zg{Bu;dx9$lgDMh2>%^F@W@lHYlnMH?#pX&ceTDj0>({7!eQ9@_O77u(=_(#ZJ_UP~NiGF+J(nt4&z$I0VuM)CeI5CZ*dg@{ zQ-7JprMOZg_@#0@9Z2OiM0ljz1|Bmk{HH7nD|pH<)SHXAHJN;R#GJPVz9CddH40pjwrT9M46&s*;1oy~$pH?e`$dNT`i(kQN-(Y;ET@DNM9V86! z0TudM$=XB}HQKRwU{Z!vvN5h$`vP``E9ba+j_FV2$+CRRuoSy2rA=a4Oj+!drBFM= otv?TEQz)b<6!0Jk@eoUiweg5-9?N)wXNhMS&&irZ91Eo9H_{Cb&;S4c literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder$SharedLoggers.class b/tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder$SharedLoggers.class new file mode 100644 index 0000000000000000000000000000000000000000..0e811b94747a26b5e2d003da0e3c35c10c7c8561 GIT binary patch literal 2532 zcmbVOZBrXn6n<_9EF{ZIX`uv4LBs-~G}el33E~SCDW=pm6{Nl{;Sv^>4Q@6t_3eYz zamN0Te$~;IL1vtOk{SPkf2E^7cQ=sT1{f74*?Z5Pm*+g^+Iv*t<i6@-plPTiKv(vfyf-YUtGjG@KHaY{!U+68JqQ(}R$zAG=WYO{14 z9Y|>C)X{}A0*#@#%seki#JRzM6Q7;*P_;pp2m#y(-Fc0;dKKwSGQioxN9d z<$Ax*P8=`boQ44%g9>I>1?FB5aNdB6m=;bFXAG3+9;8yE5~~|nmJXyOFCZ0s6ce1U|B>S;wS{bE81lp zS8$b0x@lM?$)4%hH}KkXl1|vfB!=2)jB9vR#{^y@`4#ReO7!E%^};3_rtOdsq^q$qkhq=kHF>3|7!QNIy6%{-d4`ys$yo&P%2y^L`b)oOlw( z14YTYj%nx90ZE9ZkZQ1((i8j_xO$YKcb<;3W{oBbO9a=PF>N_pT3?jT9b?g=q%~8> z8P=TPm}*}ZM%@*Y1)3=n>*Z3_w!u8gnFS9?=rj<0lYduaONuz@2y_RCs&-Duwz2L3 ztenqs7 z9}c{!w#x)SRA2|A|EHE}%(_Nyjcr;k{MNA*4~D7kd%ft#?S@T5d!tIvgl41imrwwfq{Q{s0H-vwk@4W%P1DrHPjdyY8qBTqt(xf zw}*eN^YV;y3rgiapEdk&a8u(Qu5NKJ`0Pq< zLnL>hEo`IV5n^1naM}6@Cx7DW2r~R`WjMg)cZngl(1{1QL5c3Wz^oUbm$T|7E$Cj1 zGf*8hHj}>~c76w^BY1-D*^xbH;vr%qkJ0l4ePhu?bPof=ROnX<6nOf(7+OfE<;iUf z@8CiW=EYd8+CRoi3$wqYCsDhHCZ)TBR|Ljt6SX5d7>i*3;opBIqCYZn)I**`jO))y z)fec&m*~e=r0{E!_6>2~$2`789^ave@4bvBeAMNPh#&8gDn-;LZX?U=ny`X9c#rh; z(0Y!aC_N2xw!BYz7pU3mQLQZR($d%efHGg}Lu!3QtxnWEMZ1RXDGhy3k@UVJ8q!_y za!Ef%Jw7=o*hR)xe{H*nvp}!^j5iKeZ>drVFJbi~4fug+KVZmDxsJfVqW8=}^4UsB P962nrGy0gkS=aCn(#)vl literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder.class b/tests/test_data/std/jdk/internal/logger/DefaultLoggerFinder.class new file mode 100644 index 0000000000000000000000000000000000000000..be2ffd5a9fc8e4827267e09a8c942c0ecbcf3975 GIT binary patch literal 3312 zcmbVO+fx%)82_DsYzT{lSTAT5wW1Kv)YfZ*T17xK1WFK!t<}xu01KPlxECt+e!sWA zcBYr7zV*S{8K64T=~Ev%{gXPKerI=+Y%t6)%|mwgobUX;@B4kf^PTh8zmI+gFo63p zM9?6iQN|WDF&tSaET%NW;g+H3Dczi#<5uc2pH*Dl$#`Ewno-~uLz_C!)x~jc6*b$| zOoJiO-IG~RmXwsP7;~v9Q!AtedQ?U;Vhm0FnxQ%88Mbw=H|v>-K}M^Dt-`jAVQ&>D zw`@DSc&OHSL$_Gcj)a75GM>VAhWPp=6wn-Za$I#S%~>8*425zb=$a_kO{beF;GHsd zp@U&(W^8zPaAIgAdwFo;*7)GW=twR%GL|KbPy!RK;b=u(C4!RPgQq3z6_oB{=m-V& zWH3IG9ZaM`Fg;Te_A~TsvLc6$$Iyv`g1~1Owud<$H4CoJ(}J=t9F}lIMmKsG_IZ(2 zd|y;mZrcN<;aH}w3$EmXIc{l7n$G8Vf#E~|T3Jz@yr?>)fpk~^WBCQHI%x^L4DD48 zE}5pz6(fcuj>LDAdXPUa*m}LbM=Ca;w%ZZ=IDo}15!6w5Mr^8MrsQv zh`BCfO0d!*0@74P>;VZcGwiAA{fYh%#SN0Y-&*}<8pAYR6&v^Fx+;`|n4-NfU>0a^ zv}H7dXWe3+Ta!v&r;&uGoGHc9#CI^*=*(-xI&H_zwevJp$TeJB?DBYs1+R%SMC>Bv z6dGUOHW^xTj-oD(Dy1L-Mk^Ab6@e-lnyC=}KB_eca-~4>o}?Le`^)ReorK%3>cM#u z%XvFth}smxt~!U+F;NYwQkL7!C>PujH*so2j_p`VX_PzjX2Fhw1adgM>w?Zvr>V6y zVJU{!aaY2!jC*)vgOf9-6-zp&mTFVeD`y=qDvR8oDG!|syDe9}Zt?0MrsH^v;b?t` z%6VL?UP|Dd7~aKu65f~b0X}3nSkgu4HRXXEN%*>aB766zdZwNq zK`0K;;UrT_B*BZz3cW?qDDF-)@)~`eqIo7plWSnBkba@}2yW58IM#rhkjU;fy~(~E z6y)hELKv|C;~YJO?Uv*!TGj*HCUtrLsXHV*t>82VniH9_f6yk;Evs1^Vu6c(!VxYK zkI^|p5g%B?p+AsZLEq0b>gO)P0q$3D$(lTAG}cbuM81MMm5>_f+0mPLb`8%>_a)AV z2N5})?Co2@3nFMA&=2}MBJ+D}#SaAcqX)j<2dHq;f#X>8oOj?XIgF4)I{E{L+AMVzT-{AmMtf64V-6@EfV@aVWK}N*G<0FuH=&M2)BxyC@o?BFHWp62I2R zn4U?@tm2hlu|tT8dDZt5og{B2jYUwx9eOs=+c4c~EqWI^eVagRxOfvE(MXa6CKHh# cH#U=v|NDf#KWh?aa|EAL%wOOue1nev0M + * The JDK default implementation of the {@link LoggerFinder} will + * attempt to locate and load an {@linkplain + * java.util.ServiceLoader#loadInstalled(java.lang.Class) installed} + * implementation of the {@code DefaultLoggerFinder}. If {@code java.util.logging} + * is present, this will usually resolve to an instance of {@link + * sun.util.logging.internal.LoggingProviderImpl sun.util.logging.internal.LoggingProviderImpl}. + * Otherwise, if no concrete service provider is declared for + * {@code DefaultLoggerFinder}, the default implementation provided by this class + * will be used. + *

+ * When the {@link sun.util.logging.internal.LoggingProviderImpl + * sun.util.logging.internal.LoggingProviderImpl} is not present then the + * default implementation provided by this class is to use a simple logger + * that will log messages whose level is INFO and above to the console. + * These simple loggers are not configurable. + *

+ * When configuration is needed, an application should either link with + * {@code java.util.logging} - and use the {@code java.util.logging} for + * configuration, or link with {@link LoggerFinder another implementation} + * of the {@link LoggerFinder} + * that provides the necessary configuration. + * + * @apiNote Programmers are not expected to call this class directly. + * Instead they should rely on the static methods defined by {@link + * java.lang.System java.lang.System} or {@link sun.util.logging.PlatformLogger + * sun.util.logging.PlatformLogger}. + * + * @see java.lang.System.LoggerFinder + * @see jdk.internal.logger + * @see sun.util.logging.internal + * + */ +public class DefaultLoggerFinder extends LoggerFinder { + + static final RuntimePermission LOGGERFINDER_PERMISSION = + new RuntimePermission("loggerFinder"); + + /** + * Creates a new instance of DefaultLoggerFinder. + * @throws SecurityException if the calling code does not have the + * {@code RuntimePermission("loggerFinder")} + */ + protected DefaultLoggerFinder() { + this(checkPermission()); + } + + private DefaultLoggerFinder(Void unused) { + // nothing to do. + } + + private static Void checkPermission() { + @SuppressWarnings("removal") + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(LOGGERFINDER_PERMISSION); + } + return null; + } + + // SharedLoggers is a default cache of loggers used when JUL is not + // present - in that case we use instances of SimpleConsoleLogger which + // cannot be directly configure through public APIs. + // + // We can therefore afford to simply maintain two domains - one for the + // system, and one for the application. + // + static final class SharedLoggers { + private final Map> loggers = + new HashMap<>(); + private final ReferenceQueue queue = new ReferenceQueue<>(); + + synchronized Logger get(Function loggerSupplier, final String name) { + Reference ref = loggers.get(name); + Logger w = ref == null ? null : ref.get(); + if (w == null) { + w = loggerSupplier.apply(name); + loggers.put(name, new WeakReference<>(w, queue)); + } + + // Remove stale mapping... + Collection> values = null; + while ((ref = queue.poll()) != null) { + if (values == null) values = loggers.values(); + values.remove(ref); + } + return w; + } + + static final SharedLoggers system = new SharedLoggers(); + static final SharedLoggers application = new SharedLoggers(); + } + + @SuppressWarnings("removal") + public static boolean isSystem(Module m) { + return AccessController.doPrivileged(new PrivilegedAction<>() { + @Override + public Boolean run() { + // returns true if moduleCL is the platform class loader + // or one of its ancestors. + return VM.isSystemDomainLoader(m.getClassLoader()); + } + }); + } + + @Override + public final Logger getLogger(String name, Module module) { + Objects.requireNonNull(name, "name"); + Objects.requireNonNull(module, "module"); + checkPermission(); + return demandLoggerFor(name, module); + } + + @Override + public final Logger getLocalizedLogger(String name, ResourceBundle bundle, + Module module) { + return super.getLocalizedLogger(name, bundle, module); + } + + /** + * Returns a {@link Logger logger} suitable for use within the + * given {@code module}. + * + * @implSpec The default implementation for this method is to return a + * simple logger that will print all messages of INFO level and above + * to the console. That simple logger is not configurable. + * + * @param name The name of the logger. + * @param module The module on behalf of which the logger is created. + * @return A {@link Logger logger} suitable for the application usage. + * @throws SecurityException if the calling code does not have the + * {@code RuntimePermission("loggerFinder")}. + */ + protected Logger demandLoggerFor(String name, Module module) { + checkPermission(); + if (isSystem(module)) { + return SharedLoggers.system.get(SimpleConsoleLogger::makeSimpleLogger, name); + } else { + return SharedLoggers.application.get(SimpleConsoleLogger::makeSimpleLogger, name); + } + } + +} diff --git a/tests/test_data/std/jdk/internal/logger/LazyLoggers$1.class b/tests/test_data/std/jdk/internal/logger/LazyLoggers$1.class new file mode 100644 index 0000000000000000000000000000000000000000..76511ce7a5dab63a4aef3737f0c3ef26b6ab6ba3 GIT binary patch literal 1119 zcmah}+iuf95IyT$oCKGK7AUvUmIla;T0DW2st5uRNN$T1)b~xYxEq{xupOlERqz6c z2h?Xi3NdS2iUX<|$)4HSnX@NnX8rrm&tCw#uq!Z-Gm*DYK#`$3=AXFjapl^_gRvM! z48?t^WOTrgt2a(6D4}ekV&M`jhOP1FgDq7g0>wSs^Ica2w!=Tqo!AW-)?E=Li(cSQ zdQy!e1jDK$l{lJB1|oRJ z2OdS%9Dm5Y6COytPJ{XARFWvW&V?j81g-ca2KrAbYRV**NFTGSwLi_nd6p#&r@hWQ*dshvpGwBJ|Gz?eSa1V zMNeu~tC`{2)Bl{Lf2D?=AJPaV)EP=gB8*=9Aq}tfMkx_=JsyT4G|^(%Sm?DhQzjlQ z4NtO3N+%{j~+%rE3+t3Sro+et=Rt&ulzH%2UCi-;N3=Y+UJl^XF0WoyKhX6p!+;0Mz412@SGZmL}TRE0)QR Ge}4fakq*fK literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LazyLoggers$JdkLazyLogger.class b/tests/test_data/std/jdk/internal/logger/LazyLoggers$JdkLazyLogger.class new file mode 100644 index 0000000000000000000000000000000000000000..be6d80b57649dbb6e57e555eb8e30abc04ffb87f GIT binary patch literal 1381 zcmbVM-%ry}6#h;b?N$eDLlN-@iYROYDyZ?H#>6Z^FqM~?`FvTgqpWL5+nMO2G5YA= zqAwU9jL-g2#?!j3#TbXY^xSiL&Ue1^m_xink89W#JE?X*=-xh951Wv3E zjJfE*;l(t@w&+B6O-|#9UILm9ZLmk&`d+dMamw`XfFl1r@LfCZ#=Wsg(|L~O!ts5t zA4;20%AhARBIr%OAGGDR6Bk@c!^4f32qC{G!)V73Bfb&4o+pEbE5cBQ8rBJSPe0Mo zF4;R0Y5X~MOy&jGM}2rVS;73R{soI`vQ%= zW9k?)pAy$A{MF+SdW#ah!&TO={|>-4EV9O-Y`MX3@o5P+*;|Qk)*!(SYjFa#RzJpt zKT+Rfl0IZm)e)+SW!y?oRouo(g0jju3aY3jQbC>N5*M(>)(tKx&(gp=m#T2V3tX^* HP3XS>-L8fH literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LazyLoggers$LazyLoggerAccessor.class b/tests/test_data/std/jdk/internal/logger/LazyLoggers$LazyLoggerAccessor.class new file mode 100644 index 0000000000000000000000000000000000000000..405ccf2985ea59cc31de085e50d8ec308d7157dd GIT binary patch literal 7062 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LazyLoggers$LazyLoggerFactories.class b/tests/test_data/std/jdk/internal/logger/LazyLoggers$LazyLoggerFactories.class new file mode 100644 index 0000000000000000000000000000000000000000..df96b06867f58d49c0f44f7f94260a4a35b60c41 GIT binary patch literal 1461 zcmb_c&r{Pt6#kahhQ$W0*Lw-`hqQ2*-H2 zf51C|&oJikccJij)0NH8aTpettjNu=WiN3vD}S0aj55rmfUiT@34|++$D)x;HRyz& zg0)@I)lt9|4Pyn2qsXv+(0ywN8E{Y9j^Vhy9`_8({%~YPQ-2|yH|$Q}dV-VYTwO>J zY%#1QTBDHuqQD%|t=P>Z*mdMYVHz9o9n4nmJJ?EKriJ|wXfctZAuMZa*np~KBR%iJ;<=FbYZ(q_nRyIrCk zw}j-)@Nl1dd-lFVmXhUmY^QB|Lah^HHh3c_qZ`&aE`k)5PhuYRf8lPP2e6*RxqC*O z|DQ9JkX$H3pLgl5hf*C?1H-EeWBMIiG1uzWCM7~OUDQpjBR}AW3vq3mTSGf>?NLJY zmK%B<-Vo}>ifQ%xs|to;w8{No$MpjZ52zB)xHX2tGby>Z?byDrI%hIP9Q2chhYVAv zsMN52qDkTqD5-G}s8OSo=&>Ou)h#sMq}2$f>7ydVEgEOY(nW@5K(V^~8SEQ0`trxP z{E=)K+@`;JtAHnT<|$@rR*wBKhdZ>QlL`L(iM_jnz3Bn>0-dDSh5m}!p)o_FUOmP{ zb@>y@Dd$+U^Bh_1A`dI#or}E(yn4c`6yC!kp`{9R@`@EGuT;T(LX7jUgbHzwpo-;a VT)`@hC9)K-0)xD2Si_@S{wJoUe)j+X literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LazyLoggers$LazyLoggerWrapper.class b/tests/test_data/std/jdk/internal/logger/LazyLoggers$LazyLoggerWrapper.class new file mode 100644 index 0000000000000000000000000000000000000000..2a65b1f18fd634488d3654d4d57caaa644f93b0c GIT binary patch literal 1713 zcmbVNT~8B16g@+0mzJe1RY64s1+gtk`BKy(3N?U9Q!zF5dE1V4VA-v+yDI)FO*E(v z#%F(&@$LuxfF=bWx-)m?&bjxVIdl8x@6TTV3V0U70744FD$XIoFtV$?*K&?6^xTW; zF0a`ZLtOHAj*z@$8YM^98D`Q&&rR2iM&OpuoLo{c$gsFu-^&TZ=F-sgoNhK6T;__} zr-Pz5wWizi^;(TvmMIm)C}=xE#T4}zR17PKt4JWpuyA_R*HUXXxnzi}3Pady3|o}` znUl(Q)aNFY&s1Va;k<$iZcY~&GQB|8tClUbn(bHH$|aP}RH9VUn2JldOx60t95KK! z-#S2As?iT1AJ49W+Or#i!Uy7Ml}2bRtE19vaV4HY*r z#W2{^HT#Vz_ZhNu#BvN@H*P6{gs~HB`;n$Mq^LJ|o?+#`=+9Ib!UeO=84^Wd@RGA% zgJ6{Oy!{!F&i7~Bsfnes2BER4Of(`@R(RnYPopjsD0 z!gCDA;>2w7xP};pk4W5+=EnnuXjwE2&2}VJwb?UVPerYEAa~!`8Wj^On~tpUP2qBt z>`=j+`^e}fOWd-zP0Lnrk71&ZbQsjKmnQPtE)+KVmK$Gb(RfN~pa zzw@rd6+EU~k8cv0K8Av))Q3)|IRzV3RUcnM_7#drdY36`juhT~oHPs5Jb`KY-Xd!o zA?lexGCTVn>^BtpMGrCbh1LczLtnS2f^8td3b;-7sPB(7GGx(7WHC!<18y@5P`5Zc>hbdZdt3HM>c@p7e4}>ssUYvO>c;h0Lym1-#Y0T1pjzY*Q c#Is7{1Im4z#)pwXJi;p0B2hfSItr2KKVx0ODgXcg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LazyLoggers$LoggerAccessor.class b/tests/test_data/std/jdk/internal/logger/LazyLoggers$LoggerAccessor.class new file mode 100644 index 0000000000000000000000000000000000000000..03058b70df8798da12275ca918e2e97010f32dbe GIT binary patch literal 567 zcma)3K~4fe5Ud8>0R%)vQ84jBhtiz2Or?0jLj~I z-~}&JlkS@8s-Ca!k52$SoC@R!-SOx}hOyHoR*{U7Akaqk)%(1kUTr(WYv0$_CPrY3 zP#ddPB_kCF^5JQ$eMhJS+GWgvnrK4({G$KM8aflk!4*Ng88w~i5uvqCm|LeO%UR4T zOe5u<6Eh)PGSSXrIdfs=kCo)(vYm}=-jZWQXB)B;%J*@sO)pZ`YD=j8UB&^Su@ZANg}~w3riN*g;AI*D$Ar%Rf(bO)>;^6? zXKU~PLY}`E$n$4ygA0rTg%pb@EjrlYGlw!NDOOQqY;v7bV$UmJA9WmgMKo}NmRI}% D9Wk7) literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LazyLoggers.class b/tests/test_data/std/jdk/internal/logger/LazyLoggers.class new file mode 100644 index 0000000000000000000000000000000000000000..e7874df4a1196d7f6891560577f30ef143346a79 GIT binary patch literal 4666 zcmbVQ`&Zo75&o{(Aa*Srw5Q*dv|25!1F3)TUFpu9`DW&u zxg-Am-y44c(1*1YcA-W=Ld9*U6=eSQ*(OG6R7PqEW_sE5I}{!+YtAmYo?hq(#0CtD0zE10MU#SN6}RJ#3b28+K+}xwW%XRqF}$S_&C+O1 z;I7UiamAI}RN9I*1^ZOoiTxCQPY42gXdw$_Ckje8hHr)UYZm(I8$ zn#`DEEE=Xhqvy}&Jj1q#>mb?{98%GN`vmUxaYf>1b2;60`)tc|Y}1rps(HJtL*P_r z;B$1MycrsZ2PH^$kAnLJdaI_)PgjtKVOwK1Ixg#l1>4b_FqOfcf+GSas%j`Fy`xNk zzz^GzwCPfD6vqUT(^}569YZHO9vI%au7T1q#;y|?N$C#=JQD`OCw10y3~Q$6|56&` z(1@KcnmX0UYAJe#nVBwHe%dnUY}?c|D_dMxFb#56*31ckW81kgl%Fq0C53LBlK3AG zxIp~xT|-sE8A9`Yp0JHPVWb%052^UDBzcqO( zIF~9ax2FjLXC(I@5*TKV$$_Y3<<7@dOvs()h#dotT?ooPg-0=|;EIZ?_=LcrYM59Vp6fZ=uTlKxb)^#m?+Szz)YzDM7P?eHen2e9fM8R7C5<`p|a7a&81-BQ_=@^ z|MoCcx3qF(f_0rWW-QGsI=aAPRhw6Ysy9|2w~TyTCVuVpoaqr5dmn8pa;d`X7L|!U zJ5T6)h7C&}Ef%J9=dw0s@=epQozu(-%`xP2_%h+m8YI=h?Qjt5E|-bhA9rWdkRXtd zV+zY6>uI_95pBUYqTm^UeP!ZhE02*31#LdYae>^9C|xx-n=h6)+=@^UtfdwFu*9GR zHy`J@f`56*pp|#S7C?#^uDsrPNeXoA1O^q(+NM9go!Tza)h;TAw4x0Nh${jIOsz1L z*E*`SnhxISb-g(=oJvz!yXfTf0nSdG2+LLC9+%z;>>kx!Z$y`5aTR<=pnK<)_6VER zg6=5zuE6nakNMrDG|v!A)bB=gZ`RJcjd(@i_R`=No3VTL)S{&k`?a5U;of5MzC}-5L7VUYRqqdAA5op0swZw=N;!p3y2^k&= z06(l*c~f^eg4^@Oh4@6VwINg-yu7qfnvHxfcfJ{zjGNkeHhx`(yM3BzW(`kgC98v$ zr8|A5=DKoxRO2I#g5L-nuA0Z#%@9ntycMd>x3X-aTd|z%=JLy^myy{+@u7~DQo8x} zmc>Jku~h_{C7lXZ1@7CD&uXbr@Mh`zU~9a?Ec(V}9(ld)<~JXZK${$r_-jahs&Tzj zUSJ&8T>jn#kIx*(qvs;(_?BOZe6vW22l*tps_8X|4JeaqNdDD7`Dy+yzbkcCR3HF?|#1b(V40O(fUR@;VxB-~h0Wd*4Ru#q{5Bcp0~) zucud$N?+%p8c1X9gvPdkgt*G@Qw^$^LW{_uUFhf%)5wTfA4CfcsW^ns;IlNEpmU$| z9sfLaG$ZjJv?yp*@bnOu;@X4Anrd=X!w3^m|6JWs9i*O&1Xo@!vczKXB;7CB>u7N4cX8cNBC zj2yiQbsZl}cfEy=Tu*o1z-hXi_%l8_S+jz3*>w!OjlptAnxswf3PZBYkX*xF@v4vI z-auo7B^_c(;IJQ-U68@3gLoHv842u@Uj!kZM~PHss<~?&7nhMtbNv{xtmAUoaDy}; zR-lMg)QdNxxXTEa0?-^9m8NPS>S={DXK2MDa_M#3IvzQFU>Wr?!s)Ixd~&m?z{hv! z<3H%*KhY%q74xwzGFOUsf`2x60WZ=AX_!2Imq!{?ve|~VPt&sWklYI+&4(bVlJ*d< z#r#P|29lvab@)b99_M{0fQ}73G1)Y=hWskdZD59FVyt3r1J>jU=GL&Viu4<_B7Exj z(L;s|E|9@RhT@w(f^Xs5TpOsp8!z$W_GONKGx#3gNlyQmw!V*LTnm5w06)a*+#4sY zTKPAVUnP=E@2~M&2D+2w|2q=T;`)1*xNHZ1;5taTKh`FxHTd@u-(TnXm$|-CTZa|= J32$NF{{UX3Bk%wK literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LazyLoggers.java b/tests/test_data/std/jdk/internal/logger/LazyLoggers.java new file mode 100644 index 00000000..2c624962 --- /dev/null +++ b/tests/test_data/std/jdk/internal/logger/LazyLoggers.java @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.logger; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.function.BiFunction; +import java.lang.System.LoggerFinder; +import java.lang.System.Logger; +import java.lang.ref.WeakReference; +import java.util.Objects; +import java.util.function.BooleanSupplier; + +import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder; +import jdk.internal.misc.VM; +import sun.util.logging.PlatformLogger; + +/** + * This class is a factory for Lazy Loggers; only system loggers can be + * Lazy Loggers. + */ +public final class LazyLoggers { + + static final RuntimePermission LOGGERFINDER_PERMISSION = + new RuntimePermission("loggerFinder"); + + private LazyLoggers() { + throw new InternalError(); + } + + /** + * This class is used to hold the factories that a Lazy Logger will use + * to create (or map) its wrapped logger. + * @param {@link Logger} or a subclass of {@link Logger}. + */ + private static final class LazyLoggerFactories { + + /** + * A factory method to create an SPI logger. + * Usually, this will be something like LazyLoggers::getSystemLogger. + */ + final BiFunction loggerSupplier; + + + public LazyLoggerFactories(BiFunction loggerSupplier) { + this(Objects.requireNonNull(loggerSupplier), + (Void)null); + } + + private LazyLoggerFactories(BiFunction loggerSupplier, + Void unused) { + this.loggerSupplier = loggerSupplier; + } + + } + + static interface LoggerAccessor { + /** + * The logger name. + * @return The name of the logger that is / will be lazily created. + */ + public String getLoggerName(); + + /** + * Returns the wrapped logger object. + * @return the wrapped logger object. + */ + public Logger wrapped(); + + /** + * A PlatformLogger.Bridge view of the wrapped logger object. + * @return A PlatformLogger.Bridge view of the wrapped logger object. + */ + public PlatformLogger.Bridge platform(); + } + + /** + * The LazyLoggerAccessor class holds all the logic that delays the creation + * of the SPI logger until such a time that the VM is booted and the logger + * is actually used for logging. + * + * This class uses the services of the BootstrapLogger class to instantiate + * temporary loggers if appropriate. + */ + static final class LazyLoggerAccessor implements LoggerAccessor { + + // The factories that will be used to create the logger lazyly + final LazyLoggerFactories factories; + + // We need to pass the actual caller module when creating the logger. + private final WeakReference moduleRef; + + // whether this is the loading thread, can be null + private final BooleanSupplier isLoadingThread; + + // The name of the logger that will be created lazyly + final String name; + // The plain logger SPI object - null until it is accessed for the + // first time. + private volatile Logger w; + // A PlatformLogger.Bridge view of w. + private volatile PlatformLogger.Bridge p; + + + private LazyLoggerAccessor(String name, + LazyLoggerFactories factories, + Module module) { + this(name, factories, module, null); + } + + private LazyLoggerAccessor(String name, + LazyLoggerFactories factories, + Module module, BooleanSupplier isLoading) { + + this(Objects.requireNonNull(name), Objects.requireNonNull(factories), + Objects.requireNonNull(module), isLoading, null); + } + + private LazyLoggerAccessor(String name, + LazyLoggerFactories factories, + Module module, BooleanSupplier isLoading, Void unused) { + this.name = name; + this.factories = factories; + this.moduleRef = new WeakReference<>(module); + this.isLoadingThread = isLoading; + } + + /** + * The logger name. + * @return The name of the logger that is / will be lazily created. + */ + @Override + public String getLoggerName() { + return name; + } + + // must be called in synchronized block + // set wrapped logger if not set + private void setWrappedIfNotSet(Logger wrapped) { + if (w == null) { + w = wrapped; + } + } + + /** + * Returns the logger SPI object, creating it if 'w' is still null. + * @return the logger SPI object. + */ + public Logger wrapped() { + Logger wrapped = w; + if (wrapped != null) return wrapped; + // Wrapped logger not created yet: create it. + // BootstrapLogger has the logic to decide whether to invoke the + // SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger) + // logger. + wrapped = BootstrapLogger.getLogger(this, isLoadingThread); + synchronized(this) { + // if w has already been in between, simply drop 'wrapped'. + setWrappedIfNotSet(wrapped); + return w; + } + } + + /** + * A PlatformLogger.Bridge view of the wrapped logger. + * @return A PlatformLogger.Bridge view of the wrapped logger. + */ + public PlatformLogger.Bridge platform() { + // We can afford to return the platform view of the previous + // logger - if that view is not null. + // Because that view will either be the BootstrapLogger, which + // will redirect to the new wrapper properly, or the temporary + // logger - which in effect is equivalent to logging something + // just before the application initialized LogManager. + PlatformLogger.Bridge platform = p; + if (platform != null) return platform; + synchronized (this) { + if (w != null) { + if (p == null) p = PlatformLogger.Bridge.convert(w); + return p; + } + } + // If we reach here it means that the wrapped logger may not + // have been created yet: attempt to create it. + // BootstrapLogger has the logic to decide whether to invoke the + // SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger) + // logger. + final Logger wrapped = BootstrapLogger.getLogger(this, isLoadingThread); + synchronized(this) { + // if w has already been set, simply drop 'wrapped'. + setWrappedIfNotSet(wrapped); + if (p == null) p = PlatformLogger.Bridge.convert(w); + return p; + } + } + + /** + * Makes this accessor release a temporary logger. + * This method is called + * by BootstrapLogger when JUL is the default backend and LogManager + * is initialized, in order to replace temporary SimpleConsoleLoggers by + * real JUL loggers. See BootstrapLogger for more details. + * If {@code replace} is {@code true}, then this method will force + * the accessor to eagerly recreate its wrapped logger. + * Note: passing {@code replace=false} is no guarantee that the + * method will not actually replace the released logger. + * @param temporary The temporary logger too be released. + * @param replace Whether the released logger should be eagerly + * replaced. + */ + void release(SimpleConsoleLogger temporary, boolean replace) { + PlatformLogger.ConfigurableBridge.LoggerConfiguration conf = + PlatformLogger.ConfigurableBridge.getLoggerConfiguration(temporary); + PlatformLogger.Level level = conf != null + ? conf.getPlatformLevel() + : null; + synchronized (this) { + if (this.w == temporary) { + this.w = null; this.p = null; + } + } + PlatformLogger.Bridge platform = replace || level != null + ? this.platform() : null; + + if (level != null) { + conf = (platform != null && platform != temporary) + ? PlatformLogger.ConfigurableBridge.getLoggerConfiguration(platform) + : null; + if (conf != null) conf.setPlatformLevel(level); + } + } + + /** + * Replace 'w' by the real SPI logger and flush the log messages pending + * in the temporary 'bootstrap' Logger. Called by BootstrapLogger when + * this accessor's bootstrap logger is accessed and BootstrapLogger + * notices that the VM is no longer booting. + * @param bootstrap This accessor's bootstrap logger (usually this is 'w'). + */ + Logger getConcreteLogger(BootstrapLogger bootstrap) { + assert VM.isBooted(); + synchronized(this) { + // another thread may have already invoked flush() + if (this.w == bootstrap) { + this.w = null; this.p = null; + } + } + return this.wrapped(); + } + + PlatformLogger.Bridge getConcretePlatformLogger(BootstrapLogger bootstrap) { + assert VM.isBooted(); + synchronized(this) { + // another thread may have already invoked flush() + if (this.w == bootstrap) { + this.w = null; this.p = null; + } + } + return this.platform(); + } + + // Creates the wrapped logger by invoking the SPI. + Logger createLogger() { + final Module module = moduleRef.get(); + if (module == null) { + throw new IllegalStateException("The module for which this logger" + + " was created has been garbage collected"); + } + return this.factories.loggerSupplier.apply(name, module); + } + + /** + * Creates a new lazy logger accessor for the named logger. The given + * factories will be use when it becomes necessary to actually create + * the logger. + * @param name The logger name. + * @param factories The factories that should be used to create the + * wrapped logger. + * @param module The module for which the logger is being created + * @return A new LazyLoggerAccessor. + */ + public static LazyLoggerAccessor makeAccessor(String name, + LazyLoggerFactories factories, Module module) { + return new LazyLoggerAccessor(name, factories, module); + } + + } + + /** + * An implementation of {@link Logger} that redirects all calls to a wrapped + * instance of {@code Logger}. + */ + private static class LazyLoggerWrapper + extends AbstractLoggerWrapper { + + final LoggerAccessor loggerAccessor; + + public LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier) { + this(Objects.requireNonNull(loggerSinkSupplier), (Void)null); + } + + private LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier, + Void unused) { + this.loggerAccessor = loggerSinkSupplier; + } + + @Override + final Logger wrapped() { + return loggerAccessor.wrapped(); + } + + @Override + PlatformLogger.Bridge platformProxy() { + return loggerAccessor.platform(); + } + + } + + // Do not expose this outside of this package. + private static volatile LoggerFinder provider; + @SuppressWarnings("removal") + private static LoggerFinder accessLoggerFinder() { + LoggerFinder prov = provider; + if (prov == null) { + // no need to lock: it doesn't matter if we call + // getLoggerFinder() twice - since LoggerFinder already caches + // the result. + // This is just an optimization to avoid the cost of calling + // doPrivileged every time. + final SecurityManager sm = System.getSecurityManager(); + prov = sm == null ? LoggerFinder.getLoggerFinder() : + AccessController.doPrivileged( + (PrivilegedAction)LoggerFinder::getLoggerFinder); + if (prov instanceof TemporaryLoggerFinder) return prov; + provider = prov; + } + return prov; + } + + // Avoid using lambda here as lazy loggers could be created early + // in the bootstrap sequence... + private static final BiFunction loggerSupplier = + new BiFunction<>() { + @Override + public Logger apply(String name, Module module) { + return LazyLoggers.getLoggerFromFinder(name, module); + } + }; + + private static final LazyLoggerFactories factories = + new LazyLoggerFactories<>(loggerSupplier); + + + // A concrete implementation of Logger that delegates to a System.Logger, + // but only creates the System.Logger instance lazily when it's used for + // the first time. + // The JdkLazyLogger uses a LazyLoggerAccessor objects, which relies + // on the logic embedded in BootstrapLogger to avoid loading the concrete + // logger provider until the VM has finished booting. + // + private static final class JdkLazyLogger extends LazyLoggerWrapper { + JdkLazyLogger(String name, Module module) { + this(LazyLoggerAccessor.makeAccessor(name, factories, module), + (Void)null); + } + private JdkLazyLogger(LazyLoggerAccessor holder, Void unused) { + super(holder); + } + } + + static Logger makeLazyLogger(String name, Module module, BooleanSupplier isLoading) { + final LazyLoggerAccessor holder = new LazyLoggerAccessor(name, factories, module, isLoading); + return new JdkLazyLogger(holder, null); + } + + /** + * Gets a logger from the LoggerFinder. Creates the actual concrete + * logger. + * @param name name of the logger + * @param module module on behalf of which the logger is created + * @return The logger returned by the LoggerFinder. + */ + @SuppressWarnings("removal") + static Logger getLoggerFromFinder(String name, Module module) { + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + return accessLoggerFinder().getLogger(name, module); + } else { + return AccessController.doPrivileged((PrivilegedAction) + () -> {return accessLoggerFinder().getLogger(name, module);}, + null, LOGGERFINDER_PERMISSION); + } + } + + /** + * Returns a (possibly lazy) Logger for the caller. + * + * @param name the logger name + * @param module The module on behalf of which the logger is created. + * If the module is not loaded from the Boot ClassLoader, + * the LoggerFinder is accessed and the logger returned + * by {@link LoggerFinder#getLogger(java.lang.String, java.lang.Module)} + * is returned to the caller directly. + * Otherwise, the logger returned by + * {@link #getLazyLogger(java.lang.String, java.lang.Module)} + * is returned to the caller. + * + * @return a (possibly lazy) Logger instance. + */ + public static final Logger getLogger(String name, Module module) { + if (DefaultLoggerFinder.isSystem(module)) { + return getLazyLogger(name, module); + } else { + return getLoggerFromFinder(name, module); + } + } + + /** + * Returns a (possibly lazy) Logger suitable for system classes. + * Whether the returned logger is lazy or not depend on the result + * returned by {@link BootstrapLogger#useLazyLoggers()}. + * + * @param name the logger name + * @param module the module on behalf of which the logger is created. + * @return a (possibly lazy) Logger instance. + */ + public static final Logger getLazyLogger(String name, Module module) { + + // BootstrapLogger has the logic to determine whether a LazyLogger + // should be used. Usually, it is worth it only if: + // - the VM is not yet booted + // - or, the backend is JUL and there is no configuration + // - or, the backend is a custom backend, as we don't know what + // that is going to load... + // So if for instance the VM is booted and we use JUL with a custom + // configuration, we're not going to delay the creation of loggers... + final boolean useLazyLogger = BootstrapLogger.useLazyLoggers(); + if (useLazyLogger) { + return new JdkLazyLogger(name, module); + } else { + // Directly invoke the LoggerFinder. + return getLoggerFromFinder(name, module); + } + } + +} diff --git a/tests/test_data/std/jdk/internal/logger/LocalizedLoggerWrapper.class b/tests/test_data/std/jdk/internal/logger/LocalizedLoggerWrapper.class new file mode 100644 index 0000000000000000000000000000000000000000..7c3d645ce1f120ba646bb06898e2e35202dd0e6f GIT binary patch literal 5445 zcmc&%TXR!Y6#jOTG`3A?8g7<*5u{05B8mv4luH!^0|inFf=W-DLwnlfBy*C$z~~FU z=mR+DgZ>B~bVhONgX6P5%5kl|caojUX;Uuabf!7yWMzHdx7OO<-shix|NINU6pFp* zLLiJ_1R-<_3@>L_l8#%pJ=e-5bA`o4+e@b9$4$>F7HvpPO~FvBAP-~C_A46bGmxO(p~ zx1$0p8{^hlMb^MQ#<(8{IIjb@Z6^ed`3}??))Su<2u>BUG>`*n$F;9i^7FPgqee8A zE|7K3TAsuA`eCrV}~3S9K< zVkhg`oPXLw%k1W^z*YmP9wKmI<6u6+*UkQ8l?k(Gc~+hVBv6=NZq%r)T%eESSKU}( zx6z7LvlgHU;r+k8nNJwXbSrp5GMx$AKu&J((kstuu&?)pp#m%RLt2^S@I`^Sjk!oC zo^Qr5-k}b66>6S3AWh}05_LJE?k?Nqr2-ueDzBHRZ@EgZ7uRR#ue}n~#>P*)cuwx) z^o#%8N96g5^vRP(;Ts$+HR)sDd=SxR`KoL8X5`8Gyu+uTopL{DIh7ygrA||I(RFQ4 zj+k8vgS;}@e3&GsQOBJy$Yypof305;lxLDP%OiLgd4Yo+9iPG|kddzwieWlpbkQpg z`5eE1(A6Mahj5&po}jxtzxU8*Ut;tRh{V|M2>(jA0i2}&o8(u=Df|R_=}C&7?Ni~H zz$v<;AM)v&Qt}l8bYYUNw@J`GiaO0fGU^OPou%t8oFfub_>k_I!dd#{--i;vA^Zzn zDDZCi@RS6Nr~nPh0QDyfFi3wNQ4FVBAiAt*ATi1b$Hd?0e~y8=Dt^@iE|R)ShN6L* zq5+)81qnESk10+mQh*#)1-zsImkBUP86z5S{5du^qfJuxYM%dt+-s^JsNk8m~nw4RNif)W2@K^K(pT4 zgnP%RF7sFOV(Pt$YYo+{s${fb`i9%N+>Exj740se&8>@e9T|&CP&leiWft7< zm@fPS8nh7oen3+h3a;W{sD+F}JzSP#j;in)8FRALTBT&*?#l%uyB{>B&YbqGYmj)m zm4r(q3L7ACvqpkPzdZ?hL)9dBY`BtrvJ$H})P3{r~^~ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LocalizedLoggerWrapper.java b/tests/test_data/std/jdk/internal/logger/LocalizedLoggerWrapper.java new file mode 100644 index 00000000..361ebc30 --- /dev/null +++ b/tests/test_data/std/jdk/internal/logger/LocalizedLoggerWrapper.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package jdk.internal.logger; + +import java.util.ResourceBundle; +import java.util.function.Supplier; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; + +/** + * This implementation of {@link Logger} redirects all logging method + * calls to calls to {@code log(Level, String, ResourceBundle, ...)} + * methods, passing the Logger's ResourceBundle as parameter. + * So for instance a call to {@link Logger#log(Level, String) + * log(Level.INFO, msg)} will be redirected + * to a call to {@link #log(java.lang.System.Logger.Level, + * java.util.ResourceBundle, java.lang.String, java.lang.Object...) + * this.log(Level.INFO, this.bundle, msg, (Object[]) null)}. + *

+ * Note that methods that take a {@link Supplier Supplier<String>} + * or an Object are not redirected. It is assumed that a string returned + * by a {@code Supplier} is already localized, or cannot be localized. + * + * @param Type of the wrapped Logger: {@code Logger} or an + * extension of the {@code Logger} interface. + */ +public class LocalizedLoggerWrapper extends LoggerWrapper { + + private final ResourceBundle bundle; + + public LocalizedLoggerWrapper(L wrapped, ResourceBundle bundle) { + super(wrapped); + this.bundle = bundle; + } + + public final ResourceBundle getBundle() { + return bundle; + } + + // We assume that messages returned by Supplier and Object are + // either already localized or not localizable. To be evaluated. + + // ----------------------------------------------------------------- + // Generic methods taking a Level as parameter + // ----------------------------------------------------------------- + + @Override + public final void log(Level level, String msg) { + log(level, bundle, msg, (Object[]) null); + } + + @Override + public final void log(Level level, + String msg, Throwable thrown) { + log(level, bundle, msg, thrown); + } + + @Override + public final void log(Level level, + String format, Object... params) { + log(level, bundle, format, params); + } + + @Override + public final void log(Level level, Object obj) { + wrapped.log(level, obj); + } + + @Override + public final void log(Level level, Supplier msgSupplier) { + wrapped.log(level, msgSupplier); + } + + @Override + public final void log(Level level, Supplier msgSupplier, Throwable thrown) { + wrapped.log(level, msgSupplier, thrown); + } + + @Override + public final void log(Level level, ResourceBundle bundle, String format, Object... params) { + wrapped.log(level, bundle, format, params); + } + + @Override + public final void log(Level level, ResourceBundle bundle, String key, Throwable thrown) { + wrapped.log(level, bundle, key, thrown); + } + + @Override + public final boolean isLoggable(Level level) { + return wrapped.isLoggable(level); + } + + // Override methods from PlatformLogger.Bridge that don't take a + // resource bundle... + + @Override + public final void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, + String key) { + logrb(level, sourceClass, sourceMethod, bundle, key, (Object[]) null); + } + + @Override + public final void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, + String key, Throwable thrown) { + logrb(level, sourceClass, sourceMethod, bundle, key, thrown); + } + + @Override + public final void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, + String key, Object... params) { + logrb(level, sourceClass, sourceMethod, bundle, key, params); + } + + @Override + public final void log(sun.util.logging.PlatformLogger.Level level, String msg, Throwable thrown) { + logrb(level, bundle, msg, thrown); + } + + @Override + public final void log(sun.util.logging.PlatformLogger.Level level, String msg) { + logrb(level, bundle, msg, (Object[]) null); + } + + @Override + public final void log(sun.util.logging.PlatformLogger.Level level, String format, Object... params) { + logrb(level, bundle, format, params); + } + + +} diff --git a/tests/test_data/std/jdk/internal/logger/LoggerFinderLoader$ErrorPolicy.class b/tests/test_data/std/jdk/internal/logger/LoggerFinderLoader$ErrorPolicy.class new file mode 100644 index 0000000000000000000000000000000000000000..21ec17c8739034439537c8cf404e2ebe9fdff3d9 GIT binary patch literal 1428 zcmbVLZBNrs6n^g3ty?KF$D2%0M8pl00rH}D;sA#%nFCjtS^QMCI*O%Dx{kze{v;iV z5RHb<{wU+Q*BM99L}=3c^qhOnb6$GR_aC3X0a!y;Mu1^%zxFn5Ilk#RhMl(EdfoKW z1p(`pQ!~ASYtT8K^E}tva&4>nE(!)oMF?SrP_9(kEHTU%F3zKIqKJwpCz4;Sl#2P{ zbFS-Bp$hV6xz!z^xuT*+XkPB*bKBhJs){&z$#1;8QrOAq3=6L>lY@eO49MtJF^Fqa zPt|rElc6t}D(oAFM%p%mwYf&{M17*;WY8w^+e804Jh0p)UN*iCcu4ds&T z@LscxMnmgR=)Pw;b*(c3ClLIjDsEwnA)K)s%U@;~=%i|U=2PVeLJGBEG=gXZY6Lx8 zN~xH{6mN>iq`|P1OkJuil)!HaY0a%sM|ujDV-}kSyQa5o?AoN+_)BI~(}m|rV~7{r zs$rK6&*Ic=e#tQoC`|l(=NMuyOn=XkWgNcO26b zb7N9TT^-ApouU7npal+PhxiHtgtS2dX=?=1t^lzF-w_?DBK-kX{at|fWCQmSQ3dZdNXY6N4qyDnOEapghKyQfL-g8qL zXaoh>EMbtY5IKAPZq4Bm_kW ocf&&HK0)#bF<#8s08%^Khj>JH0X&8#FoR`6zOW1#Jk2J40>axv@c;k- literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LoggerFinderLoader$TemporaryLoggerFinder$1.class b/tests/test_data/std/jdk/internal/logger/LoggerFinderLoader$TemporaryLoggerFinder$1.class new file mode 100644 index 0000000000000000000000000000000000000000..6747d5922e0200e93a7a495906acf9458cd02e67 GIT binary patch literal 738 zcmbtS%}(4f5dORbvR%SYmw(y|=U(Fog+xUMW1z9w&@x62Ua!W|R?It-0d zQ`%G=X9}#3EB@LL(5X5k9LHt_jHR%GmmWj0lTZ*O_JUXTw{i0^b&ws%#p<~Um-qu yn=Bs}+#|dtUBhec%}{PI$PKViMJ-~?^Krx7!$YyV_i>2(=;|!Em^=BbH(sS#+7` zwy;NMKk;eV8O$KgpwahO*o$6w=jS&2=TTM_?;%vfFWDwOQN)?VQ_}pS%!)b6x%fOezoC>re z!)?d5w2lgu!a)m%aG0Sd&jaGG*#sA5z;C#M$g*oDjxzMM3O@DGYep$wWpD(E4AncY z>vcTp{xwbhOAA97W=PjW7QQgE? z33=EEOnl8Sv26?5uJBHGFh7=ot%;_P&_(;!!gu(dAvIU7EKHTBXDEK@a}pF8`hRYC zp{$EV8AvMrl;`<`Ublnc*w)}Hb(?RRZ6Znj6v3GGt27>6CFzNBqkcoE1#Mx-m3)W0 zi(E;)Zz_%Orlin@$LoZ72BU1sQRrHpSaIkiV(=-u|cFj1nM z|2^D%t%y?`17p<24tnVf`qCo>hSRi5k~~9lKu>=psn0-npB@t0C&-(gL-IOHJDVgU z*;#l6_KX%C_<_FK4E%~BeRW`Rz_<=WYZ?mr>cj6TSc0TecnUr>i*d0J&JZYXe8FzQW+!NV#Vn$L?dRu17l-{%UDQM%QuTDWyq7&<2S$@DL_` zr=k6WIQ~h@9^n-J#w9$)bv%h+(^P9{P1t&M4iga-2a`BYM5oA}gmGwZPcOy1uvwEU zWYfRnx$H|69>6pn!APv(zy@r>KDLJ322!;8W(}uWHOoc`@1h&`sQAA{;XBb`ou?;- m{*82LFJdN=SD-bA}$sEPg~kej*O@$u#vP`h5U0xxYXF literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/LoggerFinderLoader.class b/tests/test_data/std/jdk/internal/logger/LoggerFinderLoader.class new file mode 100644 index 0000000000000000000000000000000000000000..fb3f8ef3eaa7fc5c6c37ca9a72bd9b711ae6e6c4 GIT binary patch literal 7519 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 s7E4`)s32z5Ebk3`E?ZM3mUH~H0^ZJu>", + SecurityConstants.FILE_READ_ACTION); + public static final RuntimePermission LOGGERFINDER_PERMISSION = + new RuntimePermission("loggerFinder"); + + // This is used to control how the LoggerFinderLoader handles + // errors when instantiating the LoggerFinder provider. + // ERROR => throws ServiceConfigurationError + // WARNING => Do not fail, use plain default (simple logger) implementation, + // prints warning on console. (this is the default) + // DEBUG => Do not fail, use plain default (simple logger) implementation, + // prints warning and exception stack trace on console. + // QUIET => Do not fail and stay silent. + private static enum ErrorPolicy { ERROR, WARNING, DEBUG, QUIET }; + + // This class is static and cannot be instantiated. + private LoggerFinderLoader() { + throw new InternalError("LoggerFinderLoader cannot be instantiated"); + } + + // record the loadingThread while loading the backend + static volatile Thread loadingThread; + // Return the loaded LoggerFinder, or load it if not already loaded. + private static System.LoggerFinder service() { + if (service != null) return service; + // ensure backend is detected before attempting to load the finder + BootstrapLogger.ensureBackendDetected(); + synchronized(lock) { + if (service != null) return service; + Thread currentThread = Thread.currentThread(); + if (loadingThread == currentThread) { + // recursive attempt to load the backend while loading the backend + // use a temporary logger finder that returns special BootstrapLogger + // which will wait until loading is finished + return TemporaryLoggerFinder.INSTANCE; + } + loadingThread = currentThread; + try { + service = loadLoggerFinder(); + } finally { + loadingThread = null; + } + } + // Since the LoggerFinder is already loaded - we can stop using + // temporary loggers. + BootstrapLogger.redirectTemporaryLoggers(); + return service; + } + + // returns true if called by the thread that loads the LoggerFinder, while + // loading the LoggerFinder. + static boolean isLoadingThread() { + return loadingThread != null && loadingThread == Thread.currentThread(); + } + + // Get configuration error policy + private static ErrorPolicy configurationErrorPolicy() { + String errorPolicy = + GetPropertyAction.privilegedGetProperty("jdk.logger.finder.error"); + if (errorPolicy == null || errorPolicy.isEmpty()) { + return ErrorPolicy.WARNING; + } + try { + return ErrorPolicy.valueOf(errorPolicy.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException x) { + return ErrorPolicy.WARNING; + } + } + + // Whether multiple provider should be considered as an error. + // This is further submitted to the configuration error policy. + private static boolean ensureSingletonProvider() { + return GetBooleanAction.privilegedGetProperty + ("jdk.logger.finder.singleton"); + } + + @SuppressWarnings("removal") + private static Iterator findLoggerFinderProviders() { + final Iterator iterator; + if (System.getSecurityManager() == null) { + iterator = ServiceLoader.load(System.LoggerFinder.class, + ClassLoader.getSystemClassLoader()).iterator(); + } else { + final PrivilegedAction> pa = + () -> ServiceLoader.load(System.LoggerFinder.class, + ClassLoader.getSystemClassLoader()).iterator(); + iterator = AccessController.doPrivileged(pa, null, + LOGGERFINDER_PERMISSION, CLASSLOADER_PERMISSION, + READ_PERMISSION); + } + return iterator; + } + + public static final class TemporaryLoggerFinder extends LoggerFinder { + private TemporaryLoggerFinder() {} + @Stable + private LoggerFinder loadedService; + + private static final BooleanSupplier isLoadingThread = new BooleanSupplier() { + @Override + public boolean getAsBoolean() { + return LoggerFinderLoader.isLoadingThread(); + } + }; + private static final TemporaryLoggerFinder INSTANCE = new TemporaryLoggerFinder(); + + @Override + public Logger getLogger(String name, Module module) { + if (loadedService == null) { + loadedService = service; + if (loadedService == null) { + return LazyLoggers.makeLazyLogger(name, module, isLoadingThread); + } + } + assert loadedService != null; + assert !LoggerFinderLoader.isLoadingThread(); + assert loadedService != this; + return LazyLoggers.getLogger(name, module); + } + } + + // Loads the LoggerFinder using ServiceLoader. If no LoggerFinder + // is found returns the default (possibly JUL based) implementation + private static System.LoggerFinder loadLoggerFinder() { + System.LoggerFinder result; + try { + // Iterator iterates with the access control context stored + // at ServiceLoader creation time. + final Iterator iterator = + findLoggerFinderProviders(); + if (iterator.hasNext()) { + result = iterator.next(); + if (iterator.hasNext() && ensureSingletonProvider()) { + throw new ServiceConfigurationError( + "More than one LoggerFinder implementation"); + } + } else { + result = loadDefaultImplementation(); + } + } catch (Error | RuntimeException x) { + // next caller will get the plain default impl (not linked + // to java.util.logging) + service = result = new DefaultLoggerFinder(); + ErrorPolicy errorPolicy = configurationErrorPolicy(); + if (errorPolicy == ErrorPolicy.ERROR) { + // rethrow any exception as a ServiceConfigurationError. + if (x instanceof Error) { + throw x; + } else { + throw new ServiceConfigurationError( + "Failed to instantiate LoggerFinder provider; Using default.", x); + } + } else if (errorPolicy != ErrorPolicy.QUIET) { + // if QUIET just silently use the plain default impl + // otherwise, log a warning, possibly adding the exception + // stack trace (if DEBUG is specified). + SimpleConsoleLogger logger = + new SimpleConsoleLogger("jdk.internal.logger", false); + logger.log(System.Logger.Level.WARNING, + "Failed to instantiate LoggerFinder provider; Using default."); + if (errorPolicy == ErrorPolicy.DEBUG) { + logger.log(System.Logger.Level.WARNING, + "Exception raised trying to instantiate LoggerFinder", x); + } + } + } + return result; + } + + @SuppressWarnings("removal") + private static System.LoggerFinder loadDefaultImplementation() { + final SecurityManager sm = System.getSecurityManager(); + final Iterator iterator; + if (sm == null) { + iterator = ServiceLoader.loadInstalled(DefaultLoggerFinder.class).iterator(); + } else { + // We use limited do privileged here - the minimum set of + // permissions required to 'see' the META-INF/services resources + // seems to be CLASSLOADER_PERMISSION and READ_PERMISSION. + // Note that do privileged is required because + // otherwise the SecurityManager will prevent the ServiceLoader + // from seeing the installed provider. + PrivilegedAction> pa = () -> + ServiceLoader.loadInstalled(DefaultLoggerFinder.class).iterator(); + iterator = AccessController.doPrivileged(pa, null, + LOGGERFINDER_PERMISSION, CLASSLOADER_PERMISSION, + READ_PERMISSION); + } + DefaultLoggerFinder result = null; + try { + // Iterator iterates with the access control context stored + // at ServiceLoader creation time. + if (iterator.hasNext()) { + result = iterator.next(); + } + } catch (RuntimeException x) { + throw new ServiceConfigurationError( + "Failed to instantiate default LoggerFinder", x); + } + if (result == null) { + result = new DefaultLoggerFinder(); + } + return result; + } + + public static System.LoggerFinder getLoggerFinder() { + @SuppressWarnings("removal") + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(LOGGERFINDER_PERMISSION); + } + return service(); + } + +} diff --git a/tests/test_data/std/jdk/internal/logger/LoggerWrapper.class b/tests/test_data/std/jdk/internal/logger/LoggerWrapper.class new file mode 100644 index 0000000000000000000000000000000000000000..e3fe71fc4486901dd97b5381e3293edae560e64f GIT binary patch literal 7179 zcmc&&TUQfT7~Ka#M$(9&6$Qa7+FaBq)wTknfTGfXC=^?@twS<|fiQ`aM5R}Izgl~5 zZTsGrKD2Aq6;~g+>}!8i?f18_+DUYc4t;Qnj?AYjQjkH>QQm z*_U)VnN)NEcb}@M>3)Izc1?Lqy*6dc((9k{U?Vn3c$|qg3;0VB4NRxfx*SOt5Z3$r zQ;no^ix*qbCLrB3q(lYUY&`h_By1z6r81i7ShhqZ&yC0B^h`ouFd4cAbu}7O7`xMp z?bso(K52~@*AurE1$^PkFnZa(U0&?Q9)Z@FV%ad1&}P(FMwioSLK7JA`B%hSo-!R* zOnp}PmOn6-!ME3oeRx8kfy~pV1=N+*hLsyi+zOA8au=0UBBMu?!HgD-EB3%mq;+yx z?-iSm&HS{Y>1XzU!2DXU+DIp7^~6n?ykYU~XWjz>cdO$yR*q$p4Lz@?GLP717itT! zwnGAU{x5B1qt)%jlQ<&aqFhM|+^)Sq!@)U+m|ikGI+M{NoV1~dOfnf)72S&DQ>^J} zfy^3-$%}1)Jab1n#tM1_QfsTAY*hM~|9I7FsN!5M=lK)Nds5)q+S+Y8dC*Iz-YJ24 zNkp0+RxbYU;Gc+cBNLbTVJ&gKx@qTaJNgz^7His}=V?NnP%G?Dk@5+*AT}6o#VN8m`WED0PZwL;eXPAJN?77Ma?4lh| zRYsi?I8p^_-o+!%01E;qDg$s_*a^m>^ROB**0EwP3!PJ+ZtS~P663#2YiB}@X>vNF z)AFdF4EG9jl$}OrB%Rhni71WT5LPv1EVD4J=#%E++89nm8T1<;eV~ zoU~N7@}$CH46==G$7L1=aW(k-hQ|UG+@Z~TGfiq9RnoJG=(w!Q3kp>=TMb9|bxK-DOdldnR^K0k@HA>pC=Zg$RMP(aKPpsyce#PJJ72gGSt>RuuL01~dnP z4%{)P5?@B|;C{b#tueRQx4mm#B-{z3p8rdBr^>BiQABj~_U zL()zYXjxLHC5gcCCTnZ&iLAH zdGu|PuodrE)(jAkpy3UH-_iOj&oflJjm~3+O0PMzK)Vl<`9q-Xt4v!tS zqY$>g64>SeF2sxAve;P&=c^Eo>TJvCVTuVy#S;kbKhWmNqAQm+rsZ}_Pm$%^!0gGw`lmeur$+W7iq0OB|(21_8$TIF(vaHQ*x61x*Sa`^Z z_TU=PQvGYuo`swKQ7$f7o5f)#Qg4y1+_PlsW=e?u$9%$g7$ zw+M@tMXwXxDwYM+tL3QrYfMGeszr5*wq9DJSjUNy#efshx}qfEo~0yNPuqSjNhmp} zMzu(WXy4>RK_ZeYPCIc(MI79-#L-BHmdRn@kCZmztP?@iMvRswdA6n`<0U;c=EPBj zr>Lwgaa3IRg+gLK(CpiKLs1;KhvGnvr%Kq8J4jEyN4NvQES_`1a~I)p&r)0)=#Vuw z6e^G{=%VHJf|D~=vD~OSE=P5>=2WspRj}M%b|R`eQ=_FxrfW(PD@~%*lw{5#$=^6; zoj9sk4pdv0#GkJjezGLKRwH~W$1VK4^>_Whu0Prg%-iY*_>dNL9X`Ux^z5dagoICU j$K8l_e1^~I`2{_{qUYE2_N}WC-% Type of the wrapped Logger: {@code Logger} or an + * extension of that interface. + */ +public class LoggerWrapper extends AbstractLoggerWrapper { + + final L wrapped; + final PlatformLogger.Bridge platformProxy; + + public LoggerWrapper(L wrapped) { + this(Objects.requireNonNull(wrapped), (Void)null); + } + + LoggerWrapper(L wrapped, Void unused) { + this.wrapped = wrapped; + this.platformProxy = (wrapped instanceof PlatformLogger.Bridge) ? + (PlatformLogger.Bridge) wrapped : null; + } + + @Override + public final L wrapped() { + return wrapped; + } + + @Override + public final PlatformLogger.Bridge platformProxy() { + return platformProxy; + } + +} diff --git a/tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger$CallerFinder$1.class b/tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger$CallerFinder$1.class new file mode 100644 index 0000000000000000000000000000000000000000..413d797d770d99627291410418ab0eb6f1f8b347 GIT binary patch literal 1111 zcmbVL(M}UV6g|@xwk@kvEC`5*TBSv0Lt@mVgxG9KY^=q!1Ru$CJ6Wb3X36f9#J^G> z)cD{B_-5kw81J?Hp9wUc*}6F_m-=k2n%~BMh2Q;p;_Ip)Eb9w zz0ztOHmkeUX0_o~8CL5T5zARz#jJ&#jcb@=n4cKTFyjkT(~;rY6AaIa7jIgcyiCdR zn76QC;|3NPo_0GuM`|NN&6T49-xs0NlE)`XxPguWCF%pL;BuuzxGQys6mL;^!ahk} zDxR0e!ZHaTNQs2k52bnMyb0y0RKgdXiZ?7-$_+XsX0|T1X!MWUBHZU~MaWz|@VGkQ zp^WDvFlCNp#PGa+xkHy3@_(Ioc;^IXTGH3t^h3)0YOHXhfFW|OjO{VTSYMQPXysr}c&90eT<>kLmWqmv=s5RrKqM8?7f!}@=2!eH05 z7NM(n6bUNx^q;=A$L}6%)IbT))zgbg(oYYGW;bc%kY_Qn@fqv`4H8%(8!rPtaEq)x z48SUG(~QMENH!*Kk&ol7kFdVr%6l4)(|?Z9tsy;EA^O^gewOcjxa>~`Y*I0jy4Sm9qrH=_Ro}N zvxemf$Kqzzw994TWDCYz#T3J~<=UpmtG(V~ZkoawF|3ks$ct&)vxZe3u^s5E`h6c& z&oHyoRjcS3wv`Y7EL#nQH zwj%v=vmHIyq+zp;E!fJixvAe?#mR`n=LCaZ7T&PQU3XM1SNDaz6+DLsr)c8n)v*oR z8CDvu&;BXOS72jJfL|dDbowU~=tIATw2lGnWZ1i0nkm0?-1EpWL#N@67$#MUCg23^TM%Q$vjyj!SLYwU};IdW%&= z<#mGLz;Y87Zqwd92^>c>fs;6;;YA&%k!R>pvALpHbqw!%cBohsu1me{IkxO@s=|^z z<{0yaDaxWm6Cwz-rcr-6q&jUe)W)6|W!P9}vDTF}f{6HGyF^9bnKvvkTAiB`&N!bk zX(yGpi`=}x9Yd~z&6sz^pyVHTvI#-6k9v#vE*NEtdsT*GafwiPYa%&7)p)yfPVs{7CIN)Tl7jPS15r7FKnc12Yt=(Y$;i6UOlwqPhz}Oc;CyK1Dxoy1eEFqQPSx6&r0bQ%L>+pJ?h*v&B&*{g zl7h|-A%C=pmaz5TWF-oA)hP;^UX=FkCi5U8E0w4irBQIwc0CPr63Ah)oTHJZ)iK-l zh*w_m^XDdEF>G%(rydQkvjr77kFM%?4VRL*)Y%Fzfhy)TT+{Ie=wRHcI!QH{Va?mK zBAZuLLGJi8CCzq7sGUltzWOfgJy7z|o#a-@6mD;xj__(F7eZ9 z(YL(10Y4yyU-1$>>7*lf&!IrSz&PFSBFf6)z)JFSbfoWLC9r@s_p#wql8QjulKy~S zLUxjYo%2fO0==j6EWJ3r*|&k>6_4EA0rketkGKocd%n| z;}&T|mA5X65crK^{T(at2R7kPY{6g3`)1#AEs6{#@G|+;umcw{NqAo&-CbyThz;`Q z8rRUH5u=PAA4(7Ptq47`SmG!nCA#qh;4jlk64yPD+O>e}P3QxuXXxQZfV&QJg@W>c zi2WOD@j$`r@^x$Qx)msjbp-6Hi`pDArcLc3k;1|s_%Cw5$ z3Jmo-12d3y$@&~@ICztG(xef`4BkRFU3$Clc5545IA`z$V{+35g*P=<*>nT~1Gz58XcW548Q((}ffIyd&9`!Ocm}sXn~R zop-tSxzD}t)lc8LdILZgu7{x@pdzTD1f>F%C-gBrX6g1wZ1Cs_Bk2j0ZZ>Vx+bR%f zYTmCRBv3uGC^7DOM!KOdGcsa0^AN^76`F?mC>N+NTIT7=(F3|QYB&uEIqr4zv>~uy z#PGU}q@_EiJzL+)QpI~TRHH^frN*D3^v7^yFzH7xo*yG%Xy~NW)U!+-zGP#(y$s$0%6zF9nU>r z%G0WfwJ#{sd@zJ40g|UUX|v7A*`Ap;+K7G#tpcqlQlo9A?HP`(=dUoFw(XgW=X#Ew z&HG5Ys%Olwy%5@n(Of%1SSt{b5YN^%gmnUSzFZQ7H;rXRjkbQnJDy4H)a{gIgs@&< znZLv}k~zop#@jlRNyBx!GPdVrEX#1p(2jSjc#npS*d(xyD#WIgj!9e$CzdeNS=albSLXvOP83FT ztJ4|DrRj*ClSw1%nHgKfuGz8WQ*e9Ev{Hr>MjU|<`ne)*kLi|~s?R!^tl@a$^)~st zsa~!a)UXHdqyBm}YuG7)HFMGEF3bvdknM3KGz`h;2zi-2pkeI5ewiK)+yTcFEBA*n zjDso;X*i7c3pA3Su_^b*^rW;cw!`rD6!h)%B|I$am}4ffFj7Td1y;Qyojc~?2p&|S zYdDIez!D!|8C63 zZrwA6I3um>%)`8UDs|kwq$7k;0cM?Aq&3*c&^dX&32dCh&|*T*p5FQffY`nL@ zJ6bQ>RIA?&`>nM}iu(OFAtgiE`o?t)Zlm3}zQNs8-?)L}b~z8jMOp=OR6eD9#z`;M z&uG<0j691~j4{e)xI0bOFr)aShH-p=>6nSMnEC=;b6A!~d2R=F6sP=xjWSO>s^Nop zOkimu-oK}>=SbJ!Kw^-6-{6iNJ$sMz4({#m9AdI6^58T=ACihQ*7GT)Ez4JjX1O7J zSU|K&hn&{%5qwl;ldNSDgw=Cs-CXRD!r21l-95dX`}&5aHJC4Rm8aX@e%;EE7uB;D z9NDvXaLU>14vpK}+~9y)C^2?wO6_cy=aNFq5@Y6k)AV076}rwiNf3*Sn2u;#5zgweE+e3KzO98+q~Zm>44acyp(HHVQz=vCciq}E zI^wGGK@TS~IVWk5V#K0mj+eYmrV}1BKm~VZTu;R-jJAF8hi|oLEz(@DadmEiK6*7 z&Yvur_i)a1#kIAvw((DprK?Gx!w8T7CgOjn8lv z!e{Y0O1N1ZM*u;}UX7^H*H9)fiHb8Q30~l=N}#W05{oOf^H2j52(<(zv3$$YO7|QV zw?tM>qS0U45^45_+k+RDR-QPAO)U{_livatS|V#^mc?d<_s$IOn;O214L6=eYhY`g z9G%Asc6I9}(Qy_FS_Ve!`meO_rQL zLx=b|3#(tCPyCX_#;&ryT!jY_5Y%~ zLh@DPQi*yi=Mwc(k!{gQbe_fPNKbyS>>73qUqgKOGImG$CNV(qz$Erw#=aj!ui*av z)|-g5yn*r-I_LofKSXVR>lF4Nj@6j77UWks75ob{@mEB|->^pfodxZKa^o!7e=)FyU@hJnXb)Be>q=7R zu_0O&BxBo4s!A#!Ifr^qgAYnUX;o?E+UHQgZsYR^1-DF~>~xTvdUNR+lto*vz_}Q` z*dM*(MCl7vD20Up3N z@hzeeq1z^WVjkw~+xQM!qTvI}0Y~4(3k5)zLoK7%%7hU2k%?uuDOU)uiVF}bO$*`0 z>1^WhAel`XBHP3jJbVd{L>?#ac1Ld_9Jr2JA{C9Cn#2>Aut6r9JPftm5Ag~D;#J;r z74yV3REXEHQe2--KowYo@A+JiUe=)8k}A~psQ5llxk#CUm+-RRUt+Y$d?%eei7TaL QEOlSQHTLbegx68?AK6S(z5oCK literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger.class b/tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger.class new file mode 100644 index 0000000000000000000000000000000000000000..08b1546540769e0018132aa67c8b60654472ff02 GIT binary patch literal 12835 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

ZzAkgM|+0+HI(;_7Vn>Fg?@o>BTRl|I6n z{is$NHP?DdTRf#Lu2M?YM61@$r2560XZ3Sa?<1E{|7og!oa&!A5A{MNpZY3!IP0q4 z!*>Z{lLYZK)RIt%GxE7uofv;E_zVgClrNG^zDUw2o7Av9ss4JYCHV{WXMIu%^|DFL zQ}bO&Td7Yp)<_?@QDSbcHaI@daGlW-Or@;xTwkLabdhgTjjG9&wbnJSDk}E)Q9S2E zQRT|0m8UcAm92c2KWsHgxmM{mW*Ge?O5$$<+?7x9o8av|hs^K`$W0;NPx_ubjSc5; zJCFPjzuoyV?s*YEtT2TSH-D5b-m#DAV^jEqxLr4wfUje|f_m13W_$(P@T$-3UKesb zfA7((7C@ z5jyM9edqAlaMug?vF?DB{vYp@*C*xWr2?bY(eTO@v?_?p)iSl5 z?>0Rkw$yk8;VR0I22v`LX1WOAsm>_Rr!pQBb`((;{lt>#jagz zb;Is*QQb#!2t${}s31-OpgFU9~H$KOVH!rvt>z=csJ(iHwwzK%#Cn?A^>J%qNGrR!QBMV5Hb zmUz&Xs13R-QMS62pCmX-G+E3TOP_@`l*?RSJ?uhhccHYFLMgbbLJ;>8(gFU$a>xg% z-GkKbL2CCPwR@1-wci51z{-(MVsZVp!u8umJV?J??)vRR^jZxqYIVUbDg_%3PGR~u zq~1-K!~B)X^%~|@bG-+%)q~mU!EE(lwz{69MxAEC0=%W#hnwaO%eOx*5k`1q-1SzLllIO@x==2I!a%UWezk4$o^Hp4U1&uXX73 zkOb_|VGjDjEJr$vfLFR<-pnvxsk&W%zQ_f&ygcRtkAwr9Lc+nP5ef&wL2m!LtrA#*0(uP~;;tU&HPTO&iVwYlpj;gfgm}gPUvnb|S6!R>K>CK^76jQP}l-!MJ zM$~9Vu*^31vC1waEv{r$Gg*FNX84$5%s5FiPSK3_(~R5R0W*X_)6I}*Y;nza+@(>( zjmAn&g3{k=^+ueN4QCp?6CVi&g-gB+GzQ#B1McD$>u#)3_j-I!>V9UIHAHjZvVDBf`2i_vs;@txh#06U`KSFlF z%1t>jYeDo?-tf`$wfOkY&kXRM3~vW=K5E3*xa8YhWPJH?{-=kBIH`P+R-e}JqP)ksw!al-^84S8$l#&hu4j2OA}rQPo(DjM}C8`0XH3zm5sDyGH&m!s}|!wlMEn xZc=;seKEeNt_jG`^V`_RTKIF_P5OL>-~0Lf9yOo_x$YZ0zQ3kU?V>#X`97>NhVlRa literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger.java b/tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger.java new file mode 100644 index 00000000..317e475d --- /dev/null +++ b/tests/test_data/std/jdk/internal/logger/SimpleConsoleLogger.java @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.logger; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.StackWalker.StackFrame; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.time.ZonedDateTime; +import java.util.Optional; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.function.Function; +import java.lang.System.Logger; +import java.util.function.Predicate; +import java.util.function.Supplier; +import sun.security.action.GetPropertyAction; +import sun.util.logging.PlatformLogger; +import sun.util.logging.PlatformLogger.ConfigurableBridge.LoggerConfiguration; + +/** + * A simple console logger to emulate the behavior of JUL loggers when + * in the default configuration. SimpleConsoleLoggers are also used when + * JUL is not present and no DefaultLoggerFinder is installed. + */ +public class SimpleConsoleLogger extends LoggerConfiguration + implements Logger, PlatformLogger.Bridge, PlatformLogger.ConfigurableBridge { + + static final Level DEFAULT_LEVEL = getDefaultLevel(); + static final PlatformLogger.Level DEFAULT_PLATFORM_LEVEL = + PlatformLogger.toPlatformLevel(DEFAULT_LEVEL); + + static Level getDefaultLevel() { + String levelName = GetPropertyAction + .privilegedGetProperty("jdk.system.logger.level", "INFO"); + try { + return Level.valueOf(levelName); + } catch (IllegalArgumentException iae) { + return Level.INFO; + } + } + + final String name; + volatile PlatformLogger.Level level; + final boolean usePlatformLevel; + SimpleConsoleLogger(String name, boolean usePlatformLevel) { + this.name = name; + this.usePlatformLevel = usePlatformLevel; + } + + String getSimpleFormatString() { + return Formatting.SIMPLE_CONSOLE_LOGGER_FORMAT; + } + + PlatformLogger.Level defaultPlatformLevel() { + return DEFAULT_PLATFORM_LEVEL; + } + + @Override + public final String getName() { + return name; + } + + private Enum logLevel(PlatformLogger.Level level) { + return usePlatformLevel ? level : level.systemLevel(); + } + + private Enum logLevel(Level level) { + return usePlatformLevel ? PlatformLogger.toPlatformLevel(level) : level; + } + + // --------------------------------------------------- + // From Logger + // --------------------------------------------------- + + @Override + public final boolean isLoggable(Level level) { + return isLoggable(PlatformLogger.toPlatformLevel(level)); + } + + @Override + public final void log(Level level, ResourceBundle bundle, String key, Throwable thrown) { + if (isLoggable(level)) { + if (bundle != null) { + key = getString(bundle, key); + } + publish(getCallerInfo(), logLevel(level), key, thrown); + } + } + + @Override + public final void log(Level level, ResourceBundle bundle, String format, Object... params) { + if (isLoggable(level)) { + if (bundle != null) { + format = getString(bundle, format); + } + publish(getCallerInfo(), logLevel(level), format, params); + } + } + + // --------------------------------------------------- + // From PlatformLogger.Bridge + // --------------------------------------------------- + + @Override + public final boolean isLoggable(PlatformLogger.Level level) { + final PlatformLogger.Level effectiveLevel = effectiveLevel(); + return level != PlatformLogger.Level.OFF + && level.ordinal() >= effectiveLevel.ordinal(); + } + + @Override + public final boolean isEnabled() { + return level != PlatformLogger.Level.OFF; + } + + @Override + public final void log(PlatformLogger.Level level, String msg) { + if (isLoggable(level)) { + publish(getCallerInfo(), logLevel(level), msg); + } + } + + @Override + public final void log(PlatformLogger.Level level, String msg, Throwable thrown) { + if (isLoggable(level)) { + publish(getCallerInfo(), logLevel(level), msg, thrown); + } + } + + @Override + public final void log(PlatformLogger.Level level, String msg, Object... params) { + if (isLoggable(level)) { + publish(getCallerInfo(), logLevel(level), msg, params); + } + } + + private PlatformLogger.Level effectiveLevel() { + if (level == null) return defaultPlatformLevel(); + return level; + } + + @Override + public final PlatformLogger.Level getPlatformLevel() { + return level; + } + + @Override + public final void setPlatformLevel(PlatformLogger.Level newLevel) { + level = newLevel; + } + + @Override + public final LoggerConfiguration getLoggerConfiguration() { + return this; + } + + /** + * Default platform logging support - output messages to System.err - + * equivalent to ConsoleHandler with SimpleFormatter. + */ + static PrintStream outputStream() { + return System.err; + } + + // Returns the caller's class and method's name; best effort + // if cannot infer, return the logger's name. + private String getCallerInfo() { + Optional frame = new CallerFinder().get(); + if (frame.isPresent()) { + return frame.get().getClassName() + " " + frame.get().getMethodName(); + } else { + return name; + } + } + + /* + * CallerFinder is a stateful predicate. + */ + @SuppressWarnings("removal") + static final class CallerFinder implements Predicate { + private static final StackWalker WALKER; + static { + final PrivilegedAction action = new PrivilegedAction<>() { + @Override + public StackWalker run() { + return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); + } + }; + WALKER = AccessController.doPrivileged(action); + } + + /** + * Returns StackFrame of the caller's frame. + * @return StackFrame of the caller's frame. + */ + Optional get() { + return WALKER.walk((s) -> s.filter(this).findFirst()); + } + + private boolean lookingForLogger = true; + /** + * Returns true if we have found the caller's frame, false if the frame + * must be skipped. + * + * @param t The frame info. + * @return true if we have found the caller's frame, false if the frame + * must be skipped. + */ + @Override + public boolean test(StackWalker.StackFrame t) { + final String cname = t.getClassName(); + // We should skip all frames until we have found the logger, + // because these frames could be frames introduced by e.g. custom + // sub classes of Handler. + if (lookingForLogger) { + // Skip all frames until we have found the first logger frame. + lookingForLogger = !isLoggerImplFrame(cname); + return false; + } + // Continue walking until we've found the relevant calling frame. + // Skips logging/logger infrastructure. + return !Formatting.isFilteredFrame(t); + } + + private boolean isLoggerImplFrame(String cname) { + return (cname.equals("sun.util.logging.PlatformLogger") || + cname.equals("jdk.internal.logger.SimpleConsoleLogger")); + } + } + + private String getCallerInfo(String sourceClassName, String sourceMethodName) { + if (sourceClassName == null) return name; + if (sourceMethodName == null) return sourceClassName; + return sourceClassName + " " + sourceMethodName; + } + + private String toString(Throwable thrown) { + String throwable = ""; + if (thrown != null) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + pw.println(); + thrown.printStackTrace(pw); + pw.close(); + throwable = sw.toString(); + } + return throwable; + } + + private synchronized String format(Enum level, + String msg, Throwable thrown, String callerInfo) { + + ZonedDateTime zdt = ZonedDateTime.now(); + String throwable = toString(thrown); + + return String.format(getSimpleFormatString(), + zdt, + callerInfo, + name, + level.name(), + msg, + throwable); + } + + // publish accepts both PlatformLogger Levels and LoggerFinder Levels. + private void publish(String callerInfo, Enum level, String msg) { + outputStream().print(format(level, msg, null, callerInfo)); + } + // publish accepts both PlatformLogger Levels and LoggerFinder Levels. + private void publish(String callerInfo, Enum level, String msg, Throwable thrown) { + outputStream().print(format(level, msg, thrown, callerInfo)); + } + // publish accepts both PlatformLogger Levels and LoggerFinder Levels. + private void publish(String callerInfo, Enum level, String msg, Object... params) { + msg = params == null || params.length == 0 ? msg + : Formatting.formatMessage(msg, params); + outputStream().print(format(level, msg, null, callerInfo)); + } + + public static SimpleConsoleLogger makeSimpleLogger(String name) { + return new SimpleConsoleLogger(name, false); + } + + @Override + public final void log(PlatformLogger.Level level, Supplier msgSupplier) { + if (isLoggable(level)) { + publish(getCallerInfo(), logLevel(level), msgSupplier.get()); + } + } + + @Override + public final void log(PlatformLogger.Level level, Throwable thrown, + Supplier msgSupplier) { + if (isLoggable(level)) { + publish(getCallerInfo(), logLevel(level), msgSupplier.get(), thrown); + } + } + + @Override + public final void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, String msg) { + if (isLoggable(level)) { + publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg); + } + } + + @Override + public final void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, Supplier msgSupplier) { + if (isLoggable(level)) { + publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msgSupplier.get()); + } + } + + @Override + public final void logp(PlatformLogger.Level level, String sourceClass, String sourceMethod, + String msg, Object... params) { + if (isLoggable(level)) { + publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg, params); + } + } + + @Override + public final void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, String msg, Throwable thrown) { + if (isLoggable(level)) { + publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg, thrown); + } + } + + @Override + public final void logp(PlatformLogger.Level level, String sourceClass, + String sourceMethod, Throwable thrown, Supplier msgSupplier) { + if (isLoggable(level)) { + publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msgSupplier.get(), thrown); + } + } + + @Override + public final void logrb(PlatformLogger.Level level, String sourceClass, + String sourceMethod, ResourceBundle bundle, String key, Object... params) { + if (isLoggable(level)) { + String msg = bundle == null ? key : getString(bundle, key); + publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg, params); + } + } + + @Override + public final void logrb(PlatformLogger.Level level, String sourceClass, + String sourceMethod, ResourceBundle bundle, String key, Throwable thrown) { + if (isLoggable(level)) { + String msg = bundle == null ? key : getString(bundle, key); + publish(getCallerInfo(sourceClass, sourceMethod), logLevel(level), msg, thrown); + } + } + + @Override + public final void logrb(PlatformLogger.Level level, ResourceBundle bundle, + String key, Object... params) { + if (isLoggable(level)) { + String msg = bundle == null ? key : getString(bundle,key); + publish(getCallerInfo(), logLevel(level), msg, params); + } + } + + @Override + public final void logrb(PlatformLogger.Level level, ResourceBundle bundle, + String key, Throwable thrown) { + if (isLoggable(level)) { + String msg = bundle == null ? key : getString(bundle,key); + publish(getCallerInfo(), logLevel(level), msg, thrown); + } + } + + static String getString(ResourceBundle bundle, String key) { + if (bundle == null || key == null) return key; + try { + return bundle.getString(key); + } catch (MissingResourceException x) { + // Emulate what java.util.logging Formatters do + // We don't want unchecked exception to propagate up to + // the caller's code. + return key; + } + } + + static final class Formatting { + // The default simple log format string. + // Used both by SimpleConsoleLogger when java.logging is not present, + // and by SurrogateLogger and java.util.logging.SimpleFormatter when + // java.logging is present. + static final String DEFAULT_FORMAT = + "%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%6$s%n"; + + // The system property key that allows to change the default log format + // when java.logging is not present. This is used to control the formatting + // of the SimpleConsoleLogger. + static final String DEFAULT_FORMAT_PROP_KEY = + "jdk.system.logger.format"; + + // The system property key that allows to change the default log format + // when java.logging is present. This is used to control the formatting + // of the SurrogateLogger (used before java.util.logging.LogManager is + // initialized) and the java.util.logging.SimpleFormatter (used after + // java.util.logging.LogManager is initialized). + static final String JUL_FORMAT_PROP_KEY = + "java.util.logging.SimpleFormatter.format"; + + // The simple console logger format string + static final String SIMPLE_CONSOLE_LOGGER_FORMAT = + getSimpleFormat(DEFAULT_FORMAT_PROP_KEY, null); + + // Make it easier to wrap Logger... + private static final String[] skips; + static { + String additionalPkgs = + GetPropertyAction.privilegedGetProperty("jdk.logger.packages"); + skips = additionalPkgs == null ? new String[0] : additionalPkgs.split(","); + } + + static boolean isFilteredFrame(StackFrame st) { + // skip logging/logger infrastructure + if (System.Logger.class.isAssignableFrom(st.getDeclaringClass())) { + return true; + } + + // fast escape path: all the prefixes below start with 's' or 'j' and + // have more than 12 characters. + final String cname = st.getClassName(); + char c = cname.length() < 12 ? 0 : cname.charAt(0); + if (c == 's') { + // skip internal machinery classes + if (cname.startsWith("sun.util.logging.")) return true; + if (cname.startsWith("sun.rmi.runtime.Log")) return true; + } else if (c == 'j') { + // Message delayed at Bootstrap: no need to go further up. + if (cname.startsWith("jdk.internal.logger.BootstrapLogger$LogEvent")) return false; + // skip public machinery classes + if (cname.startsWith("jdk.internal.logger.")) return true; + if (cname.startsWith("java.util.logging.")) return true; + if (cname.startsWith("java.lang.invoke.MethodHandle")) return true; + if (cname.startsWith("java.security.AccessController")) return true; + } + + // check additional prefixes if any are specified. + if (skips.length > 0) { + for (int i=0; i defaultPropertyGetter) { + // Double check that 'key' is one of the expected property names: + // - DEFAULT_FORMAT_PROP_KEY is used to control the + // SimpleConsoleLogger format when java.logging is + // not present. + // - JUL_FORMAT_PROP_KEY is used when this method is called + // from the SurrogateLogger subclass. It is used to control the + // SurrogateLogger format and java.util.logging.SimpleFormatter + // format when java.logging is present. + // This method should not be called with any other key. + if (!DEFAULT_FORMAT_PROP_KEY.equals(key) + && !JUL_FORMAT_PROP_KEY.equals(key)) { + throw new IllegalArgumentException("Invalid property name: " + key); + } + + // Do not use any lambda in this method. Using a lambda here causes + // jdk/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java + // to fail - because that test has a testcase which somehow references + // PlatformLogger and counts the number of generated lambda classes. + String format = GetPropertyAction.privilegedGetProperty(key); + + if (format == null && defaultPropertyGetter != null) { + format = defaultPropertyGetter.apply(key); + } + if (format != null) { + try { + // validate the user-defined format string + String.format(format, ZonedDateTime.now(), "", "", "", "", ""); + } catch (IllegalArgumentException e) { + // illegal syntax; fall back to the default format + format = DEFAULT_FORMAT; + } + } else { + format = DEFAULT_FORMAT; + } + return format; + } + + + // Copied from java.util.logging.Formatter.formatMessage + static String formatMessage(String format, Object... parameters) { + // Do the formatting. + try { + if (parameters == null || parameters.length == 0) { + // No parameters. Just return format string. + return format; + } + // Is it a java.text style format? + // Ideally we could match with + // Pattern.compile("\\{\\d").matcher(format).find()) + // However the cost is 14% higher, so we cheaply check for + // + boolean isJavaTestFormat = false; + final int len = format.length(); + for (int i=0; i= '0' && d <= '9') { + isJavaTestFormat = true; + break; + } + } + } + if (isJavaTestFormat) { + return java.text.MessageFormat.format(format, parameters); + } + return format; + } catch (Exception ex) { + // Formatting failed: use format string. + return format; + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/logger/SurrogateLogger.class b/tests/test_data/std/jdk/internal/logger/SurrogateLogger.class new file mode 100644 index 0000000000000000000000000000000000000000..c129db5ba6d770a48ac747967d7329d9741c09d3 GIT binary patch literal 2056 zcma)7TT|0O6#ll9rm3k20xDkcQnW>F6z>*6tyIBynW@&%7iTR?jid>aY@P8x`Jniq zqcgrbcdP5B?MmUh z+%X-m)e^p0x7!BU44HY`wdDfCWYK!Z-*eO9Zp*Ao-*#J-SEYuIEOZSy z1AAaFoJs`l_`cWTvI{!8^4xlTZ>e_Yx%KR|wbWR$h>{g_T(cwXh!4S=PaQ7TJii@r zDOlpYa4IU{UIQc8$1oOzlxyU}WyFb$gFJH-GiG2v#u-LhLPnKFVGI}J%EH`h9k(fM z&oyiDrcxTj(=f>}msskchJ`4Pq>8dQ$WT-=mQ}K{5}wTEUOsduWmPnnIZR+mu|CXD zO;A7LwR_e|g`=tgjxkIm;FTIG<8cEgaFTSggPQFS8?jpRd0Q~d^vCe#`U~!?3%^j8 zv=5ysrB^x%n9*?Bz!}vLGrPJ~hV=5|+7nu;-YTUUv20g7?zGuMU8t*u=+g_@#7)r&`E?bb~+tx%|y*Ex61FwW3 zA1d^SZ^XPOwix){hVbQw`$Ce?3`cjoQhI~^B7E4`5~8|O;QSz^LCXT^qu1@0%VozW zyhKi*I zL$2<1{HCBzr<%vNu_~*pWH6RpSNK(j2Z0DQR2ioK)6@*Z;jkk7e~(|oeTL(`-H}96 z!!os3qL*UZeQCHzuQ^4-J%uSXdTF{lGwUh~}^ zXg$=6oYnk{0hDeEV3>GKe+)Ay=_6jXp5S3rFi*c^aSID^@N^hTWo_cr7ij9{Xi9a% ji$r&kPAS~R9a^V|Yyo$1@Ae@Y<0&lRAZmDkm5lxu3ylNX literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/logger/SurrogateLogger.java b/tests/test_data/std/jdk/internal/logger/SurrogateLogger.java new file mode 100644 index 00000000..8507cb5d --- /dev/null +++ b/tests/test_data/std/jdk/internal/logger/SurrogateLogger.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.logger; + +import java.util.function.Function; +import sun.util.logging.PlatformLogger; + +/** + * A simple console logger used to emulate the behavior of JUL loggers when + * java.util.logging has no custom configuration. + * Surrogate loggers are usually only used temporarily, until the LogManager + * is initialized. At this point, the surrogates are replaced by an actual + * logger obtained from LogManager. + */ +public final class SurrogateLogger extends SimpleConsoleLogger { + + private static final PlatformLogger.Level JUL_DEFAULT_LEVEL = + PlatformLogger.Level.INFO; + private static volatile String simpleFormatString; + + SurrogateLogger(String name) { + super(name, true); + } + + @Override + PlatformLogger.Level defaultPlatformLevel() { + return JUL_DEFAULT_LEVEL; + } + + @Override + String getSimpleFormatString() { + if (simpleFormatString == null) { + simpleFormatString = getSimpleFormat(null); + } + return simpleFormatString; + } + + public static String getSimpleFormat(Function defaultPropertyGetter) { + return Formatting.getSimpleFormat(Formatting.JUL_FORMAT_PROP_KEY, defaultPropertyGetter); + } + + public static SurrogateLogger makeSurrogateLogger(String name) { + return new SurrogateLogger(name); + } + + public static boolean isFilteredFrame(StackWalker.StackFrame st) { + return Formatting.isFilteredFrame(st); + } +} diff --git a/tests/test_data/std/jdk/internal/logger/package-info.java b/tests/test_data/std/jdk/internal/logger/package-info.java new file mode 100644 index 00000000..46b571aa --- /dev/null +++ b/tests/test_data/std/jdk/internal/logger/package-info.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * [JDK INTERNAL] + * The {@code jdk.internal.logger} package defines an internal provider + * whose default naive implementation is replaced by the {@code java.logging} + * module when the {@code java.logging} module is present. + *

+ * Default Implementation + *

+ * The JDK default implementation of the System.LoggerFinder will attempt to + * load an installed instance of the {@link jdk.internal.logger.DefaultLoggerFinder} + * defined in this package. + * When the {@code java.util.logging} package is present, this will usually + * resolve to an instance of {@link sun.util.logging.internal.LoggingProviderImpl} - + * which provides an implementation of the Logger whose backend is a + * {@link java.util.logging.Logger java.util.logging.Logger}. + * Configuration can thus be performed by direct access to the regular + * {@code java.util.logging} APIs, + * using {@link java.util.logging.Logger java.util.logging.Logger} and + * {@link java.util.logging.LogManager} to access and configure the backend + * Loggers. + *
+ * If however {@code java.util.logging} is not linked with the application, then + * the default implementation will return a simple logger that will print out + * all log messages of INFO level and above to the console ({@code System.err}), + * as implemented by the base {@link jdk.internal.logger.DefaultLoggerFinder} class. + *

+ * Message Levels and Mapping to java.util.logging + *

+ * The {@link java.lang.System.LoggerFinder} class documentation describe how + * {@linkplain java.lang.System.Logger.Level System.Logger levels} are mapped + * to {@linkplain java.util.logging.Level JUL levels} when {@code + * java.util.logging} is the backend. + * + * @see jdk.internal.logger.DefaultLoggerFinder + * @see sun.util.logging.internal.LoggingProviderImpl + * @see java.lang.System.LoggerFinder + * @see java.lang.System.Logger + * @see sun.util.logging.PlatformLogger.Bridge + * @see sun.util.logging.internal + * + * @since 9 + */ +package jdk.internal.logger; diff --git a/tests/test_data/std/jdk/internal/math/DoubleConsts.class b/tests/test_data/std/jdk/internal/math/DoubleConsts.class new file mode 100644 index 0000000000000000000000000000000000000000..190beae83fe1a72b06a2ffa61353af82a7827692 GIT binary patch literal 670 zcmaKp%TC)+5QhJg#Bm6rAwX3^RRokf5?-+?s+0>*w~49bG_b-t2^KgQTS^?Z^p(1* z)I}eli#|*DNQD0+A$2#Mg~#9AXU?z3A3p(9u&pB@u-v)4F}xshyMgqLTNzy&)v(|4 z-AWkrqMnYFz-&j}NyC@H)!3Is8oG{54pYef<3DY6+;$|8KJ)@FdM}XN-f0RHZ1co2 zkIhQSsyb(8wedkfm;y7yE;5Lk((k)T&UL_Yb<=X}FJO+$V#6sFWmCx7ktBQyJ? zD&eIokgs`xYxQqiZnq(MAc47B*p_}%c0I*oV=B7#dIBr8{~z`p_c?6)<11zDu-|RF z$DS%%h(Ex-x;<98QJO30C}J8p(hMnq7vy}5XUT;a&ynY`Fo}Ojeih?I@=}anli$R6 znLQHfky&Ad9Sv$ht?hn?_H8)AD!=KWaSv;kcku>kYFp@?r1~C>O7E3IKAOymaL0}MIY+M*=1~f)UiWmX1 z4cHBCaMFJLoZ=>U1#A~L#cOOCZ`84|>!ooLXK9n-CQjp}ZsTTg+Qc@f|9S6eG%QZj zr*Gan=iGbGJ=;C!-mBNnJbeN{qnhZ4rVze1xg$BPE7`qe+Tx!6_O7%ay299NQ(LEH zy0huN?qt`rZOLq>+uGK%INg!imh1|_2frTy13`q&VzZ+C+H^-&!FOq zHn#OBOcO>qGd0-FNt$Y2zA$-Y;TAVgg|P~S9i7R(?QK27DnzRD2e}#qFrH?romv~f zMKr_|8=9mLXzt!DMjQxWGIg6Wf?mx2t;tp~>l6c1F^y);bf?n06jZYx(-lUINbJnA zs6W${O813Oi<#I>N^P^tDI-lR>&BCq@bA;Voh4RnfBK_tS z;8M)@V}bPjoI+%T-H7EBqSa@~G16p@Z;-)@6l$yU{Lx4QuTFoyKi%E&2Rx#%*uWAr zDU_w`IB)A&mE5_kr+dqyOqRi@GqhT~C?2vO@nDNgcDb}PPhRUqn2Uyww5%|&5?3hr zvpq67M_*js()|C4wbc@?Z3;Ej&42truOk6G!$4>l&_dXNYy9{V0~@hPA$ES)FXtLw zlg)Hd*wE&#o-NaBdwX`yaI|CiZ$P_&4jDVjY0Y-_rPEjRC;ONKwy$JY>613FS^C%< zW{|=3S|N8D$lzKo=q-#pF;|OFy9{h|sO;oHkAYr%o?+Y9)62-KZfR)|gF8>k8$D=0 zheFtiU49H0xDMAV6pe(5XrN$h>+i~Ddb$q*mkG*G&5℘2R9k` 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/math/DoubleToDecimal.java b/tests/test_data/std/jdk/internal/math/DoubleToDecimal.java new file mode 100644 index 00000000..e3472d55 --- /dev/null +++ b/tests/test_data/std/jdk/internal/math/DoubleToDecimal.java @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.math; + +import java.io.IOException; + +import static java.lang.Double.*; +import static java.lang.Long.*; +import static java.lang.Math.multiplyHigh; +import static jdk.internal.math.MathUtils.*; + +/** + * This class exposes a method to render a {@code double} as a string. + */ +public final class DoubleToDecimal { + /* + * For full details about this code see the following references: + * + * [1] Giulietti, "The Schubfach way to render doubles", + * https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb + * + * [2] IEEE Computer Society, "IEEE Standard for Floating-Point Arithmetic" + * + * [3] Bouvier & Zimmermann, "Division-Free Binary-to-Decimal Conversion" + * + * Divisions are avoided altogether for the benefit of those architectures + * that do not provide specific machine instructions or where they are slow. + * This is discussed in section 10 of [1]. + */ + + /* The precision in bits */ + static final int P = PRECISION; + + /* Exponent width in bits */ + private static final int W = (Double.SIZE - 1) - (P - 1); + + /* Minimum value of the exponent: -(2^(W-1)) - P + 3 */ + static final int Q_MIN = (-1 << (W - 1)) - P + 3; + + /* Maximum value of the exponent: 2^(W-1) - P */ + static final int Q_MAX = (1 << (W - 1)) - P; + + /* 10^(E_MIN - 1) <= MIN_VALUE < 10^E_MIN */ + static final int E_MIN = -323; + + /* 10^(E_MAX - 1) <= MAX_VALUE < 10^E_MAX */ + static final int E_MAX = 309; + + /* Threshold to detect tiny values, as in section 8.2.1 of [1] */ + static final long C_TINY = 3; + + /* The minimum and maximum k, as in section 8 of [1] */ + static final int K_MIN = -324; + static final int K_MAX = 292; + + /* H is as in section 8.1 of [1] */ + static final int H = 17; + + /* Minimum value of the significand of a normal value: 2^(P-1) */ + private static final long C_MIN = 1L << (P - 1); + + /* Mask to extract the biased exponent */ + private static final int BQ_MASK = (1 << W) - 1; + + /* Mask to extract the fraction bits */ + private static final long T_MASK = (1L << (P - 1)) - 1; + + /* Used in rop() */ + private static final long MASK_63 = (1L << 63) - 1; + + /* Used for left-to-tight digit extraction */ + private static final int MASK_28 = (1 << 28) - 1; + + private static final int NON_SPECIAL = 0; + private static final int PLUS_ZERO = 1; + private static final int MINUS_ZERO = 2; + private static final int PLUS_INF = 3; + private static final int MINUS_INF = 4; + private static final int NAN = 5; + + /* + * Room for the longer of the forms + * -ddddd.dddddddddddd H + 2 characters + * -0.00ddddddddddddddddd H + 5 characters + * -d.ddddddddddddddddE-eee H + 7 characters + * where there are H digits d + */ + public static final int MAX_CHARS = H + 7; + + private final byte[] bytes; + + /* Index into bytes of rightmost valid character */ + private int index; + + private DoubleToDecimal(boolean noChars) { + bytes = noChars ? null : new byte[MAX_CHARS]; + } + + /** + * Returns a string representation of the {@code double} + * argument. All characters mentioned below are ASCII characters. + * + * @param v the {@code double} to be converted. + * @return a string representation of the argument. + * @see Double#toString(double) + */ + public static String toString(double v) { + return new DoubleToDecimal(false).toDecimalString(v); + } + + /** + * Splits the decimal d described in + * {@link Double#toString(double)} in integers f and e + * such that d = f 10e. + * + *

Further, determines integer n such that n = 0 when + * f = 0, and + * 10n-1f < 10n + * otherwise. + * + *

The argument {@code v} is assumed to be a positive finite value or + * positive zero. + * Further, {@code fd} must not be {@code null}. + * + * @param v the finite {@code double} to be split. + * @param fd the object that will carry f, e, and n. + */ + public static void split(double v, FormattedFPDecimal fd) { + new DoubleToDecimal(true).toDecimal(v, fd); + } + + /** + * Appends the rendering of the {@code v} to {@code app}. + * + *

The outcome is the same as if {@code v} were first + * {@link #toString(double) rendered} and the resulting string were then + * {@link Appendable#append(CharSequence) appended} to {@code app}. + * + * @param v the {@code double} whose rendering is appended. + * @param app the {@link Appendable} to append to. + * @throws IOException If an I/O error occurs + */ + public static Appendable appendTo(double v, Appendable app) + throws IOException { + return new DoubleToDecimal(false).appendDecimalTo(v, app); + } + + private String toDecimalString(double v) { + return switch (toDecimal(v, null)) { + case NON_SPECIAL -> charsToString(); + case PLUS_ZERO -> "0.0"; + case MINUS_ZERO -> "-0.0"; + case PLUS_INF -> "Infinity"; + case MINUS_INF -> "-Infinity"; + default -> "NaN"; + }; + } + + private Appendable appendDecimalTo(double v, Appendable app) + throws IOException { + switch (toDecimal(v, null)) { + case NON_SPECIAL: + char[] chars = new char[index + 1]; + for (int i = 0; i < chars.length; ++i) { + chars[i] = (char) bytes[i]; + } + if (app instanceof StringBuilder builder) { + return builder.append(chars); + } + if (app instanceof StringBuffer buffer) { + return buffer.append(chars); + } + for (char c : chars) { + app.append(c); + } + return app; + case PLUS_ZERO: return app.append("0.0"); + case MINUS_ZERO: return app.append("-0.0"); + case PLUS_INF: return app.append("Infinity"); + case MINUS_INF: return app.append("-Infinity"); + default: return app.append("NaN"); + } + } + + /* + * Returns + * PLUS_ZERO iff v is 0.0 + * MINUS_ZERO iff v is -0.0 + * PLUS_INF iff v is POSITIVE_INFINITY + * MINUS_INF iff v is NEGATIVE_INFINITY + * NAN iff v is NaN + */ + private int toDecimal(double v, FormattedFPDecimal fd) { + /* + * For full details see references [2] and [1]. + * + * For finite v != 0, determine integers c and q such that + * |v| = c 2^q and + * Q_MIN <= q <= Q_MAX and + * either 2^(P-1) <= c < 2^P (normal) + * or 0 < c < 2^(P-1) and q = Q_MIN (subnormal) + */ + long bits = doubleToRawLongBits(v); + long t = bits & T_MASK; + int bq = (int) (bits >>> P - 1) & BQ_MASK; + if (bq < BQ_MASK) { + index = -1; + if (bits < 0) { + /* + * fd != null implies bytes == null and bits >= 0 + * Thus, when fd != null, control never reaches here. + */ + append('-'); + } + if (bq != 0) { + /* normal value. Here mq = -q */ + int mq = -Q_MIN + 1 - bq; + long c = C_MIN | t; + /* The fast path discussed in section 8.3 of [1] */ + if (0 < mq & mq < P) { + long f = c >> mq; + if (f << mq == c) { + return toChars(f, 0, fd); + } + } + return toDecimal(-mq, c, 0, fd); + } + if (t != 0) { + /* subnormal value */ + return t < C_TINY + ? toDecimal(Q_MIN, 10 * t, -1, fd) + : toDecimal(Q_MIN, t, 0, fd); + } + return bits == 0 ? PLUS_ZERO : MINUS_ZERO; + } + if (t != 0) { + return NAN; + } + return bits > 0 ? PLUS_INF : MINUS_INF; + } + + private int toDecimal(int q, long c, int dk, FormattedFPDecimal fd) { + /* + * The skeleton corresponds to figure 7 of [1]. + * The efficient computations are those summarized in figure 9. + * + * Here's a correspondence between Java names and names in [1], + * expressed as approximate LaTeX source code and informally. + * Other names are identical. + * cb: \bar{c} "c-bar" + * cbr: \bar{c}_r "c-bar-r" + * cbl: \bar{c}_l "c-bar-l" + * + * vb: \bar{v} "v-bar" + * vbr: \bar{v}_r "v-bar-r" + * vbl: \bar{v}_l "v-bar-l" + * + * rop: r_o' "r-o-prime" + */ + int out = (int) c & 0x1; + long cb = c << 2; + long cbr = cb + 2; + long cbl; + int k; + /* + * flog10pow2(e) = floor(log_10(2^e)) + * flog10threeQuartersPow2(e) = floor(log_10(3/4 2^e)) + * flog2pow10(e) = floor(log_2(10^e)) + */ + if (c != C_MIN | q == Q_MIN) { + /* regular spacing */ + cbl = cb - 2; + k = flog10pow2(q); + } else { + /* irregular spacing */ + cbl = cb - 1; + k = flog10threeQuartersPow2(q); + } + int h = q + flog2pow10(-k) + 2; + + /* g1 and g0 are as in section 9.8.3 of [1], so g = g1 2^63 + g0 */ + long g1 = g1(k); + long g0 = g0(k); + + long vb = rop(g1, g0, cb << h); + long vbl = rop(g1, g0, cbl << h); + long vbr = rop(g1, g0, cbr << h); + + long s = vb >> 2; + if (s >= 100) { + /* + * For n = 17, m = 1 the table in section 10 of [1] shows + * s' = floor(s / 10) = floor(s 115_292_150_460_684_698 / 2^60) + * = floor(s 115_292_150_460_684_698 2^4 / 2^64) + * + * sp10 = 10 s' + * tp10 = 10 t' + * upin iff u' = sp10 10^k in Rv + * wpin iff w' = tp10 10^k in Rv + * See section 9.3 of [1]. + */ + long sp10 = 10 * multiplyHigh(s, 115_292_150_460_684_698L << 4); + long tp10 = sp10 + 10; + boolean upin = vbl + out <= sp10 << 2; + boolean wpin = (tp10 << 2) + out <= vbr; + if (upin != wpin) { + return toChars(upin ? sp10 : tp10, k, fd); + } + } + + /* + * 10 <= s < 100 or s >= 100 and u', w' not in Rv + * uin iff u = s 10^k in Rv + * win iff w = t 10^k in Rv + * See section 9.3 of [1]. + */ + long t = s + 1; + boolean uin = vbl + out <= s << 2; + boolean win = (t << 2) + out <= vbr; + if (uin != win) { + /* Exactly one of u or w lies in Rv */ + return toChars(uin ? s : t, k + dk, fd); + } + /* + * Both u and w lie in Rv: determine the one closest to v. + * See section 9.3 of [1]. + */ + long cmp = vb - (s + t << 1); + return toChars(cmp < 0 || cmp == 0 && (s & 0x1) == 0 ? s : t, k + dk, fd); + } + + /* + * Computes rop(cp g 2^(-127)), where g = g1 2^63 + g0 + * See section 9.9 and figure 8 of [1]. + */ + private static long rop(long g1, long g0, long cp) { + long x1 = multiplyHigh(g0, cp); + long y0 = g1 * cp; + long y1 = multiplyHigh(g1, cp); + long z = (y0 >>> 1) + x1; + long vbp = y1 + (z >>> 63); + return vbp | (z & MASK_63) + MASK_63 >>> 63; + } + + /* + * Formats the decimal f 10^e. + */ + private int toChars(long f, int e, FormattedFPDecimal fd) { + /* + * For details not discussed here see section 10 of [1]. + * + * Determine len such that + * 10^(len-1) <= f < 10^len + */ + int len = flog10pow2(Long.SIZE - numberOfLeadingZeros(f)); + if (f >= pow10(len)) { + len += 1; + } + if (fd != null) { + fd.set(f, e, len); + return NON_SPECIAL; + } + + /* + * Let fp and ep be the original f and e, respectively. + * Transform f and e to ensure + * 10^(H-1) <= f < 10^H + * fp 10^ep = f 10^(e-H) = 0.f 10^e + */ + f *= pow10(H - len); + e += len; + + /* + * The toChars?() methods perform left-to-right digits extraction + * using ints, provided that the arguments are limited to 8 digits. + * Therefore, split the H = 17 digits of f into: + * h = the most significant digit of f + * m = the next 8 most significant digits of f + * l = the last 8, least significant digits of f + * + * For n = 17, m = 8 the table in section 10 of [1] shows + * floor(f / 10^8) = floor(193_428_131_138_340_668 f / 2^84) = + * floor(floor(193_428_131_138_340_668 f / 2^64) / 2^20) + * and for n = 9, m = 8 + * floor(hm / 10^8) = floor(1_441_151_881 hm / 2^57) + */ + long hm = multiplyHigh(f, 193_428_131_138_340_668L) >>> 20; + int l = (int) (f - 100_000_000L * hm); + int h = (int) (hm * 1_441_151_881L >>> 57); + int m = (int) (hm - 100_000_000 * h); + + if (0 < e && e <= 7) { + return toChars1(h, m, l, e); + } + if (-3 < e && e <= 0) { + return toChars2(h, m, l, e); + } + return toChars3(h, m, l, e); + } + + private int toChars1(int h, int m, int l, int e) { + /* + * 0 < e <= 7: plain format without leading zeroes. + * Left-to-right digits extraction: + * algorithm 1 in [3], with b = 10, k = 8, n = 28. + */ + appendDigit(h); + int y = y(m); + int t; + int i = 1; + for (; i < e; ++i) { + t = 10 * y; + appendDigit(t >>> 28); + y = t & MASK_28; + } + append('.'); + for (; i <= 8; ++i) { + t = 10 * y; + appendDigit(t >>> 28); + y = t & MASK_28; + } + lowDigits(l); + return NON_SPECIAL; + } + + private int toChars2(int h, int m, int l, int e) { + /* -3 < e <= 0: plain format with leading zeroes */ + appendDigit(0); + append('.'); + for (; e < 0; ++e) { + appendDigit(0); + } + appendDigit(h); + append8Digits(m); + lowDigits(l); + return NON_SPECIAL; + } + + private int toChars3(int h, int m, int l, int e) { + /* -3 >= e | e > 7: computerized scientific notation */ + appendDigit(h); + append('.'); + append8Digits(m); + lowDigits(l); + exponent(e - 1); + return NON_SPECIAL; + } + + private void lowDigits(int l) { + if (l != 0) { + append8Digits(l); + } + removeTrailingZeroes(); + } + + private void append8Digits(int m) { + /* + * Left-to-right digits extraction: + * algorithm 1 in [3], with b = 10, k = 8, n = 28. + */ + int y = y(m); + for (int i = 0; i < 8; ++i) { + int t = 10 * y; + appendDigit(t >>> 28); + y = t & MASK_28; + } + } + + private void removeTrailingZeroes() { + while (bytes[index] == '0') { + --index; + } + /* ... but do not remove the one directly to the right of '.' */ + if (bytes[index] == '.') { + ++index; + } + } + + private int y(int a) { + /* + * Algorithm 1 in [3] needs computation of + * floor((a + 1) 2^n / b^k) - 1 + * with a < 10^8, b = 10, k = 8, n = 28. + * Noting that + * (a + 1) 2^n <= 10^8 2^28 < 10^17 + * For n = 17, m = 8 the table in section 10 of [1] leads to: + */ + return (int) (multiplyHigh( + (long) (a + 1) << 28, + 193_428_131_138_340_668L) >>> 20) - 1; + } + + private void exponent(int e) { + append('E'); + if (e < 0) { + append('-'); + e = -e; + } + if (e < 10) { + appendDigit(e); + return; + } + int d; + if (e >= 100) { + /* + * For n = 3, m = 2 the table in section 10 of [1] shows + * floor(e / 100) = floor(1_311 e / 2^17) + */ + d = e * 1_311 >>> 17; + appendDigit(d); + e -= 100 * d; + } + /* + * For n = 2, m = 1 the table in section 10 of [1] shows + * floor(e / 10) = floor(103 e / 2^10) + */ + d = e * 103 >>> 10; + appendDigit(d); + appendDigit(e - 10 * d); + } + + private void append(int c) { + bytes[++index] = (byte) c; + } + + private void appendDigit(int d) { + bytes[++index] = (byte) ('0' + d); + } + + /* Using the deprecated constructor enhances performance */ + @SuppressWarnings("deprecation") + private String charsToString() { + return new String(bytes, 0, 0, index + 1); + } + +} diff --git a/tests/test_data/std/jdk/internal/math/FDBigInteger.class b/tests/test_data/std/jdk/internal/math/FDBigInteger.class new file mode 100644 index 0000000000000000000000000000000000000000..fb16813ca439d24714b547dc42365c67c9ea6032 GIT binary patch literal 16884 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 Hs5}23KewaO literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/math/FDBigInteger.java b/tests/test_data/std/jdk/internal/math/FDBigInteger.java new file mode 100644 index 00000000..f6d868df --- /dev/null +++ b/tests/test_data/std/jdk/internal/math/FDBigInteger.java @@ -0,0 +1,1521 @@ +/* + * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.math; + +import jdk.internal.misc.CDS; + +import java.math.BigInteger; +import java.util.Arrays; +//@ model import org.jmlspecs.models.JMLMath; + +/** + * A simple big integer package specifically for floating point base conversion. + */ +public /*@ spec_bigint_math @*/ class FDBigInteger { + + // + // This class contains many comments that start with "/*@" mark. + // They are behavourial specification in + // the Java Modelling Language (JML): + // http://www.eecs.ucf.edu/~leavens/JML//index.shtml + // + + /*@ + @ public pure model static \bigint UNSIGNED(int v) { + @ return v >= 0 ? v : v + (((\bigint)1) << 32); + @ } + @ + @ public pure model static \bigint UNSIGNED(long v) { + @ return v >= 0 ? v : v + (((\bigint)1) << 64); + @ } + @ + @ public pure model static \bigint AP(int[] data, int len) { + @ return (\sum int i; 0 <= 0 && i < len; UNSIGNED(data[i]) << (i*32)); + @ } + @ + @ public pure model static \bigint pow52(int p5, int p2) { + @ ghost \bigint v = 1; + @ for (int i = 0; i < p5; i++) v *= 5; + @ return v << p2; + @ } + @ + @ public pure model static \bigint pow10(int p10) { + @ return pow52(p10, p10); + @ } + @*/ + + static final int[] SMALL_5_POW; + + static final long[] LONG_5_POW; + + // Maximum size of cache of powers of 5 as FDBigIntegers. + private static final int MAX_FIVE_POW = 340; + + // Cache of big powers of 5 as FDBigIntegers. + private static final FDBigInteger POW_5_CACHE[]; + + // Zero as an FDBigInteger. + public static final FDBigInteger ZERO; + + // Archive proxy + private static Object[] archivedCaches; + + // Initialize FDBigInteger cache of powers of 5. + static { + CDS.initializeFromArchive(FDBigInteger.class); + Object[] caches = archivedCaches; + if (caches == null) { + long[] long5pow = { + 1L, + 5L, + 5L * 5, + 5L * 5 * 5, + 5L * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + }; + int[] small5pow = { + 1, + 5, + 5 * 5, + 5 * 5 * 5, + 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 + }; + FDBigInteger[] pow5cache = new FDBigInteger[MAX_FIVE_POW]; + int i = 0; + while (i < small5pow.length) { + FDBigInteger pow5 = new FDBigInteger(new int[] { small5pow[i] }, 0); + pow5.makeImmutable(); + pow5cache[i] = pow5; + i++; + } + FDBigInteger prev = pow5cache[i - 1]; + while (i < MAX_FIVE_POW) { + pow5cache[i] = prev = prev.mult(5); + prev.makeImmutable(); + i++; + } + FDBigInteger zero = new FDBigInteger(new int[0], 0); + zero.makeImmutable(); + archivedCaches = caches = new Object[] {small5pow, long5pow, pow5cache, zero}; + } + SMALL_5_POW = (int[])caches[0]; + LONG_5_POW = (long[])caches[1]; + POW_5_CACHE = (FDBigInteger[])caches[2]; + ZERO = (FDBigInteger)caches[3]; + } + + // Constant for casting an int to a long via bitwise AND. + private static final long LONG_MASK = 0xffffffffL; + + //@ spec_public non_null; + private int data[]; // value: data[0] is least significant + //@ spec_public; + private int offset; // number of least significant zero padding ints + //@ spec_public; + private int nWords; // data[nWords-1]!=0, all values above are zero + // if nWords==0 -> this FDBigInteger is zero + //@ spec_public; + private boolean isImmutable = false; + + /*@ + @ public invariant 0 <= nWords && nWords <= data.length && offset >= 0; + @ public invariant nWords == 0 ==> offset == 0; + @ public invariant nWords > 0 ==> data[nWords - 1] != 0; + @ public invariant (\forall int i; nWords <= i && i < data.length; data[i] == 0); + @ public pure model \bigint value() { + @ return AP(data, nWords) << (offset*32); + @ } + @*/ + + /** + * Constructs an FDBigInteger from data and padding. The + * data parameter has the least significant int at + * the zeroth index. The offset parameter gives the number of + * zero ints to be inferred below the least significant element + * of data. + * + * @param data An array containing all non-zero ints of the value. + * @param offset An offset indicating the number of zero ints to pad + * below the least significant element of data. + */ + /*@ + @ requires data != null && offset >= 0; + @ ensures this.value() == \old(AP(data, data.length) << (offset*32)); + @ ensures this.data == \old(data); + @*/ + private FDBigInteger(int[] data, int offset) { + this.data = data; + this.offset = offset; + this.nWords = data.length; + trimLeadingZeros(); + } + + /** + * Constructs an FDBigInteger from a starting value and some + * decimal digits. + * + * @param lValue The starting value. + * @param digits The decimal digits. + * @param kDigits The initial index into digits. + * @param nDigits The final index into digits. + */ + /*@ + @ requires digits != null; + @ requires 0 <= kDigits && kDigits <= nDigits && nDigits <= digits.length; + @ requires (\forall int i; 0 <= i && i < nDigits; '0' <= digits[i] && digits[i] <= '9'); + @ ensures this.value() == \old(lValue * pow10(nDigits - kDigits) + (\sum int i; kDigits <= i && i < nDigits; (digits[i] - '0') * pow10(nDigits - i - 1))); + @*/ + public FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) { + int n = Math.max((nDigits + 8) / 9, 2); // estimate size needed. + data = new int[n]; // allocate enough space + data[0] = (int) lValue; // starting value + data[1] = (int) (lValue >>> 32); + offset = 0; + nWords = 2; + int i = kDigits; + int limit = nDigits - 5; // slurp digits 5 at a time. + int v; + while (i < limit) { + int ilim = i + 5; + v = (int) digits[i++] - (int) '0'; + while (i < ilim) { + v = 10 * v + (int) digits[i++] - (int) '0'; + } + multAddMe(100000, v); // ... where 100000 is 10^5. + } + int factor = 1; + v = 0; + while (i < nDigits) { + v = 10 * v + (int) digits[i++] - (int) '0'; + factor *= 10; + } + if (factor != 1) { + multAddMe(factor, v); + } + trimLeadingZeros(); + } + + /** + * Returns an FDBigInteger with the numerical value + * 5p5 * 2p2. + * + * @param p5 The exponent of the power-of-five factor. + * @param p2 The exponent of the power-of-two factor. + * @return 5p5 * 2p2 + */ + /*@ + @ requires p5 >= 0 && p2 >= 0; + @ assignable \nothing; + @ ensures \result.value() == \old(pow52(p5, p2)); + @*/ + public static FDBigInteger valueOfPow52(int p5, int p2) { + if (p5 != 0) { + if (p2 == 0) { + return big5pow(p5); + } else if (p5 < SMALL_5_POW.length) { + int pow5 = SMALL_5_POW[p5]; + int wordcount = p2 >> 5; + int bitcount = p2 & 0x1f; + if (bitcount == 0) { + return new FDBigInteger(new int[]{pow5}, wordcount); + } else { + return new FDBigInteger(new int[]{ + pow5 << bitcount, + pow5 >>> (32 - bitcount) + }, wordcount); + } + } else { + return big5pow(p5).leftShift(p2); + } + } else { + return valueOfPow2(p2); + } + } + + /** + * Returns an FDBigInteger with the numerical value + * value * 5p5 * 2p2. + * + * @param value The constant factor. + * @param p5 The exponent of the power-of-five factor. + * @param p2 The exponent of the power-of-two factor. + * @return value * 5p5 * 2p2 + */ + /*@ + @ requires p5 >= 0 && p2 >= 0; + @ assignable \nothing; + @ ensures \result.value() == \old(UNSIGNED(value) * pow52(p5, p2)); + @*/ + public static FDBigInteger valueOfMulPow52(long value, int p5, int p2) { + assert p5 >= 0 : p5; + assert p2 >= 0 : p2; + int v0 = (int) value; + int v1 = (int) (value >>> 32); + int wordcount = p2 >> 5; + int bitcount = p2 & 0x1f; + if (p5 != 0) { + if (p5 < SMALL_5_POW.length) { + long pow5 = SMALL_5_POW[p5] & LONG_MASK; + long carry = (v0 & LONG_MASK) * pow5; + v0 = (int) carry; + carry >>>= 32; + carry = (v1 & LONG_MASK) * pow5 + carry; + v1 = (int) carry; + int v2 = (int) (carry >>> 32); + if (bitcount == 0) { + return new FDBigInteger(new int[]{v0, v1, v2}, wordcount); + } else { + return new FDBigInteger(new int[]{ + v0 << bitcount, + (v1 << bitcount) | (v0 >>> (32 - bitcount)), + (v2 << bitcount) | (v1 >>> (32 - bitcount)), + v2 >>> (32 - bitcount) + }, wordcount); + } + } else { + FDBigInteger pow5 = big5pow(p5); + int[] r; + if (v1 == 0) { + r = new int[pow5.nWords + 1 + ((p2 != 0) ? 1 : 0)]; + mult(pow5.data, pow5.nWords, v0, r); + } else { + r = new int[pow5.nWords + 2 + ((p2 != 0) ? 1 : 0)]; + mult(pow5.data, pow5.nWords, v0, v1, r); + } + return (new FDBigInteger(r, pow5.offset)).leftShift(p2); + } + } else if (p2 != 0) { + if (bitcount == 0) { + return new FDBigInteger(new int[]{v0, v1}, wordcount); + } else { + return new FDBigInteger(new int[]{ + v0 << bitcount, + (v1 << bitcount) | (v0 >>> (32 - bitcount)), + v1 >>> (32 - bitcount) + }, wordcount); + } + } + return new FDBigInteger(new int[]{v0, v1}, 0); + } + + /** + * Returns an FDBigInteger with the numerical value + * 2p2. + * + * @param p2 The exponent of 2. + * @return 2p2 + */ + /*@ + @ requires p2 >= 0; + @ assignable \nothing; + @ ensures \result.value() == pow52(0, p2); + @*/ + private static FDBigInteger valueOfPow2(int p2) { + int wordcount = p2 >> 5; + int bitcount = p2 & 0x1f; + return new FDBigInteger(new int[]{1 << bitcount}, wordcount); + } + + /** + * Removes all leading zeros from this FDBigInteger adjusting + * the offset and number of non-zero leading words accordingly. + */ + /*@ + @ requires data != null; + @ requires 0 <= nWords && nWords <= data.length && offset >= 0; + @ requires nWords == 0 ==> offset == 0; + @ ensures nWords == 0 ==> offset == 0; + @ ensures nWords > 0 ==> data[nWords - 1] != 0; + @*/ + private /*@ helper @*/ void trimLeadingZeros() { + int i = nWords; + if (i > 0 && (data[--i] == 0)) { + //for (; i > 0 && data[i - 1] == 0; i--) ; + while(i > 0 && data[i - 1] == 0) { + i--; + } + this.nWords = i; + if (i == 0) { // all words are zero + this.offset = 0; + } + } + } + + /** + * Retrieves the normalization bias of the FDBigIntger. The + * normalization bias is a left shift such that after it the highest word + * of the value will have the 4 highest bits equal to zero: + * {@code (highestWord & 0xf0000000) == 0}, but the next bit should be 1 + * {@code (highestWord & 0x08000000) != 0}. + * + * @return The normalization bias. + */ + /*@ + @ requires this.value() > 0; + @*/ + public /*@ pure @*/ int getNormalizationBias() { + if (nWords == 0) { + throw new IllegalArgumentException("Zero value cannot be normalized"); + } + int zeros = Integer.numberOfLeadingZeros(data[nWords - 1]); + return (zeros < 4) ? 28 + zeros : zeros - 4; + } + + // TODO: Why is anticount param needed if it is always 32 - bitcount? + /** + * Left shifts the contents of one int array into another. + * + * @param src The source array. + * @param idx The initial index of the source array. + * @param result The destination array. + * @param bitcount The left shift. + * @param anticount The left anti-shift, e.g., 32-bitcount. + * @param prev The prior source value. + */ + /*@ + @ requires 0 < bitcount && bitcount < 32 && anticount == 32 - bitcount; + @ requires src.length >= idx && result.length > idx; + @ assignable result[*]; + @ ensures AP(result, \old(idx + 1)) == \old((AP(src, idx) + UNSIGNED(prev) << (idx*32)) << bitcount); + @*/ + private static void leftShift(int[] src, int idx, int result[], int bitcount, int anticount, int prev){ + for (; idx > 0; idx--) { + int v = (prev << bitcount); + prev = src[idx - 1]; + v |= (prev >>> anticount); + result[idx] = v; + } + int v = prev << bitcount; + result[0] = v; + } + + /** + * Shifts this FDBigInteger to the left. The shift is performed + * in-place unless the FDBigInteger is immutable in which case + * a new instance of FDBigInteger is returned. + * + * @param shift The number of bits to shift left. + * @return The shifted FDBigInteger. + */ + /*@ + @ requires this.value() == 0 || shift == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() > 0 && shift > 0 && this.isImmutable; + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() << shift); + @ + @ also + @ + @ requires this.value() > 0 && shift > 0 && this.isImmutable; + @ assignable \nothing; + @ ensures \result == this; + @ ensures \result.value() == \old(this.value() << shift); + @*/ + public FDBigInteger leftShift(int shift) { + if (shift == 0 || nWords == 0) { + return this; + } + int wordcount = shift >> 5; + int bitcount = shift & 0x1f; + if (this.isImmutable) { + if (bitcount == 0) { + return new FDBigInteger(Arrays.copyOf(data, nWords), offset + wordcount); + } else { + int anticount = 32 - bitcount; + int idx = nWords - 1; + int prev = data[idx]; + int hi = prev >>> anticount; + int[] result; + if (hi != 0) { + result = new int[nWords + 1]; + result[nWords] = hi; + } else { + result = new int[nWords]; + } + leftShift(data,idx,result,bitcount,anticount,prev); + return new FDBigInteger(result, offset + wordcount); + } + } else { + if (bitcount != 0) { + int anticount = 32 - bitcount; + if ((data[0] << bitcount) == 0) { + int idx = 0; + int prev = data[idx]; + for (; idx < nWords - 1; idx++) { + int v = (prev >>> anticount); + prev = data[idx + 1]; + v |= (prev << bitcount); + data[idx] = v; + } + int v = prev >>> anticount; + data[idx] = v; + if(v==0) { + nWords--; + } + offset++; + } else { + int idx = nWords - 1; + int prev = data[idx]; + int hi = prev >>> anticount; + int[] result = data; + int[] src = data; + if (hi != 0) { + if(nWords == data.length) { + data = result = new int[nWords + 1]; + } + result[nWords++] = hi; + } + leftShift(src,idx,result,bitcount,anticount,prev); + } + } + offset += wordcount; + return this; + } + } + + /** + * Returns the number of ints this FDBigInteger represents. + * + * @return Number of ints required to represent this FDBigInteger. + */ + /*@ + @ requires this.value() == 0; + @ ensures \result == 0; + @ + @ also + @ + @ requires this.value() > 0; + @ ensures ((\bigint)1) << (\result - 1) <= this.value() && this.value() <= ((\bigint)1) << \result; + @*/ + private /*@ pure @*/ int size() { + return nWords + offset; + } + + + /** + * Computes + *

+     * q = (int)( this / S )
+     * this = 10 * ( this mod S )
+     * Return q.
+     * 
+ * This is the iteration step of digit development for output. + * We assume that S has been normalized, as above, and that + * "this" has been left-shifted accordingly. + * Also assumed, of course, is that the result, q, can be expressed + * as an integer, {@code 0 <= q < 10}. + * + * @param S The divisor of this FDBigInteger. + * @return q = (int)(this / S). + */ + /*@ + @ requires !this.isImmutable; + @ requires this.size() <= S.size(); + @ requires this.data.length + this.offset >= S.size(); + @ requires S.value() >= ((\bigint)1) << (S.size()*32 - 4); + @ assignable this.nWords, this.offset, this.data, this.data[*]; + @ ensures \result == \old(this.value() / S.value()); + @ ensures this.value() == \old(10 * (this.value() % S.value())); + @*/ + public int quoRemIteration(FDBigInteger S) throws IllegalArgumentException { + assert !this.isImmutable : "cannot modify immutable value"; + // ensure that this and S have the same number of + // digits. If S is properly normalized and q < 10 then + // this must be so. + int thSize = this.size(); + int sSize = S.size(); + if (thSize < sSize) { + // this value is significantly less than S, result of division is zero. + // just mult this by 10. + int p = multAndCarryBy10(this.data, this.nWords, this.data); + if(p!=0) { + this.data[nWords++] = p; + } else { + trimLeadingZeros(); + } + return 0; + } else if (thSize > sSize) { + throw new IllegalArgumentException("disparate values"); + } + // estimate q the obvious way. We will usually be + // right. If not, then we're only off by a little and + // will re-add. + long q = (this.data[this.nWords - 1] & LONG_MASK) / (S.data[S.nWords - 1] & LONG_MASK); + long diff = multDiffMe(q, S); + if (diff != 0L) { + //@ assert q != 0; + //@ assert this.offset == \old(Math.min(this.offset, S.offset)); + //@ assert this.offset <= S.offset; + + // q is too big. + // add S back in until this turns +. This should + // not be very many times! + long sum = 0L; + int tStart = S.offset - this.offset; + //@ assert tStart >= 0; + int[] sd = S.data; + int[] td = this.data; + while (sum == 0L) { + for (int sIndex = 0, tIndex = tStart; tIndex < this.nWords; sIndex++, tIndex++) { + sum += (td[tIndex] & LONG_MASK) + (sd[sIndex] & LONG_MASK); + td[tIndex] = (int) sum; + sum >>>= 32; // Signed or unsigned, answer is 0 or 1 + } + // + // Originally the following line read + // "if ( sum !=0 && sum != -1 )" + // but that would be wrong, because of the + // treatment of the two values as entirely unsigned, + // it would be impossible for a carry-out to be interpreted + // as -1 -- it would have to be a single-bit carry-out, or +1. + // + assert sum == 0 || sum == 1 : sum; // carry out of division correction + q -= 1; + } + } + // finally, we can multiply this by 10. + // it cannot overflow, right, as the high-order word has + // at least 4 high-order zeros! + int p = multAndCarryBy10(this.data, this.nWords, this.data); + assert p == 0 : p; // Carry out of *10 + trimLeadingZeros(); + return (int) q; + } + + /** + * Multiplies this FDBigInteger by 10. The operation will be + * performed in place unless the FDBigInteger is immutable in + * which case a new FDBigInteger will be returned. + * + * @return The FDBigInteger multiplied by 10. + */ + /*@ + @ requires this.value() == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() > 0 && this.isImmutable; + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() * 10); + @ + @ also + @ + @ requires this.value() > 0 && !this.isImmutable; + @ assignable this.nWords, this.data, this.data[*]; + @ ensures \result == this; + @ ensures \result.value() == \old(this.value() * 10); + @*/ + public FDBigInteger multBy10() { + if (nWords == 0) { + return this; + } + if (isImmutable) { + int[] res = new int[nWords + 1]; + res[nWords] = multAndCarryBy10(data, nWords, res); + return new FDBigInteger(res, offset); + } else { + int p = multAndCarryBy10(this.data, this.nWords, this.data); + if (p != 0) { + if (nWords == data.length) { + if (data[0] == 0) { + System.arraycopy(data, 1, data, 0, --nWords); + offset++; + } else { + data = Arrays.copyOf(data, data.length + 1); + } + } + data[nWords++] = p; + } else { + trimLeadingZeros(); + } + return this; + } + } + + /** + * Multiplies this FDBigInteger by + * 5p5 * 2p2. The operation will be + * performed in place if possible, otherwise a new FDBigInteger + * will be returned. + * + * @param p5 The exponent of the power-of-five factor. + * @param p2 The exponent of the power-of-two factor. + * @return The multiplication result. + */ + /*@ + @ requires this.value() == 0 || p5 == 0 && p2 == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() > 0 && (p5 > 0 && p2 >= 0 || p5 == 0 && p2 > 0 && this.isImmutable); + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() * pow52(p5, p2)); + @ + @ also + @ + @ requires this.value() > 0 && p5 == 0 && p2 > 0 && !this.isImmutable; + @ assignable this.nWords, this.data, this.data[*]; + @ ensures \result == this; + @ ensures \result.value() == \old(this.value() * pow52(p5, p2)); + @*/ + public FDBigInteger multByPow52(int p5, int p2) { + if (this.nWords == 0) { + return this; + } + FDBigInteger res = this; + if (p5 != 0) { + int[] r; + int extraSize = (p2 != 0) ? 1 : 0; + if (p5 < SMALL_5_POW.length) { + r = new int[this.nWords + 1 + extraSize]; + mult(this.data, this.nWords, SMALL_5_POW[p5], r); + res = new FDBigInteger(r, this.offset); + } else { + FDBigInteger pow5 = big5pow(p5); + r = new int[this.nWords + pow5.size() + extraSize]; + mult(this.data, this.nWords, pow5.data, pow5.nWords, r); + res = new FDBigInteger(r, this.offset + pow5.offset); + } + } + return res.leftShift(p2); + } + + /** + * Multiplies two big integers represented as int arrays. + * + * @param s1 The first array factor. + * @param s1Len The number of elements of s1 to use. + * @param s2 The second array factor. + * @param s2Len The number of elements of s2 to use. + * @param dst The product array. + */ + /*@ + @ requires s1 != dst && s2 != dst; + @ requires s1.length >= s1Len && s2.length >= s2Len && dst.length >= s1Len + s2Len; + @ assignable dst[0 .. s1Len + s2Len - 1]; + @ ensures AP(dst, s1Len + s2Len) == \old(AP(s1, s1Len) * AP(s2, s2Len)); + @*/ + private static void mult(int[] s1, int s1Len, int[] s2, int s2Len, int[] dst) { + for (int i = 0; i < s1Len; i++) { + long v = s1[i] & LONG_MASK; + long p = 0L; + for (int j = 0; j < s2Len; j++) { + p += (dst[i + j] & LONG_MASK) + v * (s2[j] & LONG_MASK); + dst[i + j] = (int) p; + p >>>= 32; + } + dst[i + s2Len] = (int) p; + } + } + + /** + * Subtracts the supplied FDBigInteger subtrahend from this + * FDBigInteger. Assert that the result is positive. + * If the subtrahend is immutable, store the result in this(minuend). + * If this(minuend) is immutable a new FDBigInteger is created. + * + * @param subtrahend The FDBigInteger to be subtracted. + * @return This FDBigInteger less the subtrahend. + */ + /*@ + @ requires this.isImmutable; + @ requires this.value() >= subtrahend.value(); + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() - subtrahend.value()); + @ + @ also + @ + @ requires !subtrahend.isImmutable; + @ requires this.value() >= subtrahend.value(); + @ assignable this.nWords, this.offset, this.data, this.data[*]; + @ ensures \result == this; + @ ensures \result.value() == \old(this.value() - subtrahend.value()); + @*/ + public FDBigInteger leftInplaceSub(FDBigInteger subtrahend) { + assert this.size() >= subtrahend.size() : "result should be positive"; + FDBigInteger minuend; + if (this.isImmutable) { + minuend = new FDBigInteger(this.data.clone(), this.offset); + } else { + minuend = this; + } + int offsetDiff = subtrahend.offset - minuend.offset; + int[] sData = subtrahend.data; + int[] mData = minuend.data; + int subLen = subtrahend.nWords; + int minLen = minuend.nWords; + if (offsetDiff < 0) { + // need to expand minuend + int rLen = minLen - offsetDiff; + if (rLen < mData.length) { + System.arraycopy(mData, 0, mData, -offsetDiff, minLen); + Arrays.fill(mData, 0, -offsetDiff, 0); + } else { + int[] r = new int[rLen]; + System.arraycopy(mData, 0, r, -offsetDiff, minLen); + minuend.data = mData = r; + } + minuend.offset = subtrahend.offset; + minuend.nWords = minLen = rLen; + offsetDiff = 0; + } + long borrow = 0L; + int mIndex = offsetDiff; + for (int sIndex = 0; sIndex < subLen && mIndex < minLen; sIndex++, mIndex++) { + long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; + mData[mIndex] = (int) diff; + borrow = diff >> 32; // signed shift + } + for (; borrow != 0 && mIndex < minLen; mIndex++) { + long diff = (mData[mIndex] & LONG_MASK) + borrow; + mData[mIndex] = (int) diff; + borrow = diff >> 32; // signed shift + } + assert borrow == 0L : borrow; // borrow out of subtract, + // result should be positive + minuend.trimLeadingZeros(); + return minuend; + } + + /** + * Subtracts the supplied FDBigInteger subtrahend from this + * FDBigInteger. Assert that the result is positive. + * If the this(minuend) is immutable, store the result in subtrahend. + * If subtrahend is immutable a new FDBigInteger is created. + * + * @param subtrahend The FDBigInteger to be subtracted. + * @return This FDBigInteger less the subtrahend. + */ + /*@ + @ requires subtrahend.isImmutable; + @ requires this.value() >= subtrahend.value(); + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() - subtrahend.value()); + @ + @ also + @ + @ requires !subtrahend.isImmutable; + @ requires this.value() >= subtrahend.value(); + @ assignable subtrahend.nWords, subtrahend.offset, subtrahend.data, subtrahend.data[*]; + @ ensures \result == subtrahend; + @ ensures \result.value() == \old(this.value() - subtrahend.value()); + @*/ + public FDBigInteger rightInplaceSub(FDBigInteger subtrahend) { + assert this.size() >= subtrahend.size() : "result should be positive"; + FDBigInteger minuend = this; + if (subtrahend.isImmutable) { + subtrahend = new FDBigInteger(subtrahend.data.clone(), subtrahend.offset); + } + int offsetDiff = minuend.offset - subtrahend.offset; + int[] sData = subtrahend.data; + int[] mData = minuend.data; + int subLen = subtrahend.nWords; + int minLen = minuend.nWords; + if (offsetDiff < 0) { + int rLen = minLen; + if (rLen < sData.length) { + System.arraycopy(sData, 0, sData, -offsetDiff, subLen); + Arrays.fill(sData, 0, -offsetDiff, 0); + } else { + int[] r = new int[rLen]; + System.arraycopy(sData, 0, r, -offsetDiff, subLen); + subtrahend.data = sData = r; + } + subtrahend.offset = minuend.offset; + subLen -= offsetDiff; + offsetDiff = 0; + } else { + int rLen = minLen + offsetDiff; + if (rLen >= sData.length) { + subtrahend.data = sData = Arrays.copyOf(sData, rLen); + } + } + //@ assert minuend == this && minuend.value() == \old(this.value()); + //@ assert mData == minuend.data && minLen == minuend.nWords; + //@ assert subtrahend.offset + subtrahend.data.length >= minuend.size(); + //@ assert sData == subtrahend.data; + //@ assert AP(subtrahend.data, subtrahend.data.length) << subtrahend.offset == \old(subtrahend.value()); + //@ assert subtrahend.offset == Math.min(\old(this.offset), minuend.offset); + //@ assert offsetDiff == minuend.offset - subtrahend.offset; + //@ assert 0 <= offsetDiff && offsetDiff + minLen <= sData.length; + int sIndex = 0; + long borrow = 0L; + for (; sIndex < offsetDiff; sIndex++) { + long diff = 0L - (sData[sIndex] & LONG_MASK) + borrow; + sData[sIndex] = (int) diff; + borrow = diff >> 32; // signed shift + } + //@ assert sIndex == offsetDiff; + for (int mIndex = 0; mIndex < minLen; sIndex++, mIndex++) { + //@ assert sIndex == offsetDiff + mIndex; + long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; + sData[sIndex] = (int) diff; + borrow = diff >> 32; // signed shift + } + assert borrow == 0L : borrow; // borrow out of subtract, + // result should be positive + subtrahend.nWords = sIndex; + subtrahend.trimLeadingZeros(); + return subtrahend; + + } + + /** + * Determines whether all elements of an array are zero for all indices less + * than a given index. + * + * @param a The array to be examined. + * @param from The index strictly below which elements are to be examined. + * @return Zero if all elements in range are zero, 1 otherwise. + */ + /*@ + @ requires 0 <= from && from <= a.length; + @ ensures \result == (AP(a, from) == 0 ? 0 : 1); + @*/ + private /*@ pure @*/ static int checkZeroTail(int[] a, int from) { + while (from > 0) { + if (a[--from] != 0) { + return 1; + } + } + return 0; + } + + /** + * Compares the parameter with this FDBigInteger. Returns an + * integer accordingly as: + *
{@code
+     * > 0: this > other
+     *   0: this == other
+     * < 0: this < other
+     * }
+ * + * @param other The FDBigInteger to compare. + * @return A negative value, zero, or a positive value according to the + * result of the comparison. + */ + /*@ + @ ensures \result == (this.value() < other.value() ? -1 : this.value() > other.value() ? +1 : 0); + @*/ + public /*@ pure @*/ int cmp(FDBigInteger other) { + int aSize = nWords + offset; + int bSize = other.nWords + other.offset; + if (aSize > bSize) { + return 1; + } else if (aSize < bSize) { + return -1; + } + int aLen = nWords; + int bLen = other.nWords; + while (aLen > 0 && bLen > 0) { + int a = data[--aLen]; + int b = other.data[--bLen]; + if (a != b) { + return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; + } + } + if (aLen > 0) { + return checkZeroTail(data, aLen); + } + if (bLen > 0) { + return -checkZeroTail(other.data, bLen); + } + return 0; + } + + /** + * Compares this FDBigInteger with + * 5p5 * 2p2. + * Returns an integer accordingly as: + *
{@code
+     * > 0: this > other
+     *   0: this == other
+     * < 0: this < other
+     * }
+ * @param p5 The exponent of the power-of-five factor. + * @param p2 The exponent of the power-of-two factor. + * @return A negative value, zero, or a positive value according to the + * result of the comparison. + */ + /*@ + @ requires p5 >= 0 && p2 >= 0; + @ ensures \result == (this.value() < pow52(p5, p2) ? -1 : this.value() > pow52(p5, p2) ? +1 : 0); + @*/ + public /*@ pure @*/ int cmpPow52(int p5, int p2) { + if (p5 == 0) { + int wordcount = p2 >> 5; + int bitcount = p2 & 0x1f; + int size = this.nWords + this.offset; + if (size > wordcount + 1) { + return 1; + } else if (size < wordcount + 1) { + return -1; + } + int a = this.data[this.nWords -1]; + int b = 1 << bitcount; + if (a != b) { + return ( (a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; + } + return checkZeroTail(this.data, this.nWords - 1); + } + return this.cmp(big5pow(p5).leftShift(p2)); + } + + /** + * Compares this FDBigInteger with x + y. Returns a + * value according to the comparison as: + *
{@code
+     * -1: this <  x + y
+     *  0: this == x + y
+     *  1: this >  x + y
+     * }
+ * @param x The first addend of the sum to compare. + * @param y The second addend of the sum to compare. + * @return -1, 0, or 1 according to the result of the comparison. + */ + /*@ + @ ensures \result == (this.value() < x.value() + y.value() ? -1 : this.value() > x.value() + y.value() ? +1 : 0); + @*/ + public /*@ pure @*/ int addAndCmp(FDBigInteger x, FDBigInteger y) { + FDBigInteger big; + FDBigInteger small; + int xSize = x.size(); + int ySize = y.size(); + int bSize; + int sSize; + if (xSize >= ySize) { + big = x; + small = y; + bSize = xSize; + sSize = ySize; + } else { + big = y; + small = x; + bSize = ySize; + sSize = xSize; + } + int thSize = this.size(); + if (bSize == 0) { + return thSize == 0 ? 0 : 1; + } + if (sSize == 0) { + return this.cmp(big); + } + if (bSize > thSize) { + return -1; + } + if (bSize + 1 < thSize) { + return 1; + } + long top = (big.data[big.nWords - 1] & LONG_MASK); + if (sSize == bSize) { + top += (small.data[small.nWords - 1] & LONG_MASK); + } + if ((top >>> 32) == 0) { + if (((top + 1) >>> 32) == 0) { + // good case - no carry extension + if (bSize < thSize) { + return 1; + } + // here sum.nWords == this.nWords + long v = (this.data[this.nWords - 1] & LONG_MASK); + if (v < top) { + return -1; + } + if (v > top + 1) { + return 1; + } + } + } else { // (top>>>32)!=0 guaranteed carry extension + if (bSize + 1 > thSize) { + return -1; + } + // here sum.nWords == this.nWords + top >>>= 32; + long v = (this.data[this.nWords - 1] & LONG_MASK); + if (v < top) { + return -1; + } + if (v > top + 1) { + return 1; + } + } + return this.cmp(big.add(small)); + } + + /** + * Makes this FDBigInteger immutable. + */ + /*@ + @ assignable this.isImmutable; + @ ensures this.isImmutable; + @*/ + public void makeImmutable() { + this.isImmutable = true; + } + + /** + * Multiplies this FDBigInteger by an integer. + * + * @param i The factor by which to multiply this FDBigInteger. + * @return This FDBigInteger multiplied by an integer. + */ + /*@ + @ requires this.value() == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() != 0; + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() * UNSIGNED(i)); + @*/ + private FDBigInteger mult(int i) { + if (this.nWords == 0) { + return this; + } + int[] r = new int[nWords + 1]; + mult(data, nWords, i, r); + return new FDBigInteger(r, offset); + } + + /** + * Multiplies this FDBigInteger by another FDBigInteger. + * + * @param other The FDBigInteger factor by which to multiply. + * @return The product of this and the parameter FDBigIntegers. + */ + /*@ + @ requires this.value() == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() != 0 && other.value() == 0; + @ assignable \nothing; + @ ensures \result == other; + @ + @ also + @ + @ requires this.value() != 0 && other.value() != 0; + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() * other.value()); + @*/ + private FDBigInteger mult(FDBigInteger other) { + if (this.nWords == 0) { + return this; + } + if (this.size() == 1) { + return other.mult(data[0]); + } + if (other.nWords == 0) { + return other; + } + if (other.size() == 1) { + return this.mult(other.data[0]); + } + int[] r = new int[nWords + other.nWords]; + mult(this.data, this.nWords, other.data, other.nWords, r); + return new FDBigInteger(r, this.offset + other.offset); + } + + /** + * Adds another FDBigInteger to this FDBigInteger. + * + * @param other The FDBigInteger to add. + * @return The sum of the FDBigIntegers. + */ + /*@ + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() + other.value()); + @*/ + private FDBigInteger add(FDBigInteger other) { + FDBigInteger big, small; + int bigLen, smallLen; + int tSize = this.size(); + int oSize = other.size(); + if (tSize >= oSize) { + big = this; + bigLen = tSize; + small = other; + smallLen = oSize; + } else { + big = other; + bigLen = oSize; + small = this; + smallLen = tSize; + } + int[] r = new int[bigLen + 1]; + int i = 0; + long carry = 0L; + for (; i < smallLen; i++) { + carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ) + + ((i < small.offset ? 0L : (small.data[i - small.offset] & LONG_MASK))); + r[i] = (int) carry; + carry >>= 32; // signed shift. + } + for (; i < bigLen; i++) { + carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ); + r[i] = (int) carry; + carry >>= 32; // signed shift. + } + r[bigLen] = (int) carry; + return new FDBigInteger(r, 0); + } + + + /** + * Multiplies a FDBigInteger by an int and adds another int. The + * result is computed in place. This method is intended only to be invoked + * from + * + * FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) + * . + * + * @param iv The factor by which to multiply this FDBigInteger. + * @param addend The value to add to the product of this + * FDBigInteger and iv. + */ + /*@ + @ requires this.value()*UNSIGNED(iv) + UNSIGNED(addend) < ((\bigint)1) << ((this.data.length + this.offset)*32); + @ assignable this.data[*]; + @ ensures this.value() == \old(this.value()*UNSIGNED(iv) + UNSIGNED(addend)); + @*/ + private /*@ helper @*/ void multAddMe(int iv, int addend) { + long v = iv & LONG_MASK; + // unroll 0th iteration, doing addition. + long p = v * (data[0] & LONG_MASK) + (addend & LONG_MASK); + data[0] = (int) p; + p >>>= 32; + for (int i = 1; i < nWords; i++) { + p += v * (data[i] & LONG_MASK); + data[i] = (int) p; + p >>>= 32; + } + if (p != 0L) { + data[nWords++] = (int) p; // will fail noisily if illegal! + } + } + + // + // original doc: + // + // do this -=q*S + // returns borrow + // + /** + * Multiplies the parameters and subtracts them from this + * FDBigInteger. + * + * @param q The integer parameter. + * @param S The FDBigInteger parameter. + * @return this - q*S. + */ + /*@ + @ ensures nWords == 0 ==> offset == 0; + @ ensures nWords > 0 ==> data[nWords - 1] != 0; + @*/ + /*@ + @ requires 0 < q && q <= (1L << 31); + @ requires data != null; + @ requires 0 <= nWords && nWords <= data.length && offset >= 0; + @ requires !this.isImmutable; + @ requires this.size() == S.size(); + @ requires this != S; + @ assignable this.nWords, this.offset, this.data, this.data[*]; + @ ensures -q <= \result && \result <= 0; + @ ensures this.size() == \old(this.size()); + @ ensures this.value() + (\result << (this.size()*32)) == \old(this.value() - q*S.value()); + @ ensures this.offset == \old(Math.min(this.offset, S.offset)); + @ ensures \old(this.offset <= S.offset) ==> this.nWords == \old(this.nWords); + @ ensures \old(this.offset <= S.offset) ==> this.offset == \old(this.offset); + @ ensures \old(this.offset <= S.offset) ==> this.data == \old(this.data); + @ + @ also + @ + @ requires q == 0; + @ assignable \nothing; + @ ensures \result == 0; + @*/ + private /*@ helper @*/ long multDiffMe(long q, FDBigInteger S) { + long diff = 0L; + if (q != 0) { + int deltaSize = S.offset - this.offset; + if (deltaSize >= 0) { + int[] sd = S.data; + int[] td = this.data; + for (int sIndex = 0, tIndex = deltaSize; sIndex < S.nWords; sIndex++, tIndex++) { + diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); + td[tIndex] = (int) diff; + diff >>= 32; // N.B. SIGNED shift. + } + } else { + deltaSize = -deltaSize; + int[] rd = new int[nWords + deltaSize]; + int sIndex = 0; + int rIndex = 0; + int[] sd = S.data; + for (; rIndex < deltaSize && sIndex < S.nWords; sIndex++, rIndex++) { + diff -= q * (sd[sIndex] & LONG_MASK); + rd[rIndex] = (int) diff; + diff >>= 32; // N.B. SIGNED shift. + } + int tIndex = 0; + int[] td = this.data; + for (; sIndex < S.nWords; sIndex++, tIndex++, rIndex++) { + diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); + rd[rIndex] = (int) diff; + diff >>= 32; // N.B. SIGNED shift. + } + this.nWords += deltaSize; + this.offset -= deltaSize; + this.data = rd; + } + } + return diff; + } + + + /** + * Multiplies by 10 a big integer represented as an array. The final carry + * is returned. + * + * @param src The array representation of the big integer. + * @param srcLen The number of elements of src to use. + * @param dst The product array. + * @return The final carry of the multiplication. + */ + /*@ + @ requires src.length >= srcLen && dst.length >= srcLen; + @ assignable dst[0 .. srcLen - 1]; + @ ensures 0 <= \result && \result < 10; + @ ensures AP(dst, srcLen) + (\result << (srcLen*32)) == \old(AP(src, srcLen) * 10); + @*/ + private static int multAndCarryBy10(int[] src, int srcLen, int[] dst) { + long carry = 0; + for (int i = 0; i < srcLen; i++) { + long product = (src[i] & LONG_MASK) * 10L + carry; + dst[i] = (int) product; + carry = product >>> 32; + } + return (int) carry; + } + + /** + * Multiplies by a constant value a big integer represented as an array. + * The constant factor is an int. + * + * @param src The array representation of the big integer. + * @param srcLen The number of elements of src to use. + * @param value The constant factor by which to multiply. + * @param dst The product array. + */ + /*@ + @ requires src.length >= srcLen && dst.length >= srcLen + 1; + @ assignable dst[0 .. srcLen]; + @ ensures AP(dst, srcLen + 1) == \old(AP(src, srcLen) * UNSIGNED(value)); + @*/ + private static void mult(int[] src, int srcLen, int value, int[] dst) { + long val = value & LONG_MASK; + long carry = 0; + for (int i = 0; i < srcLen; i++) { + long product = (src[i] & LONG_MASK) * val + carry; + dst[i] = (int) product; + carry = product >>> 32; + } + dst[srcLen] = (int) carry; + } + + /** + * Multiplies by a constant value a big integer represented as an array. + * The constant factor is a long represent as two ints. + * + * @param src The array representation of the big integer. + * @param srcLen The number of elements of src to use. + * @param v0 The lower 32 bits of the long factor. + * @param v1 The upper 32 bits of the long factor. + * @param dst The product array. + */ + /*@ + @ requires src != dst; + @ requires src.length >= srcLen && dst.length >= srcLen + 2; + @ assignable dst[0 .. srcLen + 1]; + @ ensures AP(dst, srcLen + 2) == \old(AP(src, srcLen) * (UNSIGNED(v0) + (UNSIGNED(v1) << 32))); + @*/ + private static void mult(int[] src, int srcLen, int v0, int v1, int[] dst) { + long v = v0 & LONG_MASK; + long carry = 0; + for (int j = 0; j < srcLen; j++) { + long product = v * (src[j] & LONG_MASK) + carry; + dst[j] = (int) product; + carry = product >>> 32; + } + dst[srcLen] = (int) carry; + v = v1 & LONG_MASK; + carry = 0; + for (int j = 0; j < srcLen; j++) { + long product = (dst[j + 1] & LONG_MASK) + v * (src[j] & LONG_MASK) + carry; + dst[j + 1] = (int) product; + carry = product >>> 32; + } + dst[srcLen + 1] = (int) carry; + } + + // Fails assertion for negative exponent. + /** + * Computes 5 raised to a given power. + * + * @param p The exponent of 5. + * @return 5p. + */ + private static FDBigInteger big5pow(int p) { + assert p >= 0 : p; // negative power of 5 + if (p < MAX_FIVE_POW) { + return POW_5_CACHE[p]; + } + return big5powRec(p); + } + + // slow path + /** + * Computes 5 raised to a given power. + * + * @param p The exponent of 5. + * @return 5p. + */ + private static FDBigInteger big5powRec(int p) { + if (p < MAX_FIVE_POW) { + return POW_5_CACHE[p]; + } + // construct the value. + // recursively. + int q, r; + // in order to compute 5^p, + // compute its square root, 5^(p/2) and square. + // or, let q = p / 2, r = p -q, then + // 5^p = 5^(q+r) = 5^q * 5^r + q = p >> 1; + r = p - q; + FDBigInteger bigq = big5powRec(q); + if (r < SMALL_5_POW.length) { + return bigq.mult(SMALL_5_POW[r]); + } else { + return bigq.mult(big5powRec(r)); + } + } + + // for debugging ... + /** + * Converts this FDBigInteger to a hexadecimal string. + * + * @return The hexadecimal string representation. + */ + public String toHexString(){ + if(nWords ==0) { + return "0"; + } + StringBuilder sb = new StringBuilder((nWords +offset)*8); + for(int i= nWords -1; i>=0; i--) { + String subStr = Integer.toHexString(data[i]); + for(int j = subStr.length(); j<8; j++) { + sb.append('0'); + } + sb.append(subStr); + } + for(int i=offset; i>0; i--) { + sb.append("00000000"); + } + return sb.toString(); + } + + // for debugging ... + /** + * Converts this FDBigInteger to a BigInteger. + * + * @return The BigInteger representation. + */ + public BigInteger toBigInteger() { + byte[] magnitude = new byte[nWords * 4 + 1]; + for (int i = 0; i < nWords; i++) { + int w = data[i]; + magnitude[magnitude.length - 4 * i - 1] = (byte) w; + magnitude[magnitude.length - 4 * i - 2] = (byte) (w >> 8); + magnitude[magnitude.length - 4 * i - 3] = (byte) (w >> 16); + magnitude[magnitude.length - 4 * i - 4] = (byte) (w >> 24); + } + return new BigInteger(magnitude).shiftLeft(offset * 32); + } + + // for debugging ... + /** + * Converts this FDBigInteger to a string. + * + * @return The string representation. + */ + @Override + public String toString(){ + return toBigInteger().toString(); + } +} diff --git a/tests/test_data/std/jdk/internal/math/FloatConsts.class b/tests/test_data/std/jdk/internal/math/FloatConsts.class new file mode 100644 index 0000000000000000000000000000000000000000..3fa6e0215ab0ace23e0783a5c0edaa9ec7094f8c GIT binary patch literal 646 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 outcome is the same as if {@code v} were first + * {@link #toString(float) rendered} and the resulting string were then + * {@link Appendable#append(CharSequence) appended} to {@code app}. + * + * @param v the {@code float} whose rendering is appended. + * @param app the {@link Appendable} to append to. + * @throws IOException If an I/O error occurs + */ + public static Appendable appendTo(float v, Appendable app) + throws IOException { + return new FloatToDecimal().appendDecimalTo(v, app); + } + + private String toDecimalString(float v) { + return switch (toDecimal(v)) { + case NON_SPECIAL -> charsToString(); + case PLUS_ZERO -> "0.0"; + case MINUS_ZERO -> "-0.0"; + case PLUS_INF -> "Infinity"; + case MINUS_INF -> "-Infinity"; + default -> "NaN"; + }; + } + + private Appendable appendDecimalTo(float v, Appendable app) + throws IOException { + switch (toDecimal(v)) { + case NON_SPECIAL: + char[] chars = new char[index + 1]; + for (int i = 0; i < chars.length; ++i) { + chars[i] = (char) bytes[i]; + } + if (app instanceof StringBuilder builder) { + return builder.append(chars); + } + if (app instanceof StringBuffer buffer) { + return buffer.append(chars); + } + for (char c : chars) { + app.append(c); + } + return app; + case PLUS_ZERO: return app.append("0.0"); + case MINUS_ZERO: return app.append("-0.0"); + case PLUS_INF: return app.append("Infinity"); + case MINUS_INF: return app.append("-Infinity"); + default: return app.append("NaN"); + } + } + + /* + * Returns + * PLUS_ZERO iff v is 0.0 + * MINUS_ZERO iff v is -0.0 + * PLUS_INF iff v is POSITIVE_INFINITY + * MINUS_INF iff v is NEGATIVE_INFINITY + * NAN iff v is NaN + */ + private int toDecimal(float v) { + /* + * For full details see references [2] and [1]. + * + * For finite v != 0, determine integers c and q such that + * |v| = c 2^q and + * Q_MIN <= q <= Q_MAX and + * either 2^(P-1) <= c < 2^P (normal) + * or 0 < c < 2^(P-1) and q = Q_MIN (subnormal) + */ + int bits = floatToRawIntBits(v); + int t = bits & T_MASK; + int bq = (bits >>> P - 1) & BQ_MASK; + if (bq < BQ_MASK) { + index = -1; + if (bits < 0) { + append('-'); + } + if (bq != 0) { + /* normal value. Here mq = -q */ + int mq = -Q_MIN + 1 - bq; + int c = C_MIN | t; + /* The fast path discussed in section 8.3 of [1] */ + if (0 < mq & mq < P) { + int f = c >> mq; + if (f << mq == c) { + return toChars(f, 0); + } + } + return toDecimal(-mq, c, 0); + } + if (t != 0) { + /* subnormal value */ + return t < C_TINY + ? toDecimal(Q_MIN, 10 * t, -1) + : toDecimal(Q_MIN, t, 0); + } + return bits == 0 ? PLUS_ZERO : MINUS_ZERO; + } + if (t != 0) { + return NAN; + } + return bits > 0 ? PLUS_INF : MINUS_INF; + } + + private int toDecimal(int q, int c, int dk) { + /* + * The skeleton corresponds to figure 7 of [1]. + * The efficient computations are those summarized in figure 9. + * Also check the appendix. + * + * Here's a correspondence between Java names and names in [1], + * expressed as approximate LaTeX source code and informally. + * Other names are identical. + * cb: \bar{c} "c-bar" + * cbr: \bar{c}_r "c-bar-r" + * cbl: \bar{c}_l "c-bar-l" + * + * vb: \bar{v} "v-bar" + * vbr: \bar{v}_r "v-bar-r" + * vbl: \bar{v}_l "v-bar-l" + * + * rop: r_o' "r-o-prime" + */ + int out = c & 0x1; + long cb = c << 2; + long cbr = cb + 2; + long cbl; + int k; + /* + * flog10pow2(e) = floor(log_10(2^e)) + * flog10threeQuartersPow2(e) = floor(log_10(3/4 2^e)) + * flog2pow10(e) = floor(log_2(10^e)) + */ + if (c != C_MIN | q == Q_MIN) { + /* regular spacing */ + cbl = cb - 2; + k = flog10pow2(q); + } else { + /* irregular spacing */ + cbl = cb - 1; + k = flog10threeQuartersPow2(q); + } + int h = q + flog2pow10(-k) + 33; + + /* g is as in the appendix */ + long g = g1(k) + 1; + + int vb = rop(g, cb << h); + int vbl = rop(g, cbl << h); + int vbr = rop(g, cbr << h); + + int s = vb >> 2; + if (s >= 100) { + /* + * For n = 9, m = 1 the table in section 10 of [1] shows + * s' = floor(s / 10) = floor(s 1_717_986_919 / 2^34) + * + * sp10 = 10 s' + * tp10 = 10 t' + * upin iff u' = sp10 10^k in Rv + * wpin iff w' = tp10 10^k in Rv + * See section 9.3 of [1]. + */ + int sp10 = 10 * (int) (s * 1_717_986_919L >>> 34); + int tp10 = sp10 + 10; + boolean upin = vbl + out <= sp10 << 2; + boolean wpin = (tp10 << 2) + out <= vbr; + if (upin != wpin) { + return toChars(upin ? sp10 : tp10, k); + } + } + + /* + * 10 <= s < 100 or s >= 100 and u', w' not in Rv + * uin iff u = s 10^k in Rv + * win iff w = t 10^k in Rv + * See section 9.3 of [1]. + */ + int t = s + 1; + boolean uin = vbl + out <= s << 2; + boolean win = (t << 2) + out <= vbr; + if (uin != win) { + /* Exactly one of u or w lies in Rv */ + return toChars(uin ? s : t, k + dk); + } + /* + * Both u and w lie in Rv: determine the one closest to v. + * See section 9.3 of [1]. + */ + int cmp = vb - (s + t << 1); + return toChars(cmp < 0 || cmp == 0 && (s & 0x1) == 0 ? s : t, k + dk); + } + + /* + * Computes rop(cp g 2^(-95)) + * See appendix and figure 11 of [1]. + */ + private static int rop(long g, long cp) { + long x1 = multiplyHigh(g, cp); + long vbp = x1 >>> 31; + return (int) (vbp | (x1 & MASK_32) + MASK_32 >>> 32); + } + + /* + * Formats the decimal f 10^e. + */ + private int toChars(int f, int e) { + /* + * For details not discussed here see section 10 of [1]. + * + * Determine len such that + * 10^(len-1) <= f < 10^len + */ + int len = flog10pow2(Integer.SIZE - numberOfLeadingZeros(f)); + if (f >= pow10(len)) { + len += 1; + } + + /* + * Let fp and ep be the original f and e, respectively. + * Transform f and e to ensure + * 10^(H-1) <= f < 10^H + * fp 10^ep = f 10^(e-H) = 0.f 10^e + */ + f *= (int)pow10(H - len); + e += len; + + /* + * The toChars?() methods perform left-to-right digits extraction + * using ints, provided that the arguments are limited to 8 digits. + * Therefore, split the H = 9 digits of f into: + * h = the most significant digit of f + * l = the last 8, least significant digits of f + * + * For n = 9, m = 8 the table in section 10 of [1] shows + * floor(f / 10^8) = floor(1_441_151_881 f / 2^57) + */ + int h = (int) (f * 1_441_151_881L >>> 57); + int l = f - 100_000_000 * h; + + if (0 < e && e <= 7) { + return toChars1(h, l, e); + } + if (-3 < e && e <= 0) { + return toChars2(h, l, e); + } + return toChars3(h, l, e); + } + + private int toChars1(int h, int l, int e) { + /* + * 0 < e <= 7: plain format without leading zeroes. + * Left-to-right digits extraction: + * algorithm 1 in [3], with b = 10, k = 8, n = 28. + */ + appendDigit(h); + int y = y(l); + int t; + int i = 1; + for (; i < e; ++i) { + t = 10 * y; + appendDigit(t >>> 28); + y = t & MASK_28; + } + append('.'); + for (; i <= 8; ++i) { + t = 10 * y; + appendDigit(t >>> 28); + y = t & MASK_28; + } + removeTrailingZeroes(); + return NON_SPECIAL; + } + + private int toChars2(int h, int l, int e) { + /* -3 < e <= 0: plain format with leading zeroes */ + appendDigit(0); + append('.'); + for (; e < 0; ++e) { + appendDigit(0); + } + appendDigit(h); + append8Digits(l); + removeTrailingZeroes(); + return NON_SPECIAL; + } + + private int toChars3(int h, int l, int e) { + /* -3 >= e | e > 7: computerized scientific notation */ + appendDigit(h); + append('.'); + append8Digits(l); + removeTrailingZeroes(); + exponent(e - 1); + return NON_SPECIAL; + } + + private void append8Digits(int m) { + /* + * Left-to-right digits extraction: + * algorithm 1 in [3], with b = 10, k = 8, n = 28. + */ + int y = y(m); + for (int i = 0; i < 8; ++i) { + int t = 10 * y; + appendDigit(t >>> 28); + y = t & MASK_28; + } + } + + private void removeTrailingZeroes() { + while (bytes[index] == '0') { + --index; + } + /* ... but do not remove the one directly to the right of '.' */ + if (bytes[index] == '.') { + ++index; + } + } + + private int y(int a) { + /* + * Algorithm 1 in [3] needs computation of + * floor((a + 1) 2^n / b^k) - 1 + * with a < 10^8, b = 10, k = 8, n = 28. + * Noting that + * (a + 1) 2^n <= 10^8 2^28 < 10^17 + * For n = 17, m = 8 the table in section 10 of [1] leads to: + */ + return (int) (multiplyHigh( + (long) (a + 1) << 28, + 193_428_131_138_340_668L) >>> 20) - 1; + } + + private void exponent(int e) { + append('E'); + if (e < 0) { + append('-'); + e = -e; + } + if (e < 10) { + appendDigit(e); + return; + } + /* + * For n = 2, m = 1 the table in section 10 of [1] shows + * floor(e / 10) = floor(103 e / 2^10) + */ + int d = e * 103 >>> 10; + appendDigit(d); + appendDigit(e - 10 * d); + } + + private void append(int c) { + bytes[++index] = (byte) c; + } + + private void appendDigit(int d) { + bytes[++index] = (byte) ('0' + d); + } + + /* Using the deprecated constructor enhances performance */ + @SuppressWarnings("deprecation") + private String charsToString() { + return new String(bytes, 0, 0, index + 1); + } + +} diff --git a/tests/test_data/std/jdk/internal/math/FloatingDecimal$1.class b/tests/test_data/std/jdk/internal/math/FloatingDecimal$1.class new file mode 100644 index 0000000000000000000000000000000000000000..dda8ceae6b0d67a18546456d352bac3d8572cea0 GIT binary patch literal 862 zcma)4T}vB56g`t&-F3TG8>9WuwwAV_eduDL4@D7btTYg{kPztOWHTm{PG(_tw$Ojo zzEo(zAK;_l-zmMbN*g2)7k2KQGxyx@^FP1N0MxM_p#m>}A7ciy49i3Ql_!epe$pNo z!F$at<%(f;M`~$z8N7|nPJoc%?XdSHk=hEQxk^Ud4w3_vaVvFyU!-!x)r&o;x%t-4 z-nZ(F#$Iu9B20t;UW7Y{1I)*`iv@<~(>-l5#4Z8JRfnrWFudE?Y)pS_@NGJkJF+Wobe_Sf}w;XuAN9ep)LqERvRxWDa?C3igAP3hvSAp5a}f zN_u={fF;!E=DYnM#F5{SwIheW5qv(y+;`H)`Ilq-@QS~Eq literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/math/FloatingDecimal$ASCIIToBinaryBuffer.class b/tests/test_data/std/jdk/internal/math/FloatingDecimal$ASCIIToBinaryBuffer.class new file mode 100644 index 0000000000000000000000000000000000000000..dbfae36d118e8b6ea753b17361fee5b74e051692 GIT binary patch literal 8383 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 JjIzk#`hU_+tFr(A literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/math/FloatingDecimal$BinaryToASCIIConverter.class b/tests/test_data/std/jdk/internal/math/FloatingDecimal$BinaryToASCIIConverter.class new file mode 100644 index 0000000000000000000000000000000000000000..8fabf9f13d934bc8436c5dd9489fef7d886e832f GIT binary patch literal 534 zcmaixK~KU!5QX2OP^ch?fO0hP02g~T;e-`pjlo3FgPs<;sf%T|X%~Wj&4WL{A7z{t z5{)tOvR^Vg`)1zTkI%Pv04~}Vat!Bl|HYBYh*qPg*uIIU0twc=i7IqnGbH3tE$W`FnPUm7~80tn}Q*o$c5*wSCgcur~?#*}WrrKjD z@+cC@pJ;}5=SM?7EAwe6dff+-420P(GgwDj2}N^uI$e*UlwQd|nuH@`ZmN(F}j%b|W@e^VEwy*2{P%hB73j#;;t? zQbXinBocF_6Jw#paPn`Q3}sI#5xXHz5J~Z7>85JGzhcc+%azJpYki&D z3`z28aE9#Ce(I`g6GBNOJDx!gdKqNhS>_Ew-X>pmM?#ii@NmRjOE)xb%jiRY1_Q`Z z^=h-pO^xAVzCFQMn<+pjNf=_twd0GLWenn!fPao*;(wxwIFHZi49*BXCq`Ar;kIau zGp{@9n!z;*3d7KT(%C(a1>3eL?OAbC&ohkdyHpH=x?;@Qjn)=7-LTndyudIXZdF6s zR*e={G>bcmX}QXVy3G~URQOKQGAUBV2rdW_e$ql)$yF(^FowYbR%GZ6=dZt7_L-VL?6N3p@(U1uh z=kJ!s$d>Yz!w|b$CNSNJP^1p}r?-6J+-?#<%^xs6&VtYiF`23x!L*XAR?DvQMP0PJ z|Ik#rB=kY<%iM9VSq?>JDyGS8Pb{47Agam^4W>36u!dTILNhA{hAW68D~2SE*_aq% zK<|)v`m~qnJc-xn`#SAb#RR6cr?3lF7=H+)c;vJU#zLEn0ktbLzi_&$z3#@W?foO>ep#J!ZK zC@JtGB>aRNe#UA1f(iUeiGK6S$oZ*4UM2cJHBW^sP*f7}+(0*N7V%b4+a$pXV)A2* ztY$}dasCPIqU?T;u#-b}*H8%%rU^l?^AW~6Ap8+2Y!5-)<8{1E7$i?z4zQwa?*8ad zA%8{+Nrr_ig~1aZ7!{v59QjuyG8RVO2qO literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/math/FloatingDecimal$HexFloatPattern.class b/tests/test_data/std/jdk/internal/math/FloatingDecimal$HexFloatPattern.class new file mode 100644 index 0000000000000000000000000000000000000000..3d4f843f06b03d95fb5f5520f78d1075b2cec978 GIT binary patch literal 753 zcmb7C+iuf95Ivhq?HJRP&{E2!5X6Jss&y+KQxR1OQIV`tsWhsT=3(P3>4uFR*_$d7 z@KJ~d5D$C+AB8%08wy1TAxk?uXJ*cv9nbe4U%vrp;E9DC@&*bvikM?q81ggjDIN~I zSG}PKG{fAE45fa~kayg+36r7gbT-zzZhfmWJ?=V=b25H++>`^UKdiean|1g7uh1Gn zzh$^?XM8ZDNF%e-&YM=h*{xf!aKnIY<0j@AmNP{YEtMCGftY#+Tx$`B3`P)*#!?A} z4adLIeW+s@4r=ZN^k-qMgazC(P_c0viwxVt{##FmDJNIni0f0Yr6R70q$vV9;_B(1 zm}bz=*2VU&fAoT3<*!W`3XP~w+RDBR#r|Z}6Y*=_OVw8VDB!BiW10GwU_qbCgyEV0 z-)d?M=1!n4f0A_=P2xbbvbii?d&p)wB}(5HiQbD6ZQv0@^`9LX?3ZCE;)dc$B1mQV z+CcD_Mw+9AVz`$Mm2NruXrl;OBF`hs$QIW=gMG}xcj!#RFiTjbyM2*>yI3L5B%)by oHH!eHitz=dPbjAZ3|9p6$m2d?IXu9_%&w9m&>qo3V-;0c=Tb$wIsgCw literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/math/FloatingDecimal$PreparedASCIIToBinaryBuffer.class b/tests/test_data/std/jdk/internal/math/FloatingDecimal$PreparedASCIIToBinaryBuffer.class new file mode 100644 index 0000000000000000000000000000000000000000..5a856fe09002cdb9d59ab69f7d3731f2a38e0a90 GIT binary patch literal 856 zcmah{%Wl&^6g@Y#<0N&P)|B#w6k5?{fwxG!L>*Z~iV9MzNL@~nN$cQ@(ZsIAPl1rA zkXY~m{0)x<8xVJ#P>HH)HuucEGv}WBn6H06e*q9;vxX8Z7q$lnWy11E9E%_k>M(fO z8_9k~C_j!>oINF2Tie|#DyX`sd02o)crqHi4q}x_twa)xMRpWKNh-2f9kygY9*bn- zm6mUWmV@VeVY|Jb?!-#yw>$Z8C^exvNb_DIyCNY_%Oqd&P{%T%GBkOn7m*8}@NmA? ze;Q$`j-}?(2+me3+U^qUFdaxjy%Q_Bn~!@^?+cbE_?@&blCIFP@n=ChJBlZSXPx=N z7c}{ZuyERC&RRUi7NPd9zgZ~a&|aGBzKmj1(dwBwJ}`^nvFyr8_9C5RF4hU_b1Nfw zZKb3R6ET@c?&ih?r4rW8pCB5%nGy&qY<;tO{ye@}6r;s)2bb8cvUk9~%~)@K0yXcS zz-?}xVDSToO1R9{H`mrT*w%MctshvjeqxQ|4JI-TS8$cloQw<=CnIEJuHpJjCMe1Q zoaRTk@A=U*dD#%GUq!+x*_kEe&T;dU%)gB}hP?Rh4EgstWDB>7SGRGezy|Iz`Yc-E Ny6>@FVcaNJ{sJ>Kx-$R( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/math/FloatingDecimal.class b/tests/test_data/std/jdk/internal/math/FloatingDecimal.class new file mode 100644 index 0000000000000000000000000000000000000000..104958700c0ffab3ba8409dc0abe46b2d9f20ea6 GIT binary patch literal 13417 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 + * instance may be obtained and reused. + */ +public class FloatingDecimal{ + // + // Constants of the implementation; + // most are IEEE-754 related. + // (There are more really boring constants at the end.) + // + static final int EXP_SHIFT = DoubleConsts.SIGNIFICAND_WIDTH - 1; + static final long FRACT_HOB = ( 1L<String. + * + * @param d The double precision value. + * @return The value converted to a String. + */ + public static String toJavaFormatString(double d) { + return getBinaryToASCIIConverter(d).toJavaFormatString(); + } + + /** + * Converts a single precision floating point value to a String. + * + * @param f The single precision value. + * @return The value converted to a String. + */ + public static String toJavaFormatString(float f) { + return getBinaryToASCIIConverter(f).toJavaFormatString(); + } + + /** + * Appends a double precision floating point value to an Appendable. + * @param d The double precision value. + * @param buf The Appendable with the value appended. + */ + public static void appendTo(double d, Appendable buf) { + getBinaryToASCIIConverter(d).appendTo(buf); + } + + /** + * Appends a single precision floating point value to an Appendable. + * @param f The single precision value. + * @param buf The Appendable with the value appended. + */ + public static void appendTo(float f, Appendable buf) { + getBinaryToASCIIConverter(f).appendTo(buf); + } + + /** + * Converts a String to a double precision floating point value. + * + * @param s The String to convert. + * @return The double precision value. + * @throws NumberFormatException If the String does not + * represent a properly formatted double precision value. + */ + public static double parseDouble(String s) throws NumberFormatException { + return readJavaFormatString(s).doubleValue(); + } + + /** + * Converts a String to a single precision floating point value. + * + * @param s The String to convert. + * @return The single precision value. + * @throws NumberFormatException If the String does not + * represent a properly formatted single precision value. + */ + public static float parseFloat(String s) throws NumberFormatException { + return readJavaFormatString(s).floatValue(); + } + + /** + * A converter which can process single or double precision floating point + * values into an ASCII String representation. + */ + public interface BinaryToASCIIConverter { + /** + * Converts a floating point value into an ASCII String. + * @return The value converted to a String. + */ + String toJavaFormatString(); + + /** + * Appends a floating point value to an Appendable. + * @param buf The Appendable to receive the value. + */ + void appendTo(Appendable buf); + + /** + * Retrieves the decimal exponent most closely corresponding to this value. + * @return The decimal exponent. + */ + int getDecimalExponent(); + + /** + * Retrieves the value as an array of digits. + * @param digits The digit array. + * @return The number of valid digits copied into the array. + */ + int getDigits(char[] digits); + + /** + * Indicates the sign of the value. + * @return {@code value < 0.0}. + */ + boolean isNegative(); + + /** + * Indicates whether the value is either infinite or not a number. + * + * @return true if and only if the value is NaN + * or infinite. + */ + boolean isExceptional(); + + /** + * Indicates whether the value was rounded up during the binary to ASCII + * conversion. + * + * @return true if and only if the value was rounded up. + */ + boolean digitsRoundedUp(); + + /** + * Indicates whether the binary to ASCII conversion was exact. + * + * @return true if any only if the conversion was exact. + */ + boolean decimalDigitsExact(); + } + + /** + * A BinaryToASCIIConverter which represents NaN + * and infinite values. + */ + private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter { + private final String image; + private boolean isNegative; + + public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) { + this.image = image; + this.isNegative = isNegative; + } + + @Override + public String toJavaFormatString() { + return image; + } + + @Override + public void appendTo(Appendable buf) { + if (buf instanceof StringBuilder) { + ((StringBuilder) buf).append(image); + } else if (buf instanceof StringBuffer) { + ((StringBuffer) buf).append(image); + } else { + assert false; + } + } + + @Override + public int getDecimalExponent() { + throw new IllegalArgumentException("Exceptional value does not have an exponent"); + } + + @Override + public int getDigits(char[] digits) { + throw new IllegalArgumentException("Exceptional value does not have digits"); + } + + @Override + public boolean isNegative() { + return isNegative; + } + + @Override + public boolean isExceptional() { + return true; + } + + @Override + public boolean digitsRoundedUp() { + throw new IllegalArgumentException("Exceptional value is not rounded"); + } + + @Override + public boolean decimalDigitsExact() { + throw new IllegalArgumentException("Exceptional value is not exact"); + } + } + + private static final String INFINITY_REP = "Infinity"; + private static final int INFINITY_LENGTH = INFINITY_REP.length(); + private static final String NAN_REP = "NaN"; + private static final int NAN_LENGTH = NAN_REP.length(); + + private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false); + private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true); + private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false); + private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'}); + private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new char[]{'0'}); + + /** + * A buffered implementation of BinaryToASCIIConverter. + */ + static class BinaryToASCIIBuffer implements BinaryToASCIIConverter { + private boolean isNegative; + private int decExponent; + private int firstDigitIndex; + private int nDigits; + private final char[] digits; + private final char[] buffer = new char[26]; + + // + // The fields below provide additional information about the result of + // the binary to decimal digits conversion done in dtoa() and roundup() + // methods. They are changed if needed by those two methods. + // + + // True if the dtoa() binary to decimal conversion was exact. + private boolean exactDecimalConversion = false; + + // True if the result of the binary to decimal conversion was rounded-up + // at the end of the conversion process, i.e. roundUp() method was called. + private boolean decimalDigitsRoundedUp = false; + + /** + * Default constructor; used for non-zero values, + * BinaryToASCIIBuffer may be thread-local and reused + */ + BinaryToASCIIBuffer(){ + this.digits = new char[20]; + } + + /** + * Creates a specialized value (positive and negative zeros). + */ + BinaryToASCIIBuffer(boolean isNegative, char[] digits){ + this.isNegative = isNegative; + this.decExponent = 0; + this.digits = digits; + this.firstDigitIndex = 0; + this.nDigits = digits.length; + } + + @Override + public String toJavaFormatString() { + int len = getChars(buffer); + return new String(buffer, 0, len); + } + + @Override + public void appendTo(Appendable buf) { + int len = getChars(buffer); + if (buf instanceof StringBuilder) { + ((StringBuilder) buf).append(buffer, 0, len); + } else if (buf instanceof StringBuffer) { + ((StringBuffer) buf).append(buffer, 0, len); + } else { + assert false; + } + } + + @Override + public int getDecimalExponent() { + return decExponent; + } + + @Override + public int getDigits(char[] digits) { + System.arraycopy(this.digits, firstDigitIndex, digits, 0, this.nDigits); + return this.nDigits; + } + + @Override + public boolean isNegative() { + return isNegative; + } + + @Override + public boolean isExceptional() { + return false; + } + + @Override + public boolean digitsRoundedUp() { + return decimalDigitsRoundedUp; + } + + @Override + public boolean decimalDigitsExact() { + return exactDecimalConversion; + } + + private void setSign(boolean isNegative) { + this.isNegative = isNegative; + } + + /** + * This is the easy subcase -- + * all the significant bits, after scaling, are held in lvalue. + * negSign and decExponent tell us what processing and scaling + * has already been done. Exceptional cases have already been + * stripped out. + * In particular: + * lvalue is a finite number (not Inf, nor NaN) + * lvalue > 0L (not zero, nor negative). + * + * The only reason that we develop the digits here, rather than + * calling on Long.toString() is that we can do it a little faster, + * and besides want to treat trailing 0s specially. If Long.toString + * changes, we should re-evaluate this strategy! + */ + private void developLongDigits( int decExponent, long lvalue, int insignificantDigits ){ + if ( insignificantDigits != 0 ){ + // Discard non-significant low-order bits, while rounding, + // up to insignificant value. + long pow10 = FDBigInteger.LONG_5_POW[insignificantDigits] << insignificantDigits; // 10^i == 5^i * 2^i; + long residue = lvalue % pow10; + lvalue /= pow10; + decExponent += insignificantDigits; + if ( residue >= (pow10>>1) ){ + // round up based on the low-order bits we're discarding + lvalue++; + } + } + int digitno = digits.length -1; + int c; + if ( lvalue <= Integer.MAX_VALUE ){ + assert lvalue > 0L : lvalue; // lvalue <= 0 + // even easier subcase! + // can do int arithmetic rather than long! + int ivalue = (int)lvalue; + c = ivalue%10; + ivalue /= 10; + while ( c == 0 ){ + decExponent++; + c = ivalue%10; + ivalue /= 10; + } + while ( ivalue != 0){ + digits[digitno--] = (char)(c+'0'); + decExponent++; + c = ivalue%10; + ivalue /= 10; + } + digits[digitno] = (char)(c+'0'); + } else { + // same algorithm as above (same bugs, too ) + // but using long arithmetic. + c = (int)(lvalue%10L); + lvalue /= 10L; + while ( c == 0 ){ + decExponent++; + c = (int)(lvalue%10L); + lvalue /= 10L; + } + while ( lvalue != 0L ){ + digits[digitno--] = (char)(c+'0'); + decExponent++; + c = (int)(lvalue%10L); + lvalue /= 10; + } + digits[digitno] = (char)(c+'0'); + } + this.decExponent = decExponent+1; + this.firstDigitIndex = digitno; + this.nDigits = this.digits.length - digitno; + } + + private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat) + { + assert fractBits > 0 ; // fractBits here can't be zero or negative + assert (fractBits & FRACT_HOB)!=0 ; // Hi-order bit should be set + // Examine number. Determine if it is an easy case, + // which we can do pretty trivially using float/long conversion, + // or whether we must do real work. + final int tailZeros = Long.numberOfTrailingZeros(fractBits); + + // number of significant bits of fractBits; + final int nFractBits = EXP_SHIFT+1-tailZeros; + + // reset flags to default values as dtoa() does not always set these + // flags and a prior call to dtoa() might have set them to incorrect + // values with respect to the current state. + decimalDigitsRoundedUp = false; + exactDecimalConversion = false; + + // number of significant bits to the right of the point. + int nTinyBits = Math.max( 0, nFractBits - binExp - 1 ); + if ( binExp <= MAX_SMALL_BIN_EXP && binExp >= MIN_SMALL_BIN_EXP ){ + // Look more closely at the number to decide if, + // with scaling by 10^nTinyBits, the result will fit in + // a long. + if ( (nTinyBits < FDBigInteger.LONG_5_POW.length) && ((nFractBits + N_5_BITS[nTinyBits]) < 64 ) ){ + // + // We can do this: + // take the fraction bits, which are normalized. + // (a) nTinyBits == 0: Shift left or right appropriately + // to align the binary point at the extreme right, i.e. + // where a long int point is expected to be. The integer + // result is easily converted to a string. + // (b) nTinyBits > 0: Shift right by EXP_SHIFT-nFractBits, + // which effectively converts to long and scales by + // 2^nTinyBits. Then multiply by 5^nTinyBits to + // complete the scaling. We know this won't overflow + // because we just counted the number of bits necessary + // in the result. The integer you get from this can + // then be converted to a string pretty easily. + // + if ( nTinyBits == 0 ) { + int insignificant; + if ( binExp > nSignificantBits ){ + insignificant = insignificantDigitsForPow2(binExp-nSignificantBits-1); + } else { + insignificant = 0; + } + if ( binExp >= EXP_SHIFT ){ + fractBits <<= (binExp-EXP_SHIFT); + } else { + fractBits >>>= (EXP_SHIFT-binExp) ; + } + developLongDigits( 0, fractBits, insignificant ); + return; + } + // + // The following causes excess digits to be printed + // out in the single-float case. Our manipulation of + // halfULP here is apparently not correct. If we + // better understand how this works, perhaps we can + // use this special case again. But for the time being, + // we do not. + // else { + // fractBits >>>= EXP_SHIFT+1-nFractBits; + // fractBits//= long5pow[ nTinyBits ]; + // halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits); + // developLongDigits( -nTinyBits, fractBits, insignificantDigits(halfULP) ); + // return; + // } + // + } + } + // + // This is the hard case. We are going to compute large positive + // integers B and S and integer decExp, s.t. + // d = ( B / S )// 10^decExp + // 1 <= B / S < 10 + // Obvious choices are: + // decExp = floor( log10(d) ) + // B = d// 2^nTinyBits// 10^max( 0, -decExp ) + // S = 10^max( 0, decExp)// 2^nTinyBits + // (noting that nTinyBits has already been forced to non-negative) + // I am also going to compute a large positive integer + // M = (1/2^nSignificantBits)// 2^nTinyBits// 10^max( 0, -decExp ) + // i.e. M is (1/2) of the ULP of d, scaled like B. + // When we iterate through dividing B/S and picking off the + // quotient bits, we will know when to stop when the remainder + // is <= M. + // + // We keep track of powers of 2 and powers of 5. + // + int decExp = estimateDecExp(fractBits,binExp); + int B2, B5; // powers of 2 and powers of 5, respectively, in B + int S2, S5; // powers of 2 and powers of 5, respectively, in S + int M2, M5; // powers of 2 and powers of 5, respectively, in M + + B5 = Math.max( 0, -decExp ); + B2 = B5 + nTinyBits + binExp; + + S5 = Math.max( 0, decExp ); + S2 = S5 + nTinyBits; + + M5 = B5; + M2 = B2 - nSignificantBits; + + // + // the long integer fractBits contains the (nFractBits) interesting + // bits from the mantissa of d ( hidden 1 added if necessary) followed + // by (EXP_SHIFT+1-nFractBits) zeros. In the interest of compactness, + // I will shift out those zeros before turning fractBits into a + // FDBigInteger. The resulting whole number will be + // d * 2^(nFractBits-1-binExp). + // + fractBits >>>= tailZeros; + B2 -= nFractBits-1; + int common2factor = Math.min( B2, S2 ); + B2 -= common2factor; + S2 -= common2factor; + M2 -= common2factor; + + // + // HACK!! For exact powers of two, the next smallest number + // is only half as far away as we think (because the meaning of + // ULP changes at power-of-two bounds) for this reason, we + // hack M2. Hope this works. + // + if ( nFractBits == 1 ) { + M2 -= 1; + } + + if ( M2 < 0 ){ + // oops. + // since we cannot scale M down far enough, + // we must scale the other values up. + B2 -= M2; + S2 -= M2; + M2 = 0; + } + // + // Construct, Scale, iterate. + // Some day, we'll write a stopping test that takes + // account of the asymmetry of the spacing of floating-point + // numbers below perfect powers of 2 + // 26 Sept 96 is not that day. + // So we use a symmetric test. + // + int ndigit = 0; + boolean low, high; + long lowDigitDifference; + int q; + + // + // Detect the special cases where all the numbers we are about + // to compute will fit in int or long integers. + // In these cases, we will avoid doing FDBigInteger arithmetic. + // We use the same algorithms, except that we "normalize" + // our FDBigIntegers before iterating. This is to make division easier, + // as it makes our fist guess (quotient of high-order words) + // more accurate! + // + // Some day, we'll write a stopping test that takes + // account of the asymmetry of the spacing of floating-point + // numbers below perfect powers of 2 + // 26 Sept 96 is not that day. + // So we use a symmetric test. + // + // binary digits needed to represent B, approx. + int Bbits = nFractBits + B2 + (( B5 < N_5_BITS.length )? N_5_BITS[B5] : ( B5*3 )); + + // binary digits needed to represent 10*S, approx. + int tenSbits = S2+1 + (( (S5+1) < N_5_BITS.length )? N_5_BITS[(S5+1)] : ( (S5+1)*3 )); + if ( Bbits < 64 && tenSbits < 64){ + if ( Bbits < 32 && tenSbits < 32){ + // wa-hoo! They're all ints! + int b = ((int)fractBits * FDBigInteger.SMALL_5_POW[B5] ) << B2; + int s = FDBigInteger.SMALL_5_POW[S5] << S2; + int m = FDBigInteger.SMALL_5_POW[M5] << M2; + int tens = s * 10; + // + // Unroll the first iteration. If our decExp estimate + // was too high, our first quotient will be zero. In this + // case, we discard it and decrement decExp. + // + ndigit = 0; + q = b / s; + b = 10 * ( b % s ); + m *= 10; + low = (b < m ); + high = (b+m > tens ); + assert q < 10 : q; // excessively large digit + if ( (q == 0) && ! high ){ + // oops. Usually ignore leading zero. + decExp--; + } else { + digits[ndigit++] = (char)('0' + q); + } + // + // HACK! Java spec sez that we always have at least + // one digit after the . in either F- or E-form output. + // Thus we will need more than one digit if we're using + // E-form + // + if ( !isCompatibleFormat ||decExp < -3 || decExp >= 8 ){ + high = low = false; + } + while( ! low && ! high ){ + q = b / s; + b = 10 * ( b % s ); + m *= 10; + assert q < 10 : q; // excessively large digit + if ( m > 0L ){ + low = (b < m ); + high = (b+m > tens ); + } else { + // hack -- m might overflow! + // in this case, it is certainly > b, + // which won't + // and b+m > tens, too, since that has overflowed + // either! + low = true; + high = true; + } + digits[ndigit++] = (char)('0' + q); + } + lowDigitDifference = (b<<1) - tens; + exactDecimalConversion = (b == 0); + } else { + // still good! they're all longs! + long b = (fractBits * FDBigInteger.LONG_5_POW[B5] ) << B2; + long s = FDBigInteger.LONG_5_POW[S5] << S2; + long m = FDBigInteger.LONG_5_POW[M5] << M2; + long tens = s * 10L; + // + // Unroll the first iteration. If our decExp estimate + // was too high, our first quotient will be zero. In this + // case, we discard it and decrement decExp. + // + ndigit = 0; + q = (int) ( b / s ); + b = 10L * ( b % s ); + m *= 10L; + low = (b < m ); + high = (b+m > tens ); + assert q < 10 : q; // excessively large digit + if ( (q == 0) && ! high ){ + // oops. Usually ignore leading zero. + decExp--; + } else { + digits[ndigit++] = (char)('0' + q); + } + // + // HACK! Java spec sez that we always have at least + // one digit after the . in either F- or E-form output. + // Thus we will need more than one digit if we're using + // E-form + // + if ( !isCompatibleFormat || decExp < -3 || decExp >= 8 ){ + high = low = false; + } + while( ! low && ! high ){ + q = (int) ( b / s ); + b = 10 * ( b % s ); + m *= 10; + assert q < 10 : q; // excessively large digit + if ( m > 0L ){ + low = (b < m ); + high = (b+m > tens ); + } else { + // hack -- m might overflow! + // in this case, it is certainly > b, + // which won't + // and b+m > tens, too, since that has overflowed + // either! + low = true; + high = true; + } + digits[ndigit++] = (char)('0' + q); + } + lowDigitDifference = (b<<1) - tens; + exactDecimalConversion = (b == 0); + } + } else { + // + // We really must do FDBigInteger arithmetic. + // Fist, construct our FDBigInteger initial values. + // + FDBigInteger Sval = FDBigInteger.valueOfPow52(S5, S2); + int shiftBias = Sval.getNormalizationBias(); + Sval = Sval.leftShift(shiftBias); // normalize so that division works better + + FDBigInteger Bval = FDBigInteger.valueOfMulPow52(fractBits, B5, B2 + shiftBias); + FDBigInteger Mval = FDBigInteger.valueOfPow52(M5 + 1, M2 + shiftBias + 1); + + FDBigInteger tenSval = FDBigInteger.valueOfPow52(S5 + 1, S2 + shiftBias + 1); //Sval.mult( 10 ); + // + // Unroll the first iteration. If our decExp estimate + // was too high, our first quotient will be zero. In this + // case, we discard it and decrement decExp. + // + ndigit = 0; + q = Bval.quoRemIteration( Sval ); + low = (Bval.cmp( Mval ) < 0); + high = tenSval.addAndCmp(Bval,Mval)<=0; + + assert q < 10 : q; // excessively large digit + if ( (q == 0) && ! high ){ + // oops. Usually ignore leading zero. + decExp--; + } else { + digits[ndigit++] = (char)('0' + q); + } + // + // HACK! Java spec sez that we always have at least + // one digit after the . in either F- or E-form output. + // Thus we will need more than one digit if we're using + // E-form + // + if (!isCompatibleFormat || decExp < -3 || decExp >= 8 ){ + high = low = false; + } + while( ! low && ! high ){ + q = Bval.quoRemIteration( Sval ); + assert q < 10 : q; // excessively large digit + Mval = Mval.multBy10(); //Mval = Mval.mult( 10 ); + low = (Bval.cmp( Mval ) < 0); + high = tenSval.addAndCmp(Bval,Mval)<=0; + digits[ndigit++] = (char)('0' + q); + } + if ( high && low ){ + Bval = Bval.leftShift(1); + lowDigitDifference = Bval.cmp(tenSval); + } else { + lowDigitDifference = 0L; // this here only for flow analysis! + } + exactDecimalConversion = (Bval.cmp( FDBigInteger.ZERO ) == 0); + } + this.decExponent = decExp+1; + this.firstDigitIndex = 0; + this.nDigits = ndigit; + // + // Last digit gets rounded based on stopping condition. + // + if ( high ){ + if ( low ){ + if ( lowDigitDifference == 0L ){ + // it's a tie! + // choose based on which digits we like. + if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) { + roundup(); + } + } else if ( lowDigitDifference > 0 ){ + roundup(); + } + } else { + roundup(); + } + } + } + + // add one to the least significant digit. + // in the unlikely event there is a carry out, deal with it. + // assert that this will only happen where there + // is only one digit, e.g. (float)1e-44 seems to do it. + // + private void roundup() { + int i = (firstDigitIndex + nDigits - 1); + int q = digits[i]; + if (q == '9') { + while (q == '9' && i > firstDigitIndex) { + digits[i] = '0'; + q = digits[--i]; + } + if (q == '9') { + // carryout! High-order 1, rest 0s, larger exp. + decExponent += 1; + digits[firstDigitIndex] = '1'; + return; + } + // else fall through. + } + digits[i] = (char) (q + 1); + decimalDigitsRoundedUp = true; + } + + /** + * Estimate decimal exponent. (If it is small-ish, + * we could double-check.) + * + * First, scale the mantissa bits such that 1 <= d2 < 2. + * We are then going to estimate + * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5) + * and so we can estimate + * log10(d) ~=~ log10(d2) + binExp * log10(2) + * take the floor and call it decExp. + */ + static int estimateDecExp(long fractBits, int binExp) { + double d2 = Double.longBitsToDouble( EXP_ONE | ( fractBits & DoubleConsts.SIGNIF_BIT_MASK ) ); + double d = (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981; + long dBits = Double.doubleToRawLongBits(d); //can't be NaN here so use raw + int exponent = (int)((dBits & DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT) - DoubleConsts.EXP_BIAS; + boolean isNegative = (dBits & DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign + if(exponent>=0 && exponent<52) { // hot path + long mask = DoubleConsts.SIGNIF_BIT_MASK >> exponent; + int r = (int)(( (dBits&DoubleConsts.SIGNIF_BIT_MASK) | FRACT_HOB )>>(EXP_SHIFT-exponent)); + return isNegative ? (((mask & dBits) == 0L ) ? -r : -r-1 ) : r; + } else if (exponent < 0) { + return (((dBits&~DoubleConsts.SIGN_BIT_MASK) == 0) ? 0 : + ( (isNegative) ? -1 : 0) ); + } else { //if (exponent >= 52) + return (int)d; + } + } + + private static int insignificantDigits(long insignificant) { + int i; + for ( i = 0; insignificant >= 10L; i++ ) { + insignificant /= 10L; + } + return i; + } + + /** + * Calculates + *

+         * insignificantDigitsForPow2(v) == insignificantDigits(1L<
+         */
+        private static int insignificantDigitsForPow2(int p2) {
+            if (p2 > 1 && p2 < insignificantDigitsNumber.length) {
+                return insignificantDigitsNumber[p2];
+            }
+            return 0;
+        }
+
+        /**
+         *  If insignificant==(1L << ixd)
+         *  i = insignificantDigitsNumber[idx] is the same as:
+         *  int i;
+         *  for ( i = 0; insignificant >= 10L; i++ )
+         *         insignificant /= 10L;
+         */
+        private static final int[] insignificantDigitsNumber = {
+            0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3,
+            4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7,
+            8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11,
+            12, 12, 12, 12, 13, 13, 13, 14, 14, 14,
+            15, 15, 15, 15, 16, 16, 16, 17, 17, 17,
+            18, 18, 18, 19
+        };
+
+        // approximately ceil( log2( long5pow[i] ) )
+        private static final int[] N_5_BITS = {
+                0,
+                3,
+                5,
+                7,
+                10,
+                12,
+                14,
+                17,
+                19,
+                21,
+                24,
+                26,
+                28,
+                31,
+                33,
+                35,
+                38,
+                40,
+                42,
+                45,
+                47,
+                49,
+                52,
+                54,
+                56,
+                59,
+                61,
+        };
+
+        private int getChars(char[] result) {
+            assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
+            int i = 0;
+            if (isNegative) {
+                result[0] = '-';
+                i = 1;
+            }
+            if (decExponent > 0 && decExponent < 8) {
+                // print digits.digits.
+                int charLength = Math.min(nDigits, decExponent);
+                System.arraycopy(digits, firstDigitIndex, result, i, charLength);
+                i += charLength;
+                if (charLength < decExponent) {
+                    charLength = decExponent - charLength;
+                    Arrays.fill(result,i,i+charLength,'0');
+                    i += charLength;
+                    result[i++] = '.';
+                    result[i++] = '0';
+                } else {
+                    result[i++] = '.';
+                    if (charLength < nDigits) {
+                        int t = nDigits - charLength;
+                        System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
+                        i += t;
+                    } else {
+                        result[i++] = '0';
+                    }
+                }
+            } else if (decExponent <= 0 && decExponent > -3) {
+                result[i++] = '0';
+                result[i++] = '.';
+                if (decExponent != 0) {
+                    Arrays.fill(result, i, i-decExponent, '0');
+                    i -= decExponent;
+                }
+                System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
+                i += nDigits;
+            } else {
+                result[i++] = digits[firstDigitIndex];
+                result[i++] = '.';
+                if (nDigits > 1) {
+                    System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1);
+                    i += nDigits - 1;
+                } else {
+                    result[i++] = '0';
+                }
+                result[i++] = 'E';
+                int e;
+                if (decExponent <= 0) {
+                    result[i++] = '-';
+                    e = -decExponent + 1;
+                } else {
+                    e = decExponent - 1;
+                }
+                // decExponent has 1, 2, or 3, digits
+                if (e <= 9) {
+                    result[i++] = (char) (e + '0');
+                } else if (e <= 99) {
+                    result[i++] = (char) (e / 10 + '0');
+                    result[i++] = (char) (e % 10 + '0');
+                } else {
+                    result[i++] = (char) (e / 100 + '0');
+                    e %= 100;
+                    result[i++] = (char) (e / 10 + '0');
+                    result[i++] = (char) (e % 10 + '0');
+                }
+            }
+            return i;
+        }
+
+    }
+
+    private static final ThreadLocal threadLocalBinaryToASCIIBuffer =
+            new ThreadLocal() {
+                @Override
+                protected BinaryToASCIIBuffer initialValue() {
+                    return new BinaryToASCIIBuffer();
+                }
+            };
+
+    private static BinaryToASCIIBuffer getBinaryToASCIIBuffer() {
+        return threadLocalBinaryToASCIIBuffer.get();
+    }
+
+    /**
+     * A converter which can process an ASCII String representation
+     * of a single or double precision floating point value into a
+     * float or a double.
+     */
+    interface ASCIIToBinaryConverter {
+
+        double doubleValue();
+
+        float floatValue();
+
+    }
+
+    /**
+     * A ASCIIToBinaryConverter container for a double.
+     */
+    static class PreparedASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+        private final double doubleVal;
+        private final float floatVal;
+
+        public PreparedASCIIToBinaryBuffer(double doubleVal, float floatVal) {
+            this.doubleVal = doubleVal;
+            this.floatVal = floatVal;
+        }
+
+        @Override
+        public double doubleValue() {
+            return doubleVal;
+        }
+
+        @Override
+        public float floatValue() {
+            return floatVal;
+        }
+    }
+
+    static final ASCIIToBinaryConverter A2BC_POSITIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
+    static final ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
+    static final ASCIIToBinaryConverter A2BC_NOT_A_NUMBER  = new PreparedASCIIToBinaryBuffer(Double.NaN, Float.NaN);
+    static final ASCIIToBinaryConverter A2BC_POSITIVE_ZERO = new PreparedASCIIToBinaryBuffer(0.0d, 0.0f);
+    static final ASCIIToBinaryConverter A2BC_NEGATIVE_ZERO = new PreparedASCIIToBinaryBuffer(-0.0d, -0.0f);
+
+    /**
+     * A buffered implementation of ASCIIToBinaryConverter.
+     */
+    static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+        boolean     isNegative;
+        int         decExponent;
+        char        digits[];
+        int         nDigits;
+
+        ASCIIToBinaryBuffer( boolean negSign, int decExponent, char[] digits, int n)
+        {
+            this.isNegative = negSign;
+            this.decExponent = decExponent;
+            this.digits = digits;
+            this.nDigits = n;
+        }
+
+        /**
+         * Takes a FloatingDecimal, which we presumably just scanned in,
+         * and finds out what its value is, as a double.
+         *
+         * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
+         * ROUNDING DIRECTION in case the result is really destined
+         * for a single-precision float.
+         */
+        @Override
+        public double doubleValue() {
+            int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1);
+            //
+            // convert the lead kDigits to a long integer.
+            //
+            // (special performance hack: start to do it using int)
+            int iValue = (int) digits[0] - (int) '0';
+            int iDigits = Math.min(kDigits, INT_DECIMAL_DIGITS);
+            for (int i = 1; i < iDigits; i++) {
+                iValue = iValue * 10 + (int) digits[i] - (int) '0';
+            }
+            long lValue = (long) iValue;
+            for (int i = iDigits; i < kDigits; i++) {
+                lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
+            }
+            double dValue = (double) lValue;
+            int exp = decExponent - kDigits;
+            //
+            // lValue now contains a long integer with the value of
+            // the first kDigits digits of the number.
+            // dValue contains the (double) of the same.
+            //
+
+            if (nDigits <= MAX_DECIMAL_DIGITS) {
+                //
+                // possibly an easy case.
+                // We know that the digits can be represented
+                // exactly. And if the exponent isn't too outrageous,
+                // the whole thing can be done with one operation,
+                // thus one rounding error.
+                // Note that all our constructors trim all leading and
+                // trailing zeros, so simple values (including zero)
+                // will always end up here
+                //
+                if (exp == 0 || dValue == 0.0) {
+                    return (isNegative) ? -dValue : dValue; // small floating integer
+                }
+                else if (exp >= 0) {
+                    if (exp <= MAX_SMALL_TEN) {
+                        //
+                        // Can get the answer with one operation,
+                        // thus one roundoff.
+                        //
+                        double rValue = dValue * SMALL_10_POW[exp];
+                        return (isNegative) ? -rValue : rValue;
+                    }
+                    int slop = MAX_DECIMAL_DIGITS - kDigits;
+                    if (exp <= MAX_SMALL_TEN + slop) {
+                        //
+                        // We can multiply dValue by 10^(slop)
+                        // and it is still "small" and exact.
+                        // Then we can multiply by 10^(exp-slop)
+                        // with one rounding.
+                        //
+                        dValue *= SMALL_10_POW[slop];
+                        double rValue = dValue * SMALL_10_POW[exp - slop];
+                        return (isNegative) ? -rValue : rValue;
+                    }
+                    //
+                    // Else we have a hard case with a positive exp.
+                    //
+                } else {
+                    if (exp >= -MAX_SMALL_TEN) {
+                        //
+                        // Can get the answer in one division.
+                        //
+                        double rValue = dValue / SMALL_10_POW[-exp];
+                        return (isNegative) ? -rValue : rValue;
+                    }
+                    //
+                    // Else we have a hard case with a negative exp.
+                    //
+                }
+            }
+
+            //
+            // Harder cases:
+            // The sum of digits plus exponent is greater than
+            // what we think we can do with one error.
+            //
+            // Start by approximating the right answer by,
+            // naively, scaling by powers of 10.
+            //
+            if (exp > 0) {
+                if (decExponent > MAX_DECIMAL_EXPONENT + 1) {
+                    //
+                    // Lets face it. This is going to be
+                    // Infinity. Cut to the chase.
+                    //
+                    return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+                }
+                if ((exp & 15) != 0) {
+                    dValue *= SMALL_10_POW[exp & 15];
+                }
+                if ((exp >>= 4) != 0) {
+                    int j;
+                    for (j = 0; exp > 1; j++, exp >>= 1) {
+                        if ((exp & 1) != 0) {
+                            dValue *= BIG_10_POW[j];
+                        }
+                    }
+                    //
+                    // The reason for the weird exp > 1 condition
+                    // in the above loop was so that the last multiply
+                    // would get unrolled. We handle it here.
+                    // It could overflow.
+                    //
+                    double t = dValue * BIG_10_POW[j];
+                    if (Double.isInfinite(t)) {
+                        //
+                        // It did overflow.
+                        // Look more closely at the result.
+                        // If the exponent is just one too large,
+                        // then use the maximum finite as our estimate
+                        // value. Else call the result infinity
+                        // and punt it.
+                        // ( I presume this could happen because
+                        // rounding forces the result here to be
+                        // an ULP or two larger than
+                        // Double.MAX_VALUE ).
+                        //
+                        t = dValue / 2.0;
+                        t *= BIG_10_POW[j];
+                        if (Double.isInfinite(t)) {
+                            return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+                        }
+                        t = Double.MAX_VALUE;
+                    }
+                    dValue = t;
+                }
+            } else if (exp < 0) {
+                exp = -exp;
+                if (decExponent < MIN_DECIMAL_EXPONENT - 1) {
+                    //
+                    // Lets face it. This is going to be
+                    // zero. Cut to the chase.
+                    //
+                    return (isNegative) ? -0.0 : 0.0;
+                }
+                if ((exp & 15) != 0) {
+                    dValue /= SMALL_10_POW[exp & 15];
+                }
+                if ((exp >>= 4) != 0) {
+                    int j;
+                    for (j = 0; exp > 1; j++, exp >>= 1) {
+                        if ((exp & 1) != 0) {
+                            dValue *= TINY_10_POW[j];
+                        }
+                    }
+                    //
+                    // The reason for the weird exp > 1 condition
+                    // in the above loop was so that the last multiply
+                    // would get unrolled. We handle it here.
+                    // It could underflow.
+                    //
+                    double t = dValue * TINY_10_POW[j];
+                    if (t == 0.0) {
+                        //
+                        // It did underflow.
+                        // Look more closely at the result.
+                        // If the exponent is just one too small,
+                        // then use the minimum finite as our estimate
+                        // value. Else call the result 0.0
+                        // and punt it.
+                        // ( I presume this could happen because
+                        // rounding forces the result here to be
+                        // an ULP or two less than
+                        // Double.MIN_VALUE ).
+                        //
+                        t = dValue * 2.0;
+                        t *= TINY_10_POW[j];
+                        if (t == 0.0) {
+                            return (isNegative) ? -0.0 : 0.0;
+                        }
+                        t = Double.MIN_VALUE;
+                    }
+                    dValue = t;
+                }
+            }
+
+            //
+            // dValue is now approximately the result.
+            // The hard part is adjusting it, by comparison
+            // with FDBigInteger arithmetic.
+            // Formulate the EXACT big-number result as
+            // bigD0 * 10^exp
+            //
+            if (nDigits > MAX_NDIGITS) {
+                nDigits = MAX_NDIGITS + 1;
+                digits[MAX_NDIGITS] = '1';
+            }
+            FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits);
+            exp = decExponent - nDigits;
+
+            long ieeeBits = Double.doubleToRawLongBits(dValue); // IEEE-754 bits of double candidate
+            final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
+            final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
+            bigD0 = bigD0.multByPow52(D5, 0);
+            bigD0.makeImmutable();   // prevent bigD0 modification inside correctionLoop
+            FDBigInteger bigD = null;
+            int prevD2 = 0;
+
+            correctionLoop:
+            while (true) {
+                // here ieeeBits can't be NaN, Infinity or zero
+                int binexp = (int) (ieeeBits >>> EXP_SHIFT);
+                long bigBbits = ieeeBits & DoubleConsts.SIGNIF_BIT_MASK;
+                if (binexp > 0) {
+                    bigBbits |= FRACT_HOB;
+                } else { // Normalize denormalized numbers.
+                    assert bigBbits != 0L : bigBbits; // doubleToBigInt(0.0)
+                    int leadingZeros = Long.numberOfLeadingZeros(bigBbits);
+                    int shift = leadingZeros - (63 - EXP_SHIFT);
+                    bigBbits <<= shift;
+                    binexp = 1 - shift;
+                }
+                binexp -= DoubleConsts.EXP_BIAS;
+                int lowOrderZeros = Long.numberOfTrailingZeros(bigBbits);
+                bigBbits >>>= lowOrderZeros;
+                final int bigIntExp = binexp - EXP_SHIFT + lowOrderZeros;
+                final int bigIntNBits = EXP_SHIFT + 1 - lowOrderZeros;
+
+                //
+                // Scale bigD, bigB appropriately for
+                // big-integer operations.
+                // Naively, we multiply by powers of ten
+                // and powers of two. What we actually do
+                // is keep track of the powers of 5 and
+                // powers of 2 we would use, then factor out
+                // common divisors before doing the work.
+                //
+                int B2 = B5; // powers of 2 in bigB
+                int D2 = D5; // powers of 2 in bigD
+                int Ulp2;   // powers of 2 in halfUlp.
+                if (bigIntExp >= 0) {
+                    B2 += bigIntExp;
+                } else {
+                    D2 -= bigIntExp;
+                }
+                Ulp2 = B2;
+                // shift bigB and bigD left by a number s. t.
+                // halfUlp is still an integer.
+                int hulpbias;
+                if (binexp <= -DoubleConsts.EXP_BIAS) {
+                    // This is going to be a denormalized number
+                    // (if not actually zero).
+                    // half an ULP is at 2^-(DoubleConsts.EXP_BIAS+EXP_SHIFT+1)
+                    hulpbias = binexp + lowOrderZeros + DoubleConsts.EXP_BIAS;
+                } else {
+                    hulpbias = 1 + lowOrderZeros;
+                }
+                B2 += hulpbias;
+                D2 += hulpbias;
+                // if there are common factors of 2, we might just as well
+                // factor them out, as they add nothing useful.
+                int common2 = Math.min(B2, Math.min(D2, Ulp2));
+                B2 -= common2;
+                D2 -= common2;
+                Ulp2 -= common2;
+                // do multiplications by powers of 5 and 2
+                FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
+                if (bigD == null || prevD2 != D2) {
+                    bigD = bigD0.leftShift(D2);
+                    prevD2 = D2;
+                }
+                //
+                // to recap:
+                // bigB is the scaled-big-int version of our floating-point
+                // candidate.
+                // bigD is the scaled-big-int version of the exact value
+                // as we understand it.
+                // halfUlp is 1/2 an ulp of bigB, except for special cases
+                // of exact powers of 2
+                //
+                // the plan is to compare bigB with bigD, and if the difference
+                // is less than halfUlp, then we're satisfied. Otherwise,
+                // use the ratio of difference to halfUlp to calculate a fudge
+                // factor to add to the floating value, then go 'round again.
+                //
+                FDBigInteger diff;
+                int cmpResult;
+                boolean overvalue;
+                if ((cmpResult = bigB.cmp(bigD)) > 0) {
+                    overvalue = true; // our candidate is too big.
+                    diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
+                    if ((bigIntNBits == 1) && (bigIntExp > -DoubleConsts.EXP_BIAS + 1)) {
+                        // candidate is a normalized exact power of 2 and
+                        // is too big (larger than Double.MIN_NORMAL). We will be subtracting.
+                        // For our purposes, ulp is the ulp of the
+                        // next smaller range.
+                        Ulp2 -= 1;
+                        if (Ulp2 < 0) {
+                            // rats. Cannot de-scale ulp this far.
+                            // must scale diff in other direction.
+                            Ulp2 = 0;
+                            diff = diff.leftShift(1);
+                        }
+                    }
+                } else if (cmpResult < 0) {
+                    overvalue = false; // our candidate is too small.
+                    diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
+                } else {
+                    // the candidate is exactly right!
+                    // this happens with surprising frequency
+                    break correctionLoop;
+                }
+                cmpResult = diff.cmpPow52(B5, Ulp2);
+                if ((cmpResult) < 0) {
+                    // difference is small.
+                    // this is close enough
+                    break correctionLoop;
+                } else if (cmpResult == 0) {
+                    // difference is exactly half an ULP
+                    // round to some other value maybe, then finish
+                    if ((ieeeBits & 1) != 0) { // half ties to even
+                        ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+                    }
+                    break correctionLoop;
+                } else {
+                    // difference is non-trivial.
+                    // could scale addend by ratio of difference to
+                    // halfUlp here, if we bothered to compute that difference.
+                    // Most of the time ( I hope ) it is about 1 anyway.
+                    ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+                    if (ieeeBits == 0 || ieeeBits == DoubleConsts.EXP_BIT_MASK) { // 0.0 or Double.POSITIVE_INFINITY
+                        break correctionLoop; // oops. Fell off end of range.
+                    }
+                    continue; // try again.
+                }
+
+            }
+            if (isNegative) {
+                ieeeBits |= DoubleConsts.SIGN_BIT_MASK;
+            }
+            return Double.longBitsToDouble(ieeeBits);
+        }
+
+        /**
+         * Takes a FloatingDecimal, which we presumably just scanned in,
+         * and finds out what its value is, as a float.
+         * This is distinct from doubleValue() to avoid the extremely
+         * unlikely case of a double rounding error, wherein the conversion
+         * to double has one rounding error, and the conversion of that double
+         * to a float has another rounding error, IN THE WRONG DIRECTION,
+         * ( because of the preference to a zero low-order bit ).
+         */
+        @Override
+        public float floatValue() {
+            int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1);
+            //
+            // convert the lead kDigits to an integer.
+            //
+            int iValue = (int) digits[0] - (int) '0';
+            for (int i = 1; i < kDigits; i++) {
+                iValue = iValue * 10 + (int) digits[i] - (int) '0';
+            }
+            float fValue = (float) iValue;
+            int exp = decExponent - kDigits;
+            //
+            // iValue now contains an integer with the value of
+            // the first kDigits digits of the number.
+            // fValue contains the (float) of the same.
+            //
+
+            if (nDigits <= SINGLE_MAX_DECIMAL_DIGITS) {
+                //
+                // possibly an easy case.
+                // We know that the digits can be represented
+                // exactly. And if the exponent isn't too outrageous,
+                // the whole thing can be done with one operation,
+                // thus one rounding error.
+                // Note that all our constructors trim all leading and
+                // trailing zeros, so simple values (including zero)
+                // will always end up here.
+                //
+                if (exp == 0 || fValue == 0.0f) {
+                    return (isNegative) ? -fValue : fValue; // small floating integer
+                } else if (exp >= 0) {
+                    if (exp <= SINGLE_MAX_SMALL_TEN) {
+                        //
+                        // Can get the answer with one operation,
+                        // thus one roundoff.
+                        //
+                        fValue *= SINGLE_SMALL_10_POW[exp];
+                        return (isNegative) ? -fValue : fValue;
+                    }
+                    int slop = SINGLE_MAX_DECIMAL_DIGITS - kDigits;
+                    if (exp <= SINGLE_MAX_SMALL_TEN + slop) {
+                        //
+                        // We can multiply fValue by 10^(slop)
+                        // and it is still "small" and exact.
+                        // Then we can multiply by 10^(exp-slop)
+                        // with one rounding.
+                        //
+                        fValue *= SINGLE_SMALL_10_POW[slop];
+                        fValue *= SINGLE_SMALL_10_POW[exp - slop];
+                        return (isNegative) ? -fValue : fValue;
+                    }
+                    //
+                    // Else we have a hard case with a positive exp.
+                    //
+                } else {
+                    if (exp >= -SINGLE_MAX_SMALL_TEN) {
+                        //
+                        // Can get the answer in one division.
+                        //
+                        fValue /= SINGLE_SMALL_10_POW[-exp];
+                        return (isNegative) ? -fValue : fValue;
+                    }
+                    //
+                    // Else we have a hard case with a negative exp.
+                    //
+                }
+            } else if ((decExponent >= nDigits) && (nDigits + decExponent <= MAX_DECIMAL_DIGITS)) {
+                //
+                // In double-precision, this is an exact floating integer.
+                // So we can compute to double, then shorten to float
+                // with one round, and get the right answer.
+                //
+                // First, finish accumulating digits.
+                // Then convert that integer to a double, multiply
+                // by the appropriate power of ten, and convert to float.
+                //
+                long lValue = (long) iValue;
+                for (int i = kDigits; i < nDigits; i++) {
+                    lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
+                }
+                double dValue = (double) lValue;
+                exp = decExponent - nDigits;
+                dValue *= SMALL_10_POW[exp];
+                fValue = (float) dValue;
+                return (isNegative) ? -fValue : fValue;
+
+            }
+            //
+            // Harder cases:
+            // The sum of digits plus exponent is greater than
+            // what we think we can do with one error.
+            //
+            // Start by approximating the right answer by,
+            // naively, scaling by powers of 10.
+            // Scaling uses doubles to avoid overflow/underflow.
+            //
+            double dValue = fValue;
+            if (exp > 0) {
+                if (decExponent > SINGLE_MAX_DECIMAL_EXPONENT + 1) {
+                    //
+                    // Lets face it. This is going to be
+                    // Infinity. Cut to the chase.
+                    //
+                    return (isNegative) ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
+                }
+                if ((exp & 15) != 0) {
+                    dValue *= SMALL_10_POW[exp & 15];
+                }
+                if ((exp >>= 4) != 0) {
+                    int j;
+                    for (j = 0; exp > 0; j++, exp >>= 1) {
+                        if ((exp & 1) != 0) {
+                            dValue *= BIG_10_POW[j];
+                        }
+                    }
+                }
+            } else if (exp < 0) {
+                exp = -exp;
+                if (decExponent < SINGLE_MIN_DECIMAL_EXPONENT - 1) {
+                    //
+                    // Lets face it. This is going to be
+                    // zero. Cut to the chase.
+                    //
+                    return (isNegative) ? -0.0f : 0.0f;
+                }
+                if ((exp & 15) != 0) {
+                    dValue /= SMALL_10_POW[exp & 15];
+                }
+                if ((exp >>= 4) != 0) {
+                    int j;
+                    for (j = 0; exp > 0; j++, exp >>= 1) {
+                        if ((exp & 1) != 0) {
+                            dValue *= TINY_10_POW[j];
+                        }
+                    }
+                }
+            }
+            fValue = Math.clamp((float) dValue, Float.MIN_VALUE, Float.MAX_VALUE);
+
+            //
+            // fValue is now approximately the result.
+            // The hard part is adjusting it, by comparison
+            // with FDBigInteger arithmetic.
+            // Formulate the EXACT big-number result as
+            // bigD0 * 10^exp
+            //
+            if (nDigits > SINGLE_MAX_NDIGITS) {
+                nDigits = SINGLE_MAX_NDIGITS + 1;
+                digits[SINGLE_MAX_NDIGITS] = '1';
+            }
+            FDBigInteger bigD0 = new FDBigInteger(iValue, digits, kDigits, nDigits);
+            exp = decExponent - nDigits;
+
+            int ieeeBits = Float.floatToRawIntBits(fValue); // IEEE-754 bits of float candidate
+            final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
+            final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
+            bigD0 = bigD0.multByPow52(D5, 0);
+            bigD0.makeImmutable();   // prevent bigD0 modification inside correctionLoop
+            FDBigInteger bigD = null;
+            int prevD2 = 0;
+
+            correctionLoop:
+            while (true) {
+                // here ieeeBits can't be NaN, Infinity or zero
+                int binexp = ieeeBits >>> SINGLE_EXP_SHIFT;
+                int bigBbits = ieeeBits & FloatConsts.SIGNIF_BIT_MASK;
+                if (binexp > 0) {
+                    bigBbits |= SINGLE_FRACT_HOB;
+                } else { // Normalize denormalized numbers.
+                    assert bigBbits != 0 : bigBbits; // floatToBigInt(0.0)
+                    int leadingZeros = Integer.numberOfLeadingZeros(bigBbits);
+                    int shift = leadingZeros - (31 - SINGLE_EXP_SHIFT);
+                    bigBbits <<= shift;
+                    binexp = 1 - shift;
+                }
+                binexp -= FloatConsts.EXP_BIAS;
+                int lowOrderZeros = Integer.numberOfTrailingZeros(bigBbits);
+                bigBbits >>>= lowOrderZeros;
+                final int bigIntExp = binexp - SINGLE_EXP_SHIFT + lowOrderZeros;
+                final int bigIntNBits = SINGLE_EXP_SHIFT + 1 - lowOrderZeros;
+
+                //
+                // Scale bigD, bigB appropriately for
+                // big-integer operations.
+                // Naively, we multiply by powers of ten
+                // and powers of two. What we actually do
+                // is keep track of the powers of 5 and
+                // powers of 2 we would use, then factor out
+                // common divisors before doing the work.
+                //
+                int B2 = B5; // powers of 2 in bigB
+                int D2 = D5; // powers of 2 in bigD
+                int Ulp2;   // powers of 2 in halfUlp.
+                if (bigIntExp >= 0) {
+                    B2 += bigIntExp;
+                } else {
+                    D2 -= bigIntExp;
+                }
+                Ulp2 = B2;
+                // shift bigB and bigD left by a number s. t.
+                // halfUlp is still an integer.
+                int hulpbias;
+                if (binexp <= -FloatConsts.EXP_BIAS) {
+                    // This is going to be a denormalized number
+                    // (if not actually zero).
+                    // half an ULP is at 2^-(FloatConsts.EXP_BIAS+SINGLE_EXP_SHIFT+1)
+                    hulpbias = binexp + lowOrderZeros + FloatConsts.EXP_BIAS;
+                } else {
+                    hulpbias = 1 + lowOrderZeros;
+                }
+                B2 += hulpbias;
+                D2 += hulpbias;
+                // if there are common factors of 2, we might just as well
+                // factor them out, as they add nothing useful.
+                int common2 = Math.min(B2, Math.min(D2, Ulp2));
+                B2 -= common2;
+                D2 -= common2;
+                Ulp2 -= common2;
+                // do multiplications by powers of 5 and 2
+                FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
+                if (bigD == null || prevD2 != D2) {
+                    bigD = bigD0.leftShift(D2);
+                    prevD2 = D2;
+                }
+                //
+                // to recap:
+                // bigB is the scaled-big-int version of our floating-point
+                // candidate.
+                // bigD is the scaled-big-int version of the exact value
+                // as we understand it.
+                // halfUlp is 1/2 an ulp of bigB, except for special cases
+                // of exact powers of 2
+                //
+                // the plan is to compare bigB with bigD, and if the difference
+                // is less than halfUlp, then we're satisfied. Otherwise,
+                // use the ratio of difference to halfUlp to calculate a fudge
+                // factor to add to the floating value, then go 'round again.
+                //
+                FDBigInteger diff;
+                int cmpResult;
+                boolean overvalue;
+                if ((cmpResult = bigB.cmp(bigD)) > 0) {
+                    overvalue = true; // our candidate is too big.
+                    diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
+                    if ((bigIntNBits == 1) && (bigIntExp > -FloatConsts.EXP_BIAS + 1)) {
+                        // candidate is a normalized exact power of 2 and
+                        // is too big (larger than Float.MIN_NORMAL). We will be subtracting.
+                        // For our purposes, ulp is the ulp of the
+                        // next smaller range.
+                        Ulp2 -= 1;
+                        if (Ulp2 < 0) {
+                            // rats. Cannot de-scale ulp this far.
+                            // must scale diff in other direction.
+                            Ulp2 = 0;
+                            diff = diff.leftShift(1);
+                        }
+                    }
+                } else if (cmpResult < 0) {
+                    overvalue = false; // our candidate is too small.
+                    diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
+                } else {
+                    // the candidate is exactly right!
+                    // this happens with surprising frequency
+                    break correctionLoop;
+                }
+                cmpResult = diff.cmpPow52(B5, Ulp2);
+                if ((cmpResult) < 0) {
+                    // difference is small.
+                    // this is close enough
+                    break correctionLoop;
+                } else if (cmpResult == 0) {
+                    // difference is exactly half an ULP
+                    // round to some other value maybe, then finish
+                    if ((ieeeBits & 1) != 0) { // half ties to even
+                        ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+                    }
+                    break correctionLoop;
+                } else {
+                    // difference is non-trivial.
+                    // could scale addend by ratio of difference to
+                    // halfUlp here, if we bothered to compute that difference.
+                    // Most of the time ( I hope ) it is about 1 anyway.
+                    ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+                    if (ieeeBits == 0 || ieeeBits == FloatConsts.EXP_BIT_MASK) { // 0.0 or Float.POSITIVE_INFINITY
+                        break correctionLoop; // oops. Fell off end of range.
+                    }
+                    continue; // try again.
+                }
+
+            }
+            if (isNegative) {
+                ieeeBits |= FloatConsts.SIGN_BIT_MASK;
+            }
+            return Float.intBitsToFloat(ieeeBits);
+        }
+
+
+        /**
+         * All the positive powers of 10 that can be
+         * represented exactly in double/float.
+         */
+        private static final double[] SMALL_10_POW = {
+            1.0e0,
+            1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
+            1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
+            1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
+            1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
+            1.0e21, 1.0e22
+        };
+
+        private static final float[] SINGLE_SMALL_10_POW = {
+            1.0e0f,
+            1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
+            1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
+        };
+
+        private static final double[] BIG_10_POW = {
+            1e16, 1e32, 1e64, 1e128, 1e256 };
+        private static final double[] TINY_10_POW = {
+            1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
+
+        private static final int MAX_SMALL_TEN = SMALL_10_POW.length-1;
+        private static final int SINGLE_MAX_SMALL_TEN = SINGLE_SMALL_10_POW.length-1;
+
+    }
+
+    /**
+     * Returns a BinaryToASCIIConverter for a double.
+     * The returned object is a ThreadLocal variable of this class.
+     *
+     * @param d The double precision value to convert.
+     * @return The converter.
+     */
+    public static BinaryToASCIIConverter getBinaryToASCIIConverter(double d) {
+        return getBinaryToASCIIConverter(d, true);
+    }
+
+    /**
+     * Returns a BinaryToASCIIConverter for a double.
+     * The returned object is a ThreadLocal variable of this class.
+     *
+     * @param d The double precision value to convert.
+     * @param isCompatibleFormat
+     * @return The converter.
+     */
+    static BinaryToASCIIConverter getBinaryToASCIIConverter(double d, boolean isCompatibleFormat) {
+        long dBits = Double.doubleToRawLongBits(d);
+        boolean isNegative = (dBits&DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign
+        long fractBits = dBits & DoubleConsts.SIGNIF_BIT_MASK;
+        int  binExp = (int)( (dBits&DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT );
+        // Discover obvious special cases of NaN and Infinity.
+        if ( binExp == (int)(DoubleConsts.EXP_BIT_MASK>>EXP_SHIFT) ) {
+            if ( fractBits == 0L ){
+                return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
+            } else {
+                return B2AC_NOT_A_NUMBER;
+            }
+        }
+        // Finish unpacking
+        // Normalize denormalized numbers.
+        // Insert assumed high-order bit for normalized numbers.
+        // Subtract exponent bias.
+        int  nSignificantBits;
+        if ( binExp == 0 ){
+            if ( fractBits == 0L ){
+                // not a denorm, just a 0!
+                return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
+            }
+            int leadingZeros = Long.numberOfLeadingZeros(fractBits);
+            int shift = leadingZeros-(63-EXP_SHIFT);
+            fractBits <<= shift;
+            binExp = 1 - shift;
+            nSignificantBits =  64-leadingZeros; // recall binExp is  - shift count.
+        } else {
+            fractBits |= FRACT_HOB;
+            nSignificantBits = EXP_SHIFT+1;
+        }
+        binExp -= DoubleConsts.EXP_BIAS;
+        BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
+        buf.setSign(isNegative);
+        // call the routine that actually does all the hard work.
+        buf.dtoa(binExp, fractBits, nSignificantBits, isCompatibleFormat);
+        return buf;
+    }
+
+    private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) {
+        int fBits = Float.floatToRawIntBits( f );
+        boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0;
+        int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK;
+        int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT;
+        // Discover obvious special cases of NaN and Infinity.
+        if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) {
+            if ( fractBits == 0L ){
+                return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
+            } else {
+                return B2AC_NOT_A_NUMBER;
+            }
+        }
+        // Finish unpacking
+        // Normalize denormalized numbers.
+        // Insert assumed high-order bit for normalized numbers.
+        // Subtract exponent bias.
+        int  nSignificantBits;
+        if ( binExp == 0 ){
+            if ( fractBits == 0 ){
+                // not a denorm, just a 0!
+                return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
+            }
+            int leadingZeros = Integer.numberOfLeadingZeros(fractBits);
+            int shift = leadingZeros-(31-SINGLE_EXP_SHIFT);
+            fractBits <<= shift;
+            binExp = 1 - shift;
+            nSignificantBits =  32 - leadingZeros; // recall binExp is  - shift count.
+        } else {
+            fractBits |= SINGLE_FRACT_HOB;
+            nSignificantBits = SINGLE_EXP_SHIFT+1;
+        }
+        binExp -= FloatConsts.EXP_BIAS;
+        BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
+        buf.setSign(isNegative);
+        // call the routine that actually does all the hard work.
+        buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true);
+        return buf;
+    }
+
+    @SuppressWarnings("fallthrough")
+    static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException {
+        boolean isNegative = false;
+        boolean signSeen   = false;
+        int     decExp;
+        char    c;
+
+    parseNumber:
+        try{
+            in = in.trim(); // don't fool around with white space.
+                            // throws NullPointerException if null
+            int len = in.length();
+            if ( len == 0 ) {
+                throw new NumberFormatException("empty String");
+            }
+            int i = 0;
+            switch (in.charAt(i)){
+            case '-':
+                isNegative = true;
+                //FALLTHROUGH
+            case '+':
+                i++;
+                signSeen = true;
+            }
+            c = in.charAt(i);
+            if(c == 'N') { // Check for NaN
+                if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) {
+                    return A2BC_NOT_A_NUMBER;
+                }
+                // something went wrong, throw exception
+                break parseNumber;
+            } else if(c == 'I') { // Check for Infinity strings
+                if((len-i)==INFINITY_LENGTH && in.indexOf(INFINITY_REP,i)==i) {
+                    return isNegative? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
+                }
+                // something went wrong, throw exception
+                break parseNumber;
+            } else if (c == '0')  { // check for hexadecimal floating-point number
+                if (len > i+1 ) {
+                    char ch = in.charAt(i+1);
+                    if (ch == 'x' || ch == 'X' ) { // possible hex string
+                        return parseHexString(in);
+                    }
+                }
+            }  // look for and process decimal floating-point string
+
+            char[] digits = new char[ len ];
+            boolean decSeen = false;
+            int nDigits = 0;
+            int decPt = 0;
+            int nLeadZero = 0;
+            int nTrailZero = 0;
+
+        skipLeadingZerosLoop:
+            while (i < len) {
+                c = in.charAt(i);
+                if (c == '0') {
+                    nLeadZero++;
+                } else if (c == '.') {
+                    if (decSeen) {
+                        // already saw one ., this is the 2nd.
+                        throw new NumberFormatException("multiple points");
+                    }
+                    decPt = i;
+                    if (signSeen) {
+                        decPt -= 1;
+                    }
+                    decSeen = true;
+                } else {
+                    break skipLeadingZerosLoop;
+                }
+                i++;
+            }
+        digitLoop:
+            while (i < len) {
+                c = in.charAt(i);
+                if (c >= '1' && c <= '9') {
+                    digits[nDigits++] = c;
+                    nTrailZero = 0;
+                } else if (c == '0') {
+                    digits[nDigits++] = c;
+                    nTrailZero++;
+                } else if (c == '.') {
+                    if (decSeen) {
+                        // already saw one ., this is the 2nd.
+                        throw new NumberFormatException("multiple points");
+                    }
+                    decPt = i;
+                    if (signSeen) {
+                        decPt -= 1;
+                    }
+                    decSeen = true;
+                } else {
+                    break digitLoop;
+                }
+                i++;
+            }
+            nDigits -=nTrailZero;
+            //
+            // At this point, we've scanned all the digits and decimal
+            // point we're going to see. Trim off leading and trailing
+            // zeros, which will just confuse us later, and adjust
+            // our initial decimal exponent accordingly.
+            // To review:
+            // we have seen i total characters.
+            // nLeadZero of them were zeros before any other digits.
+            // nTrailZero of them were zeros after any other digits.
+            // if ( decSeen ), then a . was seen after decPt characters
+            // ( including leading zeros which have been discarded )
+            // nDigits characters were neither lead nor trailing
+            // zeros, nor point
+            //
+            //
+            // special hack: if we saw no non-zero digits, then the
+            // answer is zero!
+            // Unfortunately, we feel honor-bound to keep parsing!
+            //
+            boolean isZero = (nDigits == 0);
+            if ( isZero &&  nLeadZero == 0 ){
+                // we saw NO DIGITS AT ALL,
+                // not even a crummy 0!
+                // this is not allowed.
+                break parseNumber; // go throw exception
+            }
+            //
+            // Our initial exponent is decPt, adjusted by the number of
+            // discarded zeros. Or, if there was no decPt,
+            // then its just nDigits adjusted by discarded trailing zeros.
+            //
+            if ( decSeen ){
+                decExp = decPt - nLeadZero;
+            } else {
+                decExp = nDigits + nTrailZero;
+            }
+
+            //
+            // Look for 'e' or 'E' and an optionally signed integer.
+            //
+            if ( (i < len) &&  (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
+                int expSign = 1;
+                int expVal  = 0;
+                int reallyBig = Integer.MAX_VALUE / 10;
+                boolean expOverflow = false;
+                switch( in.charAt(++i) ){
+                case '-':
+                    expSign = -1;
+                    //FALLTHROUGH
+                case '+':
+                    i++;
+                }
+                int expAt = i;
+            expLoop:
+                while ( i < len  ){
+                    if ( expVal >= reallyBig ){
+                        // the next character will cause integer
+                        // overflow.
+                        expOverflow = true;
+                    }
+                    c = in.charAt(i++);
+                    if(c>='0' && c<='9') {
+                        expVal = expVal*10 + ( (int)c - (int)'0' );
+                    } else {
+                        i--;           // back up.
+                        break expLoop; // stop parsing exponent.
+                    }
+                }
+                int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero;
+                if (expOverflow || (expVal > expLimit)) {
+                    // There is still a chance that the exponent will be safe to
+                    // use: if it would eventually decrease due to a negative
+                    // decExp, and that number is below the limit.  We check for
+                    // that here.
+                    if (!expOverflow && (expSign == 1 && decExp < 0)
+                            && (expVal + decExp) < expLimit) {
+                        // Cannot overflow: adding a positive and negative number.
+                        decExp += expVal;
+                    } else {
+                        //
+                        // The intent here is to end up with
+                        // infinity or zero, as appropriate.
+                        // The reason for yielding such a small decExponent,
+                        // rather than something intuitive such as
+                        // expSign*Integer.MAX_VALUE, is that this value
+                        // is subject to further manipulation in
+                        // doubleValue() and floatValue(), and I don't want
+                        // it to be able to cause overflow there!
+                        // (The only way we can get into trouble here is for
+                        // really outrageous nDigits+nTrailZero, such as 2
+                        // billion.)
+                        //
+                        decExp = expSign * expLimit;
+                    }
+                } else {
+                    // this should not overflow, since we tested
+                    // for expVal > (MAX+N), where N >= abs(decExp)
+                    decExp = decExp + expSign*expVal;
+                }
+
+                // if we saw something not a digit ( or end of string )
+                // after the [Ee][+-], without seeing any digits at all
+                // this is certainly an error. If we saw some digits,
+                // but then some trailing garbage, that might be ok.
+                // so we just fall through in that case.
+                // HUMBUG
+                if ( i == expAt ) {
+                    break parseNumber; // certainly bad
+                }
+            }
+            //
+            // We parsed everything we could.
+            // If there are leftovers, then this is not good input!
+            //
+            if ( i < len &&
+                ((i != len - 1) ||
+                (in.charAt(i) != 'f' &&
+                 in.charAt(i) != 'F' &&
+                 in.charAt(i) != 'd' &&
+                 in.charAt(i) != 'D'))) {
+                break parseNumber; // go throw exception
+            }
+            if(isZero) {
+                return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
+            }
+            return new ASCIIToBinaryBuffer(isNegative, decExp, digits, nDigits);
+        } catch ( StringIndexOutOfBoundsException e ){ }
+        throw new NumberFormatException("For input string: \"" + in + "\"");
+    }
+
+    private static class HexFloatPattern {
+        /**
+         * Grammar is compatible with hexadecimal floating-point constants
+         * described in section 6.4.4.2 of the C99 specification.
+         */
+        private static final Pattern VALUE = Pattern.compile(
+                   //1           234                   56                7                   8      9
+                    "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
+                    );
+    }
+
+    /**
+     * Converts string s to a suitable floating decimal; uses the
+     * double constructor and sets the roundDir variable appropriately
+     * in case the value is later converted to a float.
+     *
+     * @param s The String to parse.
+     */
+   static ASCIIToBinaryConverter parseHexString(String s) {
+            // Verify string is a member of the hexadecimal floating-point
+            // string language.
+            Matcher m = HexFloatPattern.VALUE.matcher(s);
+            boolean validInput = m.matches();
+            if (!validInput) {
+                // Input does not match pattern
+                throw new NumberFormatException("For input string: \"" + s + "\"");
+            } else { // validInput
+                //
+                // We must isolate the sign, significand, and exponent
+                // fields.  The sign value is straightforward.  Since
+                // floating-point numbers are stored with a normalized
+                // representation, the significand and exponent are
+                // interrelated.
+                //
+                // After extracting the sign, we normalized the
+                // significand as a hexadecimal value, calculating an
+                // exponent adjust for any shifts made during
+                // normalization.  If the significand is zero, the
+                // exponent doesn't need to be examined since the output
+                // will be zero.
+                //
+                // Next the exponent in the input string is extracted.
+                // Afterwards, the significand is normalized as a *binary*
+                // value and the input value's normalized exponent can be
+                // computed.  The significand bits are copied into a
+                // double significand; if the string has more logical bits
+                // than can fit in a double, the extra bits affect the
+                // round and sticky bits which are used to round the final
+                // value.
+                //
+                //  Extract significand sign
+                String group1 = m.group(1);
+                boolean isNegative = ((group1 != null) && group1.equals("-"));
+
+                //  Extract Significand magnitude
+                //
+                // Based on the form of the significand, calculate how the
+                // binary exponent needs to be adjusted to create a
+                // normalized//hexadecimal* floating-point number; that
+                // is, a number where there is one nonzero hex digit to
+                // the left of the (hexa)decimal point.  Since we are
+                // adjusting a binary, not hexadecimal exponent, the
+                // exponent is adjusted by a multiple of 4.
+                //
+                // There are a number of significand scenarios to consider;
+                // letters are used in indicate nonzero digits:
+                //
+                // 1. 000xxxx       =>      x.xxx   normalized
+                //    increase exponent by (number of x's - 1)*4
+                //
+                // 2. 000xxx.yyyy =>        x.xxyyyy        normalized
+                //    increase exponent by (number of x's - 1)*4
+                //
+                // 3. .000yyy  =>   y.yy    normalized
+                //    decrease exponent by (number of zeros + 1)*4
+                //
+                // 4. 000.00000yyy => y.yy normalized
+                //    decrease exponent by (number of zeros to right of point + 1)*4
+                //
+                // If the significand is exactly zero, return a properly
+                // signed zero.
+                //
+
+                String significandString;
+                int signifLength;
+                int exponentAdjust;
+                {
+                    int leftDigits = 0; // number of meaningful digits to
+                    // left of "decimal" point
+                    // (leading zeros stripped)
+                    int rightDigits = 0; // number of digits to right of
+                    // "decimal" point; leading zeros
+                    // must always be accounted for
+                    //
+                    // The significand is made up of either
+                    //
+                    // 1. group 4 entirely (integer portion only)
+                    //
+                    // OR
+                    //
+                    // 2. the fractional portion from group 7 plus any
+                    // (optional) integer portions from group 6.
+                    //
+                    String group4;
+                    if ((group4 = m.group(4)) != null) {  // Integer-only significand
+                        // Leading zeros never matter on the integer portion
+                        significandString = stripLeadingZeros(group4);
+                        leftDigits = significandString.length();
+                    } else {
+                        // Group 6 is the optional integer; leading zeros
+                        // never matter on the integer portion
+                        String group6 = stripLeadingZeros(m.group(6));
+                        leftDigits = group6.length();
+
+                        // fraction
+                        String group7 = m.group(7);
+                        rightDigits = group7.length();
+
+                        // Turn "integer.fraction" into "integer"+"fraction"
+                        significandString =
+                                ((group6 == null) ? "" : group6) + // is the null
+                                        // check necessary?
+                                        group7;
+                    }
+
+                    significandString = stripLeadingZeros(significandString);
+                    signifLength = significandString.length();
+
+                    //
+                    // Adjust exponent as described above
+                    //
+                    if (leftDigits >= 1) {  // Cases 1 and 2
+                        exponentAdjust = 4 * (leftDigits - 1);
+                    } else {                // Cases 3 and 4
+                        exponentAdjust = -4 * (rightDigits - signifLength + 1);
+                    }
+
+                    // If the significand is zero, the exponent doesn't
+                    // matter; return a properly signed zero.
+
+                    if (signifLength == 0) { // Only zeros in input
+                        return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
+                    }
+                }
+
+                //  Extract Exponent
+                //
+                // Use an int to read in the exponent value; this should
+                // provide more than sufficient range for non-contrived
+                // inputs.  If reading the exponent in as an int does
+                // overflow, examine the sign of the exponent and
+                // significand to determine what to do.
+                //
+                String group8 = m.group(8);
+                boolean positiveExponent = (group8 == null) || group8.equals("+");
+                long unsignedRawExponent;
+                try {
+                    unsignedRawExponent = Integer.parseInt(m.group(9));
+                }
+                catch (NumberFormatException e) {
+                    // At this point, we know the exponent is
+                    // syntactically well-formed as a sequence of
+                    // digits.  Therefore, if an NumberFormatException
+                    // is thrown, it must be due to overflowing int's
+                    // range.  Also, at this point, we have already
+                    // checked for a zero significand.  Thus the signs
+                    // of the exponent and significand determine the
+                    // final result:
+                    //
+                    //                      significand
+                    //                      +               -
+                    // exponent     +       +infinity       -infinity
+                    //              -       +0.0            -0.0
+                    return isNegative ?
+                              (positiveExponent ? A2BC_NEGATIVE_INFINITY : A2BC_NEGATIVE_ZERO)
+                            : (positiveExponent ? A2BC_POSITIVE_INFINITY : A2BC_POSITIVE_ZERO);
+
+                }
+
+                long rawExponent =
+                        (positiveExponent ? 1L : -1L) * // exponent sign
+                                unsignedRawExponent;            // exponent magnitude
+
+                // Calculate partially adjusted exponent
+                long exponent = rawExponent + exponentAdjust;
+
+                // Starting copying non-zero bits into proper position in
+                // a long; copy explicit bit too; this will be masked
+                // later for normal values.
+
+                boolean round = false;
+                boolean sticky = false;
+                int nextShift;
+                long significand = 0L;
+                // First iteration is different, since we only copy
+                // from the leading significand bit; one more exponent
+                // adjust will be needed...
+
+                // IMPORTANT: make leadingDigit a long to avoid
+                // surprising shift semantics!
+                long leadingDigit = getHexDigit(significandString, 0);
+
+                //
+                // Left shift the leading digit (53 - (bit position of
+                // leading 1 in digit)); this sets the top bit of the
+                // significand to 1.  The nextShift value is adjusted
+                // to take into account the number of bit positions of
+                // the leadingDigit actually used.  Finally, the
+                // exponent is adjusted to normalize the significand
+                // as a binary value, not just a hex value.
+                //
+                if (leadingDigit == 1) {
+                    significand |= leadingDigit << 52;
+                    nextShift = 52 - 4;
+                    // exponent += 0
+                } else if (leadingDigit <= 3) { // [2, 3]
+                    significand |= leadingDigit << 51;
+                    nextShift = 52 - 5;
+                    exponent += 1;
+                } else if (leadingDigit <= 7) { // [4, 7]
+                    significand |= leadingDigit << 50;
+                    nextShift = 52 - 6;
+                    exponent += 2;
+                } else if (leadingDigit <= 15) { // [8, f]
+                    significand |= leadingDigit << 49;
+                    nextShift = 52 - 7;
+                    exponent += 3;
+                } else {
+                    throw new AssertionError("Result from digit conversion too large!");
+                }
+                // The preceding if-else could be replaced by a single
+                // code block based on the high-order bit set in
+                // leadingDigit.  Given leadingOnePosition,
+
+                // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition);
+                // nextShift = 52 - (3 + leadingOnePosition);
+                // exponent += (leadingOnePosition-1);
+
+                //
+                // Now the exponent variable is equal to the normalized
+                // binary exponent.  Code below will make representation
+                // adjustments if the exponent is incremented after
+                // rounding (includes overflows to infinity) or if the
+                // result is subnormal.
+                //
+
+                // Copy digit into significand until the significand can't
+                // hold another full hex digit or there are no more input
+                // hex digits.
+                int i = 0;
+                for (i = 1;
+                     i < signifLength && nextShift >= 0;
+                     i++) {
+                    long currentDigit = getHexDigit(significandString, i);
+                    significand |= (currentDigit << nextShift);
+                    nextShift -= 4;
+                }
+
+                // After the above loop, the bulk of the string is copied.
+                // Now, we must copy any partial hex digits into the
+                // significand AND compute the round bit and start computing
+                // sticky bit.
+
+                if (i < signifLength) { // at least one hex input digit exists
+                    long currentDigit = getHexDigit(significandString, i);
+
+                    // from nextShift, figure out how many bits need
+                    // to be copied, if any
+                    switch (nextShift) { // must be negative
+                        case -1:
+                            // three bits need to be copied in; can
+                            // set round bit
+                            significand |= ((currentDigit & 0xEL) >> 1);
+                            round = (currentDigit & 0x1L) != 0L;
+                            break;
+
+                        case -2:
+                            // two bits need to be copied in; can
+                            // set round and start sticky
+                            significand |= ((currentDigit & 0xCL) >> 2);
+                            round = (currentDigit & 0x2L) != 0L;
+                            sticky = (currentDigit & 0x1L) != 0;
+                            break;
+
+                        case -3:
+                            // one bit needs to be copied in
+                            significand |= ((currentDigit & 0x8L) >> 3);
+                            // Now set round and start sticky, if possible
+                            round = (currentDigit & 0x4L) != 0L;
+                            sticky = (currentDigit & 0x3L) != 0;
+                            break;
+
+                        case -4:
+                            // all bits copied into significand; set
+                            // round and start sticky
+                            round = ((currentDigit & 0x8L) != 0);  // is top bit set?
+                            // nonzeros in three low order bits?
+                            sticky = (currentDigit & 0x7L) != 0;
+                            break;
+
+                        default:
+                            throw new AssertionError("Unexpected shift distance remainder.");
+                            // break;
+                    }
+
+                    // Round is set; sticky might be set.
+
+                    // For the sticky bit, it suffices to check the
+                    // current digit and test for any nonzero digits in
+                    // the remaining unprocessed input.
+                    i++;
+                    while (i < signifLength && !sticky) {
+                        currentDigit = getHexDigit(significandString, i);
+                        sticky = sticky || (currentDigit != 0);
+                        i++;
+                    }
+
+                }
+                // else all of string was seen, round and sticky are
+                // correct as false.
+
+                // Float calculations
+                int floatBits = isNegative ? FloatConsts.SIGN_BIT_MASK : 0;
+                if (exponent >= Float.MIN_EXPONENT) {
+                    if (exponent > Float.MAX_EXPONENT) {
+                        // Float.POSITIVE_INFINITY
+                        floatBits |= FloatConsts.EXP_BIT_MASK;
+                    } else {
+                        int threshShift = DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH - 1;
+                        boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky;
+                        int iValue = (int) (significand >>> threshShift);
+                        if ((iValue & 3) != 1 || floatSticky) {
+                            iValue++;
+                        }
+                        floatBits |= (((((int) exponent) + (FloatConsts.EXP_BIAS - 1))) << SINGLE_EXP_SHIFT) + (iValue >> 1);
+                    }
+                } else {
+                    if (exponent < FloatConsts.MIN_SUB_EXPONENT - 1) {
+                        // 0
+                    } else {
+                        // exponent == -127 ==> threshShift = 53 - 2 + (-149) - (-127) = 53 - 24
+                        int threshShift = (int) ((DoubleConsts.SIGNIFICAND_WIDTH - 2 + FloatConsts.MIN_SUB_EXPONENT) - exponent);
+                        assert threshShift >= DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH;
+                        assert threshShift < DoubleConsts.SIGNIFICAND_WIDTH;
+                        boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky;
+                        int iValue = (int) (significand >>> threshShift);
+                        if ((iValue & 3) != 1 || floatSticky) {
+                            iValue++;
+                        }
+                        floatBits |= iValue >> 1;
+                    }
+                }
+                float fValue = Float.intBitsToFloat(floatBits);
+
+                // Check for overflow and update exponent accordingly.
+                if (exponent > Double.MAX_EXPONENT) {         // Infinite result
+                    // overflow to properly signed infinity
+                    return isNegative ? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
+                } else {  // Finite return value
+                    if (exponent <= Double.MAX_EXPONENT && // (Usually) normal result
+                            exponent >= Double.MIN_EXPONENT) {
+
+                        // The result returned in this block cannot be a
+                        // zero or subnormal; however after the
+                        // significand is adjusted from rounding, we could
+                        // still overflow in infinity.
+
+                        // AND exponent bits into significand; if the
+                        // significand is incremented and overflows from
+                        // rounding, this combination will update the
+                        // exponent correctly, even in the case of
+                        // Double.MAX_VALUE overflowing to infinity.
+
+                        significand = ((( exponent +
+                                (long) DoubleConsts.EXP_BIAS) <<
+                                (DoubleConsts.SIGNIFICAND_WIDTH - 1))
+                                & DoubleConsts.EXP_BIT_MASK) |
+                                (DoubleConsts.SIGNIF_BIT_MASK & significand);
+
+                    } else {  // Subnormal or zero
+                        // (exponent < Double.MIN_EXPONENT)
+
+                        if (exponent < (DoubleConsts.MIN_SUB_EXPONENT - 1)) {
+                            // No way to round back to nonzero value
+                            // regardless of significand if the exponent is
+                            // less than -1075.
+                            return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
+                        } else { //  -1075 <= exponent <= MIN_EXPONENT -1 = -1023
+                            //
+                            // Find bit position to round to; recompute
+                            // round and sticky bits, and shift
+                            // significand right appropriately.
+                            //
+
+                            sticky = sticky || round;
+                            round = false;
+
+                            // Number of bits of significand to preserve is
+                            // exponent - abs_min_exp +1
+                            // check:
+                            // -1075 +1074 + 1 = 0
+                            // -1023 +1074 + 1 = 52
+
+                            int bitsDiscarded = 53 -
+                                    ((int) exponent - DoubleConsts.MIN_SUB_EXPONENT + 1);
+                            assert bitsDiscarded >= 1 && bitsDiscarded <= 53;
+
+                            // What to do here:
+                            // First, isolate the new round bit
+                            round = (significand & (1L << (bitsDiscarded - 1))) != 0L;
+                            if (bitsDiscarded > 1) {
+                                // create mask to update sticky bits; low
+                                // order bitsDiscarded bits should be 1
+                                long mask = ~((~0L) << (bitsDiscarded - 1));
+                                sticky = sticky || ((significand & mask) != 0L);
+                            }
+
+                            // Now, discard the bits
+                            significand = significand >> bitsDiscarded;
+
+                            significand = ((((long) (Double.MIN_EXPONENT - 1) + // subnorm exp.
+                                    (long) DoubleConsts.EXP_BIAS) <<
+                                    (DoubleConsts.SIGNIFICAND_WIDTH - 1))
+                                    & DoubleConsts.EXP_BIT_MASK) |
+                                    (DoubleConsts.SIGNIF_BIT_MASK & significand);
+                        }
+                    }
+
+                    // The significand variable now contains the currently
+                    // appropriate exponent bits too.
+
+                    //
+                    // Determine if significand should be incremented;
+                    // making this determination depends on the least
+                    // significant bit and the round and sticky bits.
+                    //
+                    // Round to nearest even rounding table, adapted from
+                    // table 4.7 in "Computer Arithmetic" by IsraelKoren.
+                    // The digit to the left of the "decimal" point is the
+                    // least significant bit, the digits to the right of
+                    // the point are the round and sticky bits
+                    //
+                    // Number       Round(x)
+                    // x0.00        x0.
+                    // x0.01        x0.
+                    // x0.10        x0.
+                    // x0.11        x1. = x0. +1
+                    // x1.00        x1.
+                    // x1.01        x1.
+                    // x1.10        x1. + 1
+                    // x1.11        x1. + 1
+                    //
+                    boolean leastZero = ((significand & 1L) == 0L);
+                    if ((leastZero && round && sticky) ||
+                            ((!leastZero) && round)) {
+                        significand++;
+                    }
+
+                    double value = isNegative ?
+                            Double.longBitsToDouble(significand | DoubleConsts.SIGN_BIT_MASK) :
+                            Double.longBitsToDouble(significand );
+
+                    return new PreparedASCIIToBinaryBuffer(value, fValue);
+                }
+            }
+    }
+
+    /**
+     * Returns s with any leading zeros removed.
+     */
+    static String stripLeadingZeros(String s) {
+        if(!s.isEmpty() && s.charAt(0)=='0') {
+            for(int i=1; iposition
+     * of string s.
+     */
+    static int getHexDigit(String s, int position) {
+        int value = Character.digit(s.charAt(position), 16);
+        if (value <= -1 || value >= 16) {
+            throw new AssertionError("Unexpected failure of digit conversion of " +
+                                     s.charAt(position));
+        }
+        return value;
+    }
+}
diff --git a/tests/test_data/std/jdk/internal/math/FormattedFPDecimal.class b/tests/test_data/std/jdk/internal/math/FormattedFPDecimal.class
new file mode 100644
index 0000000000000000000000000000000000000000..9d19e2ff70bd232112d1ebbd6021b75469483f39
GIT binary patch
literal 4605
zcmb7H>vI#=75`mnW!duD7GRr)Yz!2zEMpAe4d&taLFE`j0UHQy;>B9q3$mohGLJAN
zPZ9!clcvy?N76tu%Y+H$G*OG+OM?k@7!HW!tjA=X0?0Io_ij@
z^SkHX{o{YX_zi##+zG)4e-MU=07?|XC#};~Ytl-MwC+D~(jLkwl(ac1C$~$%A8i^4
zqEun!$;7EvCzZ3aDJ$7JX5~g(yVF_Tb9SQpK&L(Aj9JMLg7Ak>4l{@f6P2h^SpN9L
z&h*5Iq02#wPGTWNm@=yB#TTe7D;f#PT5&28AL>3MFFCCGHH)k$@c8X#2B4+ogK0>IVYVe
zMZH4JL~48@lSyZZ%CceNv#fE|P-6%USQf-`6D#lyg#`s;9ivv(8X~ClciKu$*!zbS
z7DYRlLB1w=ogE>p!s;LzO+?Z3NZk(QvQBD*brYW!k=zz7vf#emalA<67J5gqA5SZU
zC1@6AtYJD&u+lV8MwHf?XvI1O#duYZNS-mV0UJ58dBsJt*~AttNy%uNiS5`yM%iaG
z3clkVBHU?Wmk3J|&WMv67yS2_XvedxNH#r@N+=l79=F<^Cc4ngYU@%7D&q>#=>Jjd
zZ<>e;;cE&O4oqb2I9WYnXT|w*CVEAqs-UsYIcq26U7v~l@~*b?D&%oZRU1b~eo@1JQWgO`_k#0FEeB&T4e(#EC$(hdMoC<(P@*g@IKCTI+1(
z-M3AAM}mmVc_+?_BYDxppy(~0qt}-%);eKgNVG~>le`Pt#4yOEU@onLb4$=6-W?Ms
zaY|wSh)v>W(kU*0gHk4&g<`9ShcJdz5NQ(`yu>UEEZ)bCK^^M^;V`&FsT#z%xFTCc
zKnJIBCWx~p&f#Td_;@1_8~r&aDTrp$XV#N{GP5VZwkE$2$#JM7-qm+F-W~5C4S7{`
zq*LQLE0r6N<>jXq`58FS+aB+e!7%gO+tt@~u)SA?Oxx&4C#X`@>!j?yiLn!Q_OQin
z#iV=FLsoLY$~rRkghp=EVK}RwuHz^)M?2%Px}Tz%a#^U;ygC_ECTp{`8M3;$c7};|
z#i5)vbZVcK@dELW+XT{O(SSmEQH2DhrsKpyg!>4EGd^z7@L8IY&ZAf|v7|y1}SuV{n9fl62C$d9!wp;>9X1rL%Qm9#Y##c~4x#UCAH3I6liL<8U*u>5?~3<8>^{_8t@alGWrqW{
z!oW7X%_q}U!X>=JQ5pO2WzWE$8L;qY@BxCy?xSqGv3jvFjZpnBDCBPoFPqm0uR30<
zc&%M*)J-8gi5C4(J&Be2Vc{eq53uCe{5s<+_>TGOr?K?VG*;e6?CZ}s&ku=hHT?r^
z{NITxw!byljZN6Yr*`bcvpCEx`bCZ;?ie#*Y`B8&@h(r_Cn%EJAbvpj{Iqfe?=mX`
z?@?NXz(cGFB3N2ldW1J7`9r+#rD{`MQk@rTxQCWl{XMLY)fo4%ses#j?XQPw&k@63
zgt4zEj(Hw_G@*+nz|WJePs8#g1vBXEN4V;_Y~|f8&*#`G5co6%Qa#|n6H23S?TM4y
z=1xBR#L4VVp6AVUB~HxP=h(z+{h*QfWKIA_i)@%)Zaz5=csBZogJ4}7%Nw~ExoAyc
zcWeqBg@|0XSw!H3wkQ-8qPlF8C#f3Ol5Aj}?Ti;+qr`R-AzIu!i6wbQA8Jw0B!Yai
zFDA}h`Ya*$*|%8R5gxEcxm!C}&a_vt^%kh!=sACnx&inr=lki8o1f?1rclsnEoAm(
z;2zp$hc04MI3R)+zeF{K!$;>5i)9$cTI7nnx8}j*ZtA(b!Y850UhTse%=>E*
z>&77e*UKLt>1q$3+GM1~;kEs-1|5YSJ{n3ba{EI|oYe&C
z$80iE32xdq%wD-gsT#3Yya395W%wHrHj2NoH5DVzIHM+o%ULh%7
z<#FvbHlx?M$loXmtKAE09z&W9i|1J{tZt8dm9fahkmg)u3P=l_Hy!o=uP&
zv!vr;!m~M~QwM4y*EPM4yYza26tjvb<|6v8?kVMLA5~nE3%D?aUM{z5@@{H8H$pT6
zzH;FiPbi+laSz+pm?0n*6+PezW=k#j36B1TX(Wn}bVIpLByX_&-o#4WBG*1B3T2jS
zbqsM9MIL>;0QTyJ#EfIcY+c)gNG*@Lsnpc`h>Pkrs&Pk~clV6hOnvfI;2C|J+Ct?h
zOXD_!(VgLkbw5YAE^-Iu(j1OV@*Xh~EZLDFWL;wXlHq;AucS|j=C806pOLq});^cH
zcJt^)J#@=akDutyFF13HeTbz>c3K|a+@RDt@S!p>%yVrE@H5?girOOiD_i}>v!g*fr3<&4DMoCsm)e@6Ohq^WV}n>f)AtjxzVG
zVWOm>D)b+8D1&wM$#;zlCYNd{Im**ZjZyzGRy9aMTcl^Uy=lzU7!9=nN*r63U~OQ}
zm>c>;sQeF?`4;
zH(qupV&s!AG%wDCw~njpA|LZqB=PxX>cZ>#Cujayz+CqRwE+ROkzZw-brkM8t5 fd.scientific(prec);
+            case PLAIN      -> fd.plain(prec);
+            case GENERAL    -> fd.general(prec);
+            default         -> throw new IllegalArgumentException(
+                    String.format("unsupported form '%c'", form)
+            );
+        };
+    }
+
+    public void set(long f, int e, int n) {
+        /* Initially, n = 0 if f = 0, and 10^{n-1} <= f < 10^n if f != 0 */
+        this.f = f;
+        this.e = e;
+        this.n = n;
+    }
+
+    public char[] getExponent() {
+        return exp;
+    }
+
+    public char[] getMantissa() {
+        return digits;
+    }
+
+    public int getExponentRounded() {
+        return n + e - 1;
+    }
+
+    private FormattedFPDecimal plain(int prec) {
+        /*
+         * Rounding d = f 10^e to prec digits in plain mode means the same
+         * as rounding it to the p = n + e + prec most significand digits of d,
+         * with the understanding that p < 0 cuts off all its digits.
+         */
+        round(n + e + (long) prec);  // n + e is well inside the int range
+        return plainChars();
+    }
+
+    private FormattedFPDecimal plainChars() {
+        if (e >= 0) {
+            plainCharsPureInteger();
+        } else if (n + e > 0) {
+            plainCharsMixed();
+        } else {
+            plainCharsPureFraction();
+        }
+        return this;
+    }
+
+    private void plainCharsPureInteger() {
+        digits = new char[n + e];
+        fillWithZeros(n, n + e);
+        fillWithDigits(f, 0, n);
+    }
+
+    private void plainCharsMixed() {
+        digits = new char[n + 1];
+        long x = fillWithDigits(f, n + 1 + e, n + 1);
+        digits[n + e] = '.';
+        fillWithDigits(x, 0, n + e);
+    }
+
+    private void plainCharsPureFraction() {
+        digits = new char[2 - e];
+        long x = f;
+        fillWithDigits(x, 2 - e - n, 2 - e);
+        fillWithZeros(0, 2 - e - n);
+        digits[1] = '.';
+    }
+
+    private FormattedFPDecimal scientific(int prec) {
+        /*
+         * Rounding d = f 10^e to prec digits in scientific mode means the same
+         * as rounding it to the p = prec + 1 most significand digits of d.
+         */
+        round(prec + 1L);
+        return scientificChars(prec);
+    }
+
+    private FormattedFPDecimal scientificChars(int prec) {
+        if (prec != 0) {
+            scientificCharsWithFraction();
+        } else {
+            scientificCharsNoFraction();
+        }
+        expChars();
+        return this;
+    }
+
+    private void scientificCharsWithFraction() {
+        digits = new char[1 + n];  // room for leading digit and for '.'
+        long x = fillWithDigits(f, 2, 1 + n);
+        digits[1] = '.';
+        digits[0] = toDigit(x);
+    }
+
+    private void scientificCharsNoFraction() {
+        digits = new char[1];
+        digits[0] = toDigit(f);
+    }
+
+    private FormattedFPDecimal general(int prec) {
+        /*
+         * Rounding d = f 10^e to prec digits in general mode means the same
+         * as rounding it to the p = prec most significand digits of d, and then
+         * deciding whether to format it in plain or scientific mode, depending
+         * on the rounded value.
+         */
+        round(prec);
+        int er = getExponentRounded();
+        if (-4 <= er && er < prec) {
+            plainChars();
+        } else {
+            scientificChars(prec - 1);
+        }
+        return this;
+    }
+
+    private void expChars() {
+        int er = getExponentRounded();
+        int aer = Math.abs(er);
+        exp = new char[aer >= 100 ? 4 : 3];
+        int q;
+        if (aer >= 100) {
+            q = aer / 10;
+            exp[3] = toDigit(aer - 10 * q);
+            aer = q;
+        }
+        q = aer / 10;
+        exp[2] = toDigit(aer - 10 * q);
+        exp[1] = toDigit(q);
+        exp[0] = er >= 0 ? '+' : '-';
+    }
+
+    private void round(long pp) {
+        /*
+         * Let d = f 10^e, and let p shorten pp.
+         * This method rounds d to the p most significant digits.
+         * It does so by possibly modifying f, e and n.
+         * When f becomes 0, e and n are normalized to 0 and 1, resp.
+         *
+         * For any real x let
+         *      r(x) = floor(x + 1/2)
+         * which is rounding to the closest integer, with ties rounded toward
+         * positive infinity.
+         *
+         * When f = 0 there's not much to say, except that this holds iff n = 0.
+         *
+         * Otherwise, since
+         *      10^{n-1} <= f < 10^n
+         * it follows that
+         *      10^{e+n-1} <= d < 10^{e+n}
+         * To round d to the most significant p digits, first scale d to the
+         * range [10^{p-1}, 10^p), cutoff the fractional digits by applying r,
+         * and finally scale back.
+         * To this end, first define
+         *      ds = d 10^{p-e-n}
+         * which ensures
+         *      10^{p-1} <= ds < 10^p
+         *
+         * Now, if p < 0 (that is, if p <= -1) then
+         *      ds < 10^p <= 10^{-1} < 1/2
+         * so that
+         *      r(ds) = 0
+         * Thus, rounding d to p < 0 digits leads to 0.
+         */
+        if (n == 0 || pp < 0) {
+            f = 0;
+            e = 0;
+            n = 1;
+            return;
+        }
+
+        /*
+         * Further, if p >= n then
+         *      ds = f 10^e 10^{p-e-n} = f 10^{p-n}
+         * which shows that ds is an integer, so r(ds) = ds. That is,
+         * rounding to p >= n digits leads to a result equal to d.
+         */
+        if (pp >= n) {  // no rounding needed
+            return;
+        }
+
+        /*
+         * Finally, 0 <= p < n. When p = 0 it follows that
+         *      10^{-1} <= ds < 1
+         *      0 <= f' = r(ds) <= 1
+         * that is, f' is either 0 or 1.
+         *
+         * Otherwise
+         *      10^{p-1} <= ds < 10^p
+         *      1 <= 10^{p-1} <= f' = r(ds) <= 10^p
+         * Note that f' = 10^p is a possible outcome.
+         *
+         * Scale back, where e' = e + n - p
+         *      d' = f' 10^{e+n-p} = f' 10^e', with 10^{e+n-1} <= d' <= 10^{e+n}
+         *
+         * Since n > p, f' can be computed in integer arithmetic as follows,
+         * where / denotes division in the real numbers:
+         *      f' = r(ds) = r(f 10^{p-n}) = r(f / 10^{n-p})
+         *          = floor(f / 10^{n-p} + 1/2)
+         *          = floor((f + 10^{n-p}/2) / 10^{n-p})
+         */
+        int p = (int) pp;  // 0 <= pp < n, safe cast
+        e += n - p;  // new e is well inside the int range
+        long pow10 = MathUtils.pow10(n - p);
+        f = (f + (pow10 >> 1)) / pow10;
+        if (p == 0) {
+            n = 1;
+            if (f == 0) {
+                e = 0;
+            }
+            return;
+        }
+
+        n = p;
+        if (f == MathUtils.pow10(p)) {
+            /*
+             * f is n + 1 digits long.
+             * Absorb one trailing zero into e and reduce f accordingly.
+             */
+            f /= 10;
+            e += 1;
+        }
+    }
+
+    /*
+     * Fills the digits section with indices in [from, to) with the lower
+     * to - from digits of x (as chars), while stripping them away from x.
+     * Returns the stripped x.
+     */
+    private long fillWithDigits(long x, int from, int to) {
+        while (to > from) {
+            long q = x / 10;
+            digits[--to] = toDigit(x - q * 10);
+            x = q;
+        }
+        return x;
+    }
+
+    /*
+     * Fills the digits section with indices in [from, to) with '0'.
+     */
+    private void fillWithZeros(int from, int to) {
+        while (to > from) {
+            digits[--to] = '0';
+        }
+    }
+
+    private static char toDigit(long d) {
+        return toDigit((int) d);
+    }
+
+    private static char toDigit(int d) {
+        return (char) (d + '0');
+    }
+
+}
diff --git a/tests/test_data/std/jdk/internal/math/MathUtils.class b/tests/test_data/std/jdk/internal/math/MathUtils.class
new file mode 100644
index 0000000000000000000000000000000000000000..2faa54894541437e9bf2a30ba628244a30967f16
GIT binary patch
literal 22080
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

literal 0
HcmV?d00001

diff --git a/tests/test_data/std/jdk/internal/math/MathUtils.java b/tests/test_data/std/jdk/internal/math/MathUtils.java
new file mode 100644
index 00000000..3c52a244
--- /dev/null
+++ b/tests/test_data/std/jdk/internal/math/MathUtils.java
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.math;
+
+/**
+ * This class exposes package private utilities for other classes.
+ * Thus, all methods are assumed to be invoked with correct arguments,
+ * so these are not checked at all.
+ */
+final class MathUtils {
+    /*
+     * For full details about this code see the following reference:
+     *
+     *     Giulietti, "The Schubfach way to render doubles",
+     *     https://drive.google.com/file/d/1gp5xv4CAa78SVgCeWfGqqI4FfYYYuNFb
+     */
+
+    /*
+     * The boundaries for k in g0(int) and g1(int).
+     * K_MIN must be DoubleToDecimal.K_MIN or less.
+     * K_MAX must be DoubleToDecimal.K_MAX or more.
+     */
+    static final int K_MIN = -324;
+    static final int K_MAX = 292;
+
+    /* Must be DoubleToDecimal.H or more */
+    static final int H = 17;
+
+    /* C_10 = floor(log10(2) * 2^Q_10), A_10 = floor(log10(3/4) * 2^Q_10) */
+    private static final int Q_10 = 41;
+    private static final long C_10 = 661_971_961_083L;
+    private static final long A_10 = -274_743_187_321L;
+
+    /* C_2 = floor(log2(10) * 2^Q_2) */
+    private static final int Q_2 = 38;
+    private static final long C_2 = 913_124_641_741L;
+
+    private MathUtils() {
+        throw new RuntimeException("not supposed to be instantiated.");
+    }
+
+    /* The first powers of 10. The last entry must be 10^(DoubleToDecimal.H) */
+    private static final long[] pow10 = {
+        1L,
+        10L,
+        100L,
+        1_000L,
+        10_000L,
+        100_000L,
+        1_000_000L,
+        10_000_000L,
+        100_000_000L,
+        1_000_000_000L,
+        10_000_000_000L,
+        100_000_000_000L,
+        1_000_000_000_000L,
+        10_000_000_000_000L,
+        100_000_000_000_000L,
+        1_000_000_000_000_000L,
+        10_000_000_000_000_000L,
+        100_000_000_000_000_000L,
+    };
+
+    /**
+     * Returns 10{@code e}.
+     *
+     * @param e The exponent which must meet
+     *          0 ≤ {@code e} ≤ {@link #H}.
+     * @return 10{@code e}.
+     */
+    static long pow10(int e) {
+        return pow10[e];
+    }
+
+    /**
+     * Returns the unique integer k such that
+     * 10k ≤ 2{@code e}
+     * < 10k+1.
+     * 

+ * The result is correct when |{@code e}| ≤ 6_432_162. + * Otherwise the result is undefined. + * + * @param e The exponent of 2, which should meet + * |{@code e}| ≤ 6_432_162 for safe results. + * @return ⌊log102{@code e}⌋. + */ + static int flog10pow2(int e) { + return (int) (e * C_10 >> Q_10); + } + + /** + * Returns the unique integer k such that + * 10k ≤ 3/4 · 2{@code e} + * < 10k+1. + *

+ * The result is correct when + * -3_606_689 ≤ {@code e} ≤ 3_150_619. + * Otherwise the result is undefined. + * + * @param e The exponent of 2, which should meet + * -3_606_689 ≤ {@code e} ≤ 3_150_619 for safe results. + * @return ⌊log10(3/4 · + * 2{@code e})⌋. + */ + static int flog10threeQuartersPow2(int e) { + return (int) (e * C_10 + A_10 >> Q_10); + } + + /** + * Returns the unique integer k such that + * 2k ≤ 10{@code e} + * < 2k+1. + *

+ * The result is correct when |{@code e}| ≤ 1_838_394. + * Otherwise the result is undefined. + * + * @param e The exponent of 10, which should meet + * |{@code e}| ≤ 1_838_394 for safe results. + * @return ⌊log210{@code e}⌋. + */ + static int flog2pow10(int e) { + return (int) (e * C_2 >> Q_2); + } + + /** + * Let 10-{@code k} = β 2r, + * for the unique pair of integer r and real β meeting + * 2125β < 2126. + * Further, let g = ⌊β⌋ + 1. + * Split g into the higher 63 bits g1 and + * the lower 63 bits g0. Thus, + * g1 = + * ⌊g 2-63⌋ + * and + * g0 = + * g - g1 263. + *

+ * This method returns g1 while + * {@link #g0(int)} returns g0. + *

+ * If needed, the exponent r can be computed as + * r = {@code flog2pow10(-k)} - 125 (see {@link #flog2pow10(int)}). + * + * @param k The exponent of 10, which must meet + * {@link #K_MIN} ≤ {@code e} ≤ {@link #K_MAX}. + * @return g1 as described above. + */ + static long g1(int k) { + return g[k - K_MIN << 1]; + } + + /** + * Returns g0 as described in + * {@link #g1(int)}. + * + * @param k The exponent of 10, which must meet + * {@link #K_MIN} ≤ {@code e} ≤ {@link #K_MAX}. + * @return g0 as described in + * {@link #g1(int)}. + */ + static long g0(int k) { + return g[k - K_MIN << 1 | 1]; + } + + /* + * The precomputed values for g1(int) and g0(int). + * The first entry must be for an exponent of K_MIN or less. + * The last entry must be for an exponent of K_MAX or more. + */ + private static final long[] g = { + 0x4F0C_EDC9_5A71_8DD4L, 0x5B01_E8B0_9AA0_D1B5L, // -324 + 0x7E7B_160E_F71C_1621L, 0x119C_A780_F767_B5EEL, // -323 + 0x652F_44D8_C5B0_11B4L, 0x0E16_EC67_2C52_F7F2L, // -322 + 0x50F2_9D7A_37C0_0E29L, 0x5812_56B8_F042_5FF5L, // -321 + 0x40C2_1794_F966_71BAL, 0x79A8_4560_C035_1991L, // -320 + 0x679C_F287_F570_B5F7L, 0x75DA_089A_CD21_C281L, // -319 + 0x52E3_F539_9126_F7F9L, 0x44AE_6D48_A41B_0201L, // -318 + 0x424F_F761_40EB_F994L, 0x36F1_F106_E9AF_34CDL, // -317 + 0x6A19_8BCE_CE46_5C20L, 0x57E9_81A4_A918_547BL, // -316 + 0x54E1_3CA5_71D1_E34DL, 0x2CBA_CE1D_5413_76C9L, // -315 + 0x43E7_63B7_8E41_82A4L, 0x23C8_A4E4_4342_C56EL, // -314 + 0x6CA5_6C58_E39C_043AL, 0x060D_D4A0_6B9E_08B0L, // -313 + 0x56EA_BD13_E949_9CFBL, 0x1E71_76E6_BC7E_6D59L, // -312 + 0x4588_9743_2107_B0C8L, 0x7EC1_2BEB_C9FE_BDE1L, // -311 + 0x6F40_F205_01A5_E7A7L, 0x7E01_DFDF_A997_9635L, // -310 + 0x5900_C19D_9AEB_1FB9L, 0x4B34_B319_5479_44F7L, // -309 + 0x4733_CE17_AF22_7FC7L, 0x55C3_C27A_A9FA_9D93L, // -308 + 0x71EC_7CF2_B1D0_CC72L, 0x5606_03F7_765D_C8EAL, // -307 + 0x5B23_9728_8E40_A38EL, 0x7804_CFF9_2B7E_3A55L, // -306 + 0x48E9_45BA_0B66_E93FL, 0x1337_0CC7_55FE_9511L, // -305 + 0x74A8_6F90_123E_41FEL, 0x51F1_AE0B_BCCA_881BL, // -304 + 0x5D53_8C73_41CB_67FEL, 0x74C1_5809_63D5_39AFL, // -303 + 0x4AA9_3D29_016F_8665L, 0x43CD_E007_8310_FAF3L, // -302 + 0x7775_2EA8_024C_0A3CL, 0x0616_333F_381B_2B1EL, // -301 + 0x5F90_F220_01D6_6E96L, 0x3811_C298_F9AF_55B1L, // -300 + 0x4C73_F4E6_67DE_BEDEL, 0x600E_3547_2E25_DE28L, // -299 + 0x7A53_2170_A631_3164L, 0x3349_EED8_49D6_303FL, // -298 + 0x61DC_1AC0_84F4_2783L, 0x42A1_8BE0_3B11_C033L, // -297 + 0x4E49_AF00_6A5C_EC69L, 0x1BB4_6FE6_95A7_CCF5L, // -296 + 0x7D42_B19A_43C7_E0A8L, 0x2C53_E63D_BC3F_AE55L, // -295 + 0x6435_5AE1_CFD3_1A20L, 0x2376_51CA_FCFF_BEAAL, // -294 + 0x502A_AF1B_0CA8_E1B3L, 0x35F8_416F_30CC_9888L, // -293 + 0x4022_25AF_3D53_E7C2L, 0x5E60_3458_F3D6_E06DL, // -292 + 0x669D_0918_621F_D937L, 0x4A33_86F4_B957_CD7BL, // -291 + 0x5217_3A79_E819_7A92L, 0x6E8F_9F2A_2DDF_D796L, // -290 + 0x41AC_2EC7_ECE1_2EDBL, 0x720C_7F54_F17F_DFABL, // -289 + 0x6913_7E0C_AE35_17C6L, 0x1CE0_CBBB_1BFF_CC45L, // -288 + 0x540F_980A_24F7_4638L, 0x171A_3C95_AFFF_D69EL, // -287 + 0x433F_ACD4_EA5F_6B60L, 0x127B_63AA_F333_1218L, // -286 + 0x6B99_1487_DD65_7899L, 0x6A5F_05DE_51EB_5026L, // -285 + 0x5614_106C_B11D_FA14L, 0x5518_D17E_A7EF_7352L, // -284 + 0x44DC_D9F0_8DB1_94DDL, 0x2A7A_4132_1FF2_C2A8L, // -283 + 0x6E2E_2980_E2B5_BAFBL, 0x5D90_6850_331E_043FL, // -282 + 0x5824_EE00_B55E_2F2FL, 0x6473_86A6_8F4B_3699L, // -281 + 0x4683_F19A_2AB1_BF59L, 0x36C2_D21E_D908_F87BL, // -280 + 0x70D3_1C29_DDE9_3228L, 0x579E_1CFE_280E_5A5DL, // -279 + 0x5A42_7CEE_4B20_F4EDL, 0x2C7E_7D98_200B_7B7EL, // -278 + 0x4835_30BE_A280_C3F1L, 0x09FE_CAE0_19A2_C932L, // -277 + 0x7388_4DFD_D0CE_064EL, 0x4331_4499_C29E_0EB6L, // -276 + 0x5C6D_0B31_73D8_050BL, 0x4F5A_9D47_CEE4_D891L, // -275 + 0x49F0_D5C1_2979_9DA2L, 0x72AE_E439_7250_AD41L, // -274 + 0x764E_22CE_A8C2_95D1L, 0x377E_39F5_83B4_4868L, // -273 + 0x5EA4_E8A5_53CE_DE41L, 0x12CB_6191_3629_D387L, // -272 + 0x4BB7_2084_430B_E500L, 0x756F_8140_F821_7605L, // -271 + 0x7925_00D3_9E79_6E67L, 0x6F18_CECE_59CF_233CL, // -270 + 0x60EA_670F_B1FA_BEB9L, 0x3F47_0BD8_47D8_E8FDL, // -269 + 0x4D88_5272_F4C8_9894L, 0x329F_3CAD_0647_20CAL, // -268 + 0x7C0D_50B7_EE0D_C0EDL, 0x3765_2DE1_A3A5_0143L, // -267 + 0x633D_DA2C_BE71_6724L, 0x2C50_F181_4FB7_3436L, // -266 + 0x4F64_AE8A_31F4_5283L, 0x3D0D_8E01_0C92_902BL, // -265 + 0x7F07_7DA9_E986_EA6BL, 0x7B48_E334_E0EA_8045L, // -264 + 0x659F_97BB_2138_BB89L, 0x4907_1C2A_4D88_669DL, // -263 + 0x514C_7962_80FA_2FA1L, 0x20D2_7CEE_A46D_1EE4L, // -262 + 0x4109_FAB5_33FB_594DL, 0x670E_CA58_838A_7F1DL, // -261 + 0x680F_F788_532B_C216L, 0x0B4A_DD5A_6C10_CB62L, // -260 + 0x533F_F939_DC23_01ABL, 0x22A2_4AAE_BCDA_3C4EL, // -259 + 0x4299_942E_49B5_9AEFL, 0x354E_A225_63E1_C9D8L, // -258 + 0x6A8F_537D_42BC_2B18L, 0x554A_9D08_9FCF_A95AL, // -257 + 0x553F_75FD_CEFC_EF46L, 0x776E_E406_E63F_BAAEL, // -256 + 0x4432_C4CB_0BFD_8C38L, 0x5F8B_E99F_1E99_6225L, // -255 + 0x6D1E_07AB_4662_79F4L, 0x3279_75CB_6428_9D08L, // -254 + 0x574B_3955_D1E8_6190L, 0x2861_2B09_1CED_4A6DL, // -253 + 0x45D5_C777_DB20_4E0DL, 0x06B4_226D_B0BD_D524L, // -252 + 0x6FBC_7259_5E9A_167BL, 0x2453_6A49_1AC9_5506L, // -251 + 0x5963_8EAD_E548_11FCL, 0x1D0F_883A_7BD4_4405L, // -250 + 0x4782_D88B_1DD3_4196L, 0x4A72_D361_FCA9_D004L, // -249 + 0x726A_F411_C952_028AL, 0x43EA_EBCF_FAA9_4CD3L, // -248 + 0x5B88_C341_6DDB_353BL, 0x4FEF_230C_C887_70A9L, // -247 + 0x493A_35CD_F17C_2A96L, 0x0CBF_4F3D_6D39_26EEL, // -246 + 0x7529_EFAF_E8C6_AA89L, 0x6132_1862_485B_717CL, // -245 + 0x5DBB_2626_53D2_2207L, 0x675B_46B5_06AF_8DFDL, // -244 + 0x4AFC_1E85_0FDB_4E6CL, 0x52AF_6BC4_0559_3E64L, // -243 + 0x77F9_CA6E_7FC5_4A47L, 0x377F_12D3_3BC1_FD6DL, // -242 + 0x5FFB_0858_6637_6E9FL, 0x45FF_4242_9634_CABDL, // -241 + 0x4CC8_D379_EB5F_8BB2L, 0x6B32_9B68_782A_3BCBL, // -240 + 0x7ADA_EBF6_4565_AC51L, 0x2B84_2BDA_59DD_2C77L, // -239 + 0x6248_BCC5_0451_56A7L, 0x3C69_BCAE_AE4A_89F9L, // -238 + 0x4EA0_9704_0374_4552L, 0x6387_CA25_583B_A194L, // -237 + 0x7DCD_BE6C_D253_A21EL, 0x05A6_103B_C05F_68EDL, // -236 + 0x64A4_9857_0EA9_4E7EL, 0x37B8_0CFC_99E5_ED8AL, // -235 + 0x5083_AD12_7221_0B98L, 0x2C93_3D96_E184_BE08L, // -234 + 0x4069_5741_F4E7_3C79L, 0x7075_CADF_1AD0_9807L, // -233 + 0x670E_F203_2171_FA5CL, 0x4D89_4498_2AE7_59A4L, // -232 + 0x5272_5B35_B45B_2EB0L, 0x3E07_6A13_5585_E150L, // -231 + 0x41F5_15C4_9048_F226L, 0x64D2_BB42_AAD1_810DL, // -230 + 0x6988_22D4_1A0E_503EL, 0x07B7_9204_4482_6815L, // -229 + 0x546C_E8A9_AE71_D9CBL, 0x1FC6_0E69_D068_5344L, // -228 + 0x438A_53BA_F1F4_AE3CL, 0x196B_3EBB_0D20_429DL, // -227 + 0x6C10_85F7_E987_7D2DL, 0x0F11_FDF8_1500_6A94L, // -226 + 0x5673_9E5F_EE05_FDBDL, 0x58DB_3193_4400_5543L, // -225 + 0x4529_4B7F_F19E_6497L, 0x60AF_5ADC_3666_AA9CL, // -224 + 0x6EA8_78CC_B5CA_3A8CL, 0x344B_C493_8A3D_DDC7L, // -223 + 0x5886_C70A_2B08_2ED6L, 0x5D09_6A0F_A1CB_17D2L, // -222 + 0x46D2_38D4_EF39_BF12L, 0x173A_BB3F_B4A2_7975L, // -221 + 0x7150_5AEE_4B8F_981DL, 0x0B91_2B99_2103_F588L, // -220 + 0x5AA6_AF25_093F_ACE4L, 0x0940_EFAD_B403_2AD3L, // -219 + 0x4885_58EA_6DCC_8A50L, 0x0767_2624_9002_88A9L, // -218 + 0x7408_8E43_E2E0_DD4CL, 0x723E_A36D_B337_410EL, // -217 + 0x5CD3_A503_1BE7_1770L, 0x5B65_4F8A_F5C5_CDA5L, // -216 + 0x4A42_EA68_E31F_45F3L, 0x62B7_72D5_916B_0AEBL, // -215 + 0x76D1_770E_3832_0986L, 0x0458_B7BC_1BDE_77DDL, // -214 + 0x5F0D_F8D8_2CF4_D46BL, 0x1D13_C630_164B_9318L, // -213 + 0x4C0B_2D79_BD90_A9EFL, 0x30DC_9E8C_DEA2_DC13L, // -212 + 0x79AB_7BF5_FC1A_A97FL, 0x0160_FDAE_3104_9351L, // -211 + 0x6155_FCC4_C9AE_EDFFL, 0x1AB3_FE24_F403_A90EL, // -210 + 0x4DDE_63D0_A158_BE65L, 0x6229_981D_9002_EDA5L, // -209 + 0x7C97_061A_9BC1_30A2L, 0x69DC_2695_B337_E2A1L, // -208 + 0x63AC_04E2_1634_26E8L, 0x54B0_1EDE_28F9_821BL, // -207 + 0x4FBC_D0B4_DE90_1F20L, 0x43C0_18B1_BA61_34E2L, // -206 + 0x7F94_8121_6419_CB67L, 0x1F99_C11C_5D68_549DL, // -205 + 0x6610_674D_E9AE_3C52L, 0x4C7B_00E3_7DED_107EL, // -204 + 0x51A6_B90B_2158_3042L, 0x09FC_00B5_FE57_4065L, // -203 + 0x4152_2DA2_8113_59CEL, 0x3B30_0091_9845_CD1DL, // -202 + 0x6883_7C37_34EB_C2E3L, 0x784C_CDB5_C06F_AE95L, // -201 + 0x539C_635F_5D89_68B6L, 0x2D0A_3E2B_0059_5877L, // -200 + 0x42E3_82B2_B13A_BA2BL, 0x3DA1_CB55_99E1_1393L, // -199 + 0x6B05_9DEA_B52A_C378L, 0x629C_7888_F634_EC1EL, // -198 + 0x559E_17EE_F755_692DL, 0x3549_FA07_2B5D_89B1L, // -197 + 0x447E_798B_F911_20F1L, 0x1107_FB38_EF7E_07C1L, // -196 + 0x6D97_28DF_F4E8_34B5L, 0x01A6_5EC1_7F30_0C68L, // -195 + 0x57AC_20B3_2A53_5D5DL, 0x4E1E_B234_65C0_09EDL, // -194 + 0x4623_4D5C_21DC_4AB1L, 0x24E5_5B5D_1E33_3B24L, // -193 + 0x7038_7BC6_9C93_AAB5L, 0x216E_F894_FD1E_C506L, // -192 + 0x59C6_C96B_B076_222AL, 0x4DF2_6077_30E5_6A6CL, // -191 + 0x47D2_3ABC_8D2B_4E88L, 0x3E5B_805F_5A51_21F0L, // -190 + 0x72E9_F794_1512_1740L, 0x63C5_9A32_2A1B_697FL, // -189 + 0x5BEE_5FA9_AA74_DF67L, 0x0304_7B5B_54E2_BACCL, // -188 + 0x498B_7FBA_EEC3_E5ECL, 0x0269_FC49_10B5_623DL, // -187 + 0x75AB_FF91_7E06_3CACL, 0x6A43_2D41_B455_69FBL, // -186 + 0x5E23_32DA_CB38_308AL, 0x21CF_5767_C377_87FCL, // -185 + 0x4B4F_5BE2_3C2C_F3A1L, 0x67D9_12B9_692C_6CCAL, // -184 + 0x787E_F969_F9E1_85CFL, 0x595B_5128_A847_1476L, // -183 + 0x6065_9454_C7E7_9E3FL, 0x6115_DA86_ED05_A9F8L, // -182 + 0x4D1E_1043_D31F_B1CCL, 0x4DAB_1538_BD9E_2193L, // -181 + 0x7B63_4D39_51CC_4FADL, 0x62AB_5527_95C9_CF52L, // -180 + 0x62B5_D761_0E3D_0C8BL, 0x0222_AA86_116E_3F75L, // -179 + 0x4EF7_DF80_D830_D6D5L, 0x4E82_2204_DABE_992AL, // -178 + 0x7E59_659A_F381_57BCL, 0x1736_9CD4_9130_F510L, // -177 + 0x6514_5148_C2CD_DFC9L, 0x5F5E_E3DD_40F3_F740L, // -176 + 0x50DD_0DD3_CF0B_196EL, 0x1918_B64A_9A5C_C5CDL, // -175 + 0x40B0_D7DC_A5A2_7ABEL, 0x4746_F83B_AEB0_9E3EL, // -174 + 0x6781_5961_0903_F797L, 0x253E_59F9_1780_FD2FL, // -173 + 0x52CD_E11A_6D9C_C612L, 0x50FE_AE60_DF9A_6426L, // -172 + 0x423E_4DAE_BE17_04DBL, 0x5A65_584D_7FAE_B685L, // -171 + 0x69FD_4917_968B_3AF9L, 0x10A2_26E2_65E4_573BL, // -170 + 0x54CA_A0DF_ABA2_9594L, 0x0D4E_8581_EB1D_1295L, // -169 + 0x43D5_4D7F_BC82_1143L, 0x243E_D134_BC17_4211L, // -168 + 0x6C88_7BFF_9403_4ED2L, 0x06CA_E854_6025_3682L, // -167 + 0x56D3_9666_1002_A574L, 0x6BD5_86A9_E684_2B9BL, // -166 + 0x4576_11EB_4002_1DF7L, 0x0977_9EEE_5203_5616L, // -165 + 0x6F23_4FDE_CCD0_2FF1L, 0x5BF2_97E3_B66B_BCEFL, // -164 + 0x58E9_0CB2_3D73_598EL, 0x165B_ACB6_2B89_63F3L, // -163 + 0x4720_D6F4_FDF5_E13EL, 0x4516_23C4_EFA1_1CC2L, // -162 + 0x71CE_24BB_2FEF_CECAL, 0x3B56_9FA1_7F68_2E03L, // -161 + 0x5B0B_5095_BFF3_0BD5L, 0x15DE_E61A_CC53_5803L, // -160 + 0x48D5_DA11_665C_0977L, 0x2B18_B815_7042_ACCFL, // -159 + 0x7489_5CE8_A3C6_758BL, 0x5E8D_F355_806A_AE18L, // -158 + 0x5D3A_B0BA_1C9E_C46FL, 0x653E_5C44_66BB_BE7AL, // -157 + 0x4A95_5A2E_7D4B_D059L, 0x3765_169D_1EFC_9861L, // -156 + 0x7755_5D17_2EDF_B3C2L, 0x256E_8A94_FE60_F3CFL, // -155 + 0x5F77_7DAC_257F_C301L, 0x6ABE_D543_FEB3_F63FL, // -154 + 0x4C5F_97BC_EACC_9C01L, 0x3BCB_DDCF_FEF6_5E99L, // -153 + 0x7A32_8C61_77AD_C668L, 0x5FAC_9619_97F0_975BL, // -152 + 0x61C2_09E7_92F1_6B86L, 0x7FBD_44E1_465A_12AFL, // -151 + 0x4E34_D4B9_425A_BC6BL, 0x7FCA_9D81_0514_DBBFL, // -150 + 0x7D21_545B_9D5D_FA46L, 0x32DD_C8CE_6E87_C5FFL, // -149 + 0x641A_A9E2_E44B_2E9EL, 0x5BE4_A0A5_2539_6B32L, // -148 + 0x5015_54B5_836F_587EL, 0x7CB6_E6EA_842D_EF5CL, // -147 + 0x4011_1091_35F2_AD32L, 0x3092_5255_368B_25E3L, // -146 + 0x6681_B41B_8984_4850L, 0x4DB6_EA21_F0DE_A304L, // -145 + 0x5201_5CE2_D469_D373L, 0x57C5_881B_2718_826AL, // -144 + 0x419A_B0B5_76BB_0F8FL, 0x5FD1_39AF_527A_01EFL, // -143 + 0x68F7_8122_5791_B27FL, 0x4C81_F5E5_50C3_364AL, // -142 + 0x53F9_341B_7941_5B99L, 0x239B_2B1D_DA35_C508L, // -141 + 0x432D_C349_2DCD_E2E1L, 0x02E2_88E4_AE91_6A6DL, // -140 + 0x6B7C_6BA8_4949_6B01L, 0x516A_74A1_174F_10AEL, // -139 + 0x55FD_22ED_076D_EF34L, 0x4121_F6E7_45D8_DA25L, // -138 + 0x44CA_8257_3924_BF5DL, 0x1A81_9252_9E47_14EBL, // -137 + 0x6E10_D08B_8EA1_322EL, 0x5D9C_1D50_FD3E_87DDL, // -136 + 0x580D_73A2_D880_F4F2L, 0x17B0_1773_FDCB_9FE4L, // -135 + 0x4671_294F_139A_5D8EL, 0x4626_7929_97D6_1984L, // -134 + 0x70B5_0EE4_EC2A_2F4AL, 0x3D0A_5B75_BFBC_F59FL, // -133 + 0x5A2A_7250_BCEE_8C3BL, 0x4A6E_AF91_6630_C47FL, // -132 + 0x4821_F50D_63F2_09C9L, 0x21F2_260D_EB5A_36CCL, // -131 + 0x7369_8815_6CB6_760EL, 0x6983_7016_455D_247AL, // -130 + 0x5C54_6CDD_F091_F80BL, 0x6E02_C011_D117_5062L, // -129 + 0x49DD_23E4_C074_C66FL, 0x719B_CCDB_0DAC_404EL, // -128 + 0x762E_9FD4_6721_3D7FL, 0x68F9_47C4_E2AD_33B0L, // -127 + 0x5E8B_B310_5280_FDFFL, 0x6D94_396A_4EF0_F627L, // -126 + 0x4BA2_F5A6_A867_3199L, 0x3E10_2DEE_A58D_91B9L, // -125 + 0x7904_BC3D_DA3E_B5C2L, 0x3019_E317_6F48_E927L, // -124 + 0x60D0_9697_E1CB_C49BL, 0x4014_B5AC_5907_20ECL, // -123 + 0x4D73_ABAC_B4A3_03AFL, 0x4CDD_5E23_7A6C_1A57L, // -122 + 0x7BEC_45E1_2104_D2B2L, 0x47C8_969F_2A46_908AL, // -121 + 0x6323_6B1A_80D0_A88EL, 0x6CA0_787F_5505_406FL, // -120 + 0x4F4F_88E2_00A6_ED3FL, 0x0A19_F9FF_7737_66BFL, // -119 + 0x7EE5_A7D0_010B_1531L, 0x5CF6_5CCB_F1F2_3DFEL, // -118 + 0x6584_8640_00D5_AA8EL, 0x172B_7D6F_F4C1_CB32L, // -117 + 0x5136_D1CC_CD77_BBA4L, 0x78EF_978C_C3CE_3C28L, // -116 + 0x40F8_A7D7_0AC6_2FB7L, 0x13F2_DFA3_CFD8_3020L, // -115 + 0x67F4_3FBE_77A3_7F8BL, 0x3984_9906_1959_E699L, // -114 + 0x5329_CC98_5FB5_FFA2L, 0x6136_E0D1_ADE1_8548L, // -113 + 0x4287_D6E0_4C91_994FL, 0x00F8_B3DA_F181_376DL, // -112 + 0x6A72_F166_E0E8_F54BL, 0x1B27_862B_1C01_F247L, // -111 + 0x5528_C11F_1A53_F76FL, 0x2F52_D1BC_1667_F506L, // -110 + 0x4420_9A7F_4843_2C59L, 0x0C42_4163_451F_F738L, // -109 + 0x6D00_F732_0D38_46F4L, 0x7A03_9BD2_0833_2526L, // -108 + 0x5733_F8F4_D760_38C3L, 0x7B36_1641_A028_EA85L, // -107 + 0x45C3_2D90_AC4C_FA36L, 0x2F5E_7834_8020_BB9EL, // -106 + 0x6F9E_AF4D_E07B_29F0L, 0x4BCA_59ED_99CD_F8FCL, // -105 + 0x594B_BF71_8062_87F3L, 0x563B_7B24_7B0B_2D96L, // -104 + 0x476F_CC5A_CD1B_9FF6L, 0x11C9_2F50_626F_57ACL, // -103 + 0x724C_7A2A_E1C5_CCBDL, 0x02DB_7EE7_03E5_5912L, // -102 + 0x5B70_61BB_E7D1_7097L, 0x1BE2_CBEC_031D_E0DCL, // -101 + 0x4926_B496_530D_F3ACL, 0x164F_0989_9C17_E716L, // -100 + 0x750A_BA8A_1E7C_B913L, 0x3D4B_4275_C68C_A4F0L, // -99 + 0x5DA2_2ED4_E530_940FL, 0x4AA2_9B91_6BA3_B726L, // -98 + 0x4AE8_2577_1DC0_7672L, 0x6EE8_7C74_561C_9285L, // -97 + 0x77D9_D58B_62CD_8A51L, 0x3173_FA53_BCFA_8408L, // -96 + 0x5FE1_77A2_B571_3B74L, 0x278F_FB76_30C8_69A0L, // -95 + 0x4CB4_5FB5_5DF4_2F90L, 0x1FA6_62C4_F3D3_87B3L, // -94 + 0x7ABA_32BB_C986_B280L, 0x32A3_D13B_1FB8_D91FL, // -93 + 0x622E_8EFC_A138_8ECDL, 0x0EE9_742F_4C93_E0E6L, // -92 + 0x4E8B_A596_E760_723DL, 0x58BA_C359_0A0F_E71EL, // -91 + 0x7DAC_3C24_A567_1D2FL, 0x412A_D228_1019_71C9L, // -90 + 0x6489_C9B6_EAB8_E426L, 0x00EF_0E86_7347_8E3BL, // -89 + 0x506E_3AF8_BBC7_1CEBL, 0x1A58_D86B_8F6C_71C9L, // -88 + 0x4058_2F2D_6305_B0BCL, 0x1513_E056_0C56_C16EL, // -87 + 0x66F3_7EAF_04D5_E793L, 0x3B53_0089_AD57_9BE2L, // -86 + 0x525C_6558_D0AB_1FA9L, 0x15DC_006E_2446_164FL, // -85 + 0x41E3_8447_0D55_B2EDL, 0x5E49_99F1_B69E_783FL, // -84 + 0x696C_06D8_1555_EB15L, 0x7D42_8FE9_2430_C065L, // -83 + 0x5456_6BE0_1111_88DEL, 0x3102_0CBA_835A_3384L, // -82 + 0x4378_564C_DA74_6D7EL, 0x5A68_0A2E_CF7B_5C69L, // -81 + 0x6BF3_BD47_C3ED_7BFDL, 0x770C_DD17_B25E_FA42L, // -80 + 0x565C_976C_9CBD_FCCBL, 0x1270_B0DF_C1E5_9502L, // -79 + 0x4516_DF8A_16FE_63D5L, 0x5B8D_5A4C_9B1E_10CEL, // -78 + 0x6E8A_FF43_57FD_6C89L, 0x127B_C3AD_C4FC_E7B0L, // -77 + 0x586F_329C_4664_56D4L, 0x0EC9_6957_D0CA_52F3L, // -76 + 0x46BF_5BB0_3850_4576L, 0x3F07_8779_73D5_0F29L, // -75 + 0x7132_2C4D_26E6_D58AL, 0x31A5_A58F_1FBB_4B75L, // -74 + 0x5A8E_89D7_5252_446EL, 0x5AEA_EAD8_E62F_6F91L, // -73 + 0x4872_07DF_750E_9D25L, 0x2F22_557A_51BF_8C74L, // -72 + 0x73E9_A632_54E4_2EA2L, 0x1836_EF2A_1C65_AD86L, // -71 + 0x5CBA_EB5B_771C_F21BL, 0x2CF8_BF54_E384_8AD2L, // -70 + 0x4A2F_22AF_927D_8E7CL, 0x23FA_32AA_4F9D_3BDBL, // -69 + 0x76B1_D118_EA62_7D93L, 0x5329_EAAA_18FB_92F8L, // -68 + 0x5EF4_A747_21E8_6476L, 0x0F54_BBBB_472F_A8C6L, // -67 + 0x4BF6_EC38_E7ED_1D2BL, 0x25DD_62FC_38F2_ED6CL, // -66 + 0x798B_138E_3FE1_C845L, 0x22FB_D193_8E51_7BDFL, // -65 + 0x613C_0FA4_FFE7_D36AL, 0x4F2F_DADC_71DA_C97FL, // -64 + 0x4DC9_A61D_9986_42BBL, 0x58F3_157D_27E2_3ACCL, // -63 + 0x7C75_D695_C270_6AC5L, 0x74B8_2261_D969_F7ADL, // -62 + 0x6391_7877_CEC0_556BL, 0x1093_4EB4_ADEE_5FBEL, // -61 + 0x4FA7_9393_0BCD_1122L, 0x4075_D890_8B25_1965L, // -60 + 0x7F72_85B8_12E1_B504L, 0x00BC_8DB4_11D4_F56EL, // -59 + 0x65F5_37C6_7581_5D9CL, 0x66FD_3E29_A7DD_9125L, // -58 + 0x5190_F96B_9134_4AE3L, 0x6BFD_CB54_864A_DA84L, // -57 + 0x4140_C789_40F6_A24FL, 0x6FFE_3C43_9EA2_486AL, // -56 + 0x6867_A5A8_67F1_03B2L, 0x7FFD_2D38_FDD0_73DCL, // -55 + 0x5386_1E20_5327_3628L, 0x6664_242D_97D9_F64AL, // -54 + 0x42D1_B1B3_75B8_F820L, 0x51E9_B68A_DFE1_91D5L, // -53 + 0x6AE9_1C52_55F4_C034L, 0x1CA9_2411_6635_B621L, // -52 + 0x5587_49DB_77F7_0029L, 0x63BA_8341_1E91_5E81L, // -51 + 0x446C_3B15_F992_6687L, 0x6962_029A_7EDA_B201L, // -50 + 0x6D79_F823_28EA_3DA6L, 0x0F03_375D_97C4_5001L, // -49 + 0x5794_C682_8721_CAEBL, 0x259C_2C4A_DFD0_4001L, // -48 + 0x4610_9ECE_D281_6F22L, 0x5149_BD08_B30D_0001L, // -47 + 0x701A_97B1_50CF_1837L, 0x3542_C80D_EB48_0001L, // -46 + 0x59AE_DFC1_0D72_79C5L, 0x7768_A00B_22A0_0001L, // -45 + 0x47BF_1967_3DF5_2E37L, 0x7920_8008_E880_0001L, // -44 + 0x72CB_5BD8_6321_E38CL, 0x5B67_3341_7400_0001L, // -43 + 0x5BD5_E313_8281_82D6L, 0x7C52_8F67_9000_0001L, // -42 + 0x4977_E8DC_6867_9BDFL, 0x16A8_72B9_4000_0001L, // -41 + 0x758C_A7C7_0D72_92FEL, 0x5773_EAC2_0000_0001L, // -40 + 0x5E0A_1FD2_7128_7598L, 0x45F6_5568_0000_0001L, // -39 + 0x4B3B_4CA8_5A86_C47AL, 0x04C5_1120_0000_0001L, // -38 + 0x785E_E10D_5DA4_6D90L, 0x07A1_B500_0000_0001L, // -37 + 0x604B_E73D_E483_8AD9L, 0x52E7_C400_0000_0001L, // -36 + 0x4D09_85CB_1D36_08AEL, 0x0F1F_D000_0000_0001L, // -35 + 0x7B42_6FAB_61F0_0DE3L, 0x31CC_8000_0000_0001L, // -34 + 0x629B_8C89_1B26_7182L, 0x5B0A_0000_0000_0001L, // -33 + 0x4EE2_D6D4_15B8_5ACEL, 0x7C08_0000_0000_0001L, // -32 + 0x7E37_BE20_22C0_914BL, 0x1340_0000_0000_0001L, // -31 + 0x64F9_64E6_8233_A76FL, 0x2900_0000_0000_0001L, // -30 + 0x50C7_83EB_9B5C_85F2L, 0x5400_0000_0000_0001L, // -29 + 0x409F_9CBC_7C4A_04C2L, 0x1000_0000_0000_0001L, // -28 + 0x6765_C793_FA10_079DL, 0x0000_0000_0000_0001L, // -27 + 0x52B7_D2DC_C80C_D2E4L, 0x0000_0000_0000_0001L, // -26 + 0x422C_A8B0_A00A_4250L, 0x0000_0000_0000_0001L, // -25 + 0x69E1_0DE7_6676_D080L, 0x0000_0000_0000_0001L, // -24 + 0x54B4_0B1F_852B_DA00L, 0x0000_0000_0000_0001L, // -23 + 0x43C3_3C19_3756_4800L, 0x0000_0000_0000_0001L, // -22 + 0x6C6B_935B_8BBD_4000L, 0x0000_0000_0000_0001L, // -21 + 0x56BC_75E2_D631_0000L, 0x0000_0000_0000_0001L, // -20 + 0x4563_9182_44F4_0000L, 0x0000_0000_0000_0001L, // -19 + 0x6F05_B59D_3B20_0000L, 0x0000_0000_0000_0001L, // -18 + 0x58D1_5E17_6280_0000L, 0x0000_0000_0000_0001L, // -17 + 0x470D_E4DF_8200_0000L, 0x0000_0000_0000_0001L, // -16 + 0x71AF_D498_D000_0000L, 0x0000_0000_0000_0001L, // -15 + 0x5AF3_107A_4000_0000L, 0x0000_0000_0000_0001L, // -14 + 0x48C2_7395_0000_0000L, 0x0000_0000_0000_0001L, // -13 + 0x746A_5288_0000_0000L, 0x0000_0000_0000_0001L, // -12 + 0x5D21_DBA0_0000_0000L, 0x0000_0000_0000_0001L, // -11 + 0x4A81_7C80_0000_0000L, 0x0000_0000_0000_0001L, // -10 + 0x7735_9400_0000_0000L, 0x0000_0000_0000_0001L, // -9 + 0x5F5E_1000_0000_0000L, 0x0000_0000_0000_0001L, // -8 + 0x4C4B_4000_0000_0000L, 0x0000_0000_0000_0001L, // -7 + 0x7A12_0000_0000_0000L, 0x0000_0000_0000_0001L, // -6 + 0x61A8_0000_0000_0000L, 0x0000_0000_0000_0001L, // -5 + 0x4E20_0000_0000_0000L, 0x0000_0000_0000_0001L, // -4 + 0x7D00_0000_0000_0000L, 0x0000_0000_0000_0001L, // -3 + 0x6400_0000_0000_0000L, 0x0000_0000_0000_0001L, // -2 + 0x5000_0000_0000_0000L, 0x0000_0000_0000_0001L, // -1 + 0x4000_0000_0000_0000L, 0x0000_0000_0000_0001L, // 0 + 0x6666_6666_6666_6666L, 0x3333_3333_3333_3334L, // 1 + 0x51EB_851E_B851_EB85L, 0x0F5C_28F5_C28F_5C29L, // 2 + 0x4189_374B_C6A7_EF9DL, 0x5916_872B_020C_49BBL, // 3 + 0x68DB_8BAC_710C_B295L, 0x74F0_D844_D013_A92BL, // 4 + 0x53E2_D623_8DA3_C211L, 0x43F3_E037_0CDC_8755L, // 5 + 0x431B_DE82_D7B6_34DAL, 0x698F_E692_70B0_6C44L, // 6 + 0x6B5F_CA6A_F2BD_215EL, 0x0F4C_A41D_811A_46D4L, // 7 + 0x55E6_3B88_C230_E77EL, 0x3F70_834A_CDAE_9F10L, // 8 + 0x44B8_2FA0_9B5A_52CBL, 0x4C5A_02A2_3E25_4C0DL, // 9 + 0x6DF3_7F67_5EF6_EADFL, 0x2D5C_D103_96A2_1347L, // 10 + 0x57F5_FF85_E592_557FL, 0x3DE3_DA69_454E_75D3L, // 11 + 0x465E_6604_B7A8_4465L, 0x7E4F_E1ED_D10B_9175L, // 12 + 0x7097_09A1_25DA_0709L, 0x4A19_697C_81AC_1BEFL, // 13 + 0x5A12_6E1A_84AE_6C07L, 0x54E1_2130_67BC_E326L, // 14 + 0x480E_BE7B_9D58_566CL, 0x43E7_4DC0_52FD_8285L, // 15 + 0x734A_CA5F_6226_F0ADL, 0x530B_AF9A_1E62_6A6DL, // 16 + 0x5C3B_D519_1B52_5A24L, 0x426F_BFAE_7EB5_21F1L, // 17 + 0x49C9_7747_490E_AE83L, 0x4EBF_CC8B_9890_E7F4L, // 18 + 0x760F_253E_DB4A_B0D2L, 0x4ACC_7A78_F41B_0CBAL, // 19 + 0x5E72_8432_4908_8D75L, 0x223D_2EC7_29AF_3D62L, // 20 + 0x4B8E_D028_3A6D_3DF7L, 0x34FD_BF05_BAF2_9781L, // 21 + 0x78E4_8040_5D7B_9658L, 0x54C9_31A2_C4B7_58CFL, // 22 + 0x60B6_CD00_4AC9_4513L, 0x5D6D_C14F_03C5_E0A5L, // 23 + 0x4D5F_0A66_A23A_9DA9L, 0x3124_9AA5_9C9E_4D51L, // 24 + 0x7BCB_43D7_69F7_62A8L, 0x4EA0_F76F_60FD_4882L, // 25 + 0x6309_0312_BB2C_4EEDL, 0x254D_92BF_80CA_A068L, // 26 + 0x4F3A_68DB_C8F0_3F24L, 0x1DD7_A899_33D5_4D20L, // 27 + 0x7EC3_DAF9_4180_6506L, 0x62F2_A75B_8622_1500L, // 28 + 0x6569_7BFA_9ACD_1D9FL, 0x025B_B916_04E8_10CDL, // 29 + 0x5121_2FFB_AF0A_7E18L, 0x6849_60DE_6A53_40A4L, // 30 + 0x40E7_5996_25A1_FE7AL, 0x203A_B3E5_21DC_33B6L, // 31 + 0x67D8_8F56_A29C_CA5DL, 0x19F7_863B_6960_52BDL, // 32 + 0x5313_A5DE_E87D_6EB0L, 0x7B2C_6B62_BAB3_7564L, // 33 + 0x4276_1E4B_ED31_255AL, 0x2F56_BC4E_FBC2_C450L, // 34 + 0x6A56_96DF_E1E8_3BC3L, 0x6557_93B1_92D1_3A1AL, // 35 + 0x5512_124C_B4B9_C969L, 0x3779_42F4_7574_2E7BL, // 36 + 0x440E_750A_2A2E_3ABAL, 0x5F94_3590_5DF6_8B96L, // 37 + 0x6CE3_EE76_A9E3_912AL, 0x65B9_EF4D_6324_1289L, // 38 + 0x571C_BEC5_54B6_0DBBL, 0x6AFB_25D7_8283_4207L, // 39 + 0x45B0_989D_DD5E_7163L, 0x08C8_EB12_CECF_6806L, // 40 + 0x6F80_F42F_C897_1BD1L, 0x5ADB_11B7_B14B_D9A3L, // 41 + 0x5933_F68C_A078_E30EL, 0x157C_0E2C_8DD6_47B5L, // 42 + 0x475C_C53D_4D2D_8271L, 0x5DFC_D823_A4AB_6C91L, // 43 + 0x722E_0862_1515_9D82L, 0x632E_269F_6DDF_141BL, // 44 + 0x5B58_06B4_DDAA_E468L, 0x4F58_1EE5_F17F_4349L, // 45 + 0x4913_3890_B155_8386L, 0x72AC_E584_C132_9C3BL, // 46 + 0x74EB_8DB4_4EEF_38D7L, 0x6AAE_3C07_9B84_2D2AL, // 47 + 0x5D89_3E29_D8BF_60ACL, 0x5558_3006_1603_5755L, // 48 + 0x4AD4_31BB_13CC_4D56L, 0x7779_C004_DE69_12ABL, // 49 + 0x77B9_E92B_52E0_7BBEL, 0x258F_99A1_63DB_5111L, // 50 + 0x5FC7_EDBC_424D_2FCBL, 0x37A6_1481_1CAF_740DL, // 51 + 0x4C9F_F163_683D_BFD5L, 0x7951_AA00_E3BF_900BL, // 52 + 0x7A99_8238_A6C9_32EFL, 0x754F_7667_D2CC_19ABL, // 53 + 0x6214_682D_523A_8F26L, 0x2AA5_F853_0F09_AE22L, // 54 + 0x4E76_B9BD_DB62_0C1EL, 0x5551_9375_A5A1_581BL, // 55 + 0x7D8A_C2C9_5F03_4697L, 0x3BB5_B8BC_3C35_59C5L, // 56 + 0x646F_023A_B269_0545L, 0x7C91_6096_9691_149EL, // 57 + 0x5058_CE95_5B87_376BL, 0x16DA_B3AB_ABA7_43B2L, // 58 + 0x4047_0BAA_AF9F_5F88L, 0x78AE_F622_EFB9_02F5L, // 59 + 0x66D8_12AA_B298_98DBL, 0x0DE4_BD04_B2C1_9E54L, // 60 + 0x5246_7555_5BAD_4715L, 0x57EA_30D0_8F01_4B76L, // 61 + 0x41D1_F777_7C8A_9F44L, 0x4654_F3DA_0C01_092CL, // 62 + 0x694F_F258_C744_3207L, 0x23BB_1FC3_4668_0EACL, // 63 + 0x543F_F513_D29C_F4D2L, 0x4FC8_E635_D1EC_D88AL, // 64 + 0x4366_5DA9_754A_5D75L, 0x263A_51C4_A7F0_AD3BL, // 65 + 0x6BD6_FC42_5543_C8BBL, 0x56C3_B607_731A_AEC4L, // 66 + 0x5645_969B_7769_6D62L, 0x789C_919F_8F48_8BD0L, // 67 + 0x4504_787C_5F87_8AB5L, 0x46E3_A7B2_D906_D640L, // 68 + 0x6E6D_8D93_CC0C_1122L, 0x3E39_0C51_5B3E_239AL, // 69 + 0x5857_A476_3CD6_741BL, 0x4B60_D6A7_7C31_B615L, // 70 + 0x46AC_8391_CA45_29AFL, 0x55E7_121F_968E_2B44L, // 71 + 0x7114_05B6_106E_A919L, 0x0971_B698_F0E3_786DL, // 72 + 0x5A76_6AF8_0D25_5414L, 0x078E_2BAD_8D82_C6BDL, // 73 + 0x485E_BBF9_A41D_DCDCL, 0x6C71_BC8A_D79B_D231L, // 74 + 0x73CA_C65C_39C9_6161L, 0x2D82_C744_8C2C_8382L, // 75 + 0x5CA2_3849_C7D4_4DE7L, 0x3E02_3903_A356_CF9BL, // 76 + 0x4A1B_603B_0643_7185L, 0x7E68_2D9C_82AB_D949L, // 77 + 0x7692_3391_A39F_1C09L, 0x4A40_48FA_6AAC_8EDBL, // 78 + 0x5EDB_5C74_82E5_B007L, 0x5500_3A61_EEF0_7249L, // 79 + 0x4BE2_B05D_3584_8CD2L, 0x7733_61E7_F259_F507L, // 80 + 0x796A_B3C8_55A0_E151L, 0x3EB8_9CA6_508F_EE71L, // 81 + 0x6122_296D_114D_810DL, 0x7EFA_16EB_73A6_585BL, // 82 + 0x4DB4_EDF0_DAA4_673EL, 0x3261_ABEF_8FB8_46AFL, // 83 + 0x7C54_AFE7_C43A_3ECAL, 0x1D69_1318_E5F3_A44BL, // 84 + 0x6376_F31F_D02E_98A1L, 0x6454_0F47_1E5C_836FL, // 85 + 0x4F92_5C19_7358_7A1BL, 0x0376_729F_4B7D_35F3L, // 86 + 0x7F50_935B_EBC0_C35EL, 0x38BD_8432_1261_EFEBL, // 87 + 0x65DA_0F7C_BC9A_35E5L, 0x13CA_D028_0EB4_BFEFL, // 88 + 0x517B_3F96_FD48_2B1DL, 0x5CA2_4020_0BC3_CCBFL, // 89 + 0x412F_6612_6439_BC17L, 0x63B5_0019_A303_0A33L, // 90 + 0x684B_D683_D38F_9359L, 0x1F88_0029_04D1_A9EAL, // 91 + 0x536F_DECF_DC72_DC47L, 0x32D3_3354_03DA_EE55L, // 92 + 0x42BF_E573_16C2_49D2L, 0x5BDC_2910_0315_8B77L, // 93 + 0x6ACC_A251_BE03_A951L, 0x12F9_DB4C_D1BC_1258L, // 94 + 0x5570_81DA_FE69_5440L, 0x7594_AF70_A7C9_A847L, // 95 + 0x445A_017B_FEBA_A9CDL, 0x4476_F2C0_863A_ED06L, // 96 + 0x6D5C_CF2C_CAC4_42E2L, 0x3A57_EACD_A391_7B3CL, // 97 + 0x577D_728A_3BD0_3581L, 0x7B79_88A4_82DA_C8FDL, // 98 + 0x45FD_F53B_630C_F79BL, 0x15FA_D3B6_CF15_6D97L, // 99 + 0x6FFC_BB92_3814_BF5EL, 0x565E_1F8A_E4EF_15BEL, // 100 + 0x5996_FC74_F9AA_32B2L, 0x11E4_E608_B725_AAFFL, // 101 + 0x47AB_FD2A_6154_F55BL, 0x27EA_51A0_9284_88CCL, // 102 + 0x72AC_C843_CEEE_555EL, 0x7310_829A_8407_4146L, // 103 + 0x5BBD_6D03_0BF1_DDE5L, 0x4273_9BAE_D005_CDD2L, // 104 + 0x4964_5735_A327_E4B7L, 0x4EC2_E2F2_4004_A4A8L, // 105 + 0x756D_5855_D1D9_6DF2L, 0x4AD1_6B1D_333A_A10CL, // 106 + 0x5DF1_1377_DB14_57F5L, 0x2241_227D_C295_4DA3L, // 107 + 0x4B27_42C6_48DD_132AL, 0x4E9A_81FE_3544_3E1CL, // 108 + 0x783E_D13D_4161_B844L, 0x175D_9CC9_EED3_9694L, // 109 + 0x6032_40FD_CDE7_C69CL, 0x7917_B0A1_8BDC_7876L, // 110 + 0x4CF5_00CB_0B1F_D217L, 0x1412_F3B4_6FE3_9392L, // 111 + 0x7B21_9ADE_7832_E9BEL, 0x5351_85ED_7FD2_85B6L, // 112 + 0x6281_48B1_F9C2_5498L, 0x42A7_9E57_9975_37C5L, // 113 + 0x4ECD_D3C1_949B_76E0L, 0x3552_E512_E12A_9304L, // 114 + 0x7E16_1F9C_20F8_BE33L, 0x6EEB_081E_3510_EB39L, // 115 + 0x64DE_7FB0_1A60_9829L, 0x3F22_6CE4_F740_BC2EL, // 116 + 0x50B1_FFC0_151A_1354L, 0x3281_F0B7_2C33_C9BEL, // 117 + 0x408E_6633_4414_DC43L, 0x4201_8D5F_568F_D498L, // 118 + 0x674A_3D1E_D354_939FL, 0x1CCF_4898_8A7F_BA8DL, // 119 + 0x52A1_CA7F_0F76_DC7FL, 0x30A5_D3AD_3B99_620BL, // 120 + 0x421B_0865_A5F8_B065L, 0x73B7_DC8A_9614_4E6FL, // 121 + 0x69C4_DA3C_3CC1_1A3CL, 0x52BF_C744_2353_B0B1L, // 122 + 0x549D_7B63_63CD_AE96L, 0x7566_3903_4F76_26F4L, // 123 + 0x43B1_2F82_B63E_2545L, 0x4451_C735_D92B_525DL, // 124 + 0x6C4E_B26A_BD30_3BA2L, 0x3A1C_71EF_C1DE_EA2EL, // 125 + 0x56A5_5B88_9759_C94EL, 0x61B0_5B26_34B2_54F2L, // 126 + 0x4551_1606_DF7B_0772L, 0x1AF3_7C1E_908E_AA5BL, // 127 + 0x6EE8_233E_325E_7250L, 0x2B1F_2CFD_B417_76F8L, // 128 + 0x58B9_B5CB_5B7E_C1D9L, 0x6F4C_23FE_29AC_5F2DL, // 129 + 0x46FA_F7D5_E2CB_CE47L, 0x72A3_4FFE_87BD_18F1L, // 130 + 0x7191_8C89_6ADF_B073L, 0x0438_7FFD_A5FB_5B1BL, // 131 + 0x5ADA_D6D4_557F_C05CL, 0x0360_6664_84C9_15AFL, // 132 + 0x48AF_1243_7799_66B0L, 0x02B3_851D_3707_448CL, // 133 + 0x744B_506B_F28F_0AB3L, 0x1DEC_082E_BE72_0746L, // 134 + 0x5D09_0D23_2872_6EF5L, 0x64BC_D358_985B_3905L, // 135 + 0x4A6D_A41C_205B_8BF7L, 0x6A30_A913_AD15_C738L, // 136 + 0x7715_D360_33C5_ACBFL, 0x5D1A_A81F_7B56_0B8CL, // 137 + 0x5F44_A919_C304_8A32L, 0x7DAE_ECE5_FC44_D609L, // 138 + 0x4C36_EDAE_359D_3B5BL, 0x7E25_8A51_969D_7808L, // 139 + 0x79F1_7C49_EF61_F893L, 0x16A2_76E8_F0FB_F33FL, // 140 + 0x618D_FD07_F2B4_C6DCL, 0x121B_9253_F3FC_C299L, // 141 + 0x4E0B_30D3_2890_9F16L, 0x41AF_A843_2997_0214L, // 142 + 0x7CDE_B485_0DB4_31BDL, 0x4F7F_739E_A8F1_9CEDL, // 143 + 0x63E5_5D37_3E29_C164L, 0x3F99_294B_BA5A_E3F1L, // 144 + 0x4FEA_B0F8_FE87_CDE9L, 0x7FAD_BAA2_FB7B_E98DL, // 145 + 0x7FDD_E7F4_CA72_E30FL, 0x7F7C_5DD1_925F_DC15L, // 146 + 0x664B_1FF7_085B_E8D9L, 0x4C63_7E41_41E6_49ABL, // 147 + 0x51D5_B32C_06AF_ED7AL, 0x704F_9834_34B8_3AEFL, // 148 + 0x4177_C289_9EF3_2462L, 0x26A6_135C_F6F9_C8BFL, // 149 + 0x68BF_9DA8_FE51_D3D0L, 0x3DD6_8561_8B29_4132L, // 150 + 0x53CC_7E20_CB74_A973L, 0x4B12_044E_08ED_CDC2L, // 151 + 0x4309_FE80_A2C3_BAC2L, 0x6F41_9D0B_3A57_D7CEL, // 152 + 0x6B43_30CD_D139_2AD1L, 0x3202_94DE_C3BF_BFB0L, // 153 + 0x55CF_5A3E_40FA_88A7L, 0x419B_AA4B_CFCC_995AL, // 154 + 0x44A5_E1CB_672E_D3B9L, 0x1AE2_EEA3_0CA3_ADE1L, // 155 + 0x6DD6_3612_3EB1_52C1L, 0x77D1_7DD1_ADD2_AFCFL, // 156 + 0x57DE_91A8_3227_7567L, 0x7974_64A7_BE42_263FL, // 157 + 0x464B_A7B9_C1B9_2AB9L, 0x4790_5086_31CE_84FFL, // 158 + 0x7079_0C5C_6928_445CL, 0x0C1A_1A70_4FB0_D4CCL, // 159 + 0x59FA_7049_EDB9_D049L, 0x567B_4859_D95A_43D6L, // 160 + 0x47FB_8D07_F161_736EL, 0x11FC_39E1_7AAE_9CABL, // 161 + 0x732C_14D9_8235_857DL, 0x032D_2968_C44A_9445L, // 162 + 0x5C23_43E1_34F7_9DFDL, 0x4F57_5453_D03B_A9D1L, // 163 + 0x49B5_CFE7_5D92_E4CAL, 0x72AC_4376_402F_BB0EL, // 164 + 0x75EF_B30B_C8EB_07ABL, 0x0446_D256_CD19_2B49L, // 165 + 0x5E59_5C09_6D88_D2EFL, 0x1D05_7512_3DAD_BC3AL, // 166 + 0x4B7A_B007_8AD3_DBF2L, 0x4A6A_C40E_97BE_302FL, // 167 + 0x78C4_4CD8_DE1F_C650L, 0x7711_39B0_F2C9_E6B1L, // 168 + 0x609D_0A47_1819_6B73L, 0x78DA_948D_8F07_EBC1L, // 169 + 0x4D4A_6E9F_467A_BC5CL, 0x60AE_DD3E_0C06_5634L, // 170 + 0x7BAA_4A98_70C4_6094L, 0x344A_FB96_79A3_BD20L, // 171 + 0x62EE_A213_8D69_E6DDL, 0x103B_FC78_614F_CA80L, // 172 + 0x4F25_4E76_0ABB_1F17L, 0x2696_6393_810C_A200L, // 173 + 0x7EA2_1723_445E_9825L, 0x2423_D285_9B47_6999L, // 174 + 0x654E_78E9_037E_E01DL, 0x69B6_4204_7C39_2148L, // 175 + 0x510B_93ED_9C65_8017L, 0x6E2B_6803_9694_1AA0L, // 176 + 0x40D6_0FF1_49EA_CCDFL, 0x71BC_5336_1210_154DL, // 177 + 0x67BC_E64E_DCAA_E166L, 0x1C60_8523_5019_BBAEL, // 178 + 0x52FD_850B_E3BB_E784L, 0x7D1A_041C_4014_9625L, // 179 + 0x4264_6A6F_E963_1F9DL, 0x4A7B_367D_0010_781DL, // 180 + 0x6A3A_43E6_4238_3295L, 0x5D91_F0C8_001A_59C8L, // 181 + 0x54FB_6985_01C6_8EDEL, 0x17A7_F3D3_3348_47D4L, // 182 + 0x43FC_546A_67D2_0BE4L, 0x7953_2975_C2A0_3976L, // 183 + 0x6CC6_ED77_0C83_463BL, 0x0EEB_7589_3766_C256L, // 184 + 0x5705_8AC5_A39C_382FL, 0x2589_2AD4_2C52_3512L, // 185 + 0x459E_089E_1C7C_F9BFL, 0x37A0_EF10_2374_F742L, // 186 + 0x6F63_40FC_FA61_8F98L, 0x5901_7E80_38BB_2536L, // 187 + 0x591C_33FD_951A_D946L, 0x7A67_9866_93C8_EA91L, // 188 + 0x4749_C331_4415_7A9FL, 0x151F_AD1E_DCA0_BBA8L, // 189 + 0x720F_9EB5_39BB_F765L, 0x0832_AE97_C767_92A5L, // 190 + 0x5B3F_B22A_9496_5F84L, 0x068E_F213_05EC_7551L, // 191 + 0x48FF_C1BB_AA11_E603L, 0x1ED8_C1A8_D189_F774L, // 192 + 0x74CC_692C_434F_D66BL, 0x4AF4_690E_1C0F_F253L, // 193 + 0x5D70_5423_690C_AB89L, 0x225D_20D8_1673_2843L, // 194 + 0x4AC0_434F_873D_5607L, 0x3517_4D79_AB8F_5369L, // 195 + 0x779A_054C_0B95_5672L, 0x21BE_E25C_45B2_1F0EL, // 196 + 0x5FAE_6AA3_3C77_785BL, 0x3498_B516_9E28_18D8L, // 197 + 0x4C8B_8882_96C5_F9E2L, 0x5D46_F745_4B53_4713L, // 198 + 0x7A78_DA6A_8AD6_5C9DL, 0x7BA4_BED5_4552_0B52L, // 199 + 0x61FA_4855_3BDE_B07EL, 0x2FB6_FF11_0441_A2A8L, // 200 + 0x4E61_D377_6318_8D31L, 0x72F8_CC0D_9D01_4EEDL, // 201 + 0x7D69_5258_9E8D_AEB6L, 0x1E5A_E015_C802_17E1L, // 202 + 0x6454_41E0_7ED7_BEF8L, 0x1848_B344_A001_ACB4L, // 203 + 0x5043_67E6_CBDF_CBF9L, 0x603A_2903_B334_8A2AL, // 204 + 0x4035_ECB8_A319_6FFBL, 0x002E_8736_28F6_D4EEL, // 205 + 0x66BC_ADF4_3828_B32BL, 0x19E4_0B89_DB24_87E3L, // 206 + 0x5230_8B29_C686_F5BCL, 0x14B6_6FA1_7C1D_3983L, // 207 + 0x41C0_6F54_9ED2_5E30L, 0x1091_F2E7_967D_C79CL, // 208 + 0x6933_E554_3150_96B3L, 0x341C_B7D8_F0C9_3F5FL, // 209 + 0x5429_8443_5AA6_DEF5L, 0x767D_5FE0_C0A0_FF80L, // 210 + 0x4354_69CF_7BB8_B25EL, 0x2B97_7FE7_0080_CC66L, // 211 + 0x6BBA_42E5_92C1_1D63L, 0x5F58_CCA4_CD9A_E0A3L, // 212 + 0x562E_9BEA_DBCD_B11CL, 0x4C47_0A1D_7148_B3B6L, // 213 + 0x44F2_1655_7CA4_8DB0L, 0x3D05_A1B1_276D_5C92L, // 214 + 0x6E50_23BB_FAA0_E2B3L, 0x7B3C_35E8_3F15_60E9L, // 215 + 0x5840_1C96_621A_4EF6L, 0x2F63_5E53_65AA_B3EDL, // 216 + 0x4699_B078_4E7B_725EL, 0x591C_4B75_EAEE_F658L, // 217 + 0x70F5_E726_E3F8_B6FDL, 0x74FA_1256_44B1_8A26L, // 218 + 0x5A5E_5285_832D_5F31L, 0x43FB_41DE_9D5A_D4EBL, // 219 + 0x484B_7537_9C24_4C27L, 0x4FFC_34B2_177B_DD89L, // 220 + 0x73AB_EEBF_603A_1372L, 0x4CC6_BAB6_8BF9_6274L, // 221 + 0x5C89_8BCC_4CFB_42C2L, 0x0A38_955E_D661_1B90L, // 222 + 0x4A07_A309_D72F_689BL, 0x21C6_DDE5_784D_AFA7L, // 223 + 0x7672_9E76_2518_A75EL, 0x693E_2FD5_8D49_190BL, // 224 + 0x5EC2_185E_8413_B918L, 0x5431_BFDE_0AA0_E0D5L, // 225 + 0x4BCE_79E5_3676_2DADL, 0x29C1_664B_3BB3_E711L, // 226 + 0x794A_5CA1_F0BD_15E2L, 0x0F9B_D6DE_C5EC_A4E8L, // 227 + 0x6108_4A1B_26FD_AB1BL, 0x2616_457F_04BD_50BAL, // 228 + 0x4DA0_3B48_EBFE_227CL, 0x1E78_3798_D097_73C8L, // 229 + 0x7C33_920E_4663_6A60L, 0x30C0_58F4_80F2_52D9L, // 230 + 0x635C_74D8_384F_884DL, 0x0D66_AD90_6728_4247L, // 231 + 0x4F7D_2A46_9372_D370L, 0x711E_F140_5286_9B6CL, // 232 + 0x7F2E_AA0A_8584_8581L, 0x34FE_4ECD_50D7_5F14L, // 233 + 0x65BE_EE6E_D136_D134L, 0x2A65_0BD7_73DF_7F43L, // 234 + 0x5165_8B8B_DA92_40F6L, 0x551D_A312_C319_329CL, // 235 + 0x411E_093C_AEDB_672BL, 0x5DB1_4F42_35AD_C217L, // 236 + 0x6830_0EC7_7E2B_D845L, 0x7C4E_E536_BC49_368AL, // 237 + 0x5359_A56C_64EF_E037L, 0x7D0B_EA92_303A_9208L, // 238 + 0x42AE_1DF0_50BF_E693L, 0x173C_BBA8_2695_41A0L, // 239 + 0x6AB0_2FE6_E799_70EBL, 0x3EC7_92A6_A422_029AL, // 240 + 0x5559_BFEB_EC7A_C0BCL, 0x3239_421E_E9B4_CEE1L, // 241 + 0x4447_CCBC_BD2F_0096L, 0x5B61_01B2_5490_A581L, // 242 + 0x6D3F_ADFA_C84B_3424L, 0x2BCE_691D_541A_A268L, // 243 + 0x5766_24C8_A03C_29B6L, 0x563E_BA7D_DCE2_1B87L, // 244 + 0x45EB_50A0_8030_215EL, 0x7832_2ECB_171B_4939L, // 245 + 0x6FDE_E767_3380_3564L, 0x59E9_E478_24F8_7527L, // 246 + 0x597F_1F85_C2CC_F783L, 0x6187_E9F9_B72D_2A86L, // 247 + 0x4798_E604_9BD7_2C69L, 0x346C_BB2E_2C24_2205L, // 248 + 0x728E_3CD4_2C8B_7A42L, 0x20AD_F849_E039_D007L, // 249 + 0x5BA4_FD76_8A09_2E9BL, 0x33BE_603B_19C7_D99FL, // 250 + 0x4950_CAC5_3B3A_8BAFL, 0x42FE_B362_7B06_47B3L, // 251 + 0x754E_113B_91F7_45E5L, 0x5197_856A_5E70_72B8L, // 252 + 0x5DD8_0DC9_4192_9E51L, 0x27AC_6ABB_7EC0_5BC6L, // 253 + 0x4B13_3E3A_9ADB_B1DAL, 0x52F0_5562_CBCD_1638L, // 254 + 0x781E_C9F7_5E2C_4FC4L, 0x1E4D_556A_DFAE_89F3L, // 255 + 0x6018_A192_B1BD_0C9CL, 0x7EA4_4455_7FBE_D4C3L, // 256 + 0x4CE0_8142_27CA_707DL, 0x4BB6_9D11_32FF_109CL, // 257 + 0x7B00_CED0_3FAA_4D95L, 0x5F8A_94E8_5198_1A93L, // 258 + 0x6267_0BD9_CC88_3E11L, 0x32D5_43ED_0E13_4875L, // 259 + 0x4EB8_D647_D6D3_64DAL, 0x5BDD_CFF0_D80F_6D2BL, // 260 + 0x7DF4_8A0C_8AEB_D491L, 0x12FC_7FE7_C018_AEABL, // 261 + 0x64C3_A1A3_A256_43A7L, 0x28C9_FFEC_99AD_5889L, // 262 + 0x509C_814F_B511_CFB9L, 0x0707_FFF0_7AF1_13A1L, // 263 + 0x407D_343F_C40E_3FC7L, 0x1F39_998D_2F27_42E7L, // 264 + 0x672E_B9FF_A016_CC71L, 0x7EC2_8F48_4B72_04A4L, // 265 + 0x528B_C7FF_B345_705BL, 0x189B_A5D3_6F8E_6A1DL, // 266 + 0x4209_6CCC_8F6A_C048L, 0x7A16_1E42_BFA5_21B1L, // 267 + 0x69A8_AE14_18AA_CD41L, 0x4356_96D1_32A1_CF81L, // 268 + 0x5486_F1A9_AD55_7101L, 0x1C45_4574_2881_72CEL, // 269 + 0x439F_27BA_F111_2734L, 0x169D_D129_BA01_28A5L, // 270 + 0x6C31_D92B_1B4E_A520L, 0x242F_B50F_9001_DAA1L, // 271 + 0x568E_4755_AF72_1DB3L, 0x368C_90D9_4001_7BB4L, // 272 + 0x453E_9F77_BF8E_7E29L, 0x120A_0D7A_999A_C95DL, // 273 + 0x6ECA_98BF_98E3_FD0EL, 0x5010_1590_F5C4_7561L, // 274 + 0x58A2_13CC_7A4F_FDA5L, 0x2673_4473_F7D0_5DE8L, // 275 + 0x46E8_0FD6_C83F_FE1DL, 0x6B8F_69F6_5FD9_E4B9L, // 276 + 0x7173_4C8A_D9FF_FCFCL, 0x45B2_4323_CC8F_D45CL, // 277 + 0x5AC2_A3A2_47FF_FD96L, 0x6AF5_0283_0A0C_A9E3L, // 278 + 0x489B_B61B_6CCC_CADFL, 0x08C4_0202_6E70_87E9L, // 279 + 0x742C_5692_47AE_1164L, 0x746C_D003_E3E7_3FDBL, // 280 + 0x5CF0_4541_D2F1_A783L, 0x76BD_7336_4FEC_3315L, // 281 + 0x4A59_D101_758E_1F9CL, 0x5EFD_F5C5_0CBC_F5ABL, // 282 + 0x76F6_1B35_88E3_65C7L, 0x4B2F_EFA1_ADFB_22ABL, // 283 + 0x5F2B_48F7_A0B5_EB06L, 0x08F3_261A_F195_B555L, // 284 + 0x4C22_A0C6_1A2B_226BL, 0x20C2_84E2_5ADE_2AABL, // 285 + 0x79D1_013C_F6AB_6A45L, 0x1AD0_D49D_5E30_4444L, // 286 + 0x6174_00FD_9222_BB6AL, 0x48A7_107D_E4F3_69D0L, // 287 + 0x4DF6_6731_41B5_62BBL, 0x53B8_D9FE_50C2_BB0DL, // 288 + 0x7CBD_71E8_6922_3792L, 0x52C1_5CCA_1AD1_2B48L, // 289 + 0x63CA_C186_BA81_C60EL, 0x7567_7D6E_7BDA_8906L, // 290 + 0x4FD5_679E_FB9B_04D8L, 0x5DEC_6458_6315_3A6CL, // 291 + 0x7FBB_D8FE_5F5E_6E27L, 0x497A_3A27_04EE_C3DFL, // 292 + }; + +} diff --git a/tests/test_data/std/jdk/internal/misc/Blocker.class b/tests/test_data/std/jdk/internal/misc/Blocker.class new file mode 100644 index 0000000000000000000000000000000000000000..297f11d8209e8553a51633cd8476cdf0e26ab77d GIT binary patch literal 1422 zcmah}TTc@~6#k~SZI>;V3gxDjV#OAeDj=doTTIN*lO5STYD(|*F>O{Vf81QAl8YUqH*FnCZrOq-U?g{7C$M`p!HFO|y1Ar}PS z%q}t{vTYFEFnFbs-lQy9O0wvLnGSTKOF_4W9z+;M|9^#{*Qg4?EqhrP!sO!BzTkS1 zwv(ysMGcMJjEY|LDTr$5#{gm4_#M^xZHAy(St^%pPApXFu8JWHE4ZrRniSRI%z3V` zE1?lfd`!cL%n&jwc~jU`y`++1RN4)O*uPoZw5u4!O$}r6ez?H*Ov|y-wDu%NQbS6f z_?;7pozQSwwyc9&#S7#l(hBZsxQ8i*cw0)>``o@RcrnKf!R-n|&mOni+rcmFJ# z_J%tMt3s4T5VH&e?aU)q*&eBIyLzl*8gp{y9y0VLTRN7r1y!6$3dJO}0vTNceMr#O9 z{J`ke_$d-6-V;K49j++pm474wte^|4h+z#0tT)BQ==>=b2(#$iVF@SglACssR#}ZU zR70qaTkqg&A(ut~FPmht-epSEAoIhcE|Bk(b&Y`1u^n1v72QPFNzzGicH$J{(!7S= z2z(CChh6ggHEDk1&`0TB2c1c+GHExSH4}Nkx~Ns_&Bm+{nf&zEapw~ha`+d*UopKC gxqpTS-!EF#$Tme6r%Cz@qL@ARAxddBh{J=;ztBY}N&o-= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/Blocker.java b/tests/test_data/std/jdk/internal/misc/Blocker.java new file mode 100644 index 00000000..d41ae737 --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/Blocker.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + +/** + * Defines static methods to mark the beginning and end of a possibly blocking + * operation. The methods are intended to be used with try-finally as follows: + * {@snippet lang=java : + * boolean attempted = Blocker.begin(); + * try { + * // blocking operation + * } finally { + * Blocker.end(attempted); + * } + * } + * If invoked from a virtual thread and the underlying carrier thread is a + * CarrierThread then the code in the block runs as if it were in run in + * ForkJoinPool.ManagedBlocker. This means the pool can be expanded to support + * additional parallelism during the blocking operation. + */ +public class Blocker { + private static final JavaLangAccess JLA; + static { + JLA = SharedSecrets.getJavaLangAccess(); + if (JLA == null) { + throw new InternalError("JavaLangAccess not setup"); + } + } + + private Blocker() { } + + private static Thread currentCarrierThread() { + return JLA.currentCarrierThread(); + } + + /** + * Marks the beginning of a blocking operation. + * @return true if tryCompensate attempted + */ + public static boolean begin() { + if (VM.isBooted() + && Thread.currentThread().isVirtual() + && currentCarrierThread() instanceof CarrierThread ct) { + return ct.beginBlocking(); + } + return false; + } + + /** + * Marks the beginning of a possibly blocking operation. + * @param blocking true if the operation may block, otherwise false + * @return true if tryCompensate attempted + */ + public static boolean begin(boolean blocking) { + return (blocking) ? begin() : false; + } + + /** + * Marks the end of an operation that may have blocked. + * @param attempted if tryCompensate attempted + */ + public static void end(boolean attempted) { + if (attempted) { + CarrierThread ct = (CarrierThread) currentCarrierThread(); + ct.endBlocking(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/misc/CDS.class b/tests/test_data/std/jdk/internal/misc/CDS.class new file mode 100644 index 0000000000000000000000000000000000000000..a84035a40bc9a1f875ef7cd6907f0b8c9b19bfaf GIT binary patch literal 11828 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/CDS.java b/tests/test_data/std/jdk/internal/misc/CDS.java new file mode 100644 index 00000000..ddb25cb7 --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/CDS.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.io.InputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +import jdk.internal.access.SharedSecrets; + +public class CDS { + // Must be in sync with cdsConfig.hpp + private static final int IS_DUMPING_ARCHIVE = 1 << 0; + private static final int IS_DUMPING_STATIC_ARCHIVE = 1 << 1; + private static final int IS_LOGGING_LAMBDA_FORM_INVOKERS = 1 << 2; + private static final int IS_USING_ARCHIVE = 1 << 3; + private static final int configStatus = getCDSConfigStatus(); + + /** + * Should we log the use of lambda form invokers? + */ + public static boolean isLoggingLambdaFormInvokers() { + return (configStatus & IS_LOGGING_LAMBDA_FORM_INVOKERS) != 0; + } + + /** + * Is the VM writing to a (static or dynamic) CDS archive. + */ + public static boolean isDumpingArchive() { + return (configStatus & IS_DUMPING_ARCHIVE) != 0; + } + + /** + * Is the VM using at least one CDS archive? + */ + public static boolean isUsingArchive() { + return (configStatus & IS_USING_ARCHIVE) != 0; + } + + /** + * Is dumping static archive. + */ + public static boolean isDumpingStaticArchive() { + return (configStatus & IS_DUMPING_STATIC_ARCHIVE) != 0; + } + + private static native int getCDSConfigStatus(); + private static native void logLambdaFormInvoker(String line); + + /** + * Initialize archived static fields in the given Class using archived + * values from CDS dump time. Also initialize the classes of objects in + * the archived graph referenced by those fields. + * + * Those static fields remain as uninitialized if there is no mapped CDS + * java heap data or there is any error during initialization of the + * object class in the archived graph. + */ + public static native void initializeFromArchive(Class c); + + /** + * Ensure that the native representation of all archived java.lang.Module objects + * are properly restored. + */ + public static native void defineArchivedModules(ClassLoader platformLoader, ClassLoader systemLoader); + + /** + * Returns a predictable "random" seed derived from the VM's build ID and version, + * to be used by java.util.ImmutableCollections to ensure that archived + * ImmutableCollections are always sorted the same order for the same VM build. + */ + public static native long getRandomSeedForDumping(); + + /** + * log lambda form invoker holder, name and method type + */ + public static void logLambdaFormInvoker(String prefix, String holder, String name, String type) { + if (isLoggingLambdaFormInvokers()) { + logLambdaFormInvoker(prefix + " " + holder + " " + name + " " + type); + } + } + + /** + * log species + */ + public static void logSpeciesType(String prefix, String cn) { + if (isLoggingLambdaFormInvokers()) { + logLambdaFormInvoker(prefix + " " + cn); + } + } + + static final String DIRECT_HOLDER_CLASS_NAME = "java.lang.invoke.DirectMethodHandle$Holder"; + static final String DELEGATING_HOLDER_CLASS_NAME = "java.lang.invoke.DelegatingMethodHandle$Holder"; + static final String BASIC_FORMS_HOLDER_CLASS_NAME = "java.lang.invoke.LambdaForm$Holder"; + static final String INVOKERS_HOLDER_CLASS_NAME = "java.lang.invoke.Invokers$Holder"; + + private static boolean isValidHolderName(String name) { + return name.equals(DIRECT_HOLDER_CLASS_NAME) || + name.equals(DELEGATING_HOLDER_CLASS_NAME) || + name.equals(BASIC_FORMS_HOLDER_CLASS_NAME) || + name.equals(INVOKERS_HOLDER_CLASS_NAME); + } + + private static boolean isBasicTypeChar(char c) { + return "LIJFDV".indexOf(c) >= 0; + } + + private static boolean isValidMethodType(String type) { + String[] typeParts = type.split("_"); + // check return type (second part) + if (typeParts.length != 2 || typeParts[1].length() != 1 + || !isBasicTypeChar(typeParts[1].charAt(0))) { + return false; + } + // first part + if (!isBasicTypeChar(typeParts[0].charAt(0))) { + return false; + } + for (int i = 1; i < typeParts[0].length(); i++) { + char c = typeParts[0].charAt(i); + if (!isBasicTypeChar(c)) { + if (!(c >= '0' && c <= '9')) { + return false; + } + } + } + return true; + } + + // Throw exception on invalid input + private static void validateInputLines(String[] lines) { + for (String s: lines) { + if (!s.startsWith("[LF_RESOLVE]") && !s.startsWith("[SPECIES_RESOLVE]")) { + throw new IllegalArgumentException("Wrong prefix: " + s); + } + + String[] parts = s.split(" "); + boolean isLF = s.startsWith("[LF_RESOLVE]"); + + if (isLF) { + if (parts.length != 4) { + throw new IllegalArgumentException("Incorrect number of items in the line: " + parts.length); + } + if (!isValidHolderName(parts[1])) { + throw new IllegalArgumentException("Invalid holder class name: " + parts[1]); + } + if (!isValidMethodType(parts[3])) { + throw new IllegalArgumentException("Invalid method type: " + parts[3]); + } + } else { + if (parts.length != 2) { + throw new IllegalArgumentException("Incorrect number of items in the line: " + parts.length); + } + } + } + } + + /** + * called from vm to generate MethodHandle holder classes + * @return {@code Object[]} if holder classes can be generated. + * @param lines in format of LF_RESOLVE or SPECIES_RESOLVE output + */ + private static Object[] generateLambdaFormHolderClasses(String[] lines) { + Objects.requireNonNull(lines); + validateInputLines(lines); + Stream lineStream = Arrays.stream(lines); + Map result = SharedSecrets.getJavaLangInvokeAccess().generateHolderClasses(lineStream); + int size = result.size(); + Object[] retArray = new Object[size * 2]; + int index = 0; + for (Map.Entry entry : result.entrySet()) { + retArray[index++] = entry.getKey(); + retArray[index++] = entry.getValue(); + }; + return retArray; + } + + private static native void dumpClassList(String listFileName); + private static native void dumpDynamicArchive(String archiveFileName); + + private static String drainOutput(InputStream stream, long pid, String tail, List cmds) { + String fileName = "java_pid" + pid + "_" + tail; + new Thread( ()-> { + try (InputStreamReader isr = new InputStreamReader(stream); + BufferedReader rdr = new BufferedReader(isr); + PrintStream prt = new PrintStream(fileName)) { + prt.println("Command:"); + for (String s : cmds) { + prt.print(s + " "); + } + prt.println(""); + String line; + while((line = rdr.readLine()) != null) { + prt.println(line); + } + } catch (IOException e) { + throw new RuntimeException("IOException happens during drain stream to file " + + fileName + ": " + e.getMessage()); + }}).start(); + return fileName; + } + + private static String[] excludeFlags = { + "-XX:DumpLoadedClassList=", + "-XX:+RecordDynamicDumpInfo", + "-Xshare:", + "-XX:SharedClassListFile=", + "-XX:SharedArchiveFile=", + "-XX:ArchiveClassesAtExit="}; + private static boolean containsExcludedFlags(String testStr) { + for (String e : excludeFlags) { + if (testStr.contains(e)) { + return true; + } + } + return false; + } + + /** + * called from jcmd VM.cds to dump static or dynamic shared archive + * @param isStatic true for dump static archive or false for dynnamic archive. + * @param fileName user input archive name, can be null. + * @return The archive name if successfully dumped. + */ + private static String dumpSharedArchive(boolean isStatic, String fileName) throws Exception { + String cwd = new File("").getAbsolutePath(); // current dir used for printing message. + String currentPid = String.valueOf(ProcessHandle.current().pid()); + String archiveFileName = fileName != null ? fileName : + "java_pid" + currentPid + (isStatic ? "_static.jsa" : "_dynamic.jsa"); + + String tempArchiveFileName = archiveFileName + ".temp"; + File tempArchiveFile = new File(tempArchiveFileName); + // The operation below may cause exception if the file or its dir is protected. + if (!tempArchiveFile.exists()) { + tempArchiveFile.createNewFile(); + } + tempArchiveFile.delete(); + + if (isStatic) { + String listFileName = archiveFileName + ".classlist"; + File listFile = new File(listFileName); + if (listFile.exists()) { + listFile.delete(); + } + dumpClassList(listFileName); + String jdkHome = System.getProperty("java.home"); + String classPath = System.getProperty("java.class.path"); + List cmds = new ArrayList(); + cmds.add(jdkHome + File.separator + "bin" + File.separator + "java"); // java + cmds.add("-cp"); + cmds.add(classPath); + cmds.add("-Xlog:cds"); + cmds.add("-Xshare:dump"); + cmds.add("-XX:SharedClassListFile=" + listFileName); + cmds.add("-XX:SharedArchiveFile=" + tempArchiveFileName); + + // All runtime args. + String[] vmArgs = VM.getRuntimeArguments(); + if (vmArgs != null) { + for (String arg : vmArgs) { + if (arg != null && !containsExcludedFlags(arg)) { + cmds.add(arg); + } + } + } + + Process proc = Runtime.getRuntime().exec(cmds.toArray(new String[0])); + + // Drain stdout/stderr to files in new threads. + String stdOutFileName = drainOutput(proc.getInputStream(), proc.pid(), "stdout", cmds); + String stdErrFileName = drainOutput(proc.getErrorStream(), proc.pid(), "stderr", cmds); + + proc.waitFor(); + // done, delete classlist file. + listFile.delete(); + + // Check if archive has been successfully dumped. We won't reach here if exception happens. + // Throw exception if file is not created. + if (!tempArchiveFile.exists()) { + throw new RuntimeException("Archive file " + tempArchiveFileName + + " is not created, please check stdout file " + + cwd + File.separator + stdOutFileName + " or stderr file " + + cwd + File.separator + stdErrFileName + " for more detail"); + } + } else { + dumpDynamicArchive(tempArchiveFileName); + if (!tempArchiveFile.exists()) { + throw new RuntimeException("Archive file " + tempArchiveFileName + + " is not created, please check current working directory " + + cwd + " for process " + + currentPid + " output for more detail"); + } + } + // Override the existing archive file + File archiveFile = new File(archiveFileName); + if (archiveFile.exists()) { + archiveFile.delete(); + } + if (!tempArchiveFile.renameTo(archiveFile)) { + throw new RuntimeException("Cannot rename temp file " + tempArchiveFileName + " to archive file" + archiveFileName); + } + // Everything goes well, print out the file name. + String archiveFilePath = new File(archiveFileName).getAbsolutePath(); + System.out.println("The process was attached by jcmd and dumped a " + (isStatic ? "static" : "dynamic") + " archive " + archiveFilePath); + return archiveFilePath; + } +} diff --git a/tests/test_data/std/jdk/internal/misc/CarrierThread$1.class b/tests/test_data/std/jdk/internal/misc/CarrierThread$1.class new file mode 100644 index 0000000000000000000000000000000000000000..8f1ad64b9c29e3288223730e7369097d1b300560 GIT binary patch literal 1267 zcmah}TTc@~6#k|yY+JT~+dw|TjoE{0}h9O*6TOlr;sLH{%)P-*JDCkvj4q1k&vyU+J8%-&N?Hyz7&lmKg zOhPTCH2N{1U{J*n&PP)HC$_sGym0+cI?X+X;Ztw|7lDmnRKW!m7k#jS<7_Q}6d|s0 zUttpC4BZi(t`9QlSAL42m_MO7WNI_lJZajEQei!f9A*?;QZehZPew|0vJJUKYJ_as z3JMHkfmByew++j2sYg}e zZ8>!nCBHq{NItD}lB>e?9yu<(F!ix*3t6$a>k1bW)Y}*s^7KIC^rv@8yE$5EG&A2a zcL?^87BS4z=(~XzDAK5g0l16>+A;rn(C8n2heQB3`w7ZtWEc+6r_Uc?c%%9q$)f)L z&(E(I*_h9c9b%$d{6I(I0sJ5-0A3RGD-7T@UD-F7!P|gtjzF{YNzibG#DM5RViluU zBpaj17_J81YvfNM_6w?lkxXxyg0Hu<9VK>vX`lJ5#5!;zh`Nbe!F(HcXikulyI2Y= ON!+73O$0fb>Gu~aJ~77t literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/CarrierThread$ForkJoinPools.class b/tests/test_data/std/jdk/internal/misc/CarrierThread$ForkJoinPools.class new file mode 100644 index 0000000000000000000000000000000000000000..79a6b36a2829bf031c1b974155ca2913ce579f7e GIT binary patch literal 1115 zcmb7D(M}UV6g|@xwrm$c5L8qu7NM=e#^_s#32r3XG)PkItC{Xj+G)45WOnPPs4>w$ z@Iif0eDDMODC3=_!8RC$mzlYD?mhS1J7<3W`u+oehiw}fWG&sJ+8GB`gvCi9<1+0 zx?hi^I*6h$X0Z3_2QPO$?{TxqaIZ0u&3#|Qv0EnsFA^Dgk@AOH3zbmLZhBWM-~#3> z%saS<1qSz=`3y^K(UHoF28Tk$JQ2a8F!K8h8|6mY_>c;_{z+wboPMoRH}x+$Si&;H zqENwUpv|)Y)hjI)QSuX92_NnSuuupWzV3k&L4ZKE?R_8c?pw`IB8`+Y_ zBtM{N6K8*hRXxIN1|P{9M|d}eVB;1_DFSJ4gy0dKEcprsp?HMF9R83n-x_!i8y`}b z<UexJ^KLY@GB{N(lkhH(dS#%Yc#UXgvmdOM!2w;wE`AD5H|@RoqP@3{(|c Guzv%PI}Tz1 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/CarrierThread.class b/tests/test_data/std/jdk/internal/misc/CarrierThread.class new file mode 100644 index 0000000000000000000000000000000000000000..cf934c7a2cc19d1f09eb5782925bfdc5f0cac8d0 GIT binary patch literal 4253 zcma)9iC+}g9sfR98CZs>cm|CLhA5z6P1UyPTI0H`$Y$B4yMRY($hbSe$TCA_W{ozr zcamP|m0sE-X_~98JpvI(XkvP|`J?*j_q|#6K+!HA_PyUbe(!gDf5(3G-}gQM5XVO? zXh5TekdAd|61e|DVLD>jzUkUVF*0L$`AFPwUCVSwrd-n~2yBYSvf05zc6{VyHWBL| z$Yw@|1-7Lw7#EF5(Xb~Y!N~#FDa}U1Xhw^Mu#Q&f0zK+f$+wD;ykqA}u4~$Ul+ zCmqW^#j*NO(-F(I{G$R#yVqbIEU(3F*l~){vpr){!+UhB#|8m0D$tR-RmV}=GbYTa zJld{f6E+L9$1~}X#OaZEDwfNoGO_+dmiLokY{fPW+jZQF4uLIIwc|y@^HPpcFkOMo zlct}$?D^(Q-SWNNJvF-2Y|&6Vai4}=I_}2<0^8S;Q9z$9`B`(qr0MdeKzFTmGUqRt zc|V%0d8E7)*kQMh2c>e`2Gb`K*};+6@l+!4V=5DmrE<~$59!z=&)io&ljx7d0X?Ui5Afn>{9^rl$O>4To<=9@oj!ky6 zmK~<@BRWPgCZG|~GNc3^TCw3BBQK28IHTdLjwkS0frsl}yEU(u;eN-rdy>*^PwE(#Kwe)lggIsuOQy7gq2s(X!n%@8JvGS0Ry8tl z;XETzCY6}bF^MVen|9$=dG`K4@+5o4G+YqaQGFs;4vxg7yg4f^-VB;{i)Z@f0I5k1 zVOX%GmmQv{4fmYy(zj8`{b_;DyP5crFlKQw3?C&87j-;?O9H!;Ot+8KqD*Ca!5Ma~ zi&oK`lu>u6EI{Q(bu*TiibQKuTsiw__*`AC3<6J;2o0Z?@gV_TVR^fRq2UX+2s`XL zKJy(P?RRDjiPtOmk~Gwp1!Ak^j5`H0=ak&M8C{j1hE11%^vEXe6pH~v8a0e(@m0y~ zYYh7CCstot^|re3JYLZ7bsgW3sbqcC+sc^&TMMRVxn`jf#5v#aOI{e?!nZZNsN*~M z?rJ}llSOXI;6ML7~f0vPi!INypuUQc-d&*?Bl2IQ> zpK|g>(QC%*EQRGwdhRx*jD;ti85xgfhK3XATx?`8J;0jCF!p@I_EpMhWU~eOzj7uq zKA0XK&SnO(tgLcZ&^VP{a*%5cRTb`>?wFoK65hmI%CgOLY34lpD5(nVrt}yyTuZ4I zEQb6kizw=>$IGo*nJ5m;s-*v50RKD6L9JERR;fBDIuu|_aC4Pu9zmg+Q8g@bDq`ulL7`Urzt??KZJZKtUrKfwQW+<((N$*P6~7Do8Sj%8eC7jw zOW+-)IFdzp8P=Kh=|#-kR7|DK174*XUf~L_FmB>Q@(9cFSmw1yaiSfUF-xGhOYlC# zWvPr%J`DI>;T_h+@|^=jto&?W#() { + public ThreadGroup run() { + ThreadGroup group = JLA.currentCarrierThread().getThreadGroup(); + for (ThreadGroup p; (p = group.getParent()) != null; ) + group = p; + var carrierThreadsGroup = new ThreadGroup(group, "CarrierThreads"); + return carrierThreadsGroup; + } + }); + } + + /** + * Return an AccessControlContext that doesn't support any permissions. + */ + @SuppressWarnings("removal") + private static AccessControlContext innocuousACC() { + return new AccessControlContext(new ProtectionDomain[] { + new ProtectionDomain(null, null) + }); + } + + /** + * Defines static methods to invoke non-public ForkJoinPool methods via the + * shared secret support. + */ + private static class ForkJoinPools { + private static final JavaUtilConcurrentFJPAccess FJP_ACCESS = + SharedSecrets.getJavaUtilConcurrentFJPAccess(); + static long beginCompensatedBlock(ForkJoinPool pool) { + return FJP_ACCESS.beginCompensatedBlock(pool); + } + static void endCompensatedBlock(ForkJoinPool pool, long post) { + FJP_ACCESS.endCompensatedBlock(pool, post); + } + } + + static { + CONTEXTCLASSLOADER = U.objectFieldOffset(Thread.class, + "contextClassLoader"); + INHERITABLETHREADLOCALS = U.objectFieldOffset(Thread.class, + "inheritableThreadLocals"); + INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset(Thread.class, + "inheritedAccessControlContext"); + } +} diff --git a/tests/test_data/std/jdk/internal/misc/CarrierThreadLocal.class b/tests/test_data/std/jdk/internal/misc/CarrierThreadLocal.class new file mode 100644 index 0000000000000000000000000000000000000000..20298494e6be4b5c72269464f16f708391eae82d GIT binary patch literal 1626 zcma)+T~E_c7{~vogO!ykg1iYTf(R=p6%=3CBw0wfAd8x8*#$SIbSF?8ooPD~zmpff zTqs`n0sK(L|Jlm6x)FD=o%5XYoZs`_-+zAo0FW0_nWxd(o~yDr;3T7(qsdVPX`f!18JJz3ust41A|%pLwBc?>Rx>$smD9 z9TW>xE+(`c*Og&tAJA%%Mhi_bH;U^R({aPZI3@&^{{MuYAIqqp*_~|C;uZeotYRnh zH%F(^jhb#unwY{g@nL^_Za{o5-KwZCXHDF~oWN`#&+6y0Uj){GCR)JTChp*_z`Pgs z!rlfllzt>IF!RvBJuK>2GI1Zv0*n1>Q95w~SuII7kWnZw&Qc^RDzK7eg1h^qf8_;+ z_UctBFjn+@`MPm-#4d7&C z=`0ten{G7<&3IwEoSe!-fswphi^p^;U*74pwcB;nHJg`F8Krt7aOJ+I(mm7LJsZk9 zEOPoaemn%`)ckXo=AK^<{y(5p;3~KduYHI3!c7V*u@cxrtK6F{1!Q4ST1%X)QxbTH zM>L{v`&<>y_zHdP0@pNrrqs<`?P3}|Om(7|8~kao$$E^6U72fRC_+C&VfDJ9o-d>+UJ1$8JIGPikpBy7 C5NWvp literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/CarrierThreadLocal.java b/tests/test_data/std/jdk/internal/misc/CarrierThreadLocal.java new file mode 100644 index 00000000..b14ecaff --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/CarrierThreadLocal.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + +/** + * A {@link ThreadLocal} variant which binds its value to current thread's + * carrier thread. + */ +public class CarrierThreadLocal extends ThreadLocal { + + @Override + public T get() { + return JLA.getCarrierThreadLocal(this); + } + + @Override + public void set(T value) { + JLA.setCarrierThreadLocal(this, value); + } + + @Override + public void remove() { + JLA.removeCarrierThreadLocal(this); + } + + public boolean isPresent() { + return JLA.isCarrierThreadLocalPresent(this); + } + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); +} diff --git a/tests/test_data/std/jdk/internal/misc/ExtendedMapMode.class b/tests/test_data/std/jdk/internal/misc/ExtendedMapMode.class new file mode 100644 index 0000000000000000000000000000000000000000..3853e1b194bea6c43b95a837c28c5a68096b7a60 GIT binary patch literal 2777 zcma)8`&Sc36#gb4OX3O`6?_yGMdhIet*x~|D2Aw%gisQ(^hKA=3Jc3_y1PMX|DgWr z;~eGKb83I?>FJ-;({FZ{WKkZ%f!Ue4_nUja`}#d71mBW#qz1e`IS`L5IMx=1G+m*LkWfS%!ixfu82ZROE8rbsaZ_PNY>F z!*QB1YTBkhCU7!tMgu21IG;i{dK8?L3a13RnxLhnRYUg$S_TH^6`T>c6zm;jbqc*W ztKgi9^XL;e+XUQ&R*xoHj82l61AllT<36nv)QbKDl_Xa;iLF{=Wtm4(^7z|k1FA=?V>>`0_A>r=>LRKZ;p zV;C1W(}dd*lFDX{MVeX8j>>JSV%($x`;F0nXOsKer924e=X;;aw=eu>?cSvw) zU;Gcz_B<g!8}Tan#FAYE{D&6?L- zQ_iDB!HpBK;5NGkk!)=}&}&99>TLo?%D$$r(T@nH)n74L=NAhHHs>tOx3u-8s@CuM zns4g;BP69kA3@qjbt~#T)0 z2zaoWqkEkk=2oKxj`6fq*{Qp_A#V;|Ywulj*JWf_hW8xDXR7n|3o6R%!YYNg+f~3t z)EYY5V99J;SMdY-y3ogkS_;3wRp6=cQ5U$-jCaIKA&3{jwI`Y^r%i#wEZ*kqpLlic zAoD$!VxC926kFM$DBHrGJ$>KJs6zJz-le>Anq`$u-yrGg6z^*{XgY?c;Mw+5V6SUY zKxsTZ+QLf;ePp?tcSs9P%6ALDPRU9SMiwf^R-|N0fWRDQOO#A-OuvK}dJW}y;SY2! z48OtAca#7WzD%5Dyh!HF0ANCeOn<##TCl%`Pt-{E_pD$}~&|erSyu{7)7hCwUIGjFx^)mfL87W)GD%;aaGJm} dRw6-%YbMrUV}mPc?w!U{Y!YyUFPdL*>VKea_c8zg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/ExtendedMapMode.java b/tests/test_data/std/jdk/internal/misc/ExtendedMapMode.java new file mode 100644 index 00000000..f2852f56 --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/ExtendedMapMode.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.nio.channels.FileChannel.MapMode; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; + +/** + * JDK-specific map modes implemented in java.base. + */ +public class ExtendedMapMode { + + static final MethodHandle MAP_MODE_CONSTRUCTOR; + static { + try { + PrivilegedExceptionAction pae = () -> + MethodHandles.privateLookupIn(MapMode.class, MethodHandles.lookup()); + @SuppressWarnings("removal") + Lookup lookup = AccessController.doPrivileged(pae); + var methodType = MethodType.methodType(void.class, String.class); + MAP_MODE_CONSTRUCTOR = lookup.findConstructor(MapMode.class, methodType); + } catch (Exception e) { + throw new InternalError(e); + } + } + + public static final MapMode READ_ONLY_SYNC = newMapMode("READ_ONLY_SYNC"); + + public static final MapMode READ_WRITE_SYNC = newMapMode("READ_WRITE_SYNC"); + + private static MapMode newMapMode(String name) { + try { + return (MapMode) MAP_MODE_CONSTRUCTOR.invoke(name); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + private ExtendedMapMode() { } +} diff --git a/tests/test_data/std/jdk/internal/misc/FileSystemOption.class b/tests/test_data/std/jdk/internal/misc/FileSystemOption.class new file mode 100644 index 0000000000000000000000000000000000000000..b899e125710627f2f3eb4a2ad7905ed0a735d622 GIT binary patch literal 2567 zcmb7FZBrUo6n?H6-nyct)f&^Zd9eo2ibf*(Hky$C3H4~oE@`BY2+XBH3p|h}%Zl2mP+p5P7n=$q0mT8yGvSVz{X>D%~jt3CLgcp+v-bY9v zGW1RXU&E|e6i7qhW;iVmCN(L*SoXxU+X|5aYkbH8QvUO;gjkx1{mbcsxcr?rwC(@oPASZs@#3x>Ss^AuBwN zUX}KQg0I-_NohGXsk6e@yd;eq3ZAfWGOuRxnywWzeg9xfd%DH66dNUNQ^8ZFg?ee* zYD(MPW}?PsN&Hqpnu!y=#B_F#SsAub7X5jvVjHc~hAFT*L`D-mwNR*A<@kDB;PDkV zazj<96nXFR@CA_2b-86MSuaz#6KTsfGpDtp+0cz*l~zLOdda93jE2Ryy*So7vYM3f zdb{_h-K6uA4ly#!DcT`Cyh7bNVMhwoB!gT2qOqsT1@89kysWVWuALYSqsDpYpP7{C zQ3{==)iC`|Ob*wVC{^2oHk{DcE;?PmxFitB*H0TIlZURrRR8Q<;>f5MHQP2D$*R$8 znshlq_lWhv61eRikC&X-i&p|OgJ=|gXXfEPRs0COE&*KU;Q@gxp%Ls5rV-%6)b1`! zo$bQZ$u3OI>%!EfUHqKgY*lmVGMEjk-#pYX@`vhY49h2J?Z_0%eLRO<+{q>(LZ|5=$m!(ZC!u#4|o?| zWBi>gzs{gh+L5H9+8legTaHo(&ZEVW7aw0D?|J0LE> zx&ywEAn5>Af-MI;lVF=qDr6DP(-}d { + public static final FileSystemOption INTERRUPTIBLE = + new FileSystemOption<>(ExtendedOptions.INTERRUPTIBLE); + public static final FileSystemOption NOSHARE_READ = + new FileSystemOption<>(ExtendedOptions.NOSHARE_READ); + public static final FileSystemOption NOSHARE_WRITE = + new FileSystemOption<>(ExtendedOptions.NOSHARE_WRITE); + public static final FileSystemOption NOSHARE_DELETE = + new FileSystemOption<>(ExtendedOptions.NOSHARE_DELETE); + public static final FileSystemOption FILE_TREE = + new FileSystemOption<>(ExtendedOptions.FILE_TREE); + public static final FileSystemOption DIRECT = + new FileSystemOption<>(ExtendedOptions.DIRECT); + public static final FileSystemOption SENSITIVITY_HIGH = + new FileSystemOption<>(ExtendedOptions.SENSITIVITY_HIGH); + public static final FileSystemOption SENSITIVITY_MEDIUM = + new FileSystemOption<>(ExtendedOptions.SENSITIVITY_MEDIUM); + public static final FileSystemOption SENSITIVITY_LOW = + new FileSystemOption<>(ExtendedOptions.SENSITIVITY_LOW); + + private final ExtendedOptions.InternalOption internalOption; + private FileSystemOption(ExtendedOptions.InternalOption option) { + this.internalOption = option; + } + + /** + * Register this internal option as an OpenOption. + */ + public void register(OpenOption option) { + internalOption.register(option); + } + + /** + * Register this internal option as a CopyOption. + */ + public void register(CopyOption option) { + internalOption.register(option); + } + + /** + * Register this internal option as a WatchEvent.Modifier. + */ + public void register(WatchEvent.Modifier option) { + internalOption.register(option); + } + + /** + * Register this internal option as a WatchEvent.Modifier with the + * given parameter. + */ + public void register(WatchEvent.Modifier option, T param) { + internalOption.register(option, param); + } +} diff --git a/tests/test_data/std/jdk/internal/misc/InnocuousThread$1.class b/tests/test_data/std/jdk/internal/misc/InnocuousThread$1.class new file mode 100644 index 0000000000000000000000000000000000000000..f77fa364bf957029a4177ca655788ab1731c5419 GIT binary patch literal 1252 zcma)5?M~D{6g{&alr0rjSX2}cWYyh*RQyhskPza=H7gjF@PFt|mcj1SOj`_Zr3onU zhY#RG8E?B)io`&Z&TVf`&zyVi+@HU`{{XOoS0&_-H&C!p#1O;6LHC0rRVcLLp3|3s z>$H^e-N=uEoqa8Mx4ObGe8|13;(fs|-ag=m-0`^TIh{~T)oa9*!xl;~8O#_Na@`Xl zLnVXVj+Ekio=DJ^g=-jPuwwK_EqyJ+BL>zoQO0!x;}#}RVJM&NwY7I3T;d#Bl}d(d z4Eb7p*TfCnG;qtp6mBz2p20Uf9t3TlcZDV$q^5Hegra{gJyok`1ZF-pOiW|Oz^sM4 zm}8i~)Fdj!C9^^?@Qk5T%TT92Wio%=c$-OP6|}O_2Bf4ahkF(lP^Id1q^PiS6{Ii& z4;W?>D+1w0v9->7Ef1w9dZN4ThSH~B?JEjw)pr>R8-AC1Kh~B?Y)1V(p?Bh5#;3t| zxwp%;jNj8_A>5Y%!~OQ9wpCXe45g0jDIP|e_|6wJ=s7`}8JE)JAoJe>S2KU4zN`_E z+3_RoiY9qMoBearmt)VU%Gb*E{D4mOI}z^tT?^0foMbBT=}&hXS2pjW44S4*5rl92 zfKIbT5`<0~F9OU_gUcZ2kS~|x`2;A^TqThvhDJC~_XHjivPMs96blq9_TmYcy>tS@ zo;ksY{S9MZD4#=})*<2qwqVn0CC?QsVu{`!(Vatua&)R_jX9eszG5E}TO#7X?wcf2ai?)HfNXPq<%Kd?XmE-6MX&U7xF=+cR3KVJoJbwo!(~V8xz>>!C0V zwT$oENGX2ci^SWuaShiQ?AZHQ%RozW%D_4nD!5TX)y5oZ43+a(uMdudN1RhzQc1JT zkZ&~m7UprQgxfam;4Z`RrNvN4kBTy4QX50Bk;yTwCxiUX`eg=e`#cQ00Urq6>NGPy zCZsKk^tf+h0gIHSjuZ*e_=j5wOAL!ig`x1GSOWKrmM78|LowL#j11_gbHxNZ%|1h+ z9So>Pvt6mgUNkxodOy}Y?pok+zt6Rdzf-Va4rR!&+Pze^`euuv+>=AaO{9tM&w?hs zA(!2Z7%4bG{#)Qy=0qyrHW699Akv=LB`qk}g^ApVHKQt@E6)!?n!s1W90mg$8*m9$ z;(hNlG-C9t$E_<%_;)fi`+FiZFM^O}&!$9#PTDU*EK!>)V0eIhr4rvJfGpjD#L|4z zh0D{L!!mh3q_=Id1+q0~Z4BnDk5O_K#+Y$FWA-EAIjqn=MV!Df>a^R*dkw32L|>0- zTZ(}bFEl2B_{CtIL9`2yq;+$f=HV+u8f%2}*e`-j3K&at*s z(yTG$8_hin)3{Z_Z5wxRmtp?WVko3XMHw-wjiJ}bs+=9){h3_l0hC znwcLX(w0Sf+_y1_qbgr0&ksVHz-?g;g1(Iv zxCATlzIPlNG5pix_7x@Ex~Q2n{5v8vFN2VV&!$X-PWmrG%u$~!V0eIhr4nB!fGk~u z#L|G%jmy)T!aR9Cq_;J)1+q0~=@iUaK1IoyImLwY6_cL{&tZY~G2#S1piaA;yw|XZ zNA&fWRt`17Xt-#PIoqj!)j1)`6O_vFKJg7VKPBF0j2|uM806#gc+O}5)K#?;!XwY6zYqPTzhLr5u<;0$WWYezizY+88*5TKIN{@)ySOzo){gyZQCfKWWjc@0*9fp zK)oDHgh!TzBdKI~%#dv~`xeR!>kCkds)!0h?NStp6C10j#tyDB+;1!iB&F_!MygS} z*|#a_bqCk5LEcTI7&aTt6fotzZDEsPJBch1USwqW&V6O%RQh5hh9_PqHQ8@1bKmSU zZQy@Dk{ObA>)t1@ z)&;B&^vd8SodvQ4e&80JPI9-gjob9vp`A%|G!66ynbSat0JSKcSc z1>4UQTY1J-IiZ=_owK+kW3TzvXVfkmr$folL&?vBxr4pLRUP{zb2y;0k!TLkBxw_E HoG7i|%2ea- literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/InnocuousThread.class b/tests/test_data/std/jdk/internal/misc/InnocuousThread.class new file mode 100644 index 0000000000000000000000000000000000000000..ffbcd67a70c5ea1858a7dd3d7b10641b4a7a62e7 GIT binary patch literal 5881 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/InnocuousThread.java b/tests/test_data/std/jdk/internal/misc/InnocuousThread.java new file mode 100644 index 00000000..f8db0bc1 --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/InnocuousThread.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.ProtectionDomain; +import java.security.PrivilegedAction; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A thread that has no permissions, is not a member of any user-defined + * ThreadGroup and supports the ability to erase ThreadLocals. + */ +@SuppressWarnings("removal") +public final class InnocuousThread extends Thread { + private static final jdk.internal.misc.Unsafe UNSAFE; + private static final long THREAD_LOCALS; + private static final long INHERITABLE_THREAD_LOCALS; + private static final ThreadGroup INNOCUOUSTHREADGROUP; + private static final AccessControlContext ACC; + private static final long INHERITEDACCESSCONTROLCONTEXT; + private static final long CONTEXTCLASSLOADER; + + private static final AtomicInteger threadNumber = new AtomicInteger(1); + private static String newName() { + return "InnocuousThread-" + threadNumber.getAndIncrement(); + } + + /** + * Returns a new InnocuousThread with an auto-generated thread name, + * and its context class loader is set to the system class loader. + */ + public static Thread newThread(Runnable target) { + return newThread(newName(), target); + } + + /** + * Returns a new InnocuousThread with its context class loader + * set to the system class loader. + */ + public static Thread newThread(String name, Runnable target) { + return newThread(name, target, -1); + } + /** + * Returns a new InnocuousThread with its context class loader + * set to the system class loader. The thread priority will be + * set to the given priority. + */ + public static Thread newThread(String name, Runnable target, int priority) { + if (System.getSecurityManager() == null) { + return createThread(name, target, 0L, + ClassLoader.getSystemClassLoader(), priority); + } + return AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Thread run() { + return createThread(name, target, 0L, + ClassLoader.getSystemClassLoader(), priority); + } + }); + } + + /** + * Returns a new InnocuousThread with an auto-generated thread name. + * Its context class loader is set to null. + */ + public static Thread newSystemThread(Runnable target) { + return newSystemThread(newName(), target); + } + + /** + * Returns a new InnocuousThread with null context class loader. + */ + public static Thread newSystemThread(String name, Runnable target) { + return newSystemThread(name, target, -1); + } + + /** + * Returns a new InnocuousThread with null context class loader. + * Thread priority is set to the given priority. + */ + public static Thread newSystemThread(String name, Runnable target, int priority) { + if (System.getSecurityManager() == null) { + return createThread(name, target, 0L, null, priority); + } + return AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Thread run() { + return createThread(name, target, 0L, + null, priority); + } + }); + } + + /** + * Returns a new InnocuousThread with null context class loader. + * Thread priority is set to the given priority. + */ + public static Thread newSystemThread(String name, Runnable target, + long stackSize, int priority) { + if (System.getSecurityManager() == null) { + return createThread(name, target, stackSize, null, priority); + } + return AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Thread run() { + return createThread(name, target, 0L, + null, priority); + } + }); + } + + private static Thread createThread(String name, Runnable target, long stackSize, + ClassLoader loader, int priority) { + Thread t = new InnocuousThread(INNOCUOUSTHREADGROUP, + target, name, stackSize, loader); + if (priority >= 0) { + t.setPriority(priority); + } + return t; + } + + private InnocuousThread(ThreadGroup group, Runnable target, String name, + long stackSize, ClassLoader tccl) { + super(group, target, name, stackSize, false); + UNSAFE.putReferenceRelease(this, INHERITEDACCESSCONTROLCONTEXT, ACC); + UNSAFE.putReferenceRelease(this, CONTEXTCLASSLOADER, tccl); + } + + @Override + public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { + // silently fail + } + + @Override + public void setContextClassLoader(ClassLoader cl) { + // Allow clearing of the TCCL to remove the reference to the system classloader. + if (cl == null) + super.setContextClassLoader(null); + else + throw new SecurityException("setContextClassLoader"); + } + + /** + * Drops all thread locals (and inherited thread locals). + */ + public final void eraseThreadLocals() { + UNSAFE.putReference(this, THREAD_LOCALS, null); + UNSAFE.putReference(this, INHERITABLE_THREAD_LOCALS, null); + } + + // ensure run method is run only once + private volatile boolean hasRun; + + @Override + public void run() { + if (Thread.currentThread() == this && !hasRun) { + hasRun = true; + super.run(); + } + } + + // Use Unsafe to access Thread group and ThreadGroup parent fields + static { + try { + ACC = new AccessControlContext(new ProtectionDomain[] { + new ProtectionDomain(null, null) + }); + + // Find and use topmost ThreadGroup as parent of new group + UNSAFE = jdk.internal.misc.Unsafe.getUnsafe(); + Class tk = Thread.class; + Class gk = ThreadGroup.class; + + THREAD_LOCALS = UNSAFE.objectFieldOffset(tk, "threadLocals"); + INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset + (tk, "inheritableThreadLocals"); + INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset + (tk, "inheritedAccessControlContext"); + CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset + (tk, "contextClassLoader"); + + long gp = UNSAFE.objectFieldOffset(gk, "parent"); + ThreadGroup group = Thread.currentThread().getThreadGroup(); + + while (group != null) { + ThreadGroup parent = (ThreadGroup)UNSAFE.getReference(group, gp); + if (parent == null) + break; + group = parent; + } + final ThreadGroup root = group; + if (System.getSecurityManager() == null) { + INNOCUOUSTHREADGROUP = new ThreadGroup(root, "InnocuousThreadGroup"); + } else { + INNOCUOUSTHREADGROUP = AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public ThreadGroup run() { + return new ThreadGroup(root, "InnocuousThreadGroup"); + } + }); + } + } catch (Exception e) { + throw new Error(e); + } + } +} diff --git a/tests/test_data/std/jdk/internal/misc/InternalLock.class b/tests/test_data/std/jdk/internal/misc/InternalLock.class new file mode 100644 index 0000000000000000000000000000000000000000..42c3da4e7db33bceb6be016b9aee49e39fff129d GIT binary patch literal 1516 zcma)6T~8BH5Iwi8-F8`^R6(sDd??s1!YU}JMFc8Dq!dGuL|({JZeU^A#qF-9KL!5) zFFyDQMiL)=@Fy8#oZDTo6hcgs-aFHoGjryi>5t!EzX8Z$Qbq`22@wTn5M@Yg=&y9m z)U7pbZe@d)T!!d~VHxfyLpYsTln`S`SA#s)Ftw6xl|0AcmaCa|X|t@&bGkda<>twh zAt4+`0~8633YyT&aCKvKQ!^}=JC<&0TSmF0O$U}pVTcGI1~vb`RkET&i-IK1GPLH# z3(L=olgrbEg~|ECcz!uQmz!Z=OEN`;MMrH4&f@}u z)U!l8!qu*zL!`ADfcVn`CVe#7qf%6!(Qq1jGZ#&vW{=uvP3 z=_B(kR?05lVrW?7?lZ^U=8juo=t=v$t4~mL9m877W{$gLsOXh&Q$e5Tspi@I9Aamb zC%3lUN(>s!)O9>Aa&9Xaz##GBFFoBX6Pwz4{*z}jOO%nbS2;s--mrMV+gjnyg1%ys zCrKmI%|+cYgdI2|?z%x>9r@EAH_Omy@z-MLb56lCO@^*Cu{%`}BB|)=rOjD=J17@F z1gRU?Ujj7)3tS{$du2nkU$1b&kByYfK;(>Q)W!r)z#tcG&nfXKLkyv%RrmSC^05cvvG{z zVE{5sfgh$=wB)wX<)iJEqj7{#M1@FA>#q2&r-2j~>AG4&JVJ+!{1du>NkHDIxT z8xt!S0O@T&?FZe?oo?V~0IB z!FYR;onLTmM*WVIx`)ggC~C5Q54Uz8hd&~*3n@Z}=+GZ|8|enf5ROW!>Lrc!p&Qy^ dwJ6##PKpw5D>M@Rg_Hy}`m?IB9Qi_c{0F_!B2EAR literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/InternalLock.java b/tests/test_data/std/jdk/internal/misc/InternalLock.java new file mode 100644 index 00000000..d7a271e6 --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/InternalLock.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import java.util.concurrent.locks.ReentrantLock; + +/** + * A reentrant mutual exclusion lock for internal use. The lock does not + * implement {@link java.util.concurrent.locks.Lock} or extend {@link + * java.util.concurrent.locks.ReentrantLock} so that it can be distinguished + * from lock objects accessible to subclasses of {@link java.io.Reader} and + * {@link java.io.Writer} (it is possible to create a Reader that uses a + * lock object of type ReentrantLock for example). + */ +public class InternalLock { + private static final boolean CAN_USE_INTERNAL_LOCK; + static { + String s = System.getProperty("jdk.io.useMonitors"); + if (s != null && (s.isEmpty() || s.equals("true"))) { + CAN_USE_INTERNAL_LOCK = false; + } else { + CAN_USE_INTERNAL_LOCK = true; + } + } + + private final ReentrantLock lock; + + private InternalLock() { + this.lock = new ReentrantLock(); + } + + /** + * Returns a new InternalLock or null. + */ + public static InternalLock newLockOrNull() { + return (CAN_USE_INTERNAL_LOCK) ? new InternalLock() : null; + } + + /** + * Returns a new InternalLock or the given object. + */ + public static Object newLockOr(Object obj) { + return (CAN_USE_INTERNAL_LOCK) ? new InternalLock() : obj; + } + + public boolean tryLock() { + return lock.tryLock(); + } + + public void lock() { + lock.lock(); + } + + public void unlock() { + lock.unlock(); + } + + public boolean isHeldByCurrentThread() { + return lock.isHeldByCurrentThread(); + } +} diff --git a/tests/test_data/std/jdk/internal/misc/MethodFinder.class b/tests/test_data/std/jdk/internal/misc/MethodFinder.class new file mode 100644 index 0000000000000000000000000000000000000000..aef6b6e02cd91ae8cd1cd11cee11bdf4ebd375ea GIT binary patch literal 1766 zcmah~ZF3V<6n<{AWs_z57FsMVFKt0cLLmr>FNwui8*NRXHZ_tUj+@PGdP}lf?r!V& zQ|u4WuZS~JVbqV#_?sB<+}*U<7)L)Ox#!&T_MG#an?L`0{u_X0d}Uw=F&&zTVVqzX z-?8?sY};~L*?Wy0Zu<-;^1>1R5<@JNuIh+0O!tfmp2wvxTxUf}SH@v5oZ6LQ-}3pK z?K++>_iW#l26UJz#R$Vxs?_rjljPD>17jH1F<~N!Qw;Mv%|}_`_*^T~n>IqEYw2s$IOydm0`N0rn?r*!zqHvmAlFwSHz;LP5 zXJ^?q_q^;HwV^~^Cp(z+S7;CeEX5)%wVJN0)VEB$ ziMJR=DEJ1aQ97I7?s95hDq3@hB7wK@j*fRtyoVgaXfIpU6*P5iv$np%FcAS8I;t|? zH?gE@B$}*;j8xhWOcazhF1(6w`NB463qI1ZVxowT|4FCiFWvSUcpXKfSBD5m#VvH46IH=RHQ!&ITLC0fWOvpn-qYpGMw&* zLi6pynT!MoCY8@DQR)#Ih5e{(?RL!)7145nHD|an07LowCz5#HZg<}-qvGyKn-_)Z z@Iakdsqp0E6Z zxnY!Nzr*z6ADC2DbQ`1F@Pd@X?8)NKxV&`k5Q_)6NaveRar=9mAt!^B`2&nnWRs3} z4g%{ZlvE3fy^Rq%e@;>r3%E}u*O0@PxPynZ6kpQ@klNNEe7;MeE1V4e + *

  • be declared in this class's hierarchy
  • + *
  • have the name "main"
  • + *
  • have a single argument of type {@code String[]}, {@code String...} or no argument
  • + *
  • have the return type of void
  • + *
  • be public, protected or package private
  • + *
  • not be abstract
  • + * + * + * The method returned would be used by a launcher to initiate the execution of an + * application. + * + * Searching continues until a main method is found or the search is exhausted. The + * primary search occurs in two phases, once for a main method with a {@code + * String[]} or {@code String...} argument and failing that, once for a main method + * with a no arguments. The search itself uses recursion to first look at methods + * in this class, then default methods in this class's interface hierarchy and + * then repeating these steps with the class's super class. + * + * @apiNote The method returned may be declared in this class, a super class + * or as a default method of an interface that the class or super class + * implements. + *

    It is not possible to declare a static main method and instance main + * method with the same signature in the same class. {@jls 8.4.2} states that + * "It is a compile-time error to declare two methods with override-equivalent + * signatures in a class." + *

    {@link SecurityException SecurityExceptions} can halt + * the search. In this case, a null is returned. + * + * @return the main method if a method found or null if no method is found + * + * @jls 8.2 Class Members + * @jls 8.4 Method Declarations + * @jls 8.4.2 Method Signature + * @jls 12.1.4 Invoke a main method + */ + public static Method findMainMethod(Class cls) { + boolean isPreview = PreviewFeatures.isEnabled(); + Method mainMethod = JLA.findMethod(cls, !isPreview, "main", String[].class); + + if (isPreview && mainMethod == null) { + mainMethod = JLA.findMethod(cls, false, "main"); + } + + if (mainMethod == null) { + return null; + } + + int mods = mainMethod.getModifiers(); + + if (Modifier.isAbstract(mods) || + mainMethod.getReturnType() != void.class || + (isPreview && Modifier.isPrivate(mods)) || + (!isPreview && !Modifier.isStatic(mods))) { + return null; + } + + return mainMethod; + } + +} diff --git a/tests/test_data/std/jdk/internal/misc/OSEnvironment.class b/tests/test_data/std/jdk/internal/misc/OSEnvironment.class new file mode 100644 index 0000000000000000000000000000000000000000..3be8e953837bb5c7d496530fbd3a7cb0be5a55aa GIT binary patch literal 352 zcmah^F;2rk5S(?Kn3#|RIwT|%i2^9N2N2OjP+6o1N`H1vu;zT0E=~%5MTJDc19%i- z&p}93Y%z1Qd$XGT{CfWYFvDSr2%QA+0A2J5<5F+6vf4eWd0v{LA@ru~xVa&8&M%e; z_6Vot>RGXCjCb0qir0mjFK*qIeeEja#1qfzl_88WcIJLl<;Fkg+)C#ts|#(H+H=r9 z&A55uHDQwdv-g^ihAgZtzsRz5QEz-@0}~{2UZ@BZ4ixN*QouL`4{X1Al5r(*OVf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/OSEnvironment.java b/tests/test_data/std/jdk/internal/misc/OSEnvironment.java new file mode 100644 index 00000000..506273a5 --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/OSEnvironment.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +public class OSEnvironment { + + /* + * Initialize any miscellaneous operating system settings that need to be set + * for the class libraries. + */ + public static void initialize() { + // no-op on Solaris and Linux + } + +} diff --git a/tests/test_data/std/jdk/internal/misc/PreviewFeatures.class b/tests/test_data/std/jdk/internal/misc/PreviewFeatures.class new file mode 100644 index 0000000000000000000000000000000000000000..56451a6950152e1aee7863beb8149b66d03dc63a GIT binary patch literal 757 zcmah{%Wl&^6g`uqbz+=02`$e;-3KB?1cP8jD-e`)6g)^-@-Sr z0T!)5f;}IFxRbaEV#CIB-{;(W{Ok9(9{{#-$3+1}2PF?Pm}RI9_z4eUt`35|{y>C= zVRlO@X`V3@n;X3f%BVPSJzRpvuri2_0;!D9ipRmR%);P}7AI1i?g(y%T4W4Pd-ui5 zPWu%D+jpsb&ci%v3>BHR74OF)8jap}&|tVb#eb)=VVWk|h-fbrnj4v@_J>fU)+l3v z;dzebUx4{4F}@fNz3(d_BHtvw9xDG-nnSDPCPN*H9chsl{<;4HyA@Vwj{*tKXcZEUtQqo2 zaf;j|?=ij1M(>@0eI}!TCHmT*1Jqo?DsGYGjf-#_%j8w8j`@J4Q3fb|f%A!SY}9YZ z15K**Cs0pOq!>^?NA)AB-%)?xxO|4ipHtYmQOQGUc|-tDhyWltd0j~{DHE<2WXZ)rH|+WM3>D8Gj>2H< zg?_-$+^r4BSgD=KD%*cho)RgdwIw>ico_BvU53(-wCN?PfCO z+3Aa$owWgmJ^Kpwia;KYjX9LCZ*$XDW&2loL5@(xK^6{iltF|Vj&btMuH($+jLA^P HdAsxl!v~iD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess$ScopedAccessError.class b/tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess$ScopedAccessError.class new file mode 100644 index 0000000000000000000000000000000000000000..af78ab25c7f14ba214f5fda52fa74c2290b6f778 GIT binary patch literal 1160 zcmbVL-%k@k5dMZ1N=r+j{IGyOs-n_@TzpZJBP6C`#8gZy_JPEQ6 zPPvgr24g8?v&dnbaKGK$x1=&cE61}sGH|WB>vu)-d93A8EM>9h>VZCcQHRRNj@WqT zims8qs)yaKCj|?;(jyOz^sG0ba-*nq9Ja?WfyopKSxjM?uns|{lPM(*2TzS~^~}r$<18ps_e1T9Co*dK z()mlb8jY4Px+Mbh)DKJwD}=>=>7S6@R7&Wo=LCV^W1Bp8e{qkWL6V0xghKQXz!G9q zL=khCXS@*O%bY>{0l?o%%EI?LsIp5kv2w=jv@xWhQ2e84u!$yGig{RMf#cg(zJ$52c-5(nSL dM7?6UK2ZWoaaI|X*e>HP+YIMtu#8pA{Q_2sFfRZA literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess.class b/tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..f306d437d4cbe603c82983fe6d1b5ef4eae1144a GIT binary patch literal 98363 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 Nu{{Lso;D!#{{UVgpNRkf literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess.java b/tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess.java new file mode 100644 index 00000000..e1760325 --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/ScopedMemoryAccess.java @@ -0,0 +1,4138 @@ +/* + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.foreign.MemorySegment; +import java.lang.ref.Reference; +import java.io.FileDescriptor; +import java.util.function.Supplier; + +import jdk.internal.access.JavaNioAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.foreign.AbstractMemorySegmentImpl; +import jdk.internal.foreign.MemorySessionImpl; +import jdk.internal.util.ArraysSupport; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.vector.VectorSupport; + + +/** + * This class defines low-level methods to access on-heap and off-heap memory. The methods in this class + * can be thought of as thin wrappers around methods provided in the {@link Unsafe} class. All the methods in this + * class accept one or more {@link MemorySessionImpl} parameter, which is used to validate as to whether access to memory + * can be performed in a safe fashion - more specifically, to ensure that the memory being accessed has not + * already been released (which would result in a hard VM crash). + *

    + * Accessing and releasing memory from a single thread is not problematic - after all, a given thread cannot, + * at the same time, access a memory region and free it. But ensuring correctness of memory access + * when multiple threads are involved is much trickier, as there can be cases where a thread is accessing + * a memory region while another thread is releasing it. + *

    + * This class provides tools to manage races when multiple threads are accessing and/or releasing the same memory + * session concurrently. More specifically, when a thread wants to release a memory session, it should call the + * {@link ScopedMemoryAccess#closeScope(MemorySessionImpl)} method. This method initiates thread-local handshakes with all the other VM threads, + * which are then stopped one by one. If any thread is found accessing a resource associated to the very memory session + * being closed, the handshake fails, and the session will not be closed. + *

    + * This synchronization strategy relies on the idea that accessing memory is atomic with respect to checking the + * validity of the session associated with that memory region - that is, a thread that wants to perform memory access will be + * suspended either before a liveness check or after the memory access. To ensure this atomicity, + * all methods in this class are marked with the special {@link Scoped} annotation, which is recognized by the VM, + * and used during the thread-local handshake to detect (and stop) threads performing potentially problematic memory access + * operations. Additionally, to make sure that the session object(s) of the memory being accessed is always + * reachable during an access operation, all the methods in this class add reachability fences around the underlying + * unsafe access. + *

    + * This form of synchronization allows APIs to use plain memory access without any other form of synchronization + * which might be deemed to expensive; in other words, this approach prioritizes the performance of memory access over + * that of releasing a shared memory resource. + */ +public class ScopedMemoryAccess { + + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + private static native void registerNatives(); + static { + registerNatives(); + } + + public void closeScope(MemorySessionImpl session, ScopedAccessError error) { + closeScope0(session, error); + } + + native void closeScope0(MemorySessionImpl session, ScopedAccessError error); + + private ScopedMemoryAccess() {} + + private static final ScopedMemoryAccess theScopedMemoryAccess = new ScopedMemoryAccess(); + + public static ScopedMemoryAccess getScopedMemoryAccess() { + return theScopedMemoryAccess; + } + + public static final class ScopedAccessError extends Error { + + @SuppressWarnings("serial") + private final Supplier runtimeExceptionSupplier; + + public ScopedAccessError(Supplier runtimeExceptionSupplier) { + super("Invalid memory access", null, false, false); + this.runtimeExceptionSupplier = runtimeExceptionSupplier; + } + + static final long serialVersionUID = 1L; + + public final RuntimeException newRuntimeException() { + return runtimeExceptionSupplier.get(); + } + } + + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + @Retention(RetentionPolicy.RUNTIME) + @interface Scoped { } + + // bulk ops + + @ForceInline + public void copyMemory(MemorySessionImpl srcSession, MemorySessionImpl dstSession, + Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + try { + copyMemoryInternal(srcSession, dstSession, srcBase, srcOffset, destBase, destOffset, bytes); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void copyMemoryInternal(MemorySessionImpl srcSession, MemorySessionImpl dstSession, + Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + try { + if (srcSession != null) { + srcSession.checkValidStateRaw(); + } + if (dstSession != null) { + dstSession.checkValidStateRaw(); + } + UNSAFE.copyMemory(srcBase, srcOffset, destBase, destOffset, bytes); + } finally { + Reference.reachabilityFence(srcSession); + Reference.reachabilityFence(dstSession); + } + } + + @ForceInline + public void copySwapMemory(MemorySessionImpl srcSession, MemorySessionImpl dstSession, + Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes, long elemSize) { + try { + copySwapMemoryInternal(srcSession, dstSession, srcBase, srcOffset, destBase, destOffset, bytes, elemSize); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void copySwapMemoryInternal(MemorySessionImpl srcSession, MemorySessionImpl dstSession, + Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes, long elemSize) { + try { + if (srcSession != null) { + srcSession.checkValidStateRaw(); + } + if (dstSession != null) { + dstSession.checkValidStateRaw(); + } + UNSAFE.copySwapMemory(srcBase, srcOffset, destBase, destOffset, bytes, elemSize); + } finally { + Reference.reachabilityFence(srcSession); + Reference.reachabilityFence(dstSession); + } + } + + @ForceInline + public void setMemory(MemorySessionImpl session, Object o, long offset, long bytes, byte value) { + try { + setMemoryInternal(session, o, offset, bytes, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void setMemoryInternal(MemorySessionImpl session, Object o, long offset, long bytes, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.setMemory(o, offset, bytes, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int vectorizedMismatch(MemorySessionImpl aSession, MemorySessionImpl bSession, + Object a, long aOffset, + Object b, long bOffset, + int length, + int log2ArrayIndexScale) { + try { + return vectorizedMismatchInternal(aSession, bSession, a, aOffset, b, bOffset, length, log2ArrayIndexScale); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int vectorizedMismatchInternal(MemorySessionImpl aSession, MemorySessionImpl bSession, + Object a, long aOffset, + Object b, long bOffset, + int length, + int log2ArrayIndexScale) { + try { + if (aSession != null) { + aSession.checkValidStateRaw(); + } + if (bSession != null) { + bSession.checkValidStateRaw(); + } + return ArraysSupport.vectorizedMismatch(a, aOffset, b, bOffset, length, log2ArrayIndexScale); + } finally { + Reference.reachabilityFence(aSession); + Reference.reachabilityFence(bSession); + } + } + + @ForceInline + public boolean isLoaded(MemorySessionImpl session, long address, boolean isSync, long size) { + try { + return isLoadedInternal(session, address, isSync, size); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + public boolean isLoadedInternal(MemorySessionImpl session, long address, boolean isSync, long size) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return SharedSecrets.getJavaNioAccess().isLoaded(address, isSync, size); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void load(MemorySessionImpl session, long address, boolean isSync, long size) { + try { + loadInternal(session, address, isSync, size); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + public void loadInternal(MemorySessionImpl session, long address, boolean isSync, long size) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + SharedSecrets.getJavaNioAccess().load(address, isSync, size); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void unload(MemorySessionImpl session, long address, boolean isSync, long size) { + try { + unloadInternal(session, address, isSync, size); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + public void unloadInternal(MemorySessionImpl session, long address, boolean isSync, long size) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + SharedSecrets.getJavaNioAccess().unload(address, isSync, size); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void force(MemorySessionImpl session, FileDescriptor fd, long address, boolean isSync, long index, long length) { + try { + forceInternal(session, fd, address, isSync, index, length); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + public void forceInternal(MemorySessionImpl session, FileDescriptor fd, long address, boolean isSync, long index, long length) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + SharedSecrets.getJavaNioAccess().force(fd, address, isSync, index, length); + } finally { + Reference.reachabilityFence(session); + } + } + + // MemorySegment vector access ops + + @ForceInline + public static + , E, S extends VectorSupport.VectorSpecies> + V loadFromMemorySegment(Class vmClass, Class e, int length, + AbstractMemorySegmentImpl msp, long offset, + S s, + VectorSupport.LoadOperation defaultImpl) { + + try { + return loadFromMemorySegmentScopedInternal( + msp.sessionImpl(), + vmClass, e, length, + msp, offset, + s, + defaultImpl); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @Scoped + @ForceInline + private static + , E, S extends VectorSupport.VectorSpecies> + V loadFromMemorySegmentScopedInternal(MemorySessionImpl session, + Class vmClass, Class e, int length, + AbstractMemorySegmentImpl msp, long offset, + S s, + VectorSupport.LoadOperation defaultImpl) { + try { + session.checkValidStateRaw(); + + return VectorSupport.load(vmClass, e, length, + msp.unsafeGetBase(), msp.unsafeGetOffset() + offset, true, + msp, offset, s, + defaultImpl); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public static + , E, S extends VectorSupport.VectorSpecies, + M extends VectorSupport.VectorMask> + V loadFromMemorySegmentMasked(Class vmClass, Class maskClass, Class e, + int length, AbstractMemorySegmentImpl msp, long offset, M m, S s, int offsetInRange, + VectorSupport.LoadVectorMaskedOperation defaultImpl) { + + try { + return loadFromMemorySegmentMaskedScopedInternal( + msp.sessionImpl(), + vmClass, maskClass, e, length, + msp, offset, m, + s, offsetInRange, + defaultImpl); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @Scoped + @ForceInline + private static + , E, S extends VectorSupport.VectorSpecies, + M extends VectorSupport.VectorMask> + V loadFromMemorySegmentMaskedScopedInternal(MemorySessionImpl session, Class vmClass, + Class maskClass, Class e, int length, + AbstractMemorySegmentImpl msp, long offset, M m, + S s, int offsetInRange, + VectorSupport.LoadVectorMaskedOperation defaultImpl) { + try { + session.checkValidStateRaw(); + + return VectorSupport.loadMasked(vmClass, maskClass, e, length, + msp.unsafeGetBase(), msp.unsafeGetOffset() + offset, true, m, offsetInRange, + msp, offset, s, + defaultImpl); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public static + , E> + void storeIntoMemorySegment(Class vmClass, Class e, int length, + V v, + AbstractMemorySegmentImpl msp, long offset, + VectorSupport.StoreVectorOperation defaultImpl) { + + try { + storeIntoMemorySegmentScopedInternal( + msp.sessionImpl(), + vmClass, e, length, + v, + msp, offset, + defaultImpl); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @Scoped + @ForceInline + private static + , E> + void storeIntoMemorySegmentScopedInternal(MemorySessionImpl session, + Class vmClass, Class e, int length, + V v, + AbstractMemorySegmentImpl msp, long offset, + VectorSupport.StoreVectorOperation defaultImpl) { + try { + session.checkValidStateRaw(); + + VectorSupport.store(vmClass, e, length, + msp.unsafeGetBase(), msp.unsafeGetOffset() + offset, true, + v, + msp, offset, + defaultImpl); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public static + , E, M extends VectorSupport.VectorMask> + void storeIntoMemorySegmentMasked(Class vmClass, Class maskClass, Class e, + int length, V v, M m, + AbstractMemorySegmentImpl msp, long offset, + VectorSupport.StoreVectorMaskedOperation defaultImpl) { + + try { + storeIntoMemorySegmentMaskedScopedInternal( + msp.sessionImpl(), + vmClass, maskClass, e, length, + v, m, + msp, offset, + defaultImpl); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @Scoped + @ForceInline + private static + , E, M extends VectorSupport.VectorMask> + void storeIntoMemorySegmentMaskedScopedInternal(MemorySessionImpl session, + Class vmClass, Class maskClass, + Class e, int length, V v, M m, + AbstractMemorySegmentImpl msp, long offset, + VectorSupport.StoreVectorMaskedOperation defaultImpl) { + try { + session.checkValidStateRaw(); + + VectorSupport.storeMasked(vmClass, maskClass, e, length, + msp.unsafeGetBase(), msp.unsafeGetOffset() + offset, true, + v, m, + msp, offset, + defaultImpl); + } finally { + Reference.reachabilityFence(session); + } + } + + // typed-ops here + + // Note: all the accessor methods defined below take advantage of argument type profiling + // (see src/hotspot/share/oops/methodData.cpp) which greatly enhances performance when the same accessor + // method is used repeatedly with different 'base' objects. + @ForceInline + public byte getByte(MemorySessionImpl session, Object base, long offset) { + try { + return getByteInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getByteInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getByte(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putByte(MemorySessionImpl session, Object base, long offset, byte value) { + try { + putByteInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putByteInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putByte(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + + @ForceInline + public byte getByteVolatile(MemorySessionImpl session, Object base, long offset) { + try { + return getByteVolatileInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getByteVolatileInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getByteVolatile(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putByteVolatile(MemorySessionImpl session, Object base, long offset, byte value) { + try { + putByteVolatileInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putByteVolatileInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putByteVolatile(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getByteAcquire(MemorySessionImpl session, Object base, long offset) { + try { + return getByteAcquireInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getByteAcquireInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getByteAcquire(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putByteRelease(MemorySessionImpl session, Object base, long offset, byte value) { + try { + putByteReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putByteReleaseInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putByteRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getByteOpaque(MemorySessionImpl session, Object base, long offset) { + try { + return getByteOpaqueInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getByteOpaqueInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getByteOpaque(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public void putByteOpaque(MemorySessionImpl session, Object base, long offset, byte value) { + try { + putByteOpaqueInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putByteOpaqueInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putByteOpaque(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndAddByte(MemorySessionImpl session, Object base, long offset, byte delta) { + try { + return getAndAddByteInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndAddByteInternal(MemorySessionImpl session, Object base, long offset, byte delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddByte(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndAddByteAcquire(MemorySessionImpl session, Object base, long offset, byte delta) { + try { + return getAndAddByteAcquireInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndAddByteAcquireInternal(MemorySessionImpl session, Object base, long offset, byte delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddByteAcquire(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndAddByteRelease(MemorySessionImpl session, Object base, long offset, byte delta) { + try { + return getAndAddByteReleaseInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndAddByteReleaseInternal(MemorySessionImpl session, Object base, long offset, byte delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddByteRelease(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndBitwiseOrByte(MemorySessionImpl session, Object base, long offset, byte value) { + try { + return getAndBitwiseOrByteInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndBitwiseOrByteInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrByte(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndBitwiseOrByteAcquire(MemorySessionImpl session, Object base, long offset, byte value) { + try { + return getAndBitwiseOrByteAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndBitwiseOrByteAcquireInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrByteAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndBitwiseOrByteRelease(MemorySessionImpl session, Object base, long offset, byte value) { + try { + return getAndBitwiseOrByteReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndBitwiseOrByteReleaseInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrByteRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndBitwiseAndByte(MemorySessionImpl session, Object base, long offset, byte value) { + try { + return getAndBitwiseAndByteInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndBitwiseAndByteInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndByte(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndBitwiseAndByteAcquire(MemorySessionImpl session, Object base, long offset, byte value) { + try { + return getAndBitwiseAndByteAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndBitwiseAndByteAcquireInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndByteAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndBitwiseAndByteRelease(MemorySessionImpl session, Object base, long offset, byte value) { + try { + return getAndBitwiseAndByteReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndBitwiseAndByteReleaseInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndByteRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndBitwiseXorByte(MemorySessionImpl session, Object base, long offset, byte value) { + try { + return getAndBitwiseXorByteInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndBitwiseXorByteInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorByte(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndBitwiseXorByteAcquire(MemorySessionImpl session, Object base, long offset, byte value) { + try { + return getAndBitwiseXorByteAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndBitwiseXorByteAcquireInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorByteAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public byte getAndBitwiseXorByteRelease(MemorySessionImpl session, Object base, long offset, byte value) { + try { + return getAndBitwiseXorByteReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private byte getAndBitwiseXorByteReleaseInternal(MemorySessionImpl session, Object base, long offset, byte value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorByteRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public short getShort(MemorySessionImpl session, Object base, long offset) { + try { + return getShortInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getShortInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getShort(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putShort(MemorySessionImpl session, Object base, long offset, short value) { + try { + putShortInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putShortInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putShort(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getShortUnaligned(MemorySessionImpl session, Object base, long offset, boolean be) { + try { + return getShortUnalignedInternal(session, base, offset, be); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getShortUnalignedInternal(MemorySessionImpl session, Object base, long offset, boolean be) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getShortUnaligned(base, offset, be); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putShortUnaligned(MemorySessionImpl session, Object base, long offset, short value, boolean be) { + try { + putShortUnalignedInternal(session, base, offset, value, be); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putShortUnalignedInternal(MemorySessionImpl session, Object base, long offset, short value, boolean be) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putShortUnaligned(base, offset, value, be); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getShortVolatile(MemorySessionImpl session, Object base, long offset) { + try { + return getShortVolatileInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getShortVolatileInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getShortVolatile(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putShortVolatile(MemorySessionImpl session, Object base, long offset, short value) { + try { + putShortVolatileInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putShortVolatileInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putShortVolatile(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getShortAcquire(MemorySessionImpl session, Object base, long offset) { + try { + return getShortAcquireInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getShortAcquireInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getShortAcquire(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putShortRelease(MemorySessionImpl session, Object base, long offset, short value) { + try { + putShortReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putShortReleaseInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putShortRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getShortOpaque(MemorySessionImpl session, Object base, long offset) { + try { + return getShortOpaqueInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getShortOpaqueInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getShortOpaque(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public void putShortOpaque(MemorySessionImpl session, Object base, long offset, short value) { + try { + putShortOpaqueInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putShortOpaqueInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putShortOpaque(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndAddShort(MemorySessionImpl session, Object base, long offset, short delta) { + try { + return getAndAddShortInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndAddShortInternal(MemorySessionImpl session, Object base, long offset, short delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddShort(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndAddShortAcquire(MemorySessionImpl session, Object base, long offset, short delta) { + try { + return getAndAddShortAcquireInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndAddShortAcquireInternal(MemorySessionImpl session, Object base, long offset, short delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddShortAcquire(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndAddShortRelease(MemorySessionImpl session, Object base, long offset, short delta) { + try { + return getAndAddShortReleaseInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndAddShortReleaseInternal(MemorySessionImpl session, Object base, long offset, short delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddShortRelease(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndBitwiseOrShort(MemorySessionImpl session, Object base, long offset, short value) { + try { + return getAndBitwiseOrShortInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndBitwiseOrShortInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrShort(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndBitwiseOrShortAcquire(MemorySessionImpl session, Object base, long offset, short value) { + try { + return getAndBitwiseOrShortAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndBitwiseOrShortAcquireInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrShortAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndBitwiseOrShortRelease(MemorySessionImpl session, Object base, long offset, short value) { + try { + return getAndBitwiseOrShortReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndBitwiseOrShortReleaseInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrShortRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndBitwiseAndShort(MemorySessionImpl session, Object base, long offset, short value) { + try { + return getAndBitwiseAndShortInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndBitwiseAndShortInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndShort(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndBitwiseAndShortAcquire(MemorySessionImpl session, Object base, long offset, short value) { + try { + return getAndBitwiseAndShortAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndBitwiseAndShortAcquireInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndShortAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndBitwiseAndShortRelease(MemorySessionImpl session, Object base, long offset, short value) { + try { + return getAndBitwiseAndShortReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndBitwiseAndShortReleaseInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndShortRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndBitwiseXorShort(MemorySessionImpl session, Object base, long offset, short value) { + try { + return getAndBitwiseXorShortInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndBitwiseXorShortInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorShort(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndBitwiseXorShortAcquire(MemorySessionImpl session, Object base, long offset, short value) { + try { + return getAndBitwiseXorShortAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndBitwiseXorShortAcquireInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorShortAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public short getAndBitwiseXorShortRelease(MemorySessionImpl session, Object base, long offset, short value) { + try { + return getAndBitwiseXorShortReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private short getAndBitwiseXorShortReleaseInternal(MemorySessionImpl session, Object base, long offset, short value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorShortRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public char getChar(MemorySessionImpl session, Object base, long offset) { + try { + return getCharInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getCharInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getChar(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putChar(MemorySessionImpl session, Object base, long offset, char value) { + try { + putCharInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putCharInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putChar(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getCharUnaligned(MemorySessionImpl session, Object base, long offset, boolean be) { + try { + return getCharUnalignedInternal(session, base, offset, be); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getCharUnalignedInternal(MemorySessionImpl session, Object base, long offset, boolean be) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getCharUnaligned(base, offset, be); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putCharUnaligned(MemorySessionImpl session, Object base, long offset, char value, boolean be) { + try { + putCharUnalignedInternal(session, base, offset, value, be); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putCharUnalignedInternal(MemorySessionImpl session, Object base, long offset, char value, boolean be) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putCharUnaligned(base, offset, value, be); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getCharVolatile(MemorySessionImpl session, Object base, long offset) { + try { + return getCharVolatileInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getCharVolatileInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getCharVolatile(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putCharVolatile(MemorySessionImpl session, Object base, long offset, char value) { + try { + putCharVolatileInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putCharVolatileInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putCharVolatile(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getCharAcquire(MemorySessionImpl session, Object base, long offset) { + try { + return getCharAcquireInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getCharAcquireInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getCharAcquire(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putCharRelease(MemorySessionImpl session, Object base, long offset, char value) { + try { + putCharReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putCharReleaseInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putCharRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getCharOpaque(MemorySessionImpl session, Object base, long offset) { + try { + return getCharOpaqueInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getCharOpaqueInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getCharOpaque(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public void putCharOpaque(MemorySessionImpl session, Object base, long offset, char value) { + try { + putCharOpaqueInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putCharOpaqueInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putCharOpaque(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndAddChar(MemorySessionImpl session, Object base, long offset, char delta) { + try { + return getAndAddCharInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndAddCharInternal(MemorySessionImpl session, Object base, long offset, char delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddChar(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndAddCharAcquire(MemorySessionImpl session, Object base, long offset, char delta) { + try { + return getAndAddCharAcquireInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndAddCharAcquireInternal(MemorySessionImpl session, Object base, long offset, char delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddCharAcquire(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndAddCharRelease(MemorySessionImpl session, Object base, long offset, char delta) { + try { + return getAndAddCharReleaseInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndAddCharReleaseInternal(MemorySessionImpl session, Object base, long offset, char delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddCharRelease(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndBitwiseOrChar(MemorySessionImpl session, Object base, long offset, char value) { + try { + return getAndBitwiseOrCharInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndBitwiseOrCharInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrChar(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndBitwiseOrCharAcquire(MemorySessionImpl session, Object base, long offset, char value) { + try { + return getAndBitwiseOrCharAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndBitwiseOrCharAcquireInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrCharAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndBitwiseOrCharRelease(MemorySessionImpl session, Object base, long offset, char value) { + try { + return getAndBitwiseOrCharReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndBitwiseOrCharReleaseInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrCharRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndBitwiseAndChar(MemorySessionImpl session, Object base, long offset, char value) { + try { + return getAndBitwiseAndCharInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndBitwiseAndCharInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndChar(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndBitwiseAndCharAcquire(MemorySessionImpl session, Object base, long offset, char value) { + try { + return getAndBitwiseAndCharAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndBitwiseAndCharAcquireInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndCharAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndBitwiseAndCharRelease(MemorySessionImpl session, Object base, long offset, char value) { + try { + return getAndBitwiseAndCharReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndBitwiseAndCharReleaseInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndCharRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndBitwiseXorChar(MemorySessionImpl session, Object base, long offset, char value) { + try { + return getAndBitwiseXorCharInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndBitwiseXorCharInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorChar(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndBitwiseXorCharAcquire(MemorySessionImpl session, Object base, long offset, char value) { + try { + return getAndBitwiseXorCharAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndBitwiseXorCharAcquireInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorCharAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public char getAndBitwiseXorCharRelease(MemorySessionImpl session, Object base, long offset, char value) { + try { + return getAndBitwiseXorCharReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private char getAndBitwiseXorCharReleaseInternal(MemorySessionImpl session, Object base, long offset, char value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorCharRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public int getInt(MemorySessionImpl session, Object base, long offset) { + try { + return getIntInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getIntInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getInt(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putInt(MemorySessionImpl session, Object base, long offset, int value) { + try { + putIntInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putIntInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putInt(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getIntUnaligned(MemorySessionImpl session, Object base, long offset, boolean be) { + try { + return getIntUnalignedInternal(session, base, offset, be); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getIntUnalignedInternal(MemorySessionImpl session, Object base, long offset, boolean be) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getIntUnaligned(base, offset, be); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putIntUnaligned(MemorySessionImpl session, Object base, long offset, int value, boolean be) { + try { + putIntUnalignedInternal(session, base, offset, value, be); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putIntUnalignedInternal(MemorySessionImpl session, Object base, long offset, int value, boolean be) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putIntUnaligned(base, offset, value, be); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getIntVolatile(MemorySessionImpl session, Object base, long offset) { + try { + return getIntVolatileInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getIntVolatileInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getIntVolatile(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putIntVolatile(MemorySessionImpl session, Object base, long offset, int value) { + try { + putIntVolatileInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putIntVolatileInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putIntVolatile(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getIntAcquire(MemorySessionImpl session, Object base, long offset) { + try { + return getIntAcquireInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getIntAcquireInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getIntAcquire(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putIntRelease(MemorySessionImpl session, Object base, long offset, int value) { + try { + putIntReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putIntReleaseInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putIntRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getIntOpaque(MemorySessionImpl session, Object base, long offset) { + try { + return getIntOpaqueInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getIntOpaqueInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getIntOpaque(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public void putIntOpaque(MemorySessionImpl session, Object base, long offset, int value) { + try { + putIntOpaqueInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putIntOpaqueInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putIntOpaque(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public boolean compareAndSetInt(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + return compareAndSetIntInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean compareAndSetIntInternal(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndSetInt(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int compareAndExchangeInt(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + return compareAndExchangeIntInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int compareAndExchangeIntInternal(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeInt(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int compareAndExchangeIntAcquire(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + return compareAndExchangeIntAcquireInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int compareAndExchangeIntAcquireInternal(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeIntAcquire(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int compareAndExchangeIntRelease(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + return compareAndExchangeIntReleaseInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int compareAndExchangeIntReleaseInternal(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeIntRelease(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetIntPlain(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + return weakCompareAndSetIntPlainInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetIntPlainInternal(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetIntPlain(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetInt(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + return weakCompareAndSetIntInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetIntInternal(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetInt(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetIntAcquire(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + return weakCompareAndSetIntAcquireInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetIntAcquireInternal(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetIntAcquire(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetIntRelease(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + return weakCompareAndSetIntReleaseInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetIntReleaseInternal(MemorySessionImpl session, Object base, long offset, int expected, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetIntRelease(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndSetInt(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndSetIntInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndSetIntInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetInt(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndSetIntAcquire(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndSetIntAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndSetIntAcquireInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetIntAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndSetIntRelease(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndSetIntReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndSetIntReleaseInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetIntRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndAddInt(MemorySessionImpl session, Object base, long offset, int delta) { + try { + return getAndAddIntInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndAddIntInternal(MemorySessionImpl session, Object base, long offset, int delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddInt(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndAddIntAcquire(MemorySessionImpl session, Object base, long offset, int delta) { + try { + return getAndAddIntAcquireInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndAddIntAcquireInternal(MemorySessionImpl session, Object base, long offset, int delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddIntAcquire(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndAddIntRelease(MemorySessionImpl session, Object base, long offset, int delta) { + try { + return getAndAddIntReleaseInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndAddIntReleaseInternal(MemorySessionImpl session, Object base, long offset, int delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddIntRelease(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndBitwiseOrInt(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndBitwiseOrIntInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndBitwiseOrIntInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrInt(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndBitwiseOrIntAcquire(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndBitwiseOrIntAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndBitwiseOrIntAcquireInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrIntAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndBitwiseOrIntRelease(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndBitwiseOrIntReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndBitwiseOrIntReleaseInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrIntRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndBitwiseAndInt(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndBitwiseAndIntInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndBitwiseAndIntInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndInt(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndBitwiseAndIntAcquire(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndBitwiseAndIntAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndBitwiseAndIntAcquireInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndIntAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndBitwiseAndIntRelease(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndBitwiseAndIntReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndBitwiseAndIntReleaseInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndIntRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndBitwiseXorInt(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndBitwiseXorIntInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndBitwiseXorIntInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorInt(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndBitwiseXorIntAcquire(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndBitwiseXorIntAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndBitwiseXorIntAcquireInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorIntAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public int getAndBitwiseXorIntRelease(MemorySessionImpl session, Object base, long offset, int value) { + try { + return getAndBitwiseXorIntReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private int getAndBitwiseXorIntReleaseInternal(MemorySessionImpl session, Object base, long offset, int value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorIntRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public long getLong(MemorySessionImpl session, Object base, long offset) { + try { + return getLongInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getLongInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getLong(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putLong(MemorySessionImpl session, Object base, long offset, long value) { + try { + putLongInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putLongInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putLong(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getLongUnaligned(MemorySessionImpl session, Object base, long offset, boolean be) { + try { + return getLongUnalignedInternal(session, base, offset, be); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getLongUnalignedInternal(MemorySessionImpl session, Object base, long offset, boolean be) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getLongUnaligned(base, offset, be); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putLongUnaligned(MemorySessionImpl session, Object base, long offset, long value, boolean be) { + try { + putLongUnalignedInternal(session, base, offset, value, be); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putLongUnalignedInternal(MemorySessionImpl session, Object base, long offset, long value, boolean be) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putLongUnaligned(base, offset, value, be); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getLongVolatile(MemorySessionImpl session, Object base, long offset) { + try { + return getLongVolatileInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getLongVolatileInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getLongVolatile(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putLongVolatile(MemorySessionImpl session, Object base, long offset, long value) { + try { + putLongVolatileInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putLongVolatileInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putLongVolatile(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getLongAcquire(MemorySessionImpl session, Object base, long offset) { + try { + return getLongAcquireInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getLongAcquireInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getLongAcquire(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putLongRelease(MemorySessionImpl session, Object base, long offset, long value) { + try { + putLongReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putLongReleaseInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putLongRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getLongOpaque(MemorySessionImpl session, Object base, long offset) { + try { + return getLongOpaqueInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getLongOpaqueInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getLongOpaque(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public void putLongOpaque(MemorySessionImpl session, Object base, long offset, long value) { + try { + putLongOpaqueInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putLongOpaqueInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putLongOpaque(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public boolean compareAndSetLong(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + return compareAndSetLongInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean compareAndSetLongInternal(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndSetLong(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long compareAndExchangeLong(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + return compareAndExchangeLongInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long compareAndExchangeLongInternal(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeLong(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long compareAndExchangeLongAcquire(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + return compareAndExchangeLongAcquireInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long compareAndExchangeLongAcquireInternal(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeLongAcquire(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long compareAndExchangeLongRelease(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + return compareAndExchangeLongReleaseInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long compareAndExchangeLongReleaseInternal(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeLongRelease(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetLongPlain(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + return weakCompareAndSetLongPlainInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetLongPlainInternal(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetLongPlain(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetLong(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + return weakCompareAndSetLongInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetLongInternal(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetLong(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetLongAcquire(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + return weakCompareAndSetLongAcquireInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetLongAcquireInternal(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetLongAcquire(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetLongRelease(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + return weakCompareAndSetLongReleaseInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetLongReleaseInternal(MemorySessionImpl session, Object base, long offset, long expected, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetLongRelease(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndSetLong(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndSetLongInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndSetLongInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetLong(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndSetLongAcquire(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndSetLongAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndSetLongAcquireInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetLongAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndSetLongRelease(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndSetLongReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndSetLongReleaseInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetLongRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndAddLong(MemorySessionImpl session, Object base, long offset, long delta) { + try { + return getAndAddLongInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndAddLongInternal(MemorySessionImpl session, Object base, long offset, long delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddLong(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndAddLongAcquire(MemorySessionImpl session, Object base, long offset, long delta) { + try { + return getAndAddLongAcquireInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndAddLongAcquireInternal(MemorySessionImpl session, Object base, long offset, long delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddLongAcquire(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndAddLongRelease(MemorySessionImpl session, Object base, long offset, long delta) { + try { + return getAndAddLongReleaseInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndAddLongReleaseInternal(MemorySessionImpl session, Object base, long offset, long delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddLongRelease(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndBitwiseOrLong(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndBitwiseOrLongInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndBitwiseOrLongInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrLong(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndBitwiseOrLongAcquire(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndBitwiseOrLongAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndBitwiseOrLongAcquireInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrLongAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndBitwiseOrLongRelease(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndBitwiseOrLongReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndBitwiseOrLongReleaseInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseOrLongRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndBitwiseAndLong(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndBitwiseAndLongInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndBitwiseAndLongInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndLong(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndBitwiseAndLongAcquire(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndBitwiseAndLongAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndBitwiseAndLongAcquireInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndLongAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndBitwiseAndLongRelease(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndBitwiseAndLongReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndBitwiseAndLongReleaseInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseAndLongRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndBitwiseXorLong(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndBitwiseXorLongInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndBitwiseXorLongInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorLong(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndBitwiseXorLongAcquire(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndBitwiseXorLongAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndBitwiseXorLongAcquireInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorLongAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public long getAndBitwiseXorLongRelease(MemorySessionImpl session, Object base, long offset, long value) { + try { + return getAndBitwiseXorLongReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private long getAndBitwiseXorLongReleaseInternal(MemorySessionImpl session, Object base, long offset, long value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndBitwiseXorLongRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public float getFloat(MemorySessionImpl session, Object base, long offset) { + try { + return getFloatInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getFloatInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getFloat(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putFloat(MemorySessionImpl session, Object base, long offset, float value) { + try { + putFloatInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putFloatInternal(MemorySessionImpl session, Object base, long offset, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putFloat(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + + @ForceInline + public float getFloatVolatile(MemorySessionImpl session, Object base, long offset) { + try { + return getFloatVolatileInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getFloatVolatileInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getFloatVolatile(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putFloatVolatile(MemorySessionImpl session, Object base, long offset, float value) { + try { + putFloatVolatileInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putFloatVolatileInternal(MemorySessionImpl session, Object base, long offset, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putFloatVolatile(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float getFloatAcquire(MemorySessionImpl session, Object base, long offset) { + try { + return getFloatAcquireInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getFloatAcquireInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getFloatAcquire(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putFloatRelease(MemorySessionImpl session, Object base, long offset, float value) { + try { + putFloatReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putFloatReleaseInternal(MemorySessionImpl session, Object base, long offset, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putFloatRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float getFloatOpaque(MemorySessionImpl session, Object base, long offset) { + try { + return getFloatOpaqueInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getFloatOpaqueInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getFloatOpaque(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public void putFloatOpaque(MemorySessionImpl session, Object base, long offset, float value) { + try { + putFloatOpaqueInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putFloatOpaqueInternal(MemorySessionImpl session, Object base, long offset, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putFloatOpaque(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public boolean compareAndSetFloat(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + return compareAndSetFloatInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean compareAndSetFloatInternal(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndSetFloat(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float compareAndExchangeFloat(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + return compareAndExchangeFloatInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float compareAndExchangeFloatInternal(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeFloat(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float compareAndExchangeFloatAcquire(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + return compareAndExchangeFloatAcquireInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float compareAndExchangeFloatAcquireInternal(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeFloatAcquire(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float compareAndExchangeFloatRelease(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + return compareAndExchangeFloatReleaseInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float compareAndExchangeFloatReleaseInternal(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeFloatRelease(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetFloatPlain(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + return weakCompareAndSetFloatPlainInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetFloatPlainInternal(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetFloatPlain(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetFloat(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + return weakCompareAndSetFloatInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetFloatInternal(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetFloat(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetFloatAcquire(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + return weakCompareAndSetFloatAcquireInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetFloatAcquireInternal(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetFloatAcquire(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetFloatRelease(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + return weakCompareAndSetFloatReleaseInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetFloatReleaseInternal(MemorySessionImpl session, Object base, long offset, float expected, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetFloatRelease(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float getAndSetFloat(MemorySessionImpl session, Object base, long offset, float value) { + try { + return getAndSetFloatInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getAndSetFloatInternal(MemorySessionImpl session, Object base, long offset, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetFloat(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float getAndSetFloatAcquire(MemorySessionImpl session, Object base, long offset, float value) { + try { + return getAndSetFloatAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getAndSetFloatAcquireInternal(MemorySessionImpl session, Object base, long offset, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetFloatAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float getAndSetFloatRelease(MemorySessionImpl session, Object base, long offset, float value) { + try { + return getAndSetFloatReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getAndSetFloatReleaseInternal(MemorySessionImpl session, Object base, long offset, float value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetFloatRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float getAndAddFloat(MemorySessionImpl session, Object base, long offset, float delta) { + try { + return getAndAddFloatInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getAndAddFloatInternal(MemorySessionImpl session, Object base, long offset, float delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddFloat(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float getAndAddFloatAcquire(MemorySessionImpl session, Object base, long offset, float delta) { + try { + return getAndAddFloatAcquireInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getAndAddFloatAcquireInternal(MemorySessionImpl session, Object base, long offset, float delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddFloatAcquire(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public float getAndAddFloatRelease(MemorySessionImpl session, Object base, long offset, float delta) { + try { + return getAndAddFloatReleaseInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private float getAndAddFloatReleaseInternal(MemorySessionImpl session, Object base, long offset, float delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddFloatRelease(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double getDouble(MemorySessionImpl session, Object base, long offset) { + try { + return getDoubleInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getDoubleInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getDouble(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putDouble(MemorySessionImpl session, Object base, long offset, double value) { + try { + putDoubleInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putDoubleInternal(MemorySessionImpl session, Object base, long offset, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putDouble(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + + @ForceInline + public double getDoubleVolatile(MemorySessionImpl session, Object base, long offset) { + try { + return getDoubleVolatileInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getDoubleVolatileInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getDoubleVolatile(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putDoubleVolatile(MemorySessionImpl session, Object base, long offset, double value) { + try { + putDoubleVolatileInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putDoubleVolatileInternal(MemorySessionImpl session, Object base, long offset, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putDoubleVolatile(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double getDoubleAcquire(MemorySessionImpl session, Object base, long offset) { + try { + return getDoubleAcquireInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getDoubleAcquireInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getDoubleAcquire(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public void putDoubleRelease(MemorySessionImpl session, Object base, long offset, double value) { + try { + putDoubleReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putDoubleReleaseInternal(MemorySessionImpl session, Object base, long offset, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putDoubleRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double getDoubleOpaque(MemorySessionImpl session, Object base, long offset) { + try { + return getDoubleOpaqueInternal(session, base, offset); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getDoubleOpaqueInternal(MemorySessionImpl session, Object base, long offset) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getDoubleOpaque(base, offset); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public void putDoubleOpaque(MemorySessionImpl session, Object base, long offset, double value) { + try { + putDoubleOpaqueInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private void putDoubleOpaqueInternal(MemorySessionImpl session, Object base, long offset, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + UNSAFE.putDoubleOpaque(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + @ForceInline + public boolean compareAndSetDouble(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + return compareAndSetDoubleInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean compareAndSetDoubleInternal(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndSetDouble(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double compareAndExchangeDouble(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + return compareAndExchangeDoubleInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double compareAndExchangeDoubleInternal(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeDouble(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double compareAndExchangeDoubleAcquire(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + return compareAndExchangeDoubleAcquireInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double compareAndExchangeDoubleAcquireInternal(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeDoubleAcquire(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double compareAndExchangeDoubleRelease(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + return compareAndExchangeDoubleReleaseInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double compareAndExchangeDoubleReleaseInternal(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.compareAndExchangeDoubleRelease(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetDoublePlain(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + return weakCompareAndSetDoublePlainInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetDoublePlainInternal(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetDoublePlain(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetDouble(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + return weakCompareAndSetDoubleInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetDoubleInternal(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetDouble(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetDoubleAcquire(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + return weakCompareAndSetDoubleAcquireInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetDoubleAcquireInternal(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetDoubleAcquire(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public boolean weakCompareAndSetDoubleRelease(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + return weakCompareAndSetDoubleReleaseInternal(session, base, offset, expected, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private boolean weakCompareAndSetDoubleReleaseInternal(MemorySessionImpl session, Object base, long offset, double expected, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.weakCompareAndSetDoubleRelease(base, offset, expected, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double getAndSetDouble(MemorySessionImpl session, Object base, long offset, double value) { + try { + return getAndSetDoubleInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getAndSetDoubleInternal(MemorySessionImpl session, Object base, long offset, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetDouble(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double getAndSetDoubleAcquire(MemorySessionImpl session, Object base, long offset, double value) { + try { + return getAndSetDoubleAcquireInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getAndSetDoubleAcquireInternal(MemorySessionImpl session, Object base, long offset, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetDoubleAcquire(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double getAndSetDoubleRelease(MemorySessionImpl session, Object base, long offset, double value) { + try { + return getAndSetDoubleReleaseInternal(session, base, offset, value); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getAndSetDoubleReleaseInternal(MemorySessionImpl session, Object base, long offset, double value) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndSetDoubleRelease(base, offset, value); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double getAndAddDouble(MemorySessionImpl session, Object base, long offset, double delta) { + try { + return getAndAddDoubleInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getAndAddDoubleInternal(MemorySessionImpl session, Object base, long offset, double delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddDouble(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double getAndAddDoubleAcquire(MemorySessionImpl session, Object base, long offset, double delta) { + try { + return getAndAddDoubleAcquireInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getAndAddDoubleAcquireInternal(MemorySessionImpl session, Object base, long offset, double delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddDoubleAcquire(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + + @ForceInline + public double getAndAddDoubleRelease(MemorySessionImpl session, Object base, long offset, double delta) { + try { + return getAndAddDoubleReleaseInternal(session, base, offset, delta); + } catch (ScopedAccessError ex) { + throw ex.newRuntimeException(); + } + } + + @ForceInline @Scoped + private double getAndAddDoubleReleaseInternal(MemorySessionImpl session, Object base, long offset, double delta) { + try { + if (session != null) { + session.checkValidStateRaw(); + } + return UNSAFE.getAndAddDoubleRelease(base, offset, delta); + } finally { + Reference.reachabilityFence(session); + } + } + +} diff --git a/tests/test_data/std/jdk/internal/misc/Signal$1.class b/tests/test_data/std/jdk/internal/misc/Signal$1.class new file mode 100644 index 0000000000000000000000000000000000000000..d9d6964fb8bd64cbfaea07459042c55290aa3185 GIT binary patch literal 849 zcmaiyO>fgc5Qg7%Oxz@HV$4@5ErenqaVxAIQ7Sk@pjHY+qE+r2dzEZ(*T^6JUr4R0 za^MH_+!Op4#Hh>97vUmRPi`C zky#iV$tkV9U53^v>5Qu=7AeElsM2?T;WNDVao(S6|BK9E4wHyLosm@HusE5B^mu`GM@h)zF;AubUmDGPCNqYO zN~X6vU}%&@%8Qi1wX{$S&7-79L-Ahfq+5#`zS0+>li#T@PBN*cA4EP&A`8zM)~epl z#!K`VRw9{w;dwZt3-k{9W3n8IEZSe@3)3SeLkM;D*+uec%UH@$)ZYdr36$v}A7K8L0^mFVHV79(+=lqIJCf KT-x2PH+}=mWxwBp!U1%`>R%uaMJtlbzRDD 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 + *

  • + * Java code cannot register a handler for signals that are already used + * by the Java VM implementation. The Signal.handle + * function raises an IllegalArgumentException if such an attempt + * is made. + *
  • + * When Signal.handle is called, the VM internally registers a + * special C signal handler. There is no way to force the Java signal handler + * to run synchronously before the C signal handler returns. Instead, when the + * VM receives a signal, the special C signal handler creates a new thread + * (at priority Thread.MAX_PRIORITY) to + * run the registered Java signal handler. The C signal handler immediately + * returns. Note that because the Java signal handler runs in a newly created + * thread, it may not actually be executed until some time after the C signal + * handler returns. + * + *

    + * Signal objects are created based on their names. For example: + *

    + * new Signal("INT");
    + * 
    + * constructs a signal object corresponding to SIGINT, which is + * typically produced when the user presses Ctrl-C at the command line. + * The Signal constructor throws IllegalArgumentException + * when it is passed an unknown signal. + *

    + * This is an example of how Java code handles SIGINT: + *

    + * Signal.Handler handler = new Signal.Handler () {
    + *     public void handle(Signal sig) {
    + *       ... // handle SIGINT
    + *     }
    + * };
    + * Signal.handle(new Signal("INT"), handler);
    + * 
    + * + * @since 9 + */ +public final class Signal { + private static final Hashtable handlers = new Hashtable<>(4); + private static final Hashtable signals = new Hashtable<>(4); + + private int number; + private String name; + + /* Returns the signal number */ + public int getNumber() { + return number; + } + + /** + * Returns the signal name. + * + * @return the name of the signal. + * @see jdk.internal.misc.Signal#Signal(String name) + */ + public String getName() { + return name; + } + + /** + * Compares the equality of two Signal objects. + * + * @param obj the object to compare with. + * @return whether two Signal objects are equal. + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Signal other) { + return name.equals(other.name) && (number == other.number); + } + return false; + } + + /** + * Returns a hashcode for this Signal. + * + * @return a hash code value for this object. + */ + public int hashCode() { + return number; + } + + /** + * Returns a string representation of this signal. For example, "SIGINT" + * for an object constructed using new Signal ("INT"). + * + * @return a string representation of the signal + */ + public String toString() { + return "SIG" + name; + } + + /** + * Constructs a signal from its name. + * + * @param name the name of the signal. + * @exception IllegalArgumentException unknown signal + * @see jdk.internal.misc.Signal#getName() + */ + public Signal(String name) { + Objects.requireNonNull(name, "name"); + // Signal names are the short names; + // the "SIG" prefix is not used for compatibility with previous JDKs + if (name.startsWith("SIG")) { + throw new IllegalArgumentException("Unknown signal: " + name); + } + this.name = name; + number = findSignal0(name); + if (number < 0) { + throw new IllegalArgumentException("Unknown signal: " + name); + } + } + + /** + * Registers a signal handler. + * + * @param sig a signal + * @param handler the handler to be registered with the given signal. + * @return the old handler + * @exception IllegalArgumentException the signal is in use by the VM + * @see jdk.internal.misc.Signal#raise(Signal sig) + * @see jdk.internal.misc.Signal.Handler + * @see jdk.internal.misc.Signal.Handler#SIG_DFL + * @see jdk.internal.misc.Signal.Handler#SIG_IGN + */ + public static synchronized Signal.Handler handle(Signal sig, + Signal.Handler handler) + throws IllegalArgumentException { + Objects.requireNonNull(sig, "sig"); + Objects.requireNonNull(handler, "handler"); + long newH = (handler instanceof NativeHandler) ? + ((NativeHandler)handler).getHandler() : 2; + long oldH = handle0(sig.number, newH); + if (oldH == -1) { + throw new IllegalArgumentException + ("Signal already used by VM or OS: " + sig); + } + signals.put(sig.number, sig); + Signal.Handler oldHandler; + if (newH == 2) { + oldHandler = handlers.put(sig, handler); + } else { + oldHandler = handlers.remove(sig); + } + if (oldH == 0) { + return Signal.Handler.SIG_DFL; + } else if (oldH == 1) { + return Signal.Handler.SIG_IGN; + } else if (oldH == 2) { + return oldHandler; + } else { + return new NativeHandler(oldH); + } + } + + /** + * Raises a signal in the current process. + * + * @param sig a signal + * @see jdk.internal.misc.Signal#handle(Signal sig, Signal.Handler handler) + */ + public static void raise(Signal sig) throws IllegalArgumentException { + Objects.requireNonNull(sig, "sig"); + if (handlers.get(sig) == null) { + throw new IllegalArgumentException("Unhandled signal: " + sig); + } + raise0(sig.number); + } + + /* Called by the VM to execute Java signal handlers. */ + private static void dispatch(final int number) { + final Signal sig = signals.get(number); + final Signal.Handler handler = handlers.get(sig); + + Runnable runnable = new Runnable () { + public void run() { + // Don't bother to reset the priority. Signal handler will + // run at maximum priority inherited from the VM signal + // dispatch thread. + // Thread.currentThread().setPriority(Thread.NORM_PRIORITY); + handler.handle(sig); + } + }; + if (handler != null) { + new Thread(null, runnable, sig + " handler", 0, false).start(); + } + } + + /* Find the signal number, given a name. Returns -1 for unknown signals. */ + private static native int findSignal0(String sigName); + /* Registers a native signal handler, and returns the old handler. + * Handler values: + * 0 default handler + * 1 ignore the signal + * 2 call back to Signal.dispatch + * other arbitrary native signal handlers + */ + private static native long handle0(int sig, long nativeH); + /* Raise a given signal number */ + private static native void raise0(int sig); + + /** + * This is the signal handler interface expected in Signal.handle. + */ + public interface Handler { + + /** + * The default signal handler + */ + public static final Signal.Handler SIG_DFL = new NativeHandler(0); + /** + * Ignore the signal + */ + public static final Signal.Handler SIG_IGN = new NativeHandler(1); + + /** + * Handle the given signal + * + * @param sig a signal object + */ + public void handle(Signal sig); + } + + + /* + * A package-private class implementing a signal handler in native code. + */ + static final class NativeHandler implements Signal.Handler { + + private final long handler; + + long getHandler() { + return handler; + } + + NativeHandler(long handler) { + this.handler = handler; + } + + public void handle(Signal sig) { + throw new UnsupportedOperationException("invoking native signal handle not supported"); + } + + public String toString() { + return this == SIG_DFL ? "SIG_DFL" : + (this == SIG_IGN ? "SIG_IGN" : super.toString()); + } + } + +} diff --git a/tests/test_data/std/jdk/internal/misc/TerminatingThreadLocal$1.class b/tests/test_data/std/jdk/internal/misc/TerminatingThreadLocal$1.class new file mode 100644 index 0000000000000000000000000000000000000000..9c2d725351751ac220b551db58eacc8bdceb0cd0 GIT binary patch literal 1029 zcmb7@-EPw`6vzK=yJZU*8~XspfE6f^R)~ljZd&!GFjlD>7o93`={8pD;yTE2K)e;) zFa#10z(XO9yFmjhQi&8FpOfR?`EtJh`0@=v3!#q!iXKVF9{R@!`RD z_)83>uwCu>Si@xx>j5@!g<)rQvXv+$2396IWmwbVU02uxlT3)hP!2mYPqNgjIh`Eq zKDMy!VJE;Sv(nvvD%eGN;5NreesV}8Ve&EwPw9Z)a_p+ z#q}_H*&kD@$vl|@x;S$R_j|yze*A9|E)Bn%WM&`^q-)yV{E<9%!Klg4^*|*ljq6C* zQ4)K&&k!!!N`{qVk=nx~wKU+i*21(DPg9YiOjo5qKLAjqmu^02=Cq4QGH0osf__% svG$4ZXCj}l`8Q-}krCw>(FPyhe` literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/TerminatingThreadLocal.class b/tests/test_data/std/jdk/internal/misc/TerminatingThreadLocal.class new file mode 100644 index 0000000000000000000000000000000000000000..ad0ae75d2fb7e5d3853ebe28fa50666ddcc5cbf9 GIT binary patch literal 2247 zcmb7F?QR=I6g{(X;;(JfgfsXPVP*pg0*Bd+86d76CnYnl7o_o%nx&HI{?@s`fv7Ld2kt7m2 zMlq%^x7T=BuwCEsT+=DE>`uKCsb-aRC6;fNPch{=5tp^J8 zr=Z0JDT<1hbi9VwDM3>tn9Akj8YJ-sJ%Kb`-*yV+w&PG6yX|H%gIOI{Fh_WsOijN{ zw$o9RVEbCnUd&=1Zzhq`k%yr$*^d})QAqBZoek?drotM1B`4m}u_y^9T$)9Of{yE= z%*3~TP~1pHt0CS?@_9$cyHeM4CwEA~@9X#gHwa)h8ZRh1foE`2DsUr-l7ca8@#dB? zC}Kn*UA3FM5?#+yXbn}3QYichg=rn~-js~xqWq{-x!oY_c*SH8w@XCcrkpahWR( zAG5P5>5lxa&~l5T;y7v?LjBCi2u%pwz*XGlTn{&}zkb5i>M_e5u6U~HC zqtHl`#sp!fPQn(DV0%bmX@F8XMoBCJmXJQtqqNDjP>QKj8epJ~7^oNn@r4Y;H^?AO zn25m-%wJ%PUvS|77oTG0F)l0IGalor!jG8ZWI^F6^vc2kuKo1SUqUevRBMtWh%w9f z^VBa-l-smO extends CarrierThreadLocal { + + @Override + public void set(T value) { + super.set(value); + register(this); + } + + @Override + public void remove() { + super.remove(); + unregister(this); + } + + /** + * Invoked by a thread when terminating and this thread-local has an associated + * value for the terminating thread (even if that value is null), so that any + * native resources maintained by the value can be released. + * + * @param value current thread's value of this thread-local variable + * (may be null but only if null value was explicitly initialized) + */ + protected void threadTerminated(T value) { + } + + // following methods and field are implementation details and should only be + // called from the corresponding code int Thread/ThreadLocal class. + + /** + * Invokes the TerminatingThreadLocal's {@link #threadTerminated()} method + * on all instances registered in current thread. + */ + public static void threadTerminated() { + for (TerminatingThreadLocal ttl : REGISTRY.get()) { + ttl._threadTerminated(); + } + } + + private void _threadTerminated() { threadTerminated(get()); } + + /** + * Register given TerminatingThreadLocal + * + * @param tl the ThreadLocal to register + */ + public static void register(TerminatingThreadLocal tl) { + REGISTRY.get().add(tl); + } + + /** + * Unregister given TerminatingThreadLocal + * + * @param tl the ThreadLocal to unregister + */ + private static void unregister(TerminatingThreadLocal tl) { + REGISTRY.get().remove(tl); + } + + /** + * a per-carrier-thread registry of TerminatingThreadLocal(s) that have been registered + * but later not unregistered in a particular carrier-thread. + */ + public static final CarrierThreadLocal>> REGISTRY = + new CarrierThreadLocal<>() { + @Override + protected Collection> initialValue() { + return Collections.newSetFromMap(new IdentityHashMap<>(4)); + } + }; +} diff --git a/tests/test_data/std/jdk/internal/misc/ThreadFlock$ThreadContainerImpl.class b/tests/test_data/std/jdk/internal/misc/ThreadFlock$ThreadContainerImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..7995451d93ba2f735bf377f533bcff17108e5b7b GIT binary patch literal 3924 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 k(tn=x@@_uUbqlTQXL;JnRNcnx;O0;U7~(Qql ThreadFlock defines the {@link #open(String) open} method to open a new flock, + * the {@link #start(Thread) start} method to start a thread in the flock, and the + * {@link #close() close} method to close the flock. The {@code close} waits for all + * threads in the flock to finish. The {@link #awaitAll() awaitAll} method may be used + * to wait for all threads to finish without closing the flock. The {@link #wakeup()} + * method will cause {@code awaitAll} method to complete early, which can be used to + * support cancellation in higher-level APIs. ThreadFlock also defines the {@link + * #shutdown() shutdown} method to prevent new threads from starting while allowing + * existing threads in the flock to continue. + * + *

    Thread flocks are intended to be used in a structured manner. The + * thread that opens a new flock is the {@link #owner() owner}. The owner closes the + * flock when done, failure to do so may result in a resource leak. The {@code open} + * and {@code close} should be matched to avoid closing an enclosing flock + * while a nested flock is open. A ThreadFlock can be used with the + * try-with-resources construct if required but more likely, the close method of a + * higher-level API that implements {@link AutoCloseable} will close the flock. + * + *

    Thread flocks are conceptually nodes in a tree. A thread {@code T} started in + * flock "A" may itself open a new flock "B", implicitly forming a tree where flock + * "A" is the parent of flock "B". When nested, say where thread {@code T} opens + * flock "B" and then invokes a method that opens flock "C", then the enclosing + * flock "B" is conceptually the parent of the nested flock "C". ThreadFlock does + * not define APIs that exposes the tree structure. It does define the {@link + * #containsThread(Thread) containsThread} method to test if a flock contains a + * thread, a test that is equivalent to testing membership of flocks in the tree. + * The {@code start} and {@code shutdown} methods are confined to the flock + * owner or threads contained in the flock. The confinement check is equivalent to + * invoking the {@code containsThread} method to test if the caller is contained + * in the flock. + * + *

    Unless otherwise specified, passing a {@code null} argument to a method + * in this class will cause a {@link NullPointerException} to be thrown. + */ +public class ThreadFlock implements AutoCloseable { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private static final VarHandle THREAD_COUNT; + private static final VarHandle PERMIT; + static { + try { + MethodHandles.Lookup l = MethodHandles.lookup(); + THREAD_COUNT = l.findVarHandle(ThreadFlock.class, "threadCount", int.class); + PERMIT = l.findVarHandle(ThreadFlock.class, "permit", boolean.class); + } catch (Exception e) { + throw new InternalError(e); + } + } + + private final Set threads = ConcurrentHashMap.newKeySet(); + + // thread count, need to re-examine contention once API is stable + private volatile int threadCount; + + private final String name; + private final ScopedValueContainer.BindingsSnapshot scopedValueBindings; + private final ThreadContainerImpl container; // encapsulate for now + + // state + private volatile boolean shutdown; + private volatile boolean closed; + + // set by wakeup, cleared by awaitAll + private volatile boolean permit; + + ThreadFlock(String name) { + this.name = name; + this.scopedValueBindings = ScopedValueContainer.captureBindings(); + this.container = new ThreadContainerImpl(this); + } + + private long threadCount() { + return threadCount; + } + + private ScopedValueContainer.BindingsSnapshot scopedValueBindings() { + return scopedValueBindings; + } + + private void incrementThreadCount() { + THREAD_COUNT.getAndAdd(this, 1); + } + + /** + * Decrement the thread count. Unpark the owner if the count goes to zero. + */ + private void decrementThreadCount() { + int count = (int) THREAD_COUNT.getAndAdd(this, -1) - 1; + + // signal owner when the count goes to zero + if (count == 0) { + LockSupport.unpark(owner()); + } + } + + /** + * Invoked on the parent thread when starting {@code thread}. + */ + private void onStart(Thread thread) { + incrementThreadCount(); + boolean done = false; + try { + boolean added = threads.add(thread); + assert added; + if (shutdown) + throw new IllegalStateException("Shutdown"); + done = true; + } finally { + if (!done) { + threads.remove(thread); + decrementThreadCount(); + } + } + } + + /** + * Invoked on the terminating thread or the parent thread when starting + * {@code thread} failed. This method is only called if onStart succeeded. + */ + private void onExit(Thread thread) { + boolean removed = threads.remove(thread); + assert removed; + decrementThreadCount(); + } + + /** + * Clear wakeup permit. + */ + private void clearPermit() { + if (permit) + permit = false; + } + + /** + * Sets the wakeup permit to the given value, returning the previous value. + */ + private boolean getAndSetPermit(boolean newValue) { + if (permit != newValue) { + return (boolean) PERMIT.getAndSet(this, newValue); + } else { + return newValue; + } + } + + /** + * Throws WrongThreadException if the current thread is not the owner. + */ + private void ensureOwner() { + if (Thread.currentThread() != owner()) + throw new WrongThreadException("Current thread not owner"); + } + + /** + * Throws WrongThreadException if the current thread is not the owner + * or a thread contained in the flock. + */ + private void ensureOwnerOrContainsThread() { + Thread currentThread = Thread.currentThread(); + if (currentThread != owner() && !containsThread(currentThread)) + throw new WrongThreadException("Current thread not owner or thread in flock"); + } + + /** + * Opens a new thread flock. The flock is owned by the current thread. It can be + * named to aid debugging. + * + *

    This method captures the current thread's {@linkplain ScopedValue scoped value} + * bindings for inheritance by threads created in the flock. + * + *

    For the purposes of containment, monitoring, and debugging, the parent + * of the new flock is determined as follows: + *

      + *
    • If the current thread is the owner of open flocks then the most recently + * created, and open, flock is the parent of the new flock. In other words, the + * enclosing flock is the parent. + *
    • If the current thread is not the owner of any open flocks then the + * parent of the new flock is the current thread's flock. If the current thread + * was not started in a flock then the new flock does not have a parent. + *
    + * + * @param name the name of the flock, can be null + * @return a new thread flock + */ + public static ThreadFlock open(String name) { + var flock = new ThreadFlock(name); + flock.container.push(); + return flock; + } + + /** + * {@return the name of this flock or {@code null} if unnamed} + */ + public String name() { + return name; + } + + /** + * {@return the owner of this flock} + */ + public Thread owner() { + return container.owner(); + } + + /** + * Starts the given unstarted thread in this flock. + * + *

    The thread is started with the scoped value bindings that were captured + * when opening the flock. The bindings must match the current thread's bindings. + * + *

    This method may only be invoked by the flock owner or threads {@linkplain + * #containsThread(Thread) contained} in the flock. + * + * @param thread the unstarted thread + * @return the thread, started + * @throws IllegalStateException if this flock is shutdown or closed + * @throws IllegalThreadStateException if the given thread was already started + * @throws WrongThreadException if the current thread is not the owner or a thread + * contained in the flock + * @throws StructureViolationException if the current scoped value bindings are + * not the same as when the flock was created + */ + public Thread start(Thread thread) { + ensureOwnerOrContainsThread(); + JLA.start(thread, container); + return thread; + } + + /** + * Shutdown this flock so that no new threads can be started, existing threads + * in the flock will continue to run. This method is a no-op if the flock is + * already shutdown or closed. + * + *

    This method may only be invoked by the flock owner or threads {@linkplain + * #containsThread(Thread) contained} in the flock. + * + * @throws WrongThreadException if the current thread is not the owner or a thread + * contained in the flock + */ + public void shutdown() { + ensureOwnerOrContainsThread(); + if (!shutdown) { + shutdown = true; + } + } + + /** + * Wait for all threads in the flock to finish executing their tasks. This method + * waits until all threads finish, the {@link #wakeup() wakeup} method is invoked, + * or the current thread is interrupted. + * + *

    This method may only be invoked by the flock owner. The method trivially + * returns true when the flock is closed. + * + *

    This method clears the effect of any previous invocations of the + * {@code wakeup} method. + * + * @return true if there are no threads in the flock, false if wakeup was invoked + * and there are unfinished threads + * @throws InterruptedException if interrupted while waiting + * @throws WrongThreadException if invoked by a thread that is not the owner + */ + public boolean awaitAll() throws InterruptedException { + ensureOwner(); + + if (getAndSetPermit(false)) + return (threadCount == 0); + + while (threadCount > 0 && !permit) { + LockSupport.park(); + if (Thread.interrupted()) + throw new InterruptedException(); + } + clearPermit(); + return (threadCount == 0); + } + + /** + * Wait, up to the given waiting timeout, for all threads in the flock to finish + * executing their tasks. This method waits until all threads finish, the {@link + * #wakeup() wakeup} method is invoked, the current thread is interrupted, or + * the timeout expires. + * + *

    This method may only be invoked by the flock owner. The method trivially + * returns true when the flock is closed. + * + *

    This method clears the effect of any previous invocations of the {@code wakeup} + * method. + * + * @param timeout the maximum duration to wait + * @return true if there are no threads in the flock, false if wakeup was invoked + * and there are unfinished threads + * @throws InterruptedException if interrupted while waiting + * @throws TimeoutException if the wait timed out + * @throws WrongThreadException if invoked by a thread that is not the owner + */ + public boolean awaitAll(Duration timeout) + throws InterruptedException, TimeoutException { + Objects.requireNonNull(timeout); + ensureOwner(); + + if (getAndSetPermit(false)) + return (threadCount == 0); + + long startNanos = System.nanoTime(); + long nanos = NANOSECONDS.convert(timeout); + long remainingNanos = nanos; + while (threadCount > 0 && remainingNanos > 0 && !permit) { + LockSupport.parkNanos(remainingNanos); + if (Thread.interrupted()) + throw new InterruptedException(); + remainingNanos = nanos - (System.nanoTime() - startNanos); + } + + boolean done = (threadCount == 0); + if (!done && remainingNanos <= 0 && !permit) { + throw new TimeoutException(); + } else { + clearPermit(); + return done; + } + } + + /** + * Causes the call to {@link #awaitAll()} or {@link #awaitAll(Duration)} by the + * {@linkplain #owner() owner} to return immediately. + * + *

    If the owner is blocked in {@code awaitAll} then it will return immediately. + * If the owner is not blocked in {@code awaitAll} then its next call to wait + * will return immediately. The method does nothing when the flock is closed. + * + * @throws WrongThreadException if the current thread is not the owner or a thread + * contained in the flock + */ + public void wakeup() { + ensureOwnerOrContainsThread(); + if (!getAndSetPermit(true) && Thread.currentThread() != owner()) { + LockSupport.unpark(owner()); + } + } + + /** + * Closes this flock. This method first shuts down the flock to prevent + * new threads from starting. It then waits for the threads in the flock + * to finish executing their tasks. In other words, this method blocks until + * all threads in the flock finish. + * + *

    This method may only be invoked by the flock owner. + * + *

    If interrupted then this method continues to wait until all threads + * finish, before completing with the interrupt status set. + * + *

    A ThreadFlock is intended to be used in a structured manner. If + * this method is called to close a flock before nested flocks are closed then it + * closes the nested flocks (in the reverse order that they were created in), + * closes this flock, and then throws {@code StructureViolationException}. + * Similarly, if this method is called to close a thread flock while executing with + * scoped value bindings, and the thread flock was created before the scoped values + * were bound, then {@code StructureViolationException} is thrown after closing the + * thread flock. + * + * @throws WrongThreadException if invoked by a thread that is not the owner + * @throws StructureViolationException if a structure violation was detected + */ + public void close() { + ensureOwner(); + if (closed) + return; + + // shutdown, if not already shutdown + if (!shutdown) + shutdown = true; + + // wait for threads to finish + boolean interrupted = false; + try { + while (threadCount > 0) { + LockSupport.park(); + if (Thread.interrupted()) { + interrupted = true; + } + } + + } finally { + try { + container.close(); // may throw + } finally { + closed = true; + if (interrupted) Thread.currentThread().interrupt(); + } + } + } + + /** + * {@return true if the flock has been {@linkplain #shutdown() shut down}} + */ + public boolean isShutdown() { + return shutdown; + } + + /** + * {@return true if the flock has been {@linkplain #close() closed}} + */ + public boolean isClosed() { + return closed; + } + + /** + * {@return a stream of the threads in this flock} + * The elements of the stream are threads that were started in this flock + * but have not terminated. The stream will reflect the set of threads in the + * flock at some point at or since the creation of the stream. It may or may + * not reflect changes to the set of threads subsequent to creation of the + * stream. + */ + public Stream threads() { + return threads.stream(); + } + + /** + * Tests if this flock contains the given thread. This method returns {@code true} + * if the thread was started in this flock and has not finished. If the thread + * is not in this flock then it tests if the thread is in flocks owned by threads + * in this flock, essentially equivalent to invoking {@code containsThread} method + * on all flocks owned by the threads in this flock. + * + * @param thread the thread + * @return true if this flock contains the thread + */ + public boolean containsThread(Thread thread) { + var c = JLA.threadContainer(thread); + if (c == this.container) + return true; + if (c != null && c != ThreadContainers.root()) { + var parent = c.parent(); + while (parent != null) { + if (parent == this.container) + return true; + parent = parent.parent(); + } + } + return false; + } + + @Override + public String toString() { + String id = Objects.toIdentityString(this); + if (name != null) { + return name + "/" + id; + } else { + return id; + } + } + + /** + * A ThreadContainer backed by a ThreadFlock. + */ + private static class ThreadContainerImpl extends ThreadContainer { + private final ThreadFlock flock; + private volatile Object key; + private boolean closing; + + ThreadContainerImpl(ThreadFlock flock) { + super(/*shared*/ false); + this.flock = flock; + } + + @Override + public ThreadContainerImpl push() { + // Virtual threads in the root containers may not be tracked so need + // to register container to ensure that it is found + if (!ThreadContainers.trackAllThreads()) { + Thread thread = Thread.currentThread(); + if (thread.isVirtual() + && JLA.threadContainer(thread) == ThreadContainers.root()) { + this.key = ThreadContainers.registerContainer(this); + } + } + super.push(); + return this; + } + + /** + * Invoked by ThreadFlock.close when closing the flock. This method pops the + * container from the current thread's scope stack. + */ + void close() { + assert Thread.currentThread() == owner(); + if (!closing) { + closing = true; + boolean atTop = popForcefully(); // may block + Object key = this.key; + if (key != null) + ThreadContainers.deregisterContainer(key); + if (!atTop) + throw new StructureViolationException(); + } + } + + /** + * Invoked when an enclosing scope is closing. Invokes ThreadFlock.close to + * close the flock. This method does not pop the container from the current + * thread's scope stack. + */ + @Override + protected boolean tryClose() { + assert Thread.currentThread() == owner(); + if (!closing) { + closing = true; + flock.close(); + Object key = this.key; + if (key != null) + ThreadContainers.deregisterContainer(key); + return true; + } else { + assert false : "Should not get there"; + return false; + } + } + + @Override + public String name() { + return flock.name(); + } + @Override + public long threadCount() { + return flock.threadCount(); + } + @Override + public Stream threads() { + return flock.threads().filter(Thread::isAlive); + } + @Override + public void onStart(Thread thread) { + flock.onStart(thread); + } + @Override + public void onExit(Thread thread) { + flock.onExit(thread); + } + @Override + public ScopedValueContainer.BindingsSnapshot scopedValueBindings() { + return flock.scopedValueBindings(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/misc/ThreadTracker$ThreadRef.class b/tests/test_data/std/jdk/internal/misc/ThreadTracker$ThreadRef.class new file mode 100644 index 0000000000000000000000000000000000000000..25ab59da52148bc7ac6c20e8b12c5d7a166784c3 GIT binary patch literal 1573 zcmb7FTT|0O6#kaBq?AChauJY=irNbh@UBHbU>wR6bfCk7K5g5TrkA89DKq{Q|A4;u zAT!>E2S;E1QI2PmP}0#seds3V>^a~0zH>I)A3u-30$9gJ3|$B*2&;&on_-~J54l$7 z#(}mgN~Tq2=w8wd-C1S`B~$x7h@wY9OhqqLhE%m&({#fTmci>p<)SME?B%& z6V{Ap?TQzKR;?Uwm! zQu|cZD<045hS+H}ioz=JVx8zD@@9$G_qnA@+joYYif%Jx{(}v5Xydh`= z1VF9HQK!Yr7O#`pLGDShDoRc^^^756Iu&72xLK@r&chF4=-YE>g4?|5GaO9*QGTb} z*Uu2!Gh0?kJl0*sp4&eX^RitugdJf!o2Kn3SY(*`%M?h{$#EQ5Gfl^KEZ+3w+fnq! z8I*W8?#6Hr_Z2))k;RfkZBNE(8IIl%ny1gtWaufLfH52eC#f5UW=&{b;3hZ9bz#rs zO|#Z&W&;EFk3qoWCl+2c#fGp;mfmzsE10rg=e8Ym_!!TB2MJd1IDPFYsX42p)C%5e2m{~3A|tT9ZU9ZLQ8#AAUjfG+x&=-9|BfZifxM=(L_Bw5S!l>4#t zXRvhUBa|bux-dm+H)R27Ow&5-Md1=IlST0^8p9QOk1#T1i4n}uDq(L^xJ>R%e}M7{ zeP3|?9hpJgITu&;!hBrn0j~KFRf-N#&P3)rqOUQM`G)AWgqx+`8z|wo2!|wS$R#T; zM&JhMe7eBXL-Hhu RRFtN>j4`a>5&boc{sP_OWd8sF literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/ThreadTracker.class b/tests/test_data/std/jdk/internal/misc/ThreadTracker.class new file mode 100644 index 0000000000000000000000000000000000000000..3222e0291b553dc844aba6795cf898ee22644e53 GIT binary patch literal 1971 zcma)7TUQ%Z7~N+kFi98+O+v&9rC4lp!N%H)+CZeG#bSZl2BXENAvwZ8n7C$!cJb`5 zkoPWMeDGRYyO#F3ze!#0Gc#mDmx_6q%sJ<~>~HVyeDm_JUw;EIkI&Q4pc_b-=tIB2 z@Rs$^sK*9?rBcpayX zP!yU73`Uh7u5*VK21JIt)ikmgQ#6kYj1)phz30Wo048w8z@&*cah6eIk^Nk6e>peQgJ3w-_1>Xz$v+%yW%6~<{3 zZ>u`{{eV9Os$$|Dg{a?^JDrD8ZM|#alG;jAci*xdFO4g>YT!K+@8bh<9_N{F6OTZ? zB|Y1ft!~=7Z~41CU|+4VL+bX1!wpvo%p4Vr%l{TT)~Z^o3MA$`Ek+qyvK_gyyR$Cc zRYih8W~tM(+6~LK)jHZt_?tFSOdgknfs?+wcSCO2j=)igBOO>pNE*9FpnP1!9@tcy zbTqelSt3|{>tUiks;>0YrSoss?4jDB7#eQCBMJd)=aK);iN{M;AX` z@9erwxnKtzh8EE^yPy&Z46I1cUzUn$QfV$aj&uXrrDxz%fr|mIW9LNAeHTc_m!G_b zS;;FV+3FgHmxhcQ1rWFvtg6GKs{i@k&pl2vK4-YPMoYnevvdGadJ5wg4E_*!%<`$` zA8-~4Tt!V;g|_$*b6g2r$Bih?CiKAe^mAk%JjKWX-dHOAjKT6VoYwFSjPkcgi0|p8 zBaS@FL0JnT=R@x(@&IqzJZ>`ftstxR2gVF!=ZpaDLO1KzjHc6~^p9C*f5g;2hQ{_W z@EnB)2PpksjuB*76|g`AA8~};<^^92kemr4c9Bd(Nb<#H>2 threads = ConcurrentHashMap.newKeySet(); + + /** + * Adds the current thread to thread set if not already in the set. + * Returns a key to remove the thread or {@code null} if already in the set. + */ + public Object tryBegin() { + var threadRef = new ThreadRef(Thread.currentThread()); + return threads.add(threadRef) ? threadRef : null; + } + + /** + * Adds the current thread to thread set if not already in the set. + * Returns a key to remove the thread. + */ + public Object begin() { + var threadRef = new ThreadRef(Thread.currentThread()); + boolean added = threads.add(threadRef); + assert added; + return threadRef; + } + + /** + * Removes the thread identified by the key from the thread set. + */ + public void end(Object key) { + var threadRef = (ThreadRef) key; + assert threadRef.thread() == Thread.currentThread(); + boolean removed = threads.remove(threadRef); + assert removed; + } + + /** + * Returns true if the given thread is tracked. + */ + public boolean contains(Thread thread) { + var threadRef = new ThreadRef(thread); + return threads.contains(threadRef); + } +} diff --git a/tests/test_data/std/jdk/internal/misc/Unsafe.class b/tests/test_data/std/jdk/internal/misc/Unsafe.class new file mode 100644 index 0000000000000000000000000000000000000000..a1f1019d81527edff2bf6ac4a571a1134a71bbdf GIT binary patch literal 59478 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 z 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/Unsafe.java b/tests/test_data/std/jdk/internal/misc/Unsafe.java new file mode 100644 index 00000000..ec6b7591 --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/Unsafe.java @@ -0,0 +1,3865 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import jdk.internal.ref.Cleaner; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.IntrinsicCandidate; +import sun.nio.ch.DirectBuffer; + +import java.lang.reflect.Field; +import java.security.ProtectionDomain; + +import static jdk.internal.misc.UnsafeConstants.*; + +/** + * A collection of methods for performing low-level, unsafe operations. + * Although the class and all methods are public, use of this class is + * limited because only trusted code can obtain instances of it. + * + * Note: It is the responsibility of the caller to make sure + * arguments are checked before methods of this class are + * called. While some rudimentary checks are performed on the input, + * the checks are best effort and when performance is an overriding + * priority, as when methods of this class are optimized by the + * runtime compiler, some or all checks (if any) may be elided. Hence, + * the caller must not rely on the checks and corresponding + * exceptions! + * + * @author John R. Rose + * @see #getUnsafe + */ + +public final class Unsafe { + + private static native void registerNatives(); + static { + registerNatives(); + } + + private Unsafe() {} + + private static final Unsafe theUnsafe = new Unsafe(); + + /** + * Provides the caller with the capability of performing unsafe + * operations. + * + *

    The returned {@code Unsafe} object should be carefully guarded + * by the caller, since it can be used to read and write data at arbitrary + * memory addresses. It must never be passed to untrusted code. + * + *

    Most methods in this class are very low-level, and correspond to a + * small number of hardware instructions (on typical machines). Compilers + * are encouraged to optimize these methods accordingly. + * + *

    Here is a suggested idiom for using unsafe operations: + * + *

     {@code
    +     * class MyTrustedClass {
    +     *   private static final Unsafe unsafe = Unsafe.getUnsafe();
    +     *   ...
    +     *   private long myCountAddress = ...;
    +     *   public int getCount() { return unsafe.getByte(myCountAddress); }
    +     * }}
    + * + * (It may assist compilers to make the local variable {@code final}.) + */ + public static Unsafe getUnsafe() { + return theUnsafe; + } + + //--- peek and poke operations + // (compilers should optimize these to memory ops) + + // These work on object fields in the Java heap. + // They will not work on elements of packed arrays. + + /** + * Fetches a value from a given Java variable. + * More specifically, fetches a field or array element within the given + * object {@code o} at the given offset, or (if {@code o} is null) + * from the memory address whose numerical value is the given offset. + *

    + * The results are undefined unless one of the following cases is true: + *

      + *
    • The offset was obtained from {@link #objectFieldOffset} on + * the {@link java.lang.reflect.Field} of some Java field and the object + * referred to by {@code o} is of a class compatible with that + * field's class. + * + *
    • The offset and object reference {@code o} (either null or + * non-null) were both obtained via {@link #staticFieldOffset} + * and {@link #staticFieldBase} (respectively) from the + * reflective {@link Field} representation of some Java field. + * + *
    • The object referred to by {@code o} is an array, and the offset + * is an integer of the form {@code B+N*S}, where {@code N} is + * a valid index into the array, and {@code B} and {@code S} are + * the values obtained by {@link #arrayBaseOffset} and {@link + * #arrayIndexScale} (respectively) from the array's class. The value + * referred to is the {@code N}th element of the array. + * + *
    + *

    + * If one of the above cases is true, the call references a specific Java + * variable (field or array element). However, the results are undefined + * if that variable is not in fact of the type returned by this method. + *

    + * This method refers to a variable by means of two parameters, and so + * it provides (in effect) a double-register addressing mode + * for Java variables. When the object reference is null, this method + * uses its offset as an absolute address. This is similar in operation + * to methods such as {@link #getInt(long)}, which provide (in effect) a + * single-register addressing mode for non-Java variables. + * However, because Java variables may have a different layout in memory + * from non-Java variables, programmers should not assume that these + * two addressing modes are ever equivalent. Also, programmers should + * remember that offsets from the double-register addressing mode cannot + * be portably confused with longs used in the single-register addressing + * mode. + * + * @param o Java heap object in which the variable resides, if any, else + * null + * @param offset indication of where the variable resides in a Java heap + * object, if any, else a memory address locating the variable + * statically + * @return the value fetched from the indicated Java variable + * @throws RuntimeException No defined exceptions are thrown, not even + * {@link NullPointerException} + */ + @IntrinsicCandidate + public native int getInt(Object o, long offset); + + /** + * Stores a value into a given Java variable. + *

    + * The first two parameters are interpreted exactly as with + * {@link #getInt(Object, long)} to refer to a specific + * Java variable (field or array element). The given value + * is stored into that variable. + *

    + * The variable must be of the same type as the method + * parameter {@code x}. + * + * @param o Java heap object in which the variable resides, if any, else + * null + * @param offset indication of where the variable resides in a Java heap + * object, if any, else a memory address locating the variable + * statically + * @param x the value to store into the indicated Java variable + * @throws RuntimeException No defined exceptions are thrown, not even + * {@link NullPointerException} + */ + @IntrinsicCandidate + public native void putInt(Object o, long offset, int x); + + /** + * Fetches a reference value from a given Java variable. + * @see #getInt(Object, long) + */ + @IntrinsicCandidate + public native Object getReference(Object o, long offset); + + /** + * Stores a reference value into a given Java variable. + *

    + * Unless the reference {@code x} being stored is either null + * or matches the field type, the results are undefined. + * If the reference {@code o} is non-null, card marks or + * other store barriers for that object (if the VM requires them) + * are updated. + * @see #putInt(Object, long, int) + */ + @IntrinsicCandidate + public native void putReference(Object o, long offset, Object x); + + /** @see #getInt(Object, long) */ + @IntrinsicCandidate + public native boolean getBoolean(Object o, long offset); + + /** @see #putInt(Object, long, int) */ + @IntrinsicCandidate + public native void putBoolean(Object o, long offset, boolean x); + + /** @see #getInt(Object, long) */ + @IntrinsicCandidate + public native byte getByte(Object o, long offset); + + /** @see #putInt(Object, long, int) */ + @IntrinsicCandidate + public native void putByte(Object o, long offset, byte x); + + /** @see #getInt(Object, long) */ + @IntrinsicCandidate + public native short getShort(Object o, long offset); + + /** @see #putInt(Object, long, int) */ + @IntrinsicCandidate + public native void putShort(Object o, long offset, short x); + + /** @see #getInt(Object, long) */ + @IntrinsicCandidate + public native char getChar(Object o, long offset); + + /** @see #putInt(Object, long, int) */ + @IntrinsicCandidate + public native void putChar(Object o, long offset, char x); + + /** @see #getInt(Object, long) */ + @IntrinsicCandidate + public native long getLong(Object o, long offset); + + /** @see #putInt(Object, long, int) */ + @IntrinsicCandidate + public native void putLong(Object o, long offset, long x); + + /** @see #getInt(Object, long) */ + @IntrinsicCandidate + public native float getFloat(Object o, long offset); + + /** @see #putInt(Object, long, int) */ + @IntrinsicCandidate + public native void putFloat(Object o, long offset, float x); + + /** @see #getInt(Object, long) */ + @IntrinsicCandidate + public native double getDouble(Object o, long offset); + + /** @see #putInt(Object, long, int) */ + @IntrinsicCandidate + public native void putDouble(Object o, long offset, double x); + + /** + * Fetches a native pointer from a given memory address. If the address is + * zero, or does not point into a block obtained from {@link + * #allocateMemory}, the results are undefined. + * + *

    If the native pointer is less than 64 bits wide, it is extended as + * an unsigned number to a Java long. The pointer may be indexed by any + * given byte offset, simply by adding that offset (as a simple integer) to + * the long representing the pointer. The number of bytes actually read + * from the target address may be determined by consulting {@link + * #addressSize}. + * + * @see #allocateMemory + * @see #getInt(Object, long) + */ + @ForceInline + public long getAddress(Object o, long offset) { + if (ADDRESS_SIZE == 4) { + return Integer.toUnsignedLong(getInt(o, offset)); + } else { + return getLong(o, offset); + } + } + + /** + * Stores a native pointer into a given memory address. If the address is + * zero, or does not point into a block obtained from {@link + * #allocateMemory}, the results are undefined. + * + *

    The number of bytes actually written at the target address may be + * determined by consulting {@link #addressSize}. + * + * @see #allocateMemory + * @see #putInt(Object, long, int) + */ + @ForceInline + public void putAddress(Object o, long offset, long x) { + if (ADDRESS_SIZE == 4) { + putInt(o, offset, (int)x); + } else { + putLong(o, offset, x); + } + } + + // These read VM internal data. + + /** + * Fetches an uncompressed reference value from a given native variable + * ignoring the VM's compressed references mode. + * + * @param address a memory address locating the variable + * @return the value fetched from the indicated native variable + */ + public native Object getUncompressedObject(long address); + + // These work on values in the C heap. + + /** + * Fetches a value from a given memory address. If the address is zero, or + * does not point into a block obtained from {@link #allocateMemory}, the + * results are undefined. + * + * @see #allocateMemory + */ + @ForceInline + public byte getByte(long address) { + return getByte(null, address); + } + + /** + * Stores a value into a given memory address. If the address is zero, or + * does not point into a block obtained from {@link #allocateMemory}, the + * results are undefined. + * + * @see #getByte(long) + */ + @ForceInline + public void putByte(long address, byte x) { + putByte(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public short getShort(long address) { + return getShort(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putShort(long address, short x) { + putShort(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public char getChar(long address) { + return getChar(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putChar(long address, char x) { + putChar(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public int getInt(long address) { + return getInt(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putInt(long address, int x) { + putInt(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public long getLong(long address) { + return getLong(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putLong(long address, long x) { + putLong(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public float getFloat(long address) { + return getFloat(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putFloat(long address, float x) { + putFloat(null, address, x); + } + + /** @see #getByte(long) */ + @ForceInline + public double getDouble(long address) { + return getDouble(null, address); + } + + /** @see #putByte(long, byte) */ + @ForceInline + public void putDouble(long address, double x) { + putDouble(null, address, x); + } + + /** @see #getAddress(Object, long) */ + @ForceInline + public long getAddress(long address) { + return getAddress(null, address); + } + + /** @see #putAddress(Object, long, long) */ + @ForceInline + public void putAddress(long address, long x) { + putAddress(null, address, x); + } + + + + //--- helper methods for validating various types of objects/values + + /** + * Create an exception reflecting that some of the input was invalid + * + * Note: It is the responsibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @return an exception object + */ + private RuntimeException invalidInput() { + return new IllegalArgumentException(); + } + + /** + * Check if a value is 32-bit clean (32 MSB are all zero) + * + * @param value the 64-bit value to check + * + * @return true if the value is 32-bit clean + */ + private boolean is32BitClean(long value) { + return value >>> 32 == 0; + } + + /** + * Check the validity of a size (the equivalent of a size_t) + * + * @throws RuntimeException if the size is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkSize(long size) { + if (ADDRESS_SIZE == 4) { + // Note: this will also check for negative sizes + if (!is32BitClean(size)) { + throw invalidInput(); + } + } else if (size < 0) { + throw invalidInput(); + } + } + + /** + * Check the validity of a native address (the equivalent of void*) + * + * @throws RuntimeException if the address is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkNativeAddress(long address) { + if (ADDRESS_SIZE == 4) { + // Accept both zero and sign extended pointers. A valid + // pointer will, after the +1 below, either have produced + // the value 0x0 or 0x1. Masking off the low bit allows + // for testing against 0. + if ((((address >> 32) + 1) & ~1) != 0) { + throw invalidInput(); + } + } + } + + /** + * Check the validity of an offset, relative to a base object + * + * @param o the base object + * @param offset the offset to check + * + * @throws RuntimeException if the size is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkOffset(Object o, long offset) { + if (ADDRESS_SIZE == 4) { + // Note: this will also check for negative offsets + if (!is32BitClean(offset)) { + throw invalidInput(); + } + } else if (offset < 0) { + throw invalidInput(); + } + } + + /** + * Check the validity of a double-register pointer + * + * Note: This code deliberately does *not* check for NPE for (at + * least) three reasons: + * + * 1) NPE is not just NULL/0 - there is a range of values all + * resulting in an NPE, which is not trivial to check for + * + * 2) It is the responsibility of the callers of Unsafe methods + * to verify the input, so throwing an exception here is not really + * useful - passing in a NULL pointer is a critical error and the + * must not expect an exception to be thrown anyway. + * + * 3) the actual operations will detect NULL pointers anyway by + * means of traps and signals (like SIGSEGV). + * + * @param o Java heap object, or null + * @param offset indication of where the variable resides in a Java heap + * object, if any, else a memory address locating the variable + * statically + * + * @throws RuntimeException if the pointer is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkPointer(Object o, long offset) { + if (o == null) { + checkNativeAddress(offset); + } else { + checkOffset(o, offset); + } + } + + /** + * Check if a type is a primitive array type + * + * @param c the type to check + * + * @return true if the type is a primitive array type + */ + private void checkPrimitiveArray(Class c) { + Class componentType = c.getComponentType(); + if (componentType == null || !componentType.isPrimitive()) { + throw invalidInput(); + } + } + + /** + * Check that a pointer is a valid primitive array type pointer + * + * Note: pointers off-heap are considered to be primitive arrays + * + * @throws RuntimeException if the pointer is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkPrimitivePointer(Object o, long offset) { + checkPointer(o, offset); + + if (o != null) { + // If on heap, it must be a primitive array + checkPrimitiveArray(o.getClass()); + } + } + + + //--- wrappers for malloc, realloc, free: + + /** + * Round up allocation size to a multiple of HeapWordSize. + */ + private long alignToHeapWordSize(long bytes) { + if (bytes >= 0) { + return (bytes + ADDRESS_SIZE - 1) & ~(ADDRESS_SIZE - 1); + } else { + throw invalidInput(); + } + } + + /** + * Allocates a new block of native memory, of the given size in bytes. The + * contents of the memory are uninitialized; they will generally be + * garbage. The resulting native pointer will be zero if and only if the + * requested size is zero. The resulting native pointer will be aligned for + * all value types. Dispose of this memory by calling {@link #freeMemory} + * or resize it with {@link #reallocateMemory}. + * + * Note: It is the responsibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large + * for the native size_t type + * + * @throws OutOfMemoryError if the allocation is refused by the system + * + * @see #getByte(long) + * @see #putByte(long, byte) + */ + public long allocateMemory(long bytes) { + bytes = alignToHeapWordSize(bytes); + + allocateMemoryChecks(bytes); + + if (bytes == 0) { + return 0; + } + + long p = allocateMemory0(bytes); + if (p == 0) { + throw new OutOfMemoryError("Unable to allocate " + bytes + " bytes"); + } + + return p; + } + + /** + * Validate the arguments to allocateMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void allocateMemoryChecks(long bytes) { + checkSize(bytes); + } + + /** + * Resizes a new block of native memory, to the given size in bytes. The + * contents of the new block past the size of the old block are + * uninitialized; they will generally be garbage. The resulting native + * pointer will be zero if and only if the requested size is zero. The + * resulting native pointer will be aligned for all value types. Dispose + * of this memory by calling {@link #freeMemory}, or resize it with {@link + * #reallocateMemory}. The address passed to this method may be null, in + * which case an allocation will be performed. + * + * Note: It is the responsibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large + * for the native size_t type + * + * @throws OutOfMemoryError if the allocation is refused by the system + * + * @see #allocateMemory + */ + public long reallocateMemory(long address, long bytes) { + bytes = alignToHeapWordSize(bytes); + + reallocateMemoryChecks(address, bytes); + + if (bytes == 0) { + freeMemory(address); + return 0; + } + + long p = (address == 0) ? allocateMemory0(bytes) : reallocateMemory0(address, bytes); + if (p == 0) { + throw new OutOfMemoryError("Unable to allocate " + bytes + " bytes"); + } + + return p; + } + + /** + * Validate the arguments to reallocateMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void reallocateMemoryChecks(long address, long bytes) { + checkPointer(null, address); + checkSize(bytes); + } + + /** + * Sets all bytes in a given block of memory to a fixed value + * (usually zero). + * + *

    This method determines a block's base address by means of two parameters, + * and so it provides (in effect) a double-register addressing mode, + * as discussed in {@link #getInt(Object,long)}. When the object reference is null, + * the offset supplies an absolute base address. + * + *

    The stores are in coherent (atomic) units of a size determined + * by the address and length parameters. If the effective address and + * length are all even modulo 8, the stores take place in 'long' units. + * If the effective address and length are (resp.) even modulo 4 or 2, + * the stores take place in units of 'int' or 'short'. + * + * Note: It is the responsibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * + * @since 1.7 + */ + public void setMemory(Object o, long offset, long bytes, byte value) { + setMemoryChecks(o, offset, bytes, value); + + if (bytes == 0) { + return; + } + + setMemory0(o, offset, bytes, value); + } + + /** + * Sets all bytes in a given block of memory to a fixed value + * (usually zero). This provides a single-register addressing mode, + * as discussed in {@link #getInt(Object,long)}. + * + *

    Equivalent to {@code setMemory(null, address, bytes, value)}. + */ + public void setMemory(long address, long bytes, byte value) { + setMemory(null, address, bytes, value); + } + + /** + * Validate the arguments to setMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void setMemoryChecks(Object o, long offset, long bytes, byte value) { + checkPrimitivePointer(o, offset); + checkSize(bytes); + } + + /** + * Sets all bytes in a given block of memory to a copy of another + * block. + * + *

    This method determines each block's base address by means of two parameters, + * and so it provides (in effect) a double-register addressing mode, + * as discussed in {@link #getInt(Object,long)}. When the object reference is null, + * the offset supplies an absolute base address. + * + *

    The transfers are in coherent (atomic) units of a size determined + * by the address and length parameters. If the effective addresses and + * length are all even modulo 8, the transfer takes place in 'long' units. + * If the effective addresses and length are (resp.) even modulo 4 or 2, + * the transfer takes place in units of 'int' or 'short'. + * + * Note: It is the responsibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * + * @since 1.7 + */ + public void copyMemory(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + copyMemoryChecks(srcBase, srcOffset, destBase, destOffset, bytes); + + if (bytes == 0) { + return; + } + + copyMemory0(srcBase, srcOffset, destBase, destOffset, bytes); + } + + /** + * Sets all bytes in a given block of memory to a copy of another + * block. This provides a single-register addressing mode, + * as discussed in {@link #getInt(Object,long)}. + * + * Equivalent to {@code copyMemory(null, srcAddress, null, destAddress, bytes)}. + */ + public void copyMemory(long srcAddress, long destAddress, long bytes) { + copyMemory(null, srcAddress, null, destAddress, bytes); + } + + /** + * Validate the arguments to copyMemory + * + * @throws RuntimeException if any of the arguments is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void copyMemoryChecks(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + checkSize(bytes); + checkPrimitivePointer(srcBase, srcOffset); + checkPrimitivePointer(destBase, destOffset); + } + + /** + * Copies all elements from one block of memory to another block, + * *unconditionally* byte swapping the elements on the fly. + * + *

    This method determines each block's base address by means of two parameters, + * and so it provides (in effect) a double-register addressing mode, + * as discussed in {@link #getInt(Object,long)}. When the object reference is null, + * the offset supplies an absolute base address. + * + * Note: It is the responsibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * + * @since 9 + */ + public void copySwapMemory(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes, long elemSize) { + copySwapMemoryChecks(srcBase, srcOffset, destBase, destOffset, bytes, elemSize); + + if (bytes == 0) { + return; + } + + copySwapMemory0(srcBase, srcOffset, destBase, destOffset, bytes, elemSize); + } + + private void copySwapMemoryChecks(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes, long elemSize) { + checkSize(bytes); + + if (elemSize != 2 && elemSize != 4 && elemSize != 8) { + throw invalidInput(); + } + if (bytes % elemSize != 0) { + throw invalidInput(); + } + + checkPrimitivePointer(srcBase, srcOffset); + checkPrimitivePointer(destBase, destOffset); + } + + /** + * Copies all elements from one block of memory to another block, byte swapping the + * elements on the fly. + * + * This provides a single-register addressing mode, as + * discussed in {@link #getInt(Object,long)}. + * + * Equivalent to {@code copySwapMemory(null, srcAddress, null, destAddress, bytes, elemSize)}. + */ + public void copySwapMemory(long srcAddress, long destAddress, long bytes, long elemSize) { + copySwapMemory(null, srcAddress, null, destAddress, bytes, elemSize); + } + + /** + * Disposes of a block of native memory, as obtained from {@link + * #allocateMemory} or {@link #reallocateMemory}. The address passed to + * this method may be null, in which case no action is taken. + * + * Note: It is the responsibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * + * @see #allocateMemory + */ + public void freeMemory(long address) { + freeMemoryChecks(address); + + if (address == 0) { + return; + } + + freeMemory0(address); + } + + /** + * Validate the arguments to freeMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void freeMemoryChecks(long address) { + checkPointer(null, address); + } + + /** + * Ensure writeback of a specified virtual memory address range + * from cache to physical memory. All bytes in the address range + * are guaranteed to have been written back to physical memory on + * return from this call i.e. subsequently executed store + * instructions are guaranteed not to be visible before the + * writeback is completed. + * + * @param address + * the lowest byte address that must be guaranteed written + * back to memory. bytes at lower addresses may also be + * written back. + * + * @param length + * the length in bytes of the region starting at address + * that must be guaranteed written back to memory. + * + * @throws RuntimeException if memory writeback is not supported + * on the current hardware of if the arguments are invalid. + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + * + * @since 14 + */ + + public void writebackMemory(long address, long length) { + checkWritebackEnabled(); + checkWritebackMemory(address, length); + + // perform any required pre-writeback barrier + writebackPreSync0(); + + // write back one cache line at a time + long line = dataCacheLineAlignDown(address); + long end = address + length; + while (line < end) { + writeback0(line); + line += dataCacheLineFlushSize(); + } + + // perform any required post-writeback barrier + writebackPostSync0(); + } + + /** + * Validate the arguments to writebackMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkWritebackMemory(long address, long length) { + checkNativeAddress(address); + checkSize(length); + } + + /** + * Validate that the current hardware supports memory writeback. + * (Note: this is a belt and braces check. Clients are + * expected to test whether writeback is enabled by calling + * ({@link isWritebackEnabled #isWritebackEnabled} and avoid + * calling method {@link writeback #writeback} if it is disabled). + * + * + * @throws RuntimeException if memory writeback is not supported + */ + private void checkWritebackEnabled() { + if (!isWritebackEnabled()) { + throw new RuntimeException("writebackMemory not enabled!"); + } + } + + /** + * force writeback of an individual cache line. + * + * @param address + * the start address of the cache line to be written back + */ + @IntrinsicCandidate + private native void writeback0(long address); + + /** + * Serialize writeback operations relative to preceding memory writes. + */ + @IntrinsicCandidate + private native void writebackPreSync0(); + + /** + * Serialize writeback operations relative to following memory writes. + */ + @IntrinsicCandidate + private native void writebackPostSync0(); + + //--- random queries + + /** + * This constant differs from all results that will ever be returned from + * {@link #staticFieldOffset}, {@link #objectFieldOffset}, + * or {@link #arrayBaseOffset}. + */ + public static final int INVALID_FIELD_OFFSET = -1; + + /** + * Reports the location of a given field in the storage allocation of its + * class. Do not expect to perform any sort of arithmetic on this offset; + * it is just a cookie which is passed to the unsafe heap memory accessors. + * + *

    Any given field will always have the same offset and base, and no + * two distinct fields of the same class will ever have the same offset + * and base. + * + *

    As of 1.4.1, offsets for fields are represented as long values, + * although the Sun JVM does not use the most significant 32 bits. + * However, JVM implementations which store static fields at absolute + * addresses can use long offsets and null base pointers to express + * the field locations in a form usable by {@link #getInt(Object,long)}. + * Therefore, code which will be ported to such JVMs on 64-bit platforms + * must preserve all bits of static field offsets. + * @see #getInt(Object, long) + */ + public long objectFieldOffset(Field f) { + if (f == null) { + throw new NullPointerException(); + } + + return objectFieldOffset0(f); + } + + /** + * Reports the location of the field with a given name in the storage + * allocation of its class. + * + * @throws NullPointerException if any parameter is {@code null}. + * @throws InternalError if there is no field named {@code name} declared + * in class {@code c}, i.e., if {@code c.getDeclaredField(name)} + * would throw {@code java.lang.NoSuchFieldException}. + * + * @see #objectFieldOffset(Field) + */ + public long objectFieldOffset(Class c, String name) { + if (c == null || name == null) { + throw new NullPointerException(); + } + + return objectFieldOffset1(c, name); + } + + /** + * Reports the location of a given static field, in conjunction with {@link + * #staticFieldBase}. + *

    Do not expect to perform any sort of arithmetic on this offset; + * it is just a cookie which is passed to the unsafe heap memory accessors. + * + *

    Any given field will always have the same offset, and no two distinct + * fields of the same class will ever have the same offset. + * + *

    As of 1.4.1, offsets for fields are represented as long values, + * although the Sun JVM does not use the most significant 32 bits. + * It is hard to imagine a JVM technology which needs more than + * a few bits to encode an offset within a non-array object, + * However, for consistency with other methods in this class, + * this method reports its result as a long value. + * @see #getInt(Object, long) + */ + public long staticFieldOffset(Field f) { + if (f == null) { + throw new NullPointerException(); + } + + return staticFieldOffset0(f); + } + + /** + * Reports the location of a given static field, in conjunction with {@link + * #staticFieldOffset}. + *

    Fetch the base "Object", if any, with which static fields of the + * given class can be accessed via methods like {@link #getInt(Object, + * long)}. This value may be null. This value may refer to an object + * which is a "cookie", not guaranteed to be a real Object, and it should + * not be used in any way except as argument to the get and put routines in + * this class. + */ + public Object staticFieldBase(Field f) { + if (f == null) { + throw new NullPointerException(); + } + + return staticFieldBase0(f); + } + + /** + * Detects if the given class may need to be initialized. This is often + * needed in conjunction with obtaining the static field base of a + * class. + * @return false only if a call to {@code ensureClassInitialized} would have no effect + */ + public boolean shouldBeInitialized(Class c) { + if (c == null) { + throw new NullPointerException(); + } + + return shouldBeInitialized0(c); + } + + /** + * Ensures the given class has been initialized (see JVMS-5.5 for details). + * This is often needed in conjunction with obtaining the static field base + * of a class. + * + * The call returns when either class {@code c} is fully initialized or + * class {@code c} is being initialized and the call is performed from + * the initializing thread. In the latter case a subsequent call to + * {@link #shouldBeInitialized} will return {@code true}. + */ + public void ensureClassInitialized(Class c) { + if (c == null) { + throw new NullPointerException(); + } + + ensureClassInitialized0(c); + } + + /** + * Reports the offset of the first element in the storage allocation of a + * given array class. If {@link #arrayIndexScale} returns a non-zero value + * for the same class, you may use that scale factor, together with this + * base offset, to form new offsets to access elements of arrays of the + * given class. + * + * @see #getInt(Object, long) + * @see #putInt(Object, long, int) + */ + public int arrayBaseOffset(Class arrayClass) { + if (arrayClass == null) { + throw new NullPointerException(); + } + + return arrayBaseOffset0(arrayClass); + } + + + /** The value of {@code arrayBaseOffset(boolean[].class)} */ + public static final int ARRAY_BOOLEAN_BASE_OFFSET + = theUnsafe.arrayBaseOffset(boolean[].class); + + /** The value of {@code arrayBaseOffset(byte[].class)} */ + public static final int ARRAY_BYTE_BASE_OFFSET + = theUnsafe.arrayBaseOffset(byte[].class); + + /** The value of {@code arrayBaseOffset(short[].class)} */ + public static final int ARRAY_SHORT_BASE_OFFSET + = theUnsafe.arrayBaseOffset(short[].class); + + /** The value of {@code arrayBaseOffset(char[].class)} */ + public static final int ARRAY_CHAR_BASE_OFFSET + = theUnsafe.arrayBaseOffset(char[].class); + + /** The value of {@code arrayBaseOffset(int[].class)} */ + public static final int ARRAY_INT_BASE_OFFSET + = theUnsafe.arrayBaseOffset(int[].class); + + /** The value of {@code arrayBaseOffset(long[].class)} */ + public static final int ARRAY_LONG_BASE_OFFSET + = theUnsafe.arrayBaseOffset(long[].class); + + /** The value of {@code arrayBaseOffset(float[].class)} */ + public static final int ARRAY_FLOAT_BASE_OFFSET + = theUnsafe.arrayBaseOffset(float[].class); + + /** The value of {@code arrayBaseOffset(double[].class)} */ + public static final int ARRAY_DOUBLE_BASE_OFFSET + = theUnsafe.arrayBaseOffset(double[].class); + + /** The value of {@code arrayBaseOffset(Object[].class)} */ + public static final int ARRAY_OBJECT_BASE_OFFSET + = theUnsafe.arrayBaseOffset(Object[].class); + + /** + * Reports the scale factor for addressing elements in the storage + * allocation of a given array class. However, arrays of "narrow" types + * will generally not work properly with accessors like {@link + * #getByte(Object, long)}, so the scale factor for such classes is reported + * as zero. + * + * @see #arrayBaseOffset + * @see #getInt(Object, long) + * @see #putInt(Object, long, int) + */ + public int arrayIndexScale(Class arrayClass) { + if (arrayClass == null) { + throw new NullPointerException(); + } + + return arrayIndexScale0(arrayClass); + } + + + /** The value of {@code arrayIndexScale(boolean[].class)} */ + public static final int ARRAY_BOOLEAN_INDEX_SCALE + = theUnsafe.arrayIndexScale(boolean[].class); + + /** The value of {@code arrayIndexScale(byte[].class)} */ + public static final int ARRAY_BYTE_INDEX_SCALE + = theUnsafe.arrayIndexScale(byte[].class); + + /** The value of {@code arrayIndexScale(short[].class)} */ + public static final int ARRAY_SHORT_INDEX_SCALE + = theUnsafe.arrayIndexScale(short[].class); + + /** The value of {@code arrayIndexScale(char[].class)} */ + public static final int ARRAY_CHAR_INDEX_SCALE + = theUnsafe.arrayIndexScale(char[].class); + + /** The value of {@code arrayIndexScale(int[].class)} */ + public static final int ARRAY_INT_INDEX_SCALE + = theUnsafe.arrayIndexScale(int[].class); + + /** The value of {@code arrayIndexScale(long[].class)} */ + public static final int ARRAY_LONG_INDEX_SCALE + = theUnsafe.arrayIndexScale(long[].class); + + /** The value of {@code arrayIndexScale(float[].class)} */ + public static final int ARRAY_FLOAT_INDEX_SCALE + = theUnsafe.arrayIndexScale(float[].class); + + /** The value of {@code arrayIndexScale(double[].class)} */ + public static final int ARRAY_DOUBLE_INDEX_SCALE + = theUnsafe.arrayIndexScale(double[].class); + + /** The value of {@code arrayIndexScale(Object[].class)} */ + public static final int ARRAY_OBJECT_INDEX_SCALE + = theUnsafe.arrayIndexScale(Object[].class); + + /** + * Reports the size in bytes of a native pointer, as stored via {@link + * #putAddress}. This value will be either 4 or 8. Note that the sizes of + * other primitive types (as stored in native memory blocks) is determined + * fully by their information content. + */ + public int addressSize() { + return ADDRESS_SIZE; + } + + /** The value of {@code addressSize()} */ + public static final int ADDRESS_SIZE = ADDRESS_SIZE0; + + /** + * Reports the size in bytes of a native memory page (whatever that is). + * This value will always be a power of two. + */ + public int pageSize() { return PAGE_SIZE; } + + /** + * Reports the size in bytes of a data cache line written back by + * the hardware cache line flush operation available to the JVM or + * 0 if data cache line flushing is not enabled. + */ + public int dataCacheLineFlushSize() { return DATA_CACHE_LINE_FLUSH_SIZE; } + + /** + * Rounds down address to a data cache line boundary as + * determined by {@link #dataCacheLineFlushSize} + * @return the rounded down address + */ + public long dataCacheLineAlignDown(long address) { + return (address & ~(DATA_CACHE_LINE_FLUSH_SIZE - 1)); + } + + /** + * Returns true if data cache line writeback + */ + public static boolean isWritebackEnabled() { return DATA_CACHE_LINE_FLUSH_SIZE != 0; } + + //--- random trusted operations from JNI: + + /** + * Tells the VM to define a class, without security checks. By default, the + * class loader and protection domain come from the caller's class. + */ + public Class defineClass(String name, byte[] b, int off, int len, + ClassLoader loader, + ProtectionDomain protectionDomain) { + if (b == null) { + throw new NullPointerException(); + } + if (len < 0) { + throw new ArrayIndexOutOfBoundsException(); + } + + return defineClass0(name, b, off, len, loader, protectionDomain); + } + + public native Class defineClass0(String name, byte[] b, int off, int len, + ClassLoader loader, + ProtectionDomain protectionDomain); + + /** + * Allocates an instance but does not run any constructor. + * Initializes the class if it has not yet been. + */ + @IntrinsicCandidate + public native Object allocateInstance(Class cls) + throws InstantiationException; + + /** + * Allocates an array of a given type, but does not do zeroing. + *

    + * This method should only be used in the very rare cases where a high-performance code + * overwrites the destination array completely, and compilers cannot assist in zeroing elimination. + * In an overwhelming majority of cases, a normal Java allocation should be used instead. + *

    + * Users of this method are required to overwrite the initial (garbage) array contents + * before allowing untrusted code, or code in other threads, to observe the reference + * to the newly allocated array. In addition, the publication of the array reference must be + * safe according to the Java Memory Model requirements. + *

    + * The safest approach to deal with an uninitialized array is to keep the reference to it in local + * variable at least until the initialization is complete, and then publish it once, either + * by writing it to a volatile field, or storing it into a final field in constructor, + * or issuing a {@link #storeFence} before publishing the reference. + *

    + * @implnote This method can only allocate primitive arrays, to avoid garbage reference + * elements that could break heap integrity. + * + * @param componentType array component type to allocate + * @param length array size to allocate + * @throws IllegalArgumentException if component type is null, or not a primitive class; + * or the length is negative + */ + public Object allocateUninitializedArray(Class componentType, int length) { + if (componentType == null) { + throw new IllegalArgumentException("Component type is null"); + } + if (!componentType.isPrimitive()) { + throw new IllegalArgumentException("Component type is not primitive"); + } + if (length < 0) { + throw new IllegalArgumentException("Negative length"); + } + return allocateUninitializedArray0(componentType, length); + } + + @IntrinsicCandidate + private Object allocateUninitializedArray0(Class componentType, int length) { + // These fallbacks provide zeroed arrays, but intrinsic is not required to + // return the zeroed arrays. + if (componentType == byte.class) return new byte[length]; + if (componentType == boolean.class) return new boolean[length]; + if (componentType == short.class) return new short[length]; + if (componentType == char.class) return new char[length]; + if (componentType == int.class) return new int[length]; + if (componentType == float.class) return new float[length]; + if (componentType == long.class) return new long[length]; + if (componentType == double.class) return new double[length]; + return null; + } + + /** Throws the exception without telling the verifier. */ + public native void throwException(Throwable ee); + + /** + * Atomically updates Java variable to {@code x} if it is currently + * holding {@code expected}. + * + *

    This operation has memory semantics of a {@code volatile} read + * and write. Corresponds to C11 atomic_compare_exchange_strong. + * + * @return {@code true} if successful + */ + @IntrinsicCandidate + public final native boolean compareAndSetReference(Object o, long offset, + Object expected, + Object x); + + @IntrinsicCandidate + public final native Object compareAndExchangeReference(Object o, long offset, + Object expected, + Object x); + + @IntrinsicCandidate + public final Object compareAndExchangeReferenceAcquire(Object o, long offset, + Object expected, + Object x) { + return compareAndExchangeReference(o, offset, expected, x); + } + + @IntrinsicCandidate + public final Object compareAndExchangeReferenceRelease(Object o, long offset, + Object expected, + Object x) { + return compareAndExchangeReference(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetReferencePlain(Object o, long offset, + Object expected, + Object x) { + return compareAndSetReference(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetReferenceAcquire(Object o, long offset, + Object expected, + Object x) { + return compareAndSetReference(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetReferenceRelease(Object o, long offset, + Object expected, + Object x) { + return compareAndSetReference(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetReference(Object o, long offset, + Object expected, + Object x) { + return compareAndSetReference(o, offset, expected, x); + } + + /** + * Atomically updates Java variable to {@code x} if it is currently + * holding {@code expected}. + * + *

    This operation has memory semantics of a {@code volatile} read + * and write. Corresponds to C11 atomic_compare_exchange_strong. + * + * @return {@code true} if successful + */ + @IntrinsicCandidate + public final native boolean compareAndSetInt(Object o, long offset, + int expected, + int x); + + @IntrinsicCandidate + public final native int compareAndExchangeInt(Object o, long offset, + int expected, + int x); + + @IntrinsicCandidate + public final int compareAndExchangeIntAcquire(Object o, long offset, + int expected, + int x) { + return compareAndExchangeInt(o, offset, expected, x); + } + + @IntrinsicCandidate + public final int compareAndExchangeIntRelease(Object o, long offset, + int expected, + int x) { + return compareAndExchangeInt(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetIntPlain(Object o, long offset, + int expected, + int x) { + return compareAndSetInt(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetIntAcquire(Object o, long offset, + int expected, + int x) { + return compareAndSetInt(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetIntRelease(Object o, long offset, + int expected, + int x) { + return compareAndSetInt(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetInt(Object o, long offset, + int expected, + int x) { + return compareAndSetInt(o, offset, expected, x); + } + + @IntrinsicCandidate + public final byte compareAndExchangeByte(Object o, long offset, + byte expected, + byte x) { + long wordOffset = offset & ~3; + int shift = (int) (offset & 3) << 3; + if (BIG_ENDIAN) { + shift = 24 - shift; + } + int mask = 0xFF << shift; + int maskedExpected = (expected & 0xFF) << shift; + int maskedX = (x & 0xFF) << shift; + int fullWord; + do { + fullWord = getIntVolatile(o, wordOffset); + if ((fullWord & mask) != maskedExpected) + return (byte) ((fullWord & mask) >> shift); + } while (!weakCompareAndSetInt(o, wordOffset, + fullWord, (fullWord & ~mask) | maskedX)); + return expected; + } + + @IntrinsicCandidate + public final boolean compareAndSetByte(Object o, long offset, + byte expected, + byte x) { + return compareAndExchangeByte(o, offset, expected, x) == expected; + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetByte(Object o, long offset, + byte expected, + byte x) { + return compareAndSetByte(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetByteAcquire(Object o, long offset, + byte expected, + byte x) { + return weakCompareAndSetByte(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetByteRelease(Object o, long offset, + byte expected, + byte x) { + return weakCompareAndSetByte(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetBytePlain(Object o, long offset, + byte expected, + byte x) { + return weakCompareAndSetByte(o, offset, expected, x); + } + + @IntrinsicCandidate + public final byte compareAndExchangeByteAcquire(Object o, long offset, + byte expected, + byte x) { + return compareAndExchangeByte(o, offset, expected, x); + } + + @IntrinsicCandidate + public final byte compareAndExchangeByteRelease(Object o, long offset, + byte expected, + byte x) { + return compareAndExchangeByte(o, offset, expected, x); + } + + @IntrinsicCandidate + public final short compareAndExchangeShort(Object o, long offset, + short expected, + short x) { + if ((offset & 3) == 3) { + throw new IllegalArgumentException("Update spans the word, not supported"); + } + long wordOffset = offset & ~3; + int shift = (int) (offset & 3) << 3; + if (BIG_ENDIAN) { + shift = 16 - shift; + } + int mask = 0xFFFF << shift; + int maskedExpected = (expected & 0xFFFF) << shift; + int maskedX = (x & 0xFFFF) << shift; + int fullWord; + do { + fullWord = getIntVolatile(o, wordOffset); + if ((fullWord & mask) != maskedExpected) { + return (short) ((fullWord & mask) >> shift); + } + } while (!weakCompareAndSetInt(o, wordOffset, + fullWord, (fullWord & ~mask) | maskedX)); + return expected; + } + + @IntrinsicCandidate + public final boolean compareAndSetShort(Object o, long offset, + short expected, + short x) { + return compareAndExchangeShort(o, offset, expected, x) == expected; + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetShort(Object o, long offset, + short expected, + short x) { + return compareAndSetShort(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetShortAcquire(Object o, long offset, + short expected, + short x) { + return weakCompareAndSetShort(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetShortRelease(Object o, long offset, + short expected, + short x) { + return weakCompareAndSetShort(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetShortPlain(Object o, long offset, + short expected, + short x) { + return weakCompareAndSetShort(o, offset, expected, x); + } + + + @IntrinsicCandidate + public final short compareAndExchangeShortAcquire(Object o, long offset, + short expected, + short x) { + return compareAndExchangeShort(o, offset, expected, x); + } + + @IntrinsicCandidate + public final short compareAndExchangeShortRelease(Object o, long offset, + short expected, + short x) { + return compareAndExchangeShort(o, offset, expected, x); + } + + @ForceInline + private char s2c(short s) { + return (char) s; + } + + @ForceInline + private short c2s(char s) { + return (short) s; + } + + @ForceInline + public final boolean compareAndSetChar(Object o, long offset, + char expected, + char x) { + return compareAndSetShort(o, offset, c2s(expected), c2s(x)); + } + + @ForceInline + public final char compareAndExchangeChar(Object o, long offset, + char expected, + char x) { + return s2c(compareAndExchangeShort(o, offset, c2s(expected), c2s(x))); + } + + @ForceInline + public final char compareAndExchangeCharAcquire(Object o, long offset, + char expected, + char x) { + return s2c(compareAndExchangeShortAcquire(o, offset, c2s(expected), c2s(x))); + } + + @ForceInline + public final char compareAndExchangeCharRelease(Object o, long offset, + char expected, + char x) { + return s2c(compareAndExchangeShortRelease(o, offset, c2s(expected), c2s(x))); + } + + @ForceInline + public final boolean weakCompareAndSetChar(Object o, long offset, + char expected, + char x) { + return weakCompareAndSetShort(o, offset, c2s(expected), c2s(x)); + } + + @ForceInline + public final boolean weakCompareAndSetCharAcquire(Object o, long offset, + char expected, + char x) { + return weakCompareAndSetShortAcquire(o, offset, c2s(expected), c2s(x)); + } + + @ForceInline + public final boolean weakCompareAndSetCharRelease(Object o, long offset, + char expected, + char x) { + return weakCompareAndSetShortRelease(o, offset, c2s(expected), c2s(x)); + } + + @ForceInline + public final boolean weakCompareAndSetCharPlain(Object o, long offset, + char expected, + char x) { + return weakCompareAndSetShortPlain(o, offset, c2s(expected), c2s(x)); + } + + /** + * The JVM converts integral values to boolean values using two + * different conventions, byte testing against zero and truncation + * to least-significant bit. + * + *

    The JNI documents specify that, at least for returning + * values from native methods, a Java boolean value is converted + * to the value-set 0..1 by first truncating to a byte (0..255 or + * maybe -128..127) and then testing against zero. Thus, Java + * booleans in non-Java data structures are by convention + * represented as 8-bit containers containing either zero (for + * false) or any non-zero value (for true). + * + *

    Java booleans in the heap are also stored in bytes, but are + * strongly normalized to the value-set 0..1 (i.e., they are + * truncated to the least-significant bit). + * + *

    The main reason for having different conventions for + * conversion is performance: Truncation to the least-significant + * bit can be usually implemented with fewer (machine) + * instructions than byte testing against zero. + * + *

    A number of Unsafe methods load boolean values from the heap + * as bytes. Unsafe converts those values according to the JNI + * rules (i.e, using the "testing against zero" convention). The + * method {@code byte2bool} implements that conversion. + * + * @param b the byte to be converted to boolean + * @return the result of the conversion + */ + @ForceInline + private boolean byte2bool(byte b) { + return b != 0; + } + + /** + * Convert a boolean value to a byte. The return value is strongly + * normalized to the value-set 0..1 (i.e., the value is truncated + * to the least-significant bit). See {@link #byte2bool(byte)} for + * more details on conversion conventions. + * + * @param b the boolean to be converted to byte (and then normalized) + * @return the result of the conversion + */ + @ForceInline + private byte bool2byte(boolean b) { + return b ? (byte)1 : (byte)0; + } + + @ForceInline + public final boolean compareAndSetBoolean(Object o, long offset, + boolean expected, + boolean x) { + return compareAndSetByte(o, offset, bool2byte(expected), bool2byte(x)); + } + + @ForceInline + public final boolean compareAndExchangeBoolean(Object o, long offset, + boolean expected, + boolean x) { + return byte2bool(compareAndExchangeByte(o, offset, bool2byte(expected), bool2byte(x))); + } + + @ForceInline + public final boolean compareAndExchangeBooleanAcquire(Object o, long offset, + boolean expected, + boolean x) { + return byte2bool(compareAndExchangeByteAcquire(o, offset, bool2byte(expected), bool2byte(x))); + } + + @ForceInline + public final boolean compareAndExchangeBooleanRelease(Object o, long offset, + boolean expected, + boolean x) { + return byte2bool(compareAndExchangeByteRelease(o, offset, bool2byte(expected), bool2byte(x))); + } + + @ForceInline + public final boolean weakCompareAndSetBoolean(Object o, long offset, + boolean expected, + boolean x) { + return weakCompareAndSetByte(o, offset, bool2byte(expected), bool2byte(x)); + } + + @ForceInline + public final boolean weakCompareAndSetBooleanAcquire(Object o, long offset, + boolean expected, + boolean x) { + return weakCompareAndSetByteAcquire(o, offset, bool2byte(expected), bool2byte(x)); + } + + @ForceInline + public final boolean weakCompareAndSetBooleanRelease(Object o, long offset, + boolean expected, + boolean x) { + return weakCompareAndSetByteRelease(o, offset, bool2byte(expected), bool2byte(x)); + } + + @ForceInline + public final boolean weakCompareAndSetBooleanPlain(Object o, long offset, + boolean expected, + boolean x) { + return weakCompareAndSetBytePlain(o, offset, bool2byte(expected), bool2byte(x)); + } + + /** + * Atomically updates Java variable to {@code x} if it is currently + * holding {@code expected}. + * + *

    This operation has memory semantics of a {@code volatile} read + * and write. Corresponds to C11 atomic_compare_exchange_strong. + * + * @return {@code true} if successful + */ + @ForceInline + public final boolean compareAndSetFloat(Object o, long offset, + float expected, + float x) { + return compareAndSetInt(o, offset, + Float.floatToRawIntBits(expected), + Float.floatToRawIntBits(x)); + } + + @ForceInline + public final float compareAndExchangeFloat(Object o, long offset, + float expected, + float x) { + int w = compareAndExchangeInt(o, offset, + Float.floatToRawIntBits(expected), + Float.floatToRawIntBits(x)); + return Float.intBitsToFloat(w); + } + + @ForceInline + public final float compareAndExchangeFloatAcquire(Object o, long offset, + float expected, + float x) { + int w = compareAndExchangeIntAcquire(o, offset, + Float.floatToRawIntBits(expected), + Float.floatToRawIntBits(x)); + return Float.intBitsToFloat(w); + } + + @ForceInline + public final float compareAndExchangeFloatRelease(Object o, long offset, + float expected, + float x) { + int w = compareAndExchangeIntRelease(o, offset, + Float.floatToRawIntBits(expected), + Float.floatToRawIntBits(x)); + return Float.intBitsToFloat(w); + } + + @ForceInline + public final boolean weakCompareAndSetFloatPlain(Object o, long offset, + float expected, + float x) { + return weakCompareAndSetIntPlain(o, offset, + Float.floatToRawIntBits(expected), + Float.floatToRawIntBits(x)); + } + + @ForceInline + public final boolean weakCompareAndSetFloatAcquire(Object o, long offset, + float expected, + float x) { + return weakCompareAndSetIntAcquire(o, offset, + Float.floatToRawIntBits(expected), + Float.floatToRawIntBits(x)); + } + + @ForceInline + public final boolean weakCompareAndSetFloatRelease(Object o, long offset, + float expected, + float x) { + return weakCompareAndSetIntRelease(o, offset, + Float.floatToRawIntBits(expected), + Float.floatToRawIntBits(x)); + } + + @ForceInline + public final boolean weakCompareAndSetFloat(Object o, long offset, + float expected, + float x) { + return weakCompareAndSetInt(o, offset, + Float.floatToRawIntBits(expected), + Float.floatToRawIntBits(x)); + } + + /** + * Atomically updates Java variable to {@code x} if it is currently + * holding {@code expected}. + * + *

    This operation has memory semantics of a {@code volatile} read + * and write. Corresponds to C11 atomic_compare_exchange_strong. + * + * @return {@code true} if successful + */ + @ForceInline + public final boolean compareAndSetDouble(Object o, long offset, + double expected, + double x) { + return compareAndSetLong(o, offset, + Double.doubleToRawLongBits(expected), + Double.doubleToRawLongBits(x)); + } + + @ForceInline + public final double compareAndExchangeDouble(Object o, long offset, + double expected, + double x) { + long w = compareAndExchangeLong(o, offset, + Double.doubleToRawLongBits(expected), + Double.doubleToRawLongBits(x)); + return Double.longBitsToDouble(w); + } + + @ForceInline + public final double compareAndExchangeDoubleAcquire(Object o, long offset, + double expected, + double x) { + long w = compareAndExchangeLongAcquire(o, offset, + Double.doubleToRawLongBits(expected), + Double.doubleToRawLongBits(x)); + return Double.longBitsToDouble(w); + } + + @ForceInline + public final double compareAndExchangeDoubleRelease(Object o, long offset, + double expected, + double x) { + long w = compareAndExchangeLongRelease(o, offset, + Double.doubleToRawLongBits(expected), + Double.doubleToRawLongBits(x)); + return Double.longBitsToDouble(w); + } + + @ForceInline + public final boolean weakCompareAndSetDoublePlain(Object o, long offset, + double expected, + double x) { + return weakCompareAndSetLongPlain(o, offset, + Double.doubleToRawLongBits(expected), + Double.doubleToRawLongBits(x)); + } + + @ForceInline + public final boolean weakCompareAndSetDoubleAcquire(Object o, long offset, + double expected, + double x) { + return weakCompareAndSetLongAcquire(o, offset, + Double.doubleToRawLongBits(expected), + Double.doubleToRawLongBits(x)); + } + + @ForceInline + public final boolean weakCompareAndSetDoubleRelease(Object o, long offset, + double expected, + double x) { + return weakCompareAndSetLongRelease(o, offset, + Double.doubleToRawLongBits(expected), + Double.doubleToRawLongBits(x)); + } + + @ForceInline + public final boolean weakCompareAndSetDouble(Object o, long offset, + double expected, + double x) { + return weakCompareAndSetLong(o, offset, + Double.doubleToRawLongBits(expected), + Double.doubleToRawLongBits(x)); + } + + /** + * Atomically updates Java variable to {@code x} if it is currently + * holding {@code expected}. + * + *

    This operation has memory semantics of a {@code volatile} read + * and write. Corresponds to C11 atomic_compare_exchange_strong. + * + * @return {@code true} if successful + */ + @IntrinsicCandidate + public final native boolean compareAndSetLong(Object o, long offset, + long expected, + long x); + + @IntrinsicCandidate + public final native long compareAndExchangeLong(Object o, long offset, + long expected, + long x); + + @IntrinsicCandidate + public final long compareAndExchangeLongAcquire(Object o, long offset, + long expected, + long x) { + return compareAndExchangeLong(o, offset, expected, x); + } + + @IntrinsicCandidate + public final long compareAndExchangeLongRelease(Object o, long offset, + long expected, + long x) { + return compareAndExchangeLong(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetLongPlain(Object o, long offset, + long expected, + long x) { + return compareAndSetLong(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetLongAcquire(Object o, long offset, + long expected, + long x) { + return compareAndSetLong(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetLongRelease(Object o, long offset, + long expected, + long x) { + return compareAndSetLong(o, offset, expected, x); + } + + @IntrinsicCandidate + public final boolean weakCompareAndSetLong(Object o, long offset, + long expected, + long x) { + return compareAndSetLong(o, offset, expected, x); + } + + /** + * Fetches a reference value from a given Java variable, with volatile + * load semantics. Otherwise identical to {@link #getReference(Object, long)} + */ + @IntrinsicCandidate + public native Object getReferenceVolatile(Object o, long offset); + + /** + * Stores a reference value into a given Java variable, with + * volatile store semantics. Otherwise identical to {@link #putReference(Object, long, Object)} + */ + @IntrinsicCandidate + public native void putReferenceVolatile(Object o, long offset, Object x); + + /** Volatile version of {@link #getInt(Object, long)} */ + @IntrinsicCandidate + public native int getIntVolatile(Object o, long offset); + + /** Volatile version of {@link #putInt(Object, long, int)} */ + @IntrinsicCandidate + public native void putIntVolatile(Object o, long offset, int x); + + /** Volatile version of {@link #getBoolean(Object, long)} */ + @IntrinsicCandidate + public native boolean getBooleanVolatile(Object o, long offset); + + /** Volatile version of {@link #putBoolean(Object, long, boolean)} */ + @IntrinsicCandidate + public native void putBooleanVolatile(Object o, long offset, boolean x); + + /** Volatile version of {@link #getByte(Object, long)} */ + @IntrinsicCandidate + public native byte getByteVolatile(Object o, long offset); + + /** Volatile version of {@link #putByte(Object, long, byte)} */ + @IntrinsicCandidate + public native void putByteVolatile(Object o, long offset, byte x); + + /** Volatile version of {@link #getShort(Object, long)} */ + @IntrinsicCandidate + public native short getShortVolatile(Object o, long offset); + + /** Volatile version of {@link #putShort(Object, long, short)} */ + @IntrinsicCandidate + public native void putShortVolatile(Object o, long offset, short x); + + /** Volatile version of {@link #getChar(Object, long)} */ + @IntrinsicCandidate + public native char getCharVolatile(Object o, long offset); + + /** Volatile version of {@link #putChar(Object, long, char)} */ + @IntrinsicCandidate + public native void putCharVolatile(Object o, long offset, char x); + + /** Volatile version of {@link #getLong(Object, long)} */ + @IntrinsicCandidate + public native long getLongVolatile(Object o, long offset); + + /** Volatile version of {@link #putLong(Object, long, long)} */ + @IntrinsicCandidate + public native void putLongVolatile(Object o, long offset, long x); + + /** Volatile version of {@link #getFloat(Object, long)} */ + @IntrinsicCandidate + public native float getFloatVolatile(Object o, long offset); + + /** Volatile version of {@link #putFloat(Object, long, float)} */ + @IntrinsicCandidate + public native void putFloatVolatile(Object o, long offset, float x); + + /** Volatile version of {@link #getDouble(Object, long)} */ + @IntrinsicCandidate + public native double getDoubleVolatile(Object o, long offset); + + /** Volatile version of {@link #putDouble(Object, long, double)} */ + @IntrinsicCandidate + public native void putDoubleVolatile(Object o, long offset, double x); + + + + /** Acquire version of {@link #getReferenceVolatile(Object, long)} */ + @IntrinsicCandidate + public final Object getReferenceAcquire(Object o, long offset) { + return getReferenceVolatile(o, offset); + } + + /** Acquire version of {@link #getBooleanVolatile(Object, long)} */ + @IntrinsicCandidate + public final boolean getBooleanAcquire(Object o, long offset) { + return getBooleanVolatile(o, offset); + } + + /** Acquire version of {@link #getByteVolatile(Object, long)} */ + @IntrinsicCandidate + public final byte getByteAcquire(Object o, long offset) { + return getByteVolatile(o, offset); + } + + /** Acquire version of {@link #getShortVolatile(Object, long)} */ + @IntrinsicCandidate + public final short getShortAcquire(Object o, long offset) { + return getShortVolatile(o, offset); + } + + /** Acquire version of {@link #getCharVolatile(Object, long)} */ + @IntrinsicCandidate + public final char getCharAcquire(Object o, long offset) { + return getCharVolatile(o, offset); + } + + /** Acquire version of {@link #getIntVolatile(Object, long)} */ + @IntrinsicCandidate + public final int getIntAcquire(Object o, long offset) { + return getIntVolatile(o, offset); + } + + /** Acquire version of {@link #getFloatVolatile(Object, long)} */ + @IntrinsicCandidate + public final float getFloatAcquire(Object o, long offset) { + return getFloatVolatile(o, offset); + } + + /** Acquire version of {@link #getLongVolatile(Object, long)} */ + @IntrinsicCandidate + public final long getLongAcquire(Object o, long offset) { + return getLongVolatile(o, offset); + } + + /** Acquire version of {@link #getDoubleVolatile(Object, long)} */ + @IntrinsicCandidate + public final double getDoubleAcquire(Object o, long offset) { + return getDoubleVolatile(o, offset); + } + + /* + * Versions of {@link #putReferenceVolatile(Object, long, Object)} + * that do not guarantee immediate visibility of the store to + * other threads. This method is generally only useful if the + * underlying field is a Java volatile (or if an array cell, one + * that is otherwise only accessed using volatile accesses). + * + * Corresponds to C11 atomic_store_explicit(..., memory_order_release). + */ + + /** Release version of {@link #putReferenceVolatile(Object, long, Object)} */ + @IntrinsicCandidate + public final void putReferenceRelease(Object o, long offset, Object x) { + putReferenceVolatile(o, offset, x); + } + + /** Release version of {@link #putBooleanVolatile(Object, long, boolean)} */ + @IntrinsicCandidate + public final void putBooleanRelease(Object o, long offset, boolean x) { + putBooleanVolatile(o, offset, x); + } + + /** Release version of {@link #putByteVolatile(Object, long, byte)} */ + @IntrinsicCandidate + public final void putByteRelease(Object o, long offset, byte x) { + putByteVolatile(o, offset, x); + } + + /** Release version of {@link #putShortVolatile(Object, long, short)} */ + @IntrinsicCandidate + public final void putShortRelease(Object o, long offset, short x) { + putShortVolatile(o, offset, x); + } + + /** Release version of {@link #putCharVolatile(Object, long, char)} */ + @IntrinsicCandidate + public final void putCharRelease(Object o, long offset, char x) { + putCharVolatile(o, offset, x); + } + + /** Release version of {@link #putIntVolatile(Object, long, int)} */ + @IntrinsicCandidate + public final void putIntRelease(Object o, long offset, int x) { + putIntVolatile(o, offset, x); + } + + /** Release version of {@link #putFloatVolatile(Object, long, float)} */ + @IntrinsicCandidate + public final void putFloatRelease(Object o, long offset, float x) { + putFloatVolatile(o, offset, x); + } + + /** Release version of {@link #putLongVolatile(Object, long, long)} */ + @IntrinsicCandidate + public final void putLongRelease(Object o, long offset, long x) { + putLongVolatile(o, offset, x); + } + + /** Release version of {@link #putDoubleVolatile(Object, long, double)} */ + @IntrinsicCandidate + public final void putDoubleRelease(Object o, long offset, double x) { + putDoubleVolatile(o, offset, x); + } + + // ------------------------------ Opaque -------------------------------------- + + /** Opaque version of {@link #getReferenceVolatile(Object, long)} */ + @IntrinsicCandidate + public final Object getReferenceOpaque(Object o, long offset) { + return getReferenceVolatile(o, offset); + } + + /** Opaque version of {@link #getBooleanVolatile(Object, long)} */ + @IntrinsicCandidate + public final boolean getBooleanOpaque(Object o, long offset) { + return getBooleanVolatile(o, offset); + } + + /** Opaque version of {@link #getByteVolatile(Object, long)} */ + @IntrinsicCandidate + public final byte getByteOpaque(Object o, long offset) { + return getByteVolatile(o, offset); + } + + /** Opaque version of {@link #getShortVolatile(Object, long)} */ + @IntrinsicCandidate + public final short getShortOpaque(Object o, long offset) { + return getShortVolatile(o, offset); + } + + /** Opaque version of {@link #getCharVolatile(Object, long)} */ + @IntrinsicCandidate + public final char getCharOpaque(Object o, long offset) { + return getCharVolatile(o, offset); + } + + /** Opaque version of {@link #getIntVolatile(Object, long)} */ + @IntrinsicCandidate + public final int getIntOpaque(Object o, long offset) { + return getIntVolatile(o, offset); + } + + /** Opaque version of {@link #getFloatVolatile(Object, long)} */ + @IntrinsicCandidate + public final float getFloatOpaque(Object o, long offset) { + return getFloatVolatile(o, offset); + } + + /** Opaque version of {@link #getLongVolatile(Object, long)} */ + @IntrinsicCandidate + public final long getLongOpaque(Object o, long offset) { + return getLongVolatile(o, offset); + } + + /** Opaque version of {@link #getDoubleVolatile(Object, long)} */ + @IntrinsicCandidate + public final double getDoubleOpaque(Object o, long offset) { + return getDoubleVolatile(o, offset); + } + + /** Opaque version of {@link #putReferenceVolatile(Object, long, Object)} */ + @IntrinsicCandidate + public final void putReferenceOpaque(Object o, long offset, Object x) { + putReferenceVolatile(o, offset, x); + } + + /** Opaque version of {@link #putBooleanVolatile(Object, long, boolean)} */ + @IntrinsicCandidate + public final void putBooleanOpaque(Object o, long offset, boolean x) { + putBooleanVolatile(o, offset, x); + } + + /** Opaque version of {@link #putByteVolatile(Object, long, byte)} */ + @IntrinsicCandidate + public final void putByteOpaque(Object o, long offset, byte x) { + putByteVolatile(o, offset, x); + } + + /** Opaque version of {@link #putShortVolatile(Object, long, short)} */ + @IntrinsicCandidate + public final void putShortOpaque(Object o, long offset, short x) { + putShortVolatile(o, offset, x); + } + + /** Opaque version of {@link #putCharVolatile(Object, long, char)} */ + @IntrinsicCandidate + public final void putCharOpaque(Object o, long offset, char x) { + putCharVolatile(o, offset, x); + } + + /** Opaque version of {@link #putIntVolatile(Object, long, int)} */ + @IntrinsicCandidate + public final void putIntOpaque(Object o, long offset, int x) { + putIntVolatile(o, offset, x); + } + + /** Opaque version of {@link #putFloatVolatile(Object, long, float)} */ + @IntrinsicCandidate + public final void putFloatOpaque(Object o, long offset, float x) { + putFloatVolatile(o, offset, x); + } + + /** Opaque version of {@link #putLongVolatile(Object, long, long)} */ + @IntrinsicCandidate + public final void putLongOpaque(Object o, long offset, long x) { + putLongVolatile(o, offset, x); + } + + /** Opaque version of {@link #putDoubleVolatile(Object, long, double)} */ + @IntrinsicCandidate + public final void putDoubleOpaque(Object o, long offset, double x) { + putDoubleVolatile(o, offset, x); + } + + /** + * Unblocks the given thread blocked on {@code park}, or, if it is + * not blocked, causes the subsequent call to {@code park} not to + * block. Note: this operation is "unsafe" solely because the + * caller must somehow ensure that the thread has not been + * destroyed. Nothing special is usually required to ensure this + * when called from Java (in which there will ordinarily be a live + * reference to the thread) but this is not nearly-automatically + * so when calling from native code. + * + * @param thread the thread to unpark. + */ + @IntrinsicCandidate + public native void unpark(Object thread); + + /** + * Blocks current thread, returning when a balancing + * {@code unpark} occurs, or a balancing {@code unpark} has + * already occurred, or the thread is interrupted, or, if not + * absolute and time is not zero, the given time nanoseconds have + * elapsed, or if absolute, the given deadline in milliseconds + * since Epoch has passed, or spuriously (i.e., returning for no + * "reason"). Note: This operation is in the Unsafe class only + * because {@code unpark} is, so it would be strange to place it + * elsewhere. + */ + @IntrinsicCandidate + public native void park(boolean isAbsolute, long time); + + /** + * Gets the load average in the system run queue assigned + * to the available processors averaged over various periods of time. + * This method retrieves the given {@code nelem} samples and + * assigns to the elements of the given {@code loadavg} array. + * The system imposes a maximum of 3 samples, representing + * averages over the last 1, 5, and 15 minutes, respectively. + * + * @param loadavg an array of double of size nelems + * @param nelems the number of samples to be retrieved and + * must be 1 to 3. + * + * @return the number of samples actually retrieved; or -1 + * if the load average is unobtainable. + */ + public int getLoadAverage(double[] loadavg, int nelems) { + if (nelems < 0 || nelems > 3 || nelems > loadavg.length) { + throw new ArrayIndexOutOfBoundsException(); + } + + return getLoadAverage0(loadavg, nelems); + } + + // The following contain CAS-based Java implementations used on + // platforms not supporting native instructions + + /** + * Atomically adds the given value to the current value of a field + * or array element within the given object {@code o} + * at the given {@code offset}. + * + * @param o object/array to update the field/element in + * @param offset field/element offset + * @param delta the value to add + * @return the previous value + * @since 1.8 + */ + @IntrinsicCandidate + public final int getAndAddInt(Object o, long offset, int delta) { + int v; + do { + v = getIntVolatile(o, offset); + } while (!weakCompareAndSetInt(o, offset, v, v + delta)); + return v; + } + + @ForceInline + public final int getAndAddIntRelease(Object o, long offset, int delta) { + int v; + do { + v = getInt(o, offset); + } while (!weakCompareAndSetIntRelease(o, offset, v, v + delta)); + return v; + } + + @ForceInline + public final int getAndAddIntAcquire(Object o, long offset, int delta) { + int v; + do { + v = getIntAcquire(o, offset); + } while (!weakCompareAndSetIntAcquire(o, offset, v, v + delta)); + return v; + } + + /** + * Atomically adds the given value to the current value of a field + * or array element within the given object {@code o} + * at the given {@code offset}. + * + * @param o object/array to update the field/element in + * @param offset field/element offset + * @param delta the value to add + * @return the previous value + * @since 1.8 + */ + @IntrinsicCandidate + public final long getAndAddLong(Object o, long offset, long delta) { + long v; + do { + v = getLongVolatile(o, offset); + } while (!weakCompareAndSetLong(o, offset, v, v + delta)); + return v; + } + + @ForceInline + public final long getAndAddLongRelease(Object o, long offset, long delta) { + long v; + do { + v = getLong(o, offset); + } while (!weakCompareAndSetLongRelease(o, offset, v, v + delta)); + return v; + } + + @ForceInline + public final long getAndAddLongAcquire(Object o, long offset, long delta) { + long v; + do { + v = getLongAcquire(o, offset); + } while (!weakCompareAndSetLongAcquire(o, offset, v, v + delta)); + return v; + } + + @IntrinsicCandidate + public final byte getAndAddByte(Object o, long offset, byte delta) { + byte v; + do { + v = getByteVolatile(o, offset); + } while (!weakCompareAndSetByte(o, offset, v, (byte) (v + delta))); + return v; + } + + @ForceInline + public final byte getAndAddByteRelease(Object o, long offset, byte delta) { + byte v; + do { + v = getByte(o, offset); + } while (!weakCompareAndSetByteRelease(o, offset, v, (byte) (v + delta))); + return v; + } + + @ForceInline + public final byte getAndAddByteAcquire(Object o, long offset, byte delta) { + byte v; + do { + v = getByteAcquire(o, offset); + } while (!weakCompareAndSetByteAcquire(o, offset, v, (byte) (v + delta))); + return v; + } + + @IntrinsicCandidate + public final short getAndAddShort(Object o, long offset, short delta) { + short v; + do { + v = getShortVolatile(o, offset); + } while (!weakCompareAndSetShort(o, offset, v, (short) (v + delta))); + return v; + } + + @ForceInline + public final short getAndAddShortRelease(Object o, long offset, short delta) { + short v; + do { + v = getShort(o, offset); + } while (!weakCompareAndSetShortRelease(o, offset, v, (short) (v + delta))); + return v; + } + + @ForceInline + public final short getAndAddShortAcquire(Object o, long offset, short delta) { + short v; + do { + v = getShortAcquire(o, offset); + } while (!weakCompareAndSetShortAcquire(o, offset, v, (short) (v + delta))); + return v; + } + + @ForceInline + public final char getAndAddChar(Object o, long offset, char delta) { + return (char) getAndAddShort(o, offset, (short) delta); + } + + @ForceInline + public final char getAndAddCharRelease(Object o, long offset, char delta) { + return (char) getAndAddShortRelease(o, offset, (short) delta); + } + + @ForceInline + public final char getAndAddCharAcquire(Object o, long offset, char delta) { + return (char) getAndAddShortAcquire(o, offset, (short) delta); + } + + @ForceInline + public final float getAndAddFloat(Object o, long offset, float delta) { + int expectedBits; + float v; + do { + // Load and CAS with the raw bits to avoid issues with NaNs and + // possible bit conversion from signaling NaNs to quiet NaNs that + // may result in the loop not terminating. + expectedBits = getIntVolatile(o, offset); + v = Float.intBitsToFloat(expectedBits); + } while (!weakCompareAndSetInt(o, offset, + expectedBits, Float.floatToRawIntBits(v + delta))); + return v; + } + + @ForceInline + public final float getAndAddFloatRelease(Object o, long offset, float delta) { + int expectedBits; + float v; + do { + // Load and CAS with the raw bits to avoid issues with NaNs and + // possible bit conversion from signaling NaNs to quiet NaNs that + // may result in the loop not terminating. + expectedBits = getInt(o, offset); + v = Float.intBitsToFloat(expectedBits); + } while (!weakCompareAndSetIntRelease(o, offset, + expectedBits, Float.floatToRawIntBits(v + delta))); + return v; + } + + @ForceInline + public final float getAndAddFloatAcquire(Object o, long offset, float delta) { + int expectedBits; + float v; + do { + // Load and CAS with the raw bits to avoid issues with NaNs and + // possible bit conversion from signaling NaNs to quiet NaNs that + // may result in the loop not terminating. + expectedBits = getIntAcquire(o, offset); + v = Float.intBitsToFloat(expectedBits); + } while (!weakCompareAndSetIntAcquire(o, offset, + expectedBits, Float.floatToRawIntBits(v + delta))); + return v; + } + + @ForceInline + public final double getAndAddDouble(Object o, long offset, double delta) { + long expectedBits; + double v; + do { + // Load and CAS with the raw bits to avoid issues with NaNs and + // possible bit conversion from signaling NaNs to quiet NaNs that + // may result in the loop not terminating. + expectedBits = getLongVolatile(o, offset); + v = Double.longBitsToDouble(expectedBits); + } while (!weakCompareAndSetLong(o, offset, + expectedBits, Double.doubleToRawLongBits(v + delta))); + return v; + } + + @ForceInline + public final double getAndAddDoubleRelease(Object o, long offset, double delta) { + long expectedBits; + double v; + do { + // Load and CAS with the raw bits to avoid issues with NaNs and + // possible bit conversion from signaling NaNs to quiet NaNs that + // may result in the loop not terminating. + expectedBits = getLong(o, offset); + v = Double.longBitsToDouble(expectedBits); + } while (!weakCompareAndSetLongRelease(o, offset, + expectedBits, Double.doubleToRawLongBits(v + delta))); + return v; + } + + @ForceInline + public final double getAndAddDoubleAcquire(Object o, long offset, double delta) { + long expectedBits; + double v; + do { + // Load and CAS with the raw bits to avoid issues with NaNs and + // possible bit conversion from signaling NaNs to quiet NaNs that + // may result in the loop not terminating. + expectedBits = getLongAcquire(o, offset); + v = Double.longBitsToDouble(expectedBits); + } while (!weakCompareAndSetLongAcquire(o, offset, + expectedBits, Double.doubleToRawLongBits(v + delta))); + return v; + } + + /** + * Atomically exchanges the given value with the current value of + * a field or array element within the given object {@code o} + * at the given {@code offset}. + * + * @param o object/array to update the field/element in + * @param offset field/element offset + * @param newValue new value + * @return the previous value + * @since 1.8 + */ + @IntrinsicCandidate + public final int getAndSetInt(Object o, long offset, int newValue) { + int v; + do { + v = getIntVolatile(o, offset); + } while (!weakCompareAndSetInt(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final int getAndSetIntRelease(Object o, long offset, int newValue) { + int v; + do { + v = getInt(o, offset); + } while (!weakCompareAndSetIntRelease(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final int getAndSetIntAcquire(Object o, long offset, int newValue) { + int v; + do { + v = getIntAcquire(o, offset); + } while (!weakCompareAndSetIntAcquire(o, offset, v, newValue)); + return v; + } + + /** + * Atomically exchanges the given value with the current value of + * a field or array element within the given object {@code o} + * at the given {@code offset}. + * + * @param o object/array to update the field/element in + * @param offset field/element offset + * @param newValue new value + * @return the previous value + * @since 1.8 + */ + @IntrinsicCandidate + public final long getAndSetLong(Object o, long offset, long newValue) { + long v; + do { + v = getLongVolatile(o, offset); + } while (!weakCompareAndSetLong(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final long getAndSetLongRelease(Object o, long offset, long newValue) { + long v; + do { + v = getLong(o, offset); + } while (!weakCompareAndSetLongRelease(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final long getAndSetLongAcquire(Object o, long offset, long newValue) { + long v; + do { + v = getLongAcquire(o, offset); + } while (!weakCompareAndSetLongAcquire(o, offset, v, newValue)); + return v; + } + + /** + * Atomically exchanges the given reference value with the current + * reference value of a field or array element within the given + * object {@code o} at the given {@code offset}. + * + * @param o object/array to update the field/element in + * @param offset field/element offset + * @param newValue new value + * @return the previous value + * @since 1.8 + */ + @IntrinsicCandidate + public final Object getAndSetReference(Object o, long offset, Object newValue) { + Object v; + do { + v = getReferenceVolatile(o, offset); + } while (!weakCompareAndSetReference(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final Object getAndSetReferenceRelease(Object o, long offset, Object newValue) { + Object v; + do { + v = getReference(o, offset); + } while (!weakCompareAndSetReferenceRelease(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final Object getAndSetReferenceAcquire(Object o, long offset, Object newValue) { + Object v; + do { + v = getReferenceAcquire(o, offset); + } while (!weakCompareAndSetReferenceAcquire(o, offset, v, newValue)); + return v; + } + + @IntrinsicCandidate + public final byte getAndSetByte(Object o, long offset, byte newValue) { + byte v; + do { + v = getByteVolatile(o, offset); + } while (!weakCompareAndSetByte(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final byte getAndSetByteRelease(Object o, long offset, byte newValue) { + byte v; + do { + v = getByte(o, offset); + } while (!weakCompareAndSetByteRelease(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final byte getAndSetByteAcquire(Object o, long offset, byte newValue) { + byte v; + do { + v = getByteAcquire(o, offset); + } while (!weakCompareAndSetByteAcquire(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final boolean getAndSetBoolean(Object o, long offset, boolean newValue) { + return byte2bool(getAndSetByte(o, offset, bool2byte(newValue))); + } + + @ForceInline + public final boolean getAndSetBooleanRelease(Object o, long offset, boolean newValue) { + return byte2bool(getAndSetByteRelease(o, offset, bool2byte(newValue))); + } + + @ForceInline + public final boolean getAndSetBooleanAcquire(Object o, long offset, boolean newValue) { + return byte2bool(getAndSetByteAcquire(o, offset, bool2byte(newValue))); + } + + @IntrinsicCandidate + public final short getAndSetShort(Object o, long offset, short newValue) { + short v; + do { + v = getShortVolatile(o, offset); + } while (!weakCompareAndSetShort(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final short getAndSetShortRelease(Object o, long offset, short newValue) { + short v; + do { + v = getShort(o, offset); + } while (!weakCompareAndSetShortRelease(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final short getAndSetShortAcquire(Object o, long offset, short newValue) { + short v; + do { + v = getShortAcquire(o, offset); + } while (!weakCompareAndSetShortAcquire(o, offset, v, newValue)); + return v; + } + + @ForceInline + public final char getAndSetChar(Object o, long offset, char newValue) { + return s2c(getAndSetShort(o, offset, c2s(newValue))); + } + + @ForceInline + public final char getAndSetCharRelease(Object o, long offset, char newValue) { + return s2c(getAndSetShortRelease(o, offset, c2s(newValue))); + } + + @ForceInline + public final char getAndSetCharAcquire(Object o, long offset, char newValue) { + return s2c(getAndSetShortAcquire(o, offset, c2s(newValue))); + } + + @ForceInline + public final float getAndSetFloat(Object o, long offset, float newValue) { + int v = getAndSetInt(o, offset, Float.floatToRawIntBits(newValue)); + return Float.intBitsToFloat(v); + } + + @ForceInline + public final float getAndSetFloatRelease(Object o, long offset, float newValue) { + int v = getAndSetIntRelease(o, offset, Float.floatToRawIntBits(newValue)); + return Float.intBitsToFloat(v); + } + + @ForceInline + public final float getAndSetFloatAcquire(Object o, long offset, float newValue) { + int v = getAndSetIntAcquire(o, offset, Float.floatToRawIntBits(newValue)); + return Float.intBitsToFloat(v); + } + + @ForceInline + public final double getAndSetDouble(Object o, long offset, double newValue) { + long v = getAndSetLong(o, offset, Double.doubleToRawLongBits(newValue)); + return Double.longBitsToDouble(v); + } + + @ForceInline + public final double getAndSetDoubleRelease(Object o, long offset, double newValue) { + long v = getAndSetLongRelease(o, offset, Double.doubleToRawLongBits(newValue)); + return Double.longBitsToDouble(v); + } + + @ForceInline + public final double getAndSetDoubleAcquire(Object o, long offset, double newValue) { + long v = getAndSetLongAcquire(o, offset, Double.doubleToRawLongBits(newValue)); + return Double.longBitsToDouble(v); + } + + + // The following contain CAS-based Java implementations used on + // platforms not supporting native instructions + + @ForceInline + public final boolean getAndBitwiseOrBoolean(Object o, long offset, boolean mask) { + return byte2bool(getAndBitwiseOrByte(o, offset, bool2byte(mask))); + } + + @ForceInline + public final boolean getAndBitwiseOrBooleanRelease(Object o, long offset, boolean mask) { + return byte2bool(getAndBitwiseOrByteRelease(o, offset, bool2byte(mask))); + } + + @ForceInline + public final boolean getAndBitwiseOrBooleanAcquire(Object o, long offset, boolean mask) { + return byte2bool(getAndBitwiseOrByteAcquire(o, offset, bool2byte(mask))); + } + + @ForceInline + public final boolean getAndBitwiseAndBoolean(Object o, long offset, boolean mask) { + return byte2bool(getAndBitwiseAndByte(o, offset, bool2byte(mask))); + } + + @ForceInline + public final boolean getAndBitwiseAndBooleanRelease(Object o, long offset, boolean mask) { + return byte2bool(getAndBitwiseAndByteRelease(o, offset, bool2byte(mask))); + } + + @ForceInline + public final boolean getAndBitwiseAndBooleanAcquire(Object o, long offset, boolean mask) { + return byte2bool(getAndBitwiseAndByteAcquire(o, offset, bool2byte(mask))); + } + + @ForceInline + public final boolean getAndBitwiseXorBoolean(Object o, long offset, boolean mask) { + return byte2bool(getAndBitwiseXorByte(o, offset, bool2byte(mask))); + } + + @ForceInline + public final boolean getAndBitwiseXorBooleanRelease(Object o, long offset, boolean mask) { + return byte2bool(getAndBitwiseXorByteRelease(o, offset, bool2byte(mask))); + } + + @ForceInline + public final boolean getAndBitwiseXorBooleanAcquire(Object o, long offset, boolean mask) { + return byte2bool(getAndBitwiseXorByteAcquire(o, offset, bool2byte(mask))); + } + + + @ForceInline + public final byte getAndBitwiseOrByte(Object o, long offset, byte mask) { + byte current; + do { + current = getByteVolatile(o, offset); + } while (!weakCompareAndSetByte(o, offset, + current, (byte) (current | mask))); + return current; + } + + @ForceInline + public final byte getAndBitwiseOrByteRelease(Object o, long offset, byte mask) { + byte current; + do { + current = getByte(o, offset); + } while (!weakCompareAndSetByteRelease(o, offset, + current, (byte) (current | mask))); + return current; + } + + @ForceInline + public final byte getAndBitwiseOrByteAcquire(Object o, long offset, byte mask) { + byte current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getByte(o, offset); + } while (!weakCompareAndSetByteAcquire(o, offset, + current, (byte) (current | mask))); + return current; + } + + @ForceInline + public final byte getAndBitwiseAndByte(Object o, long offset, byte mask) { + byte current; + do { + current = getByteVolatile(o, offset); + } while (!weakCompareAndSetByte(o, offset, + current, (byte) (current & mask))); + return current; + } + + @ForceInline + public final byte getAndBitwiseAndByteRelease(Object o, long offset, byte mask) { + byte current; + do { + current = getByte(o, offset); + } while (!weakCompareAndSetByteRelease(o, offset, + current, (byte) (current & mask))); + return current; + } + + @ForceInline + public final byte getAndBitwiseAndByteAcquire(Object o, long offset, byte mask) { + byte current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getByte(o, offset); + } while (!weakCompareAndSetByteAcquire(o, offset, + current, (byte) (current & mask))); + return current; + } + + @ForceInline + public final byte getAndBitwiseXorByte(Object o, long offset, byte mask) { + byte current; + do { + current = getByteVolatile(o, offset); + } while (!weakCompareAndSetByte(o, offset, + current, (byte) (current ^ mask))); + return current; + } + + @ForceInline + public final byte getAndBitwiseXorByteRelease(Object o, long offset, byte mask) { + byte current; + do { + current = getByte(o, offset); + } while (!weakCompareAndSetByteRelease(o, offset, + current, (byte) (current ^ mask))); + return current; + } + + @ForceInline + public final byte getAndBitwiseXorByteAcquire(Object o, long offset, byte mask) { + byte current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getByte(o, offset); + } while (!weakCompareAndSetByteAcquire(o, offset, + current, (byte) (current ^ mask))); + return current; + } + + + @ForceInline + public final char getAndBitwiseOrChar(Object o, long offset, char mask) { + return s2c(getAndBitwiseOrShort(o, offset, c2s(mask))); + } + + @ForceInline + public final char getAndBitwiseOrCharRelease(Object o, long offset, char mask) { + return s2c(getAndBitwiseOrShortRelease(o, offset, c2s(mask))); + } + + @ForceInline + public final char getAndBitwiseOrCharAcquire(Object o, long offset, char mask) { + return s2c(getAndBitwiseOrShortAcquire(o, offset, c2s(mask))); + } + + @ForceInline + public final char getAndBitwiseAndChar(Object o, long offset, char mask) { + return s2c(getAndBitwiseAndShort(o, offset, c2s(mask))); + } + + @ForceInline + public final char getAndBitwiseAndCharRelease(Object o, long offset, char mask) { + return s2c(getAndBitwiseAndShortRelease(o, offset, c2s(mask))); + } + + @ForceInline + public final char getAndBitwiseAndCharAcquire(Object o, long offset, char mask) { + return s2c(getAndBitwiseAndShortAcquire(o, offset, c2s(mask))); + } + + @ForceInline + public final char getAndBitwiseXorChar(Object o, long offset, char mask) { + return s2c(getAndBitwiseXorShort(o, offset, c2s(mask))); + } + + @ForceInline + public final char getAndBitwiseXorCharRelease(Object o, long offset, char mask) { + return s2c(getAndBitwiseXorShortRelease(o, offset, c2s(mask))); + } + + @ForceInline + public final char getAndBitwiseXorCharAcquire(Object o, long offset, char mask) { + return s2c(getAndBitwiseXorShortAcquire(o, offset, c2s(mask))); + } + + + @ForceInline + public final short getAndBitwiseOrShort(Object o, long offset, short mask) { + short current; + do { + current = getShortVolatile(o, offset); + } while (!weakCompareAndSetShort(o, offset, + current, (short) (current | mask))); + return current; + } + + @ForceInline + public final short getAndBitwiseOrShortRelease(Object o, long offset, short mask) { + short current; + do { + current = getShort(o, offset); + } while (!weakCompareAndSetShortRelease(o, offset, + current, (short) (current | mask))); + return current; + } + + @ForceInline + public final short getAndBitwiseOrShortAcquire(Object o, long offset, short mask) { + short current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getShort(o, offset); + } while (!weakCompareAndSetShortAcquire(o, offset, + current, (short) (current | mask))); + return current; + } + + @ForceInline + public final short getAndBitwiseAndShort(Object o, long offset, short mask) { + short current; + do { + current = getShortVolatile(o, offset); + } while (!weakCompareAndSetShort(o, offset, + current, (short) (current & mask))); + return current; + } + + @ForceInline + public final short getAndBitwiseAndShortRelease(Object o, long offset, short mask) { + short current; + do { + current = getShort(o, offset); + } while (!weakCompareAndSetShortRelease(o, offset, + current, (short) (current & mask))); + return current; + } + + @ForceInline + public final short getAndBitwiseAndShortAcquire(Object o, long offset, short mask) { + short current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getShort(o, offset); + } while (!weakCompareAndSetShortAcquire(o, offset, + current, (short) (current & mask))); + return current; + } + + @ForceInline + public final short getAndBitwiseXorShort(Object o, long offset, short mask) { + short current; + do { + current = getShortVolatile(o, offset); + } while (!weakCompareAndSetShort(o, offset, + current, (short) (current ^ mask))); + return current; + } + + @ForceInline + public final short getAndBitwiseXorShortRelease(Object o, long offset, short mask) { + short current; + do { + current = getShort(o, offset); + } while (!weakCompareAndSetShortRelease(o, offset, + current, (short) (current ^ mask))); + return current; + } + + @ForceInline + public final short getAndBitwiseXorShortAcquire(Object o, long offset, short mask) { + short current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getShort(o, offset); + } while (!weakCompareAndSetShortAcquire(o, offset, + current, (short) (current ^ mask))); + return current; + } + + + @ForceInline + public final int getAndBitwiseOrInt(Object o, long offset, int mask) { + int current; + do { + current = getIntVolatile(o, offset); + } while (!weakCompareAndSetInt(o, offset, + current, current | mask)); + return current; + } + + @ForceInline + public final int getAndBitwiseOrIntRelease(Object o, long offset, int mask) { + int current; + do { + current = getInt(o, offset); + } while (!weakCompareAndSetIntRelease(o, offset, + current, current | mask)); + return current; + } + + @ForceInline + public final int getAndBitwiseOrIntAcquire(Object o, long offset, int mask) { + int current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getInt(o, offset); + } while (!weakCompareAndSetIntAcquire(o, offset, + current, current | mask)); + return current; + } + + /** + * Atomically replaces the current value of a field or array element within + * the given object with the result of bitwise AND between the current value + * and mask. + * + * @param o object/array to update the field/element in + * @param offset field/element offset + * @param mask the mask value + * @return the previous value + * @since 9 + */ + @ForceInline + public final int getAndBitwiseAndInt(Object o, long offset, int mask) { + int current; + do { + current = getIntVolatile(o, offset); + } while (!weakCompareAndSetInt(o, offset, + current, current & mask)); + return current; + } + + @ForceInline + public final int getAndBitwiseAndIntRelease(Object o, long offset, int mask) { + int current; + do { + current = getInt(o, offset); + } while (!weakCompareAndSetIntRelease(o, offset, + current, current & mask)); + return current; + } + + @ForceInline + public final int getAndBitwiseAndIntAcquire(Object o, long offset, int mask) { + int current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getInt(o, offset); + } while (!weakCompareAndSetIntAcquire(o, offset, + current, current & mask)); + return current; + } + + @ForceInline + public final int getAndBitwiseXorInt(Object o, long offset, int mask) { + int current; + do { + current = getIntVolatile(o, offset); + } while (!weakCompareAndSetInt(o, offset, + current, current ^ mask)); + return current; + } + + @ForceInline + public final int getAndBitwiseXorIntRelease(Object o, long offset, int mask) { + int current; + do { + current = getInt(o, offset); + } while (!weakCompareAndSetIntRelease(o, offset, + current, current ^ mask)); + return current; + } + + @ForceInline + public final int getAndBitwiseXorIntAcquire(Object o, long offset, int mask) { + int current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getInt(o, offset); + } while (!weakCompareAndSetIntAcquire(o, offset, + current, current ^ mask)); + return current; + } + + + @ForceInline + public final long getAndBitwiseOrLong(Object o, long offset, long mask) { + long current; + do { + current = getLongVolatile(o, offset); + } while (!weakCompareAndSetLong(o, offset, + current, current | mask)); + return current; + } + + @ForceInline + public final long getAndBitwiseOrLongRelease(Object o, long offset, long mask) { + long current; + do { + current = getLong(o, offset); + } while (!weakCompareAndSetLongRelease(o, offset, + current, current | mask)); + return current; + } + + @ForceInline + public final long getAndBitwiseOrLongAcquire(Object o, long offset, long mask) { + long current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getLong(o, offset); + } while (!weakCompareAndSetLongAcquire(o, offset, + current, current | mask)); + return current; + } + + @ForceInline + public final long getAndBitwiseAndLong(Object o, long offset, long mask) { + long current; + do { + current = getLongVolatile(o, offset); + } while (!weakCompareAndSetLong(o, offset, + current, current & mask)); + return current; + } + + @ForceInline + public final long getAndBitwiseAndLongRelease(Object o, long offset, long mask) { + long current; + do { + current = getLong(o, offset); + } while (!weakCompareAndSetLongRelease(o, offset, + current, current & mask)); + return current; + } + + @ForceInline + public final long getAndBitwiseAndLongAcquire(Object o, long offset, long mask) { + long current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getLong(o, offset); + } while (!weakCompareAndSetLongAcquire(o, offset, + current, current & mask)); + return current; + } + + @ForceInline + public final long getAndBitwiseXorLong(Object o, long offset, long mask) { + long current; + do { + current = getLongVolatile(o, offset); + } while (!weakCompareAndSetLong(o, offset, + current, current ^ mask)); + return current; + } + + @ForceInline + public final long getAndBitwiseXorLongRelease(Object o, long offset, long mask) { + long current; + do { + current = getLong(o, offset); + } while (!weakCompareAndSetLongRelease(o, offset, + current, current ^ mask)); + return current; + } + + @ForceInline + public final long getAndBitwiseXorLongAcquire(Object o, long offset, long mask) { + long current; + do { + // Plain read, the value is a hint, the acquire CAS does the work + current = getLong(o, offset); + } while (!weakCompareAndSetLongAcquire(o, offset, + current, current ^ mask)); + return current; + } + + + + /** + * Ensures that loads before the fence will not be reordered with loads and + * stores after the fence; a "LoadLoad plus LoadStore barrier". + * + * Corresponds to C11 atomic_thread_fence(memory_order_acquire) + * (an "acquire fence"). + * + * Provides a LoadLoad barrier followed by a LoadStore barrier. + * + * @since 1.8 + */ + @IntrinsicCandidate + public final void loadFence() { + // If loadFence intrinsic is not available, fall back to full fence. + fullFence(); + } + + /** + * Ensures that loads and stores before the fence will not be reordered with + * stores after the fence; a "StoreStore plus LoadStore barrier". + * + * Corresponds to C11 atomic_thread_fence(memory_order_release) + * (a "release fence"). + * + * Provides a StoreStore barrier followed by a LoadStore barrier. + * + * @since 1.8 + */ + @IntrinsicCandidate + public final void storeFence() { + // If storeFence intrinsic is not available, fall back to full fence. + fullFence(); + } + + /** + * Ensures that loads and stores before the fence will not be reordered + * with loads and stores after the fence. Implies the effects of both + * loadFence() and storeFence(), and in addition, the effect of a StoreLoad + * barrier. + * + * Corresponds to C11 atomic_thread_fence(memory_order_seq_cst). + * @since 1.8 + */ + @IntrinsicCandidate + public native void fullFence(); + + /** + * Ensures that loads before the fence will not be reordered with + * loads after the fence. + * + * @implNote + * This method is operationally equivalent to {@link #loadFence()}. + * + * @since 9 + */ + public final void loadLoadFence() { + loadFence(); + } + + /** + * Ensures that stores before the fence will not be reordered with + * stores after the fence. + * + * @since 9 + */ + @IntrinsicCandidate + public final void storeStoreFence() { + // If storeStoreFence intrinsic is not available, fall back to storeFence. + storeFence(); + } + + /** + * Throws IllegalAccessError; for use by the VM for access control + * error support. + * @since 1.8 + */ + private static void throwIllegalAccessError() { + throw new IllegalAccessError(); + } + + /** + * Throws NoSuchMethodError; for use by the VM for redefinition support. + * @since 13 + */ + private static void throwNoSuchMethodError() { + throw new NoSuchMethodError(); + } + + /** + * @return Returns true if the native byte ordering of this + * platform is big-endian, false if it is little-endian. + */ + public final boolean isBigEndian() { return BIG_ENDIAN; } + + /** + * @return Returns true if this platform is capable of performing + * accesses at addresses which are not aligned for the type of the + * primitive type being accessed, false otherwise. + */ + public final boolean unalignedAccess() { return UNALIGNED_ACCESS; } + + /** + * Fetches a value at some byte offset into a given Java object. + * More specifically, fetches a value within the given object + * o at the given offset, or (if o is + * null) from the memory address whose numerical value is the + * given offset.

    + * + * The specification of this method is the same as {@link + * #getLong(Object, long)} except that the offset does not need to + * have been obtained from {@link #objectFieldOffset} on the + * {@link java.lang.reflect.Field} of some Java field. The value + * in memory is raw data, and need not correspond to any Java + * variable. Unless o is null, the value accessed + * must be entirely within the allocated object. The endianness + * of the value in memory is the endianness of the native platform. + * + *

    The read will be atomic with respect to the largest power + * of two that divides the GCD of the offset and the storage size. + * For example, getLongUnaligned will make atomic reads of 2-, 4-, + * or 8-byte storage units if the offset is zero mod 2, 4, or 8, + * respectively. There are no other guarantees of atomicity. + *

    + * 8-byte atomicity is only guaranteed on platforms on which + * support atomic accesses to longs. + * + * @param o Java heap object in which the value resides, if any, else + * null + * @param offset The offset in bytes from the start of the object + * @return the value fetched from the indicated object + * @throws RuntimeException No defined exceptions are thrown, not even + * {@link NullPointerException} + * @since 9 + */ + @IntrinsicCandidate + public final long getLongUnaligned(Object o, long offset) { + if ((offset & 7) == 0) { + return getLong(o, offset); + } else if ((offset & 3) == 0) { + return makeLong(getInt(o, offset), + getInt(o, offset + 4)); + } else if ((offset & 1) == 0) { + return makeLong(getShort(o, offset), + getShort(o, offset + 2), + getShort(o, offset + 4), + getShort(o, offset + 6)); + } else { + return makeLong(getByte(o, offset), + getByte(o, offset + 1), + getByte(o, offset + 2), + getByte(o, offset + 3), + getByte(o, offset + 4), + getByte(o, offset + 5), + getByte(o, offset + 6), + getByte(o, offset + 7)); + } + } + /** + * As {@link #getLongUnaligned(Object, long)} but with an + * additional argument which specifies the endianness of the value + * as stored in memory. + * + * @param o Java heap object in which the variable resides + * @param offset The offset in bytes from the start of the object + * @param bigEndian The endianness of the value + * @return the value fetched from the indicated object + * @since 9 + */ + public final long getLongUnaligned(Object o, long offset, boolean bigEndian) { + return convEndian(bigEndian, getLongUnaligned(o, offset)); + } + + /** @see #getLongUnaligned(Object, long) */ + @IntrinsicCandidate + public final int getIntUnaligned(Object o, long offset) { + if ((offset & 3) == 0) { + return getInt(o, offset); + } else if ((offset & 1) == 0) { + return makeInt(getShort(o, offset), + getShort(o, offset + 2)); + } else { + return makeInt(getByte(o, offset), + getByte(o, offset + 1), + getByte(o, offset + 2), + getByte(o, offset + 3)); + } + } + /** @see #getLongUnaligned(Object, long, boolean) */ + public final int getIntUnaligned(Object o, long offset, boolean bigEndian) { + return convEndian(bigEndian, getIntUnaligned(o, offset)); + } + + /** @see #getLongUnaligned(Object, long) */ + @IntrinsicCandidate + public final short getShortUnaligned(Object o, long offset) { + if ((offset & 1) == 0) { + return getShort(o, offset); + } else { + return makeShort(getByte(o, offset), + getByte(o, offset + 1)); + } + } + /** @see #getLongUnaligned(Object, long, boolean) */ + public final short getShortUnaligned(Object o, long offset, boolean bigEndian) { + return convEndian(bigEndian, getShortUnaligned(o, offset)); + } + + /** @see #getLongUnaligned(Object, long) */ + @IntrinsicCandidate + public final char getCharUnaligned(Object o, long offset) { + if ((offset & 1) == 0) { + return getChar(o, offset); + } else { + return (char)makeShort(getByte(o, offset), + getByte(o, offset + 1)); + } + } + + /** @see #getLongUnaligned(Object, long, boolean) */ + public final char getCharUnaligned(Object o, long offset, boolean bigEndian) { + return convEndian(bigEndian, getCharUnaligned(o, offset)); + } + + /** + * Stores a value at some byte offset into a given Java object. + *

    + * The specification of this method is the same as {@link + * #getLong(Object, long)} except that the offset does not need to + * have been obtained from {@link #objectFieldOffset} on the + * {@link java.lang.reflect.Field} of some Java field. The value + * in memory is raw data, and need not correspond to any Java + * variable. The endianness of the value in memory is the + * endianness of the native platform. + *

    + * The write will be atomic with respect to the largest power of + * two that divides the GCD of the offset and the storage size. + * For example, putLongUnaligned will make atomic writes of 2-, 4-, + * or 8-byte storage units if the offset is zero mod 2, 4, or 8, + * respectively. There are no other guarantees of atomicity. + *

    + * 8-byte atomicity is only guaranteed on platforms on which + * support atomic accesses to longs. + * + * @param o Java heap object in which the value resides, if any, else + * null + * @param offset The offset in bytes from the start of the object + * @param x the value to store + * @throws RuntimeException No defined exceptions are thrown, not even + * {@link NullPointerException} + * @since 9 + */ + @IntrinsicCandidate + public final void putLongUnaligned(Object o, long offset, long x) { + if ((offset & 7) == 0) { + putLong(o, offset, x); + } else if ((offset & 3) == 0) { + putLongParts(o, offset, + (int)(x >> 0), + (int)(x >>> 32)); + } else if ((offset & 1) == 0) { + putLongParts(o, offset, + (short)(x >>> 0), + (short)(x >>> 16), + (short)(x >>> 32), + (short)(x >>> 48)); + } else { + putLongParts(o, offset, + (byte)(x >>> 0), + (byte)(x >>> 8), + (byte)(x >>> 16), + (byte)(x >>> 24), + (byte)(x >>> 32), + (byte)(x >>> 40), + (byte)(x >>> 48), + (byte)(x >>> 56)); + } + } + + /** + * As {@link #putLongUnaligned(Object, long, long)} but with an additional + * argument which specifies the endianness of the value as stored in memory. + * @param o Java heap object in which the value resides + * @param offset The offset in bytes from the start of the object + * @param x the value to store + * @param bigEndian The endianness of the value + * @throws RuntimeException No defined exceptions are thrown, not even + * {@link NullPointerException} + * @since 9 + */ + public final void putLongUnaligned(Object o, long offset, long x, boolean bigEndian) { + putLongUnaligned(o, offset, convEndian(bigEndian, x)); + } + + /** @see #putLongUnaligned(Object, long, long) */ + @IntrinsicCandidate + public final void putIntUnaligned(Object o, long offset, int x) { + if ((offset & 3) == 0) { + putInt(o, offset, x); + } else if ((offset & 1) == 0) { + putIntParts(o, offset, + (short)(x >> 0), + (short)(x >>> 16)); + } else { + putIntParts(o, offset, + (byte)(x >>> 0), + (byte)(x >>> 8), + (byte)(x >>> 16), + (byte)(x >>> 24)); + } + } + /** @see #putLongUnaligned(Object, long, long, boolean) */ + public final void putIntUnaligned(Object o, long offset, int x, boolean bigEndian) { + putIntUnaligned(o, offset, convEndian(bigEndian, x)); + } + + /** @see #putLongUnaligned(Object, long, long) */ + @IntrinsicCandidate + public final void putShortUnaligned(Object o, long offset, short x) { + if ((offset & 1) == 0) { + putShort(o, offset, x); + } else { + putShortParts(o, offset, + (byte)(x >>> 0), + (byte)(x >>> 8)); + } + } + /** @see #putLongUnaligned(Object, long, long, boolean) */ + public final void putShortUnaligned(Object o, long offset, short x, boolean bigEndian) { + putShortUnaligned(o, offset, convEndian(bigEndian, x)); + } + + /** @see #putLongUnaligned(Object, long, long) */ + @IntrinsicCandidate + public final void putCharUnaligned(Object o, long offset, char x) { + putShortUnaligned(o, offset, (short)x); + } + /** @see #putLongUnaligned(Object, long, long, boolean) */ + public final void putCharUnaligned(Object o, long offset, char x, boolean bigEndian) { + putCharUnaligned(o, offset, convEndian(bigEndian, x)); + } + + private static int pickPos(int top, int pos) { return BIG_ENDIAN ? top - pos : pos; } + + // These methods construct integers from bytes. The byte ordering + // is the native endianness of this platform. + private static long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) { + return ((toUnsignedLong(i0) << pickPos(56, 0)) + | (toUnsignedLong(i1) << pickPos(56, 8)) + | (toUnsignedLong(i2) << pickPos(56, 16)) + | (toUnsignedLong(i3) << pickPos(56, 24)) + | (toUnsignedLong(i4) << pickPos(56, 32)) + | (toUnsignedLong(i5) << pickPos(56, 40)) + | (toUnsignedLong(i6) << pickPos(56, 48)) + | (toUnsignedLong(i7) << pickPos(56, 56))); + } + private static long makeLong(short i0, short i1, short i2, short i3) { + return ((toUnsignedLong(i0) << pickPos(48, 0)) + | (toUnsignedLong(i1) << pickPos(48, 16)) + | (toUnsignedLong(i2) << pickPos(48, 32)) + | (toUnsignedLong(i3) << pickPos(48, 48))); + } + private static long makeLong(int i0, int i1) { + return (toUnsignedLong(i0) << pickPos(32, 0)) + | (toUnsignedLong(i1) << pickPos(32, 32)); + } + private static int makeInt(short i0, short i1) { + return (toUnsignedInt(i0) << pickPos(16, 0)) + | (toUnsignedInt(i1) << pickPos(16, 16)); + } + private static int makeInt(byte i0, byte i1, byte i2, byte i3) { + return ((toUnsignedInt(i0) << pickPos(24, 0)) + | (toUnsignedInt(i1) << pickPos(24, 8)) + | (toUnsignedInt(i2) << pickPos(24, 16)) + | (toUnsignedInt(i3) << pickPos(24, 24))); + } + private static short makeShort(byte i0, byte i1) { + return (short)((toUnsignedInt(i0) << pickPos(8, 0)) + | (toUnsignedInt(i1) << pickPos(8, 8))); + } + + private static byte pick(byte le, byte be) { return BIG_ENDIAN ? be : le; } + private static short pick(short le, short be) { return BIG_ENDIAN ? be : le; } + private static int pick(int le, int be) { return BIG_ENDIAN ? be : le; } + + // These methods write integers to memory from smaller parts + // provided by their caller. The ordering in which these parts + // are written is the native endianness of this platform. + private void putLongParts(Object o, long offset, byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) { + putByte(o, offset + 0, pick(i0, i7)); + putByte(o, offset + 1, pick(i1, i6)); + putByte(o, offset + 2, pick(i2, i5)); + putByte(o, offset + 3, pick(i3, i4)); + putByte(o, offset + 4, pick(i4, i3)); + putByte(o, offset + 5, pick(i5, i2)); + putByte(o, offset + 6, pick(i6, i1)); + putByte(o, offset + 7, pick(i7, i0)); + } + private void putLongParts(Object o, long offset, short i0, short i1, short i2, short i3) { + putShort(o, offset + 0, pick(i0, i3)); + putShort(o, offset + 2, pick(i1, i2)); + putShort(o, offset + 4, pick(i2, i1)); + putShort(o, offset + 6, pick(i3, i0)); + } + private void putLongParts(Object o, long offset, int i0, int i1) { + putInt(o, offset + 0, pick(i0, i1)); + putInt(o, offset + 4, pick(i1, i0)); + } + private void putIntParts(Object o, long offset, short i0, short i1) { + putShort(o, offset + 0, pick(i0, i1)); + putShort(o, offset + 2, pick(i1, i0)); + } + private void putIntParts(Object o, long offset, byte i0, byte i1, byte i2, byte i3) { + putByte(o, offset + 0, pick(i0, i3)); + putByte(o, offset + 1, pick(i1, i2)); + putByte(o, offset + 2, pick(i2, i1)); + putByte(o, offset + 3, pick(i3, i0)); + } + private void putShortParts(Object o, long offset, byte i0, byte i1) { + putByte(o, offset + 0, pick(i0, i1)); + putByte(o, offset + 1, pick(i1, i0)); + } + + // Zero-extend an integer + private static int toUnsignedInt(byte n) { return n & 0xff; } + private static int toUnsignedInt(short n) { return n & 0xffff; } + private static long toUnsignedLong(byte n) { return n & 0xffl; } + private static long toUnsignedLong(short n) { return n & 0xffffl; } + private static long toUnsignedLong(int n) { return n & 0xffffffffl; } + + // Maybe byte-reverse an integer + private static char convEndian(boolean big, char n) { return big == BIG_ENDIAN ? n : Character.reverseBytes(n); } + private static short convEndian(boolean big, short n) { return big == BIG_ENDIAN ? n : Short.reverseBytes(n) ; } + private static int convEndian(boolean big, int n) { return big == BIG_ENDIAN ? n : Integer.reverseBytes(n) ; } + private static long convEndian(boolean big, long n) { return big == BIG_ENDIAN ? n : Long.reverseBytes(n) ; } + + + + private native long allocateMemory0(long bytes); + private native long reallocateMemory0(long address, long bytes); + private native void freeMemory0(long address); + @IntrinsicCandidate + private native void setMemory0(Object o, long offset, long bytes, byte value); + @IntrinsicCandidate + private native void copyMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); + private native void copySwapMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes, long elemSize); + private native long objectFieldOffset0(Field f); + private native long objectFieldOffset1(Class c, String name); + private native long staticFieldOffset0(Field f); + private native Object staticFieldBase0(Field f); + private native boolean shouldBeInitialized0(Class c); + private native void ensureClassInitialized0(Class c); + private native int arrayBaseOffset0(Class arrayClass); + private native int arrayIndexScale0(Class arrayClass); + private native int getLoadAverage0(double[] loadavg, int nelems); + + + /** + * Invokes the given direct byte buffer's cleaner, if any. + * + * @param directBuffer a direct byte buffer + * @throws NullPointerException if {@code directBuffer} is null + * @throws IllegalArgumentException if {@code directBuffer} is non-direct, + * or is a {@link java.nio.Buffer#slice slice}, or is a + * {@link java.nio.Buffer#duplicate duplicate} + */ + public void invokeCleaner(java.nio.ByteBuffer directBuffer) { + if (!directBuffer.isDirect()) + throw new IllegalArgumentException("buffer is non-direct"); + + DirectBuffer db = (DirectBuffer) directBuffer; + if (db.attachment() != null) + throw new IllegalArgumentException("duplicate or slice"); + + Cleaner cleaner = db.cleaner(); + if (cleaner != null) { + cleaner.clean(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/misc/UnsafeConstants.class b/tests/test_data/std/jdk/internal/misc/UnsafeConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..198baf810c6cc5cccfee82188bc7c9a8ffd9bc33 GIT binary patch literal 583 zcmah`%TB{E5FGbG9|S0+h4Q9w0S<%{7b+x^gc2zVh|nImL~a@&B~7I^#=bqace3hEh-53pEtcje6GU`CiO0(Fmd- zK4M63@3afZqmV;U!6X!hdarw@22tz}BN3|oVC1Q-Xe6$EZ4ixO5yc~hDX!}mhU2)7 zd1dS~FjI<5E0~cAg>&9C5=vHQ6_hc@P&_u9u3_sYx2fSuQdI@>k}9=qZkbKn&|R)+ zq$|mqf<>ver1MMeYFs-tT+6f#_rz*Br-?j6MjLc}h8Zh}e0$vQ_`^%l38_-H2A&Ap zVi?H$r4Ecr^{hfNJ^$ oIf^NY5=Dh#L5eX*u_bB%Vq`F;_Inb1Knahi;E8T*5SK#z3l%zR)Bpeg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/UnsafeConstants.java b/tests/test_data/std/jdk/internal/misc/UnsafeConstants.java new file mode 100644 index 00000000..65ee7b3a --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/UnsafeConstants.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Red Hat Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +/** + * A class used to expose details of the underlying hardware that + * configure the operation of class Unsafe. This class is + * package-private as the only intended client is class Unsafe. + * All fields in this class must be static final constants. + * + * @since 13 + * + * @implNote + * + * The JVM injects hardware-specific values into all the static fields + * of this class during JVM initialization. The static initialization + * block is executed when the class is initialized then JVM injection + * updates the fields with the correct constants. The static block + * is required to prevent the fields from being considered constant + * variables, so the field values will be not be compiled directly into + * any class that uses them. + */ + +final class UnsafeConstants { + + /** + * This constructor is private because the class is not meant to + * be instantiated. + */ + private UnsafeConstants() {} + + /** + * The size in bytes of a native pointer, as stored via {@link + * #putAddress}. This value will be either 4 or 8. Note that the + * sizes of other primitive types (as stored in native memory + * blocks) is determined fully by their information content. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final int ADDRESS_SIZE0; + + /** + * The size in bytes of a native memory page (whatever that is). + * This value will always be a power of two. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final int PAGE_SIZE; + + /** + * Flag whose value is true if and only if the native endianness + * of this platform is big. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final boolean BIG_ENDIAN; + + /** + * Flag whose value is true if and only if the platform can + * perform unaligned accesses + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final boolean UNALIGNED_ACCESS; + + /** + * The size of an L1 data cache line which will be either a power + * of two or zero. + * + *

    A non-zero value indicates that writeback to memory is + * enabled for the current processor. The value defines the + * natural alignment and size of any data cache line committed to + * memory by a single writeback operation. If data cache line + * writeback is not enabled for the current hardware the field + * will have value 0. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final int DATA_CACHE_LINE_FLUSH_SIZE; + + static { + ADDRESS_SIZE0 = 0; + PAGE_SIZE = 0; + BIG_ENDIAN = false; + UNALIGNED_ACCESS = false; + DATA_CACHE_LINE_FLUSH_SIZE = 0; + } +} diff --git a/tests/test_data/std/jdk/internal/misc/VM$BufferPool.class b/tests/test_data/std/jdk/internal/misc/VM$BufferPool.class new file mode 100644 index 0000000000000000000000000000000000000000..ae537aedd89c599c263260b0011738ff5ea0071c GIT binary patch literal 320 zcmZvX!A=4(6h&_lXJ7;bqtTZRpvOZUu%sDyVUO z`x0m^kS$&7OS;vDz3HmB+Id+urx5R4h$&9_zyCHC7~ES+J~t`^3amO*NCbEX?hJIf j%rO$auphlW`+v-K2NN5Ir|(<0dt9UntPhm87LLP?kbMOPe-oAzefu2wsq5-!?9e9oY_2U-&14 zL|G(0fWP2@Meq-ZxvrI^2@((XngdT>To^BHHUjHksomH0rBq`_NotHn2sm1ts)y> z$xig4U&4TlK@9zat097VAg*=8p$^w7`}^G4vu%@M@-$t^a5W{rJyioGMW^RvjNm+t zMAdbMfq2%RNZr_yiRUp~#HfTZ8J9#+BW}e~EW=i`qLML8o-V4E#m%i!nRrDt+iJPY z^%{|gpO7&rf`{lncVubJm}$&NxGW=%1Qp_!;V&j_nWP-HMe1_Wrs}%fm5^o_YXz(mHbbl?K8Bv!As7qk zc#ggn0K>451lg-}3gH?(A@Thn&vo*M8%DN$_89Dq4_TzQxCZ-*8}wT~0pKQX(WwKs ztHG}k_U{%xL3$QBM)cwAd&nQq%kU1vPw8+Wu;YQ9dW%`X5{6(Ip-f=k5M|#n$bMjy z{lpCWg?aY7${fWMmT-sAcj*zeoOqIcmK421xQAumu3(jHFL~Cmg7t{_SFB(IvA=mt BUeo{p literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/VM.class b/tests/test_data/std/jdk/internal/misc/VM.class new file mode 100644 index 0000000000000000000000000000000000000000..93129e065f3439c4db831c9cb8f5d42736fac20d GIT binary patch literal 7547 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/VM.java b/tests/test_data/std/jdk/internal/misc/VM.java new file mode 100644 index 00000000..de6f011f --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/VM.java @@ -0,0 +1,507 @@ +/* + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import static java.lang.Thread.State.*; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import jdk.internal.access.SharedSecrets; +import jdk.internal.vm.annotation.Stable; +import sun.nio.ch.FileChannelImpl; + +public class VM { + + // the init level when the VM is fully initialized + private static final int JAVA_LANG_SYSTEM_INITED = 1; + private static final int MODULE_SYSTEM_INITED = 2; + private static final int SYSTEM_LOADER_INITIALIZING = 3; + private static final int SYSTEM_BOOTED = 4; + private static final int SYSTEM_SHUTDOWN = 5; + + // 0, 1, 2, ... + private static volatile int initLevel; + private static final Object lock = new Object(); + + /** + * Sets the init level. + * + * @see java.lang.System#initPhase1 + * @see java.lang.System#initPhase2 + * @see java.lang.System#initPhase3 + */ + public static void initLevel(int value) { + synchronized (lock) { + if (value <= initLevel || value > SYSTEM_SHUTDOWN) + throw new InternalError("Bad level: " + value); + initLevel = value; + lock.notifyAll(); + } + } + + /** + * Returns the current init level. + */ + public static int initLevel() { + return initLevel; + } + + /** + * Waits for the init level to get the given value. + */ + public static void awaitInitLevel(int value) throws InterruptedException { + synchronized (lock) { + while (initLevel < value) { + lock.wait(); + } + } + } + + /** + * Returns {@code true} if the module system has been initialized. + * @see java.lang.System#initPhase2 + */ + public static boolean isModuleSystemInited() { + return initLevel >= MODULE_SYSTEM_INITED; + } + + private static @Stable boolean javaLangInvokeInited; + public static void setJavaLangInvokeInited() { + if (javaLangInvokeInited) { + throw new InternalError("java.lang.invoke already inited"); + } + javaLangInvokeInited = true; + } + + public static boolean isJavaLangInvokeInited() { + return javaLangInvokeInited; + } + + /** + * Returns {@code true} if the VM is fully initialized. + */ + public static boolean isBooted() { + return initLevel >= SYSTEM_BOOTED; + } + + /** + * Set shutdown state. Shutdown completes when all registered shutdown + * hooks have been run. + * + * @see java.lang.Shutdown + */ + public static void shutdown() { + initLevel(SYSTEM_SHUTDOWN); + } + + /** + * Returns {@code true} if the VM has been shutdown + */ + public static boolean isShutdown() { + return initLevel == SYSTEM_SHUTDOWN; + } + + // A user-settable upper limit on the maximum amount of allocatable direct + // buffer memory. This value may be changed during VM initialization if + // "java" is launched with "-XX:MaxDirectMemorySize=". + // + // The initial value of this field is arbitrary; during JRE initialization + // it will be reset to the value specified on the command line, if any, + // otherwise to Runtime.getRuntime().maxMemory(). + // + private static long directMemory = 64 * 1024 * 1024; + + // Returns the maximum amount of allocatable direct buffer memory. + // The directMemory variable is initialized during system initialization + // in the saveAndRemoveProperties method. + // + public static long maxDirectMemory() { + return directMemory; + } + + // User-controllable flag that determines if direct buffers should be page + // aligned. The "-XX:+PageAlignDirectMemory" option can be used to force + // buffers, allocated by ByteBuffer.allocateDirect, to be page aligned. + @Stable + private static boolean pageAlignDirectMemory; + + // Returns {@code true} if the direct buffers should be page aligned. This + // variable is initialized by saveAndRemoveProperties. + public static boolean isDirectMemoryPageAligned() { + return pageAlignDirectMemory; + } + + private static int classFileMajorVersion; + private static int classFileMinorVersion; + private static final int PREVIEW_MINOR_VERSION = 65535; + + /** + * Tests if the given version is a supported {@code class} + * file version. + * + * A {@code class} file depends on the preview features of Java SE {@code N} + * if the major version is {@code N} and the minor version is 65535. + * This method returns {@code true} if the given version is a supported + * {@code class} file version regardless of whether the preview features + * are enabled or not. + * + * @jvms 4.1 Table 4.1-A. class file format major versions + */ + public static boolean isSupportedClassFileVersion(int major, int minor) { + if (major < 45 || major > classFileMajorVersion) return false; + // for major version is between 45 and 55 inclusive, the minor version may be any value + if (major < 56) return true; + // otherwise, the minor version must be 0 or 65535 + return minor == 0 || minor == PREVIEW_MINOR_VERSION; + } + + /** + * Tests if the given version is a supported {@code class} + * file version for module descriptor. + * + * major.minor version >= 53.0 + */ + public static boolean isSupportedModuleDescriptorVersion(int major, int minor) { + if (major < 53 || major > classFileMajorVersion) return false; + // for major version is between 45 and 55 inclusive, the minor version may be any value + if (major < 56) return true; + // otherwise, the minor version must be 0 or 65535 + // preview features do not apply to module-info.class but JVMS allows it + return minor == 0 || minor == PREVIEW_MINOR_VERSION; + } + + /** + * Returns true if the given class loader is the bootstrap class loader + * or the platform class loader. + */ + public static boolean isSystemDomainLoader(ClassLoader loader) { + return loader == null || loader == ClassLoader.getPlatformClassLoader(); + } + + /** + * Returns the system property of the specified key saved at + * system initialization time. This method should only be used + * for the system properties that are not changed during runtime. + * + * Note that the saved system properties do not include + * the ones set by java.lang.VersionProps.init(). + */ + public static String getSavedProperty(String key) { + if (savedProps == null) + throw new IllegalStateException("Not yet initialized"); + + return savedProps.get(key); + } + + /** + * Gets an unmodifiable view of the system properties saved at system + * initialization time. This method should only be used + * for the system properties that are not changed during runtime. + * + * Note that the saved system properties do not include + * the ones set by java.lang.VersionProps.init(). + */ + public static Map getSavedProperties() { + if (savedProps == null) + throw new IllegalStateException("Not yet initialized"); + + return Collections.unmodifiableMap(savedProps); + } + + private static Map savedProps; + + // Save a private copy of the system properties and remove + // the system properties that are not intended for public access. + // + // This method can only be invoked during system initialization. + public static void saveProperties(Map props) { + if (initLevel() != 0) + throw new IllegalStateException("Wrong init level"); + + // only main thread is running at this time, so savedProps and + // its content will be correctly published to threads started later + if (savedProps == null) { + savedProps = props; + } + + // Set the maximum amount of direct memory. This value is controlled + // by the vm option -XX:MaxDirectMemorySize=. + // The maximum amount of allocatable direct buffer memory (in bytes) + // from the system property sun.nio.MaxDirectMemorySize set by the VM. + // If not set or set to -1, the max memory will be used + // The system property will be removed. + String s = props.get("sun.nio.MaxDirectMemorySize"); + if (s == null || s.isEmpty() || s.equals("-1")) { + // -XX:MaxDirectMemorySize not given, take default + directMemory = Runtime.getRuntime().maxMemory(); + } else { + long l = Long.parseLong(s); + if (l > -1) + directMemory = l; + } + + // Check if direct buffers should be page aligned + s = props.get("sun.nio.PageAlignDirectMemory"); + if ("true".equals(s)) + pageAlignDirectMemory = true; + + s = props.get("java.class.version"); + int index = s.indexOf('.'); + try { + classFileMajorVersion = Integer.parseInt(s.substring(0, index)); + classFileMinorVersion = Integer.parseInt(s.substring(index + 1)); + } catch (NumberFormatException e) { + throw new InternalError(e); + } + } + + // Initialize any miscellaneous operating system settings that need to be + // set for the class libraries. + // + public static void initializeOSEnvironment() { + if (initLevel() == 0) { + OSEnvironment.initialize(); + } + } + + /* Current count of objects pending for finalization */ + private static volatile int finalRefCount; + + /* Peak count of objects pending for finalization */ + private static volatile int peakFinalRefCount; + + /* + * Gets the number of objects pending for finalization. + * + * @return the number of objects pending for finalization. + */ + public static int getFinalRefCount() { + return finalRefCount; + } + + /* + * Gets the peak number of objects pending for finalization. + * + * @return the peak number of objects pending for finalization. + */ + public static int getPeakFinalRefCount() { + return peakFinalRefCount; + } + + /* + * Add {@code n} to the objects pending for finalization count. + * + * @param n an integer value to be added to the objects pending + * for finalization count + */ + public static void addFinalRefCount(int n) { + // The caller must hold lock to synchronize the update. + + finalRefCount += n; + if (finalRefCount > peakFinalRefCount) { + peakFinalRefCount = finalRefCount; + } + } + + /** + * Returns Thread.State for the given threadStatus + */ + public static Thread.State toThreadState(int threadStatus) { + if ((threadStatus & JVMTI_THREAD_STATE_RUNNABLE) != 0) { + return RUNNABLE; + } else if ((threadStatus & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) != 0) { + return BLOCKED; + } else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) != 0) { + return WAITING; + } else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) != 0) { + return TIMED_WAITING; + } else if ((threadStatus & JVMTI_THREAD_STATE_TERMINATED) != 0) { + return TERMINATED; + } else if ((threadStatus & JVMTI_THREAD_STATE_ALIVE) == 0) { + return NEW; + } else { + return RUNNABLE; + } + } + + /* The threadStatus field is set by the VM at state transition + * in the hotspot implementation. Its value is set according to + * the JVM TI specification GetThreadState function. + */ + private static final int JVMTI_THREAD_STATE_ALIVE = 0x0001; + private static final int JVMTI_THREAD_STATE_TERMINATED = 0x0002; + private static final int JVMTI_THREAD_STATE_RUNNABLE = 0x0004; + private static final int JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400; + private static final int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010; + private static final int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020; + + /* + * Returns the first user-defined class loader up the execution stack, + * or the platform class loader if only code from the platform or + * bootstrap class loader is on the stack. + */ + public static ClassLoader latestUserDefinedLoader() { + ClassLoader loader = latestUserDefinedLoader0(); + return loader != null ? loader : ClassLoader.getPlatformClassLoader(); + } + + /* + * Returns the first user-defined class loader up the execution stack, + * or null if only code from the platform or bootstrap class loader is + * on the stack. VM does not keep a reference of platform loader and so + * it returns null. + * + * This method should be replaced with StackWalker::walk and then we can + * remove the logic in the VM. + */ + private static native ClassLoader latestUserDefinedLoader0(); + + /** + * Returns {@code true} if we are in a set UID program. + */ + public static boolean isSetUID() { + long uid = getuid(); + long euid = geteuid(); + long gid = getgid(); + long egid = getegid(); + return uid != euid || gid != egid; + } + + /** + * Returns the real user ID of the calling process, + * or -1 if the value is not available. + */ + public static native long getuid(); + + /** + * Returns the effective user ID of the calling process, + * or -1 if the value is not available. + */ + public static native long geteuid(); + + /** + * Returns the real group ID of the calling process, + * or -1 if the value is not available. + */ + public static native long getgid(); + + /** + * Returns the effective group ID of the calling process, + * or -1 if the value is not available. + */ + public static native long getegid(); + + /** + * Get a nanosecond time stamp adjustment in the form of a single long. + * + * This value can be used to create an instant using + * {@link java.time.Instant#ofEpochSecond(long, long) + * java.time.Instant.ofEpochSecond(offsetInSeconds, + * getNanoTimeAdjustment(offsetInSeconds))}. + *

    + * The value returned has the best resolution available to the JVM on + * the current system. + * This is usually down to microseconds - or tenth of microseconds - + * depending on the OS/Hardware and the JVM implementation. + * + * @param offsetInSeconds The offset in seconds from which the nanosecond + * time stamp should be computed. + * + * @apiNote The offset should be recent enough - so that + * {@code offsetInSeconds} is within {@code +/- 2^32} seconds of the + * current UTC time. If the offset is too far off, {@code -1} will be + * returned. As such, {@code -1} must not be considered as a valid + * nano time adjustment, but as an exception value indicating + * that an offset closer to the current time should be used. + * + * @return A nanosecond time stamp adjustment in the form of a single long. + * If the offset is too far off the current time, this method returns -1. + * In that case, the caller should call this method again, passing a + * more accurate offset. + */ + public static native long getNanoTimeAdjustment(long offsetInSeconds); + + /** + * Returns the VM arguments for this runtime environment. + * + * @implNote + * The HotSpot JVM processes the input arguments from multiple sources + * in the following order: + * 1. JAVA_TOOL_OPTIONS environment variable + * 2. Options from JNI Invocation API + * 3. _JAVA_OPTIONS environment variable + * + * If VM options file is specified via -XX:VMOptionsFile, the vm options + * file is read and expanded in place of -XX:VMOptionFile option. + */ + public static native String[] getRuntimeArguments(); + + static { + initialize(); + } + private static native void initialize(); + + /** + * Provides access to information on buffer usage. + */ + public interface BufferPool { + String getName(); + long getCount(); + long getTotalCapacity(); + long getMemoryUsed(); + } + + private static class BufferPoolsHolder { + static final List BUFFER_POOLS; + + static { + ArrayList bufferPools = new ArrayList<>(3); + bufferPools.add(SharedSecrets.getJavaNioAccess().getDirectBufferPool()); + bufferPools.add(FileChannelImpl.getMappedBufferPool()); + bufferPools.add(FileChannelImpl.getSyncMappedBufferPool()); + + BUFFER_POOLS = Collections.unmodifiableList(bufferPools); + } + } + + /** + * @return the list of buffer pools. + */ + public static List getBufferPools() { + return BufferPoolsHolder.BUFFER_POOLS; + } + + /** + * Return the initial value of System.err that was set during VM initialization. + */ + public static PrintStream initialErr() { + return SharedSecrets.getJavaLangAccess().initialSystemErr(); + } +} diff --git a/tests/test_data/std/jdk/internal/misc/VirtualThreads.class b/tests/test_data/std/jdk/internal/misc/VirtualThreads.class new file mode 100644 index 0000000000000000000000000000000000000000..ffb83813d6559afc0ed67ca104fc24d88b26e98a GIT binary patch literal 1458 zcma)6YfsZq7=F$+R#u9@xQYVfz5!BExhROv0lHa0Es*#@lhU0)q3cN3k@&O3L_ib$ zXyT7DzUOR+10sG|&*gnC@8#_0uP@&KWU#6tgs_5$hB`zUn)j?jOLr}AM_=FG<95Ih zU2r@nSY!w%Q(H0ABc?#r&;X4gv6tW19WUU%XSsU8DcSm#;|FES-PrZHl`j!0XQUa1 zjG9Qxwt1pH@BGL?(rHhL8FYUo3Pp+^>{95}9S7riP* z7obh55JSUSdTrfY&aAI3nGAi#Kf~t*`GAH&!K|%j4I^8Hs&p}|VFaTL3JD!@pU4N3 zxoZehIhDGT(l91d7ljeEn9y(slMJn8?^3N8+LIMl+44%$=0(ZwVoJe14fpYYq5rB* zn7fwG^Cq`_9#Fknc6dVNvKV1}VnR!iE*RtIX?_ltf#<`}wanG;?yNR)U` zK2R}@M`Cv8FQj4yzT@psDl`O{VxBWJ8IH%-%7tz2Z&=$doy3izZMj>P?}&Z%FcR#F z_7Bt=zhbmWvCgx+A_cP?LrfHR)1%>FsL#{vyCg@ir%;`zXr=sg63C|^ zHUZ^(YcvDP-e0v2s?JoiSoUqc;t21pH8WqD6jYd^{)gyYGjxmhNvkOB>0#5!0_}AA zGWyny9fN(OMF@{&kT{&cBK>NW06f7{+Qn#=&cMU+hR%+loT8CI5HLv~{zQNoQlFKO zHaZu2a|p{Dl_0&Rh=(PnB3i*@D1PZLVHIgSlfoICv1}tkCV;Nq6SVX65pE@p(Ek}j zvyqO-36kfD#3>SZMbWPj#~XCQl-vpOL3mOU+)=t)rd5c(QK=Up7b}?j<2oc$6|Tol zF&?_)`W?l;uW|hxFNnDwSz@f@z9cn)&J*aLpb*y&G=9bO+xYA;9)7=QdX#`ks(y<8 Stj3WevM^W&alNEv2*z(_tvmMs literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/misc/VirtualThreads.java b/tests/test_data/std/jdk/internal/misc/VirtualThreads.java new file mode 100644 index 00000000..04a93afa --- /dev/null +++ b/tests/test_data/std/jdk/internal/misc/VirtualThreads.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.RejectedExecutionException; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + +/** + * Defines static methods to support execution in the context of a virtual thread. + */ +public final class VirtualThreads { + private static final JavaLangAccess JLA; + static { + JLA = SharedSecrets.getJavaLangAccess(); + if (JLA == null) { + throw new InternalError("JavaLangAccess not setup"); + } + } + private VirtualThreads() { } + + /** + * Parks the current virtual thread until it is unparked or interrupted. + * If already unparked then the parking permit is consumed and this method + * completes immediately (meaning it doesn't yield). It also completes + * immediately if the interrupt status is set. + * @throws WrongThreadException if the current thread is not a virtual thread + */ + public static void park() { + JLA.parkVirtualThread(); + } + + /** + * Parks the current virtual thread up to the given waiting time or until it + * is unparked or interrupted. If already unparked then the parking permit is + * consumed and this method completes immediately (meaning it doesn't yield). + * It also completes immediately if the interrupt status is set or the waiting + * time is {@code <= 0}. + * @param nanos the maximum number of nanoseconds to wait + * @throws WrongThreadException if the current thread is not a virtual thread + */ + public static void park(long nanos) { + JLA.parkVirtualThread(nanos); + } + + /** + * Parks the current virtual thread until the given deadline or until is is + * unparked or interrupted. If already unparked then the parking permit is + * consumed and this method completes immediately (meaning it doesn't yield). + * It also completes immediately if the interrupt status is set or the + * deadline has past. + * @param deadline absolute time, in milliseconds, from the epoch + * @throws WrongThreadException if the current thread is not a virtual thread + */ + public static void parkUntil(long deadline) { + long millis = deadline - System.currentTimeMillis(); + long nanos = TimeUnit.NANOSECONDS.convert(millis, TimeUnit.MILLISECONDS); + park(nanos); + } + + /** + * Re-enables a virtual thread for scheduling. If the thread was parked then + * it will be unblocked, otherwise its next attempt to park will not block + * @param thread the virtual thread to unpark + * @throws IllegalArgumentException if the thread is not a virtual thread + * @throws RejectedExecutionException if the scheduler cannot accept a task + */ + public static void unpark(Thread thread) { + JLA.unparkVirtualThread(thread); + } +} diff --git a/tests/test_data/std/jdk/internal/module/ArchivedBootLayer.class b/tests/test_data/std/jdk/internal/module/ArchivedBootLayer.class new file mode 100644 index 0000000000000000000000000000000000000000..6f03738c17298b862f0d1054d82be263b66fae59 GIT binary patch literal 886 zcma)5+iuf95IyTSvE#b8(54j1t!>&kNVNnKNTfo7pgb9PXcdXajk9VuY;4JKD#2HA z6$m6gfR94Vt}RkjRqD&`&e@qWXV2Kb|NQs`pocvV7Ag*GA63*CR>u5{hl(dB;p^d8 z#5qIlP$n{e%1~(sgF0N)9e6$#;4`$wqqm_bL~${8UaEHrv4^GRgE4K{E(+##OBDGB~Ao3{_RQ?;gggoS}D=&azna zrPkEEFsTDQ8r&rZE&4nxczPUkYUpv(UL}l-1vyJmpCX;-b-sah?tg{zks=E>XCEPz(ZfOt8@MKoNtfx;@{_g0cc>WfD|UONbAs$ zVVK(EkGSb_uW#Pp-m|TcA+zatPFQD{s8l<7JMg$`?)$xw zYn#^tYu9;X_wLHq+W{Z!Qs7-aY!6%~{F+-2dEXu~u&#)9TE`g?sze4~dDdu~hkl@3 zheCf=M-e50vEz6>J7BobdWkX0sLY$vpeCGVbj;!$!=&YVJ5GNT@X+x+hNY9fjktw$ zF6)@b0wJD zM-k7o9M8Tt+TXT=Z}_%Ll48rZxZB}@BieNUAY^ms^ z5tu2DM9t(*;1*|E5rdrKik-lomOFu7lRJSsLvca&%5$DFYthLzNM59DOrFQ2RoH08 z6HGm(O-jPeNMT(EUh`*JmlU_^p+uQ=}+Vy%r9JC zFQ?1eQy70>=_S#`e+aNcEp}y^x^jugPtM{mfzpVbppmdHNg4@4mBbfY0xn5lT8u_Q pCkU+iut8vMQEWw{Wf>936m!q8F3>Q^BZbB%@(oDRBzX$A{{twf0^k4u literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ArchivedModuleGraph.java b/tests/test_data/std/jdk/internal/module/ArchivedModuleGraph.java new file mode 100644 index 00000000..8b91ab67 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ArchivedModuleGraph.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.module; + +import java.util.Objects; +import java.util.function.Function; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import jdk.internal.misc.CDS; + +/** + * Used by ModuleBootstrap for archiving the configuration for the boot layer, + * and the system module finder. + */ +class ArchivedModuleGraph { + private static ArchivedModuleGraph archivedModuleGraph; + + private final boolean hasSplitPackages; + private final boolean hasIncubatorModules; + private final ModuleFinder finder; + private final Configuration configuration; + private final Function classLoaderFunction; + private final String mainModule; + + private ArchivedModuleGraph(boolean hasSplitPackages, + boolean hasIncubatorModules, + ModuleFinder finder, + Configuration configuration, + Function classLoaderFunction, + String mainModule) { + this.hasSplitPackages = hasSplitPackages; + this.hasIncubatorModules = hasIncubatorModules; + this.finder = finder; + this.configuration = configuration; + this.classLoaderFunction = classLoaderFunction; + this.mainModule = mainModule; + } + + ModuleFinder finder() { + return finder; + } + + Configuration configuration() { + return configuration; + } + + Function classLoaderFunction() { + return classLoaderFunction; + } + + boolean hasSplitPackages() { + return hasSplitPackages; + } + + boolean hasIncubatorModules() { + return hasIncubatorModules; + } + + /** + * Returns the ArchivedModuleGraph for the given initial module. + */ + static ArchivedModuleGraph get(String mainModule) { + ArchivedModuleGraph graph = archivedModuleGraph; + if ((graph != null) && Objects.equals(graph.mainModule, mainModule)) { + return graph; + } else { + return null; + } + } + + /** + * Archive the module graph for the given initial module. + */ + static void archive(boolean hasSplitPackages, + boolean hasIncubatorModules, + ModuleFinder finder, + Configuration configuration, + Function classLoaderFunction, + String mainModule) { + archivedModuleGraph = new ArchivedModuleGraph(hasSplitPackages, + hasIncubatorModules, + finder, + configuration, + classLoaderFunction, + mainModule); + } + + static { + CDS.initializeFromArchive(ArchivedModuleGraph.class); + } +} diff --git a/tests/test_data/std/jdk/internal/module/Builder.class b/tests/test_data/std/jdk/internal/module/Builder.class new file mode 100644 index 0000000000000000000000000000000000000000..e810190c5131cad79936795b7e02196bd97cdf4c GIT binary patch literal 8392 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 mods, + String mn, + String compiledVersion) + { + Version version = null; + if (compiledVersion != null) { + // use the cached version if the same version string + Version ver = cachedVersion; + if (ver != null && compiledVersion.equals(ver.toString())) { + version = ver; + } else { + version = Version.parse(compiledVersion); + } + } + return JLMA.newRequires(mods, mn, version); + } + + /** + * Returns a {@link Requires} for a dependence on a module with the given + * (and possibly empty) set of modifiers, and optionally the version + * recorded at compile time. + */ + public static Requires newRequires(Set mods, + String mn) + { + return newRequires(mods, mn, null); + } + + /** + * Returns a {@link Exports} for a qualified export, with + * the given (and possibly empty) set of modifiers, + * to a set of target modules. + */ + public static Exports newExports(Set ms, + String pn, + Set targets) { + return JLMA.newExports(ms, pn, targets); + } + + /** + * Returns an {@link Opens} for an unqualified open with a given set of + * modifiers. + */ + public static Opens newOpens(Set ms, String pn) { + return JLMA.newOpens(ms, pn); + } + + /** + * Returns an {@link Opens} for a qualified opens, with + * the given (and possibly empty) set of modifiers, + * to a set of target modules. + */ + public static Opens newOpens(Set ms, + String pn, + Set targets) { + return JLMA.newOpens(ms, pn, targets); + } + + /** + * Returns a {@link Exports} for an unqualified export with a given set + * of modifiers. + */ + public static Exports newExports(Set ms, String pn) { + return JLMA.newExports(ms, pn); + } + + /** + * Returns a {@link Provides} for a service with a given list of + * implementation classes. + */ + public static Provides newProvides(String st, List pcs) { + return JLMA.newProvides(st, pcs); + } + + final String name; + boolean open, synthetic, mandated; + Set requires; + Set exports; + Set opens; + Set packages; + Set uses; + Set provides; + Version version; + String mainClass; + + Builder(String name) { + this.name = name; + this.requires = Set.of(); + this.exports = Set.of(); + this.opens = Set.of(); + this.provides = Set.of(); + this.uses = Set.of(); + } + + Builder open(boolean value) { + this.open = value; + return this; + } + + Builder synthetic(boolean value) { + this.synthetic = value; + return this; + } + + Builder mandated(boolean value) { + this.mandated = value; + return this; + } + + /** + * Sets module exports. + */ + public Builder exports(Exports[] exports) { + this.exports = Set.of(exports); + return this; + } + + /** + * Sets module opens. + */ + public Builder opens(Opens[] opens) { + this.opens = Set.of(opens); + return this; + } + + /** + * Sets module requires. + */ + public Builder requires(Requires[] requires) { + this.requires = Set.of(requires); + return this; + } + + /** + * Adds a set of (possible empty) packages. + */ + public Builder packages(Set packages) { + this.packages = packages; + return this; + } + + /** + * Sets the set of service dependences. + */ + public Builder uses(Set uses) { + this.uses = uses; + return this; + } + + /** + * Sets module provides. + */ + public Builder provides(Provides[] provides) { + this.provides = Set.of(provides); + return this; + } + + /** + * Sets the module version. + * + * @throws IllegalArgumentException if {@code v} is null or cannot be + * parsed as a version string + * + * @see Version#parse(String) + */ + public Builder version(String v) { + Version ver = cachedVersion; + if (ver != null && v.equals(ver.toString())) { + version = ver; + } else { + cachedVersion = version = Version.parse(v); + } + return this; + } + + /** + * Sets the module main class. + */ + public Builder mainClass(String mc) { + mainClass = mc; + return this; + } + + /** + * Returns an immutable set of the module modifiers derived from the flags. + */ + private Set modifiers() { + int n = 0; + if (open) n++; + if (synthetic) n++; + if (mandated) n++; + if (n == 0) { + return Set.of(); + } else { + ModuleDescriptor.Modifier[] mods = new ModuleDescriptor.Modifier[n]; + if (open) mods[--n] = ModuleDescriptor.Modifier.OPEN; + if (synthetic) mods[--n] = ModuleDescriptor.Modifier.SYNTHETIC; + if (mandated) mods[--n] = ModuleDescriptor.Modifier.MANDATED; + return Set.of(mods); + } + } + + /** + * Builds a {@code ModuleDescriptor} from the components. + */ + public ModuleDescriptor build(int hashCode) { + assert name != null; + return JLMA.newModuleDescriptor(name, + version, + modifiers(), + requires, + exports, + opens, + uses, + provides, + packages, + mainClass, + hashCode); + } +} diff --git a/tests/test_data/std/jdk/internal/module/Checks.class b/tests/test_data/std/jdk/internal/module/Checks.class new file mode 100644 index 0000000000000000000000000000000000000000..7bacba633c9f826c44132d4f581aa14a4777b9c9 GIT binary patch literal 4401 zcmbVP33wFc8GdJXlbwVO2|o}B39uYOvLS>30+Nu5X_U}#$Wm<3RwlEv$&ks+GCLax zJ*+3%+iE>%6|}bWz{;T^NRgHvwD!JFtF`xiUp!j-{xKpW1NB7k5Rp$Ljlte|42HlQ_Hn%&d5se7lPdkTtMOxyHY6$ESRwuPZ8 zm^-qm!?KJX&06dBWcm%;Yu}?ADbI9l6{R$`F=JWLekYN!jHs>k8>I*%B5x{FFtxUG z#7x|CO}nSLZd)nJQ4z+Z2m~gNawoe*LD;kt#-2?{1x2+T9d#Y@#MB5XF-<{9I@6u@ zO)039s~2BUiYm+qqdI~b%v3OAXQHpsv^~SMHLEe}YGYfkq4%YEyO~~3Iyw@J%uJew z`!Zf{4`a51X=B5=B4b(!!!5-u1SQOkU>@d^P%V`*?1X}b@hG^+<(!#j6$=zhUmfkR z2Q;qFPjX9yKqxE**$PP>)3lRL{w?Ii+@7j>@rEQraj3 z9*;#8O$s6@P4Cls@~N%DvIv&rQU&F%u`6S`#@4}mkj z1Ek5#87RkEsl6){gcx~;idQOVSv^AQuDm&af7D6lsn(_WsA=pjx;cWYv4v^d(jIT$vaOvSm1oJz zc&61DH@xNv*os$&u`PmY@EQeWz7+GTJgGajrGsxAkhSrn5d2OwgT#vDsm@tYurMDNL!{6=%{7TQ{2hqTG%h5oqY7a@DiO?+MJB-Nj`ca=!MB@u?)M%>-Fhiv2RCT1eUZrWvt!JG^@g9xSH$& z^jbwqmRp*+=9nRbyB)_eG`1%?P}J=jTAzvm`qDk?MTJDIqwgxK^1q)dCSpg_a3s5bm-B2G|}UDykbAE zGLtIaC+nm?Wf`&^)7pc)n$M0T;GkTi&lL%v0KGqdUZkEACnKRIiN}Yj?fP4$>V#&NT@i*(M9=R*fqS2 zOYVmlNxIi}X_(V=$dg;1B$2Xv>s~UY;^T5tCS@?nr{t#Hrk{;ZuiHfHghv$;eFY@4kW75QzdGml{(G8iQ zuhPu!UVr#?Y1@@~{U#@qnxD6CbJFIUO~rQ=DA&u{`+fvJzz>-MC#hh5?X?BHEnj0} zDwaOQ%^q@_aoHc|jb3djIG^p*&8^M6wT%TRi{G@3jhX&#!`-S;Qwl_0}jK#0_ZO~GA&vRaE&b~^rZj_nnQO}jRP4R5M&%Xrtz8k%;IoHawRzkabHQqSE zOke2ybX;dg2vTJ-ou(^YQrKkF7TwBy<&?&qjH?@0GXFfB{S;U%14R>iae!YY5RnfV!hPHPMgzu*XDG=*Q{R}8)agZMQ^ z0iJEZZ~T3~<&G$dCcemZv+fY zagXy;C+GSA^CH#R5UXe4*VI=m9>V2;gP2vIj(RDIwh>X(k0e+4sn zW!5PEBe@EY7K>&IBO68YbE`YPNCzancTI(}LX}u_TIIHAm zN0cn{lvU^gdIQ`@mv5pjZsr&4Ei`{CX5%(~dhf#m+>S-mo-9GB$Vw_YugIocMkjDr zR*?bfHLJ))+&iMkDg`egJ3VQF<6n5idGce{NI~L^~58>oixH!B*yK zrY!9>EbVpmGg+cjR)?xWesMRAP2W|y)1rfest}>D%xgkBS`WQ+w4U}F{$Cpfs>qi7 zU5w;zl6Vj1;9eI0eQX8yvl{pFL+k-+c|CSP zL&tI&iZLCM>HzKD=~Eq~l~q2~AzxwhP&7MN{OeJ~VjolgE!q0#f8}x_dWOd2Wt}AW zRr^tX44Yyn5f9K`N+%W^MpsMqFs|P(A34z1)Np6=VbsKGxYjyz7(4y78jf_?GM^8P z=qpRdVNAxOn2N_x&0y!^C_CG6)ZuYX%eCPyNmBfOXX9-+ek{aZN_?WaR}+@XPXGV_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/Checks.java b/tests/test_data/std/jdk/internal/module/Checks.java new file mode 100644 index 00000000..7965391f --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/Checks.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.util.Set; + +/** + * Utility class for checking module, package, and class names. + */ + +public final class Checks { + + private Checks() { } + + /** + * Checks a name to ensure that it's a legal module name. + * + * @throws IllegalArgumentException if name is null or not a legal + * module name + */ + public static String requireModuleName(String name) { + if (name == null) + throw new IllegalArgumentException("Null module name"); + int next; + int off = 0; + while ((next = name.indexOf('.', off)) != -1) { + String id = name.substring(off, next); + if (!isJavaIdentifier(id)) { + throw new IllegalArgumentException(name + ": Invalid module name" + + ": '" + id + "' is not a Java identifier"); + } + off = next+1; + } + String last = name.substring(off); + if (!isJavaIdentifier(last)) { + throw new IllegalArgumentException(name + ": Invalid module name" + + ": '" + last + "' is not a Java identifier"); + } + return name; + } + + /** + * Checks a name to ensure that it's a legal package name. + * + * @throws IllegalArgumentException if name is null or not a legal + * package name + */ + public static String requirePackageName(String name) { + return requireTypeName("package name", name); + } + + /** + * Returns {@code true} if the given name is a legal package name. + */ + public static boolean isPackageName(String name) { + return isTypeName(name); + } + + /** + * Checks a name to ensure that it's a legal qualified class name + * + * @throws IllegalArgumentException if name is null or not a legal + * qualified class name + */ + public static String requireServiceTypeName(String name) { + return requireQualifiedClassName("service type name", name); + } + + /** + * Checks a name to ensure that it's a legal qualified class name. + * + * @throws IllegalArgumentException if name is null or not a legal + * qualified class name + */ + public static String requireServiceProviderName(String name) { + return requireQualifiedClassName("service provider name", name); + } + + /** + * Checks a name to ensure that it's a legal qualified class name in + * a named package. + * + * @throws IllegalArgumentException if name is null or not a legal + * qualified class name in a named package + */ + public static String requireQualifiedClassName(String what, String name) { + requireTypeName(what, name); + if (name.indexOf('.') == -1) + throw new IllegalArgumentException(name + ": is not a qualified name of" + + " a Java class in a named package"); + return name; + } + + /** + * Returns {@code true} if the given name is a legal class name. + */ + public static boolean isClassName(String name) { + return isTypeName(name); + } + + /** + * Returns {@code true} if the given name is a legal type name. + */ + private static boolean isTypeName(String name) { + int next; + int off = 0; + while ((next = name.indexOf('.', off)) != -1) { + String id = name.substring(off, next); + if (!isJavaIdentifier(id)) + return false; + off = next+1; + } + String last = name.substring(off); + return isJavaIdentifier(last); + } + + /** + * Checks if the given name is a legal type name. + * + * @throws IllegalArgumentException if name is null or not a legal + * type name + */ + private static String requireTypeName(String what, String name) { + if (name == null) + throw new IllegalArgumentException("Null " + what); + int next; + int off = 0; + while ((next = name.indexOf('.', off)) != -1) { + String id = name.substring(off, next); + if (!isJavaIdentifier(id)) { + throw new IllegalArgumentException(name + ": Invalid " + what + + ": '" + id + "' is not a Java identifier"); + } + off = next + 1; + } + String last = name.substring(off); + if (!isJavaIdentifier(last)) { + throw new IllegalArgumentException(name + ": Invalid " + what + + ": '" + last + "' is not a Java identifier"); + } + return name; + } + + /** + * Returns true if the given string is a legal Java identifier, + * otherwise false. + */ + public static boolean isJavaIdentifier(String str) { + if (str.isEmpty() || RESERVED.contains(str)) + return false; + + int first = Character.codePointAt(str, 0); + if (!Character.isJavaIdentifierStart(first)) + return false; + + int i = Character.charCount(first); + while (i < str.length()) { + int cp = Character.codePointAt(str, i); + if (!Character.isJavaIdentifierPart(cp)) + return false; + i += Character.charCount(cp); + } + + return true; + } + + // keywords, boolean and null literals, not allowed in identifiers + private static final Set RESERVED = Set.of( + "abstract", + "assert", + "boolean", + "break", + "byte", + "case", + "catch", + "char", + "class", + "const", + "continue", + "default", + "do", + "double", + "else", + "enum", + "extends", + "final", + "finally", + "float", + "for", + "goto", + "if", + "implements", + "import", + "instanceof", + "int", + "interface", + "long", + "native", + "new", + "package", + "private", + "protected", + "public", + "return", + "short", + "static", + "strictfp", + "super", + "switch", + "synchronized", + "this", + "throw", + "throws", + "transient", + "try", + "void", + "volatile", + "while", + "true", + "false", + "null", + "_" + ); +} diff --git a/tests/test_data/std/jdk/internal/module/ClassFileConstants.class b/tests/test_data/std/jdk/internal/module/ClassFileConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..703e5448002c964ef847564a36661c8a27fd0591 GIT binary patch literal 1132 zcma)+TT|0O6vxlD1!5_*R1^^}-~|Ddc)!6oF3FZ=Op{KM*5N6$EtwJs$xM?vKKhk> za>fTgfFH{7Y)WwlUwp~V@4x>&=j_=t`Stt9PXN$hw+sa+&OoUGQ!q`ScFaF>HRAC= zwR^`wKO-=`8^&SwoNgAJxvZrQJ`uOPt!&i1zHlP8IQ9R zkG5>RV=@AD^KV=?8;0>b?uI$F~4D$Oo1AKvYU*C{XitZ zN?aY)%LEq3svh)41NJ2g;xtTR0@ZO|zfHA|bf38jTqQ6+j@{<{6FvyAx`i`WiyD@% znbbw!vN)XA(Bfg7-w6vnGkVn7XPyE#2vo)O`=hj7hk5D=1&?&j3U5SAfO1ti+I}-tH@6zev14|;^)XOBz}pN6~sRQ*H_pf6<31m)Yf+(-}08d#;@20 VZ0Z~QR>lT+3-6F{BJo>*oj=E!)=>Ze literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ClassFileConstants.java b/tests/test_data/std/jdk/internal/module/ClassFileConstants.java new file mode 100644 index 00000000..66e241ee --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ClassFileConstants.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + + +// Constants in module-info.class files + +public class ClassFileConstants { + + private ClassFileConstants() { } + + // Attribute names + public static final String MODULE = "Module"; + public static final String SOURCE_FILE = "SourceFile"; + public static final String SDE = "SourceDebugExtension"; + + public static final String MODULE_PACKAGES = "ModulePackages"; + public static final String MODULE_MAIN_CLASS = "ModuleMainClass"; + public static final String MODULE_TARGET = "ModuleTarget"; + public static final String MODULE_HASHES = "ModuleHashes"; + public static final String MODULE_RESOLUTION = "ModuleResolution"; + + // access, requires, exports, and opens flags + public static final int ACC_MODULE = 0x8000; + public static final int ACC_OPEN = 0x0020; + public static final int ACC_TRANSITIVE = 0x0020; + public static final int ACC_STATIC_PHASE = 0x0040; + public static final int ACC_SYNTHETIC = 0x1000; + public static final int ACC_MANDATED = 0x8000; + + // ModuleResolution_attribute resolution flags + public static final int DO_NOT_RESOLVE_BY_DEFAULT = 0x0001; + public static final int WARN_DEPRECATED = 0x0002; + public static final int WARN_DEPRECATED_FOR_REMOVAL = 0x0004; + public static final int WARN_INCUBATING = 0x0008; + +} diff --git a/tests/test_data/std/jdk/internal/module/DefaultRoots.class b/tests/test_data/std/jdk/internal/module/DefaultRoots.class new file mode 100644 index 0000000000000000000000000000000000000000..18d0d3115f68bf86dbd9c3aaa9b2de6185ed77d3 GIT binary patch literal 3677 zcma)9Sy$Ue6#m963Pyk-Ta!RmlCrchX|p@c0)%V^5=he~T@qo-L?BD9EYr|^U(c(UnWjK%S9j9eTyPCDKCZioMl_>EK}UqN5T(&(^uu`sJTk*4wo;FgNtJCg1Sf^mUiVbKNSX;7Nrke;d zhUrQ#4s?Z}FQYN+S(y&v6WFL?6E+LfX}O#^E3j#KfI|UN58qZ5+tA67XSJNb{$=ei z2;9kh1UqDS?iDx^DDiT;OtKPTHOn~Jh8k>)q6fVS?o)9;b}}_fVmDx$CRt-Uc{=Rc z%rgT}=5P?8g^ixSeJXb00rDl~%M0{{eO@9HU=8s!5yfuoQLtCVKI|tArqa`K!(#p{ z&5Q^B4(b`LV7g&cbuxN8E8;0ptym#m`US(>TixJ- z43EEYS4&L~Yq@|Du>eTWqdJ-I;}ua<$y*7e2X3+IKGHSo=oycI3&($1j7sEY5suph zC#4S=lFqGRcJ7pIgm;L3*OODbk?IVOK! zT~yk|y`gXhOD%PHJ&HH*rh>OrWbw9a`&Ar}B^6Jg910&+LX=;eFT z%lB2dD8z7)$VX!MSYTg83n46F6G4Sh0je2s6I%~C83 zYsQ||<4KR)%!-!L^ZPWe1k_WOr8@(rme1?*zz+^F1wW7mOQN%!qY8fF1?J9M z*|_|u@D8(^*J=5qaO8!W*S{-#i*pnl>w5l#_=A%OG(P2LpbHaxs{RI~kmlP8d5Ph! zE1X~FD3u=VnTH}Uk0ycJSP9P7MmXz`vn>(y-p2NY#jap+4&C#JNANeAf2R)L?nc4` zp~kQW>#>(&`v~y>R}SI`pAyd+-zIcq_(toPC}(=&$$ zOLlz!21EYUW7^Z_YcUa(=Q?GjmP>(__MTff5O{ewaA+P!1a4vAH}3O&SkLGIXLwsm z^8bio#$$w+rcvJM&xGu?vnyCYEGnxcu+z^`qHUs`Q#Ya1{)*ZfskkPTl;Mz)COid) z-}C&dL!|Mjpgz`dpf62CGCv(Xy|*wjkFkhEdIQb9bGUG0iT-BV0fX1d1h;c61-ruw zF+Vb;61FH>+~8Sce+(>^Jeb3!N*?Sf^WbS*qu!DS1To8n2%f>S9Cy>PFSzy`Uck%V p>=nF*cY?L+_#jyO5FZ6=pWt(ROUX9sI8EMshjsWKKjLSs`yYjs=j#9f literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/DefaultRoots.java b/tests/test_data/std/jdk/internal/module/DefaultRoots.java new file mode 100644 index 00000000..54c7a2c1 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/DefaultRoots.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Defines methods to compute the default set of root modules for the unnamed + * module. + */ + +public final class DefaultRoots { + private DefaultRoots() { } + + /** + * Returns the default set of root modules for the unnamed module from the + * modules observable with the intersection of two module finders. + * + * The first module finder should be the module finder that finds modules on + * the upgrade module path or among the system modules. The second module + * finder should be the module finder that finds all modules on the module + * path, or a subset of when using --limit-modules. + */ + static Set compute(ModuleFinder finder1, ModuleFinder finder2) { + return finder1.findAll().stream() + .filter(mref -> !ModuleResolution.doNotResolveByDefault(mref)) + .map(ModuleReference::descriptor) + .filter(descriptor -> finder2.find(descriptor.name()).isPresent() + && exportsAPI(descriptor)) + .map(ModuleDescriptor::name) + .collect(Collectors.toSet()); + } + + /** + * Returns the default set of root modules for the unnamed module from the + * modules observable with the given module finder. + * + * This method is used by the jlink system modules plugin. + */ + public static Set compute(ModuleFinder finder) { + return compute(finder, finder); + } + + /** + * Returns true if the given module exports a package to all modules + */ + private static boolean exportsAPI(ModuleDescriptor descriptor) { + return descriptor.exports() + .stream() + .filter(e -> !e.isQualified()) + .findAny() + .isPresent(); + } +} diff --git a/tests/test_data/std/jdk/internal/module/ExplodedSystemModules.class b/tests/test_data/std/jdk/internal/module/ExplodedSystemModules.class new file mode 100644 index 0000000000000000000000000000000000000000..a2212e8b05876e084e4ee54b6753145ba9f1bf31 GIT binary patch literal 1251 zcma))T~8B16o%g^m6lS3;s=UffT&$1ZuG*NlEwsUASq&4LZVzvx0CIZ?QSzWYxF;P z;}wY}dhd@ip6PCAB@^kzo}HQVKId!Z_n+@S0qkJ2f&ykrC{}R=vkXgp{)xLGj{^6g z(-*#GnBA6<)J=w&x^rAYnPFut+KaSM5f58R#j1jmi8asQ^t-37%zf@4?xvw|Tc3wv z+!bB#OQOYKe{`6Xu)wfxlm8=QDDDu;u-KN7c$W@3LLKo=NGHqf*yrIfSJLeB!=moV zgyC7+7TH=zgPQO0#2bcEzvuob4+I6Eo^<9ExGQ#p&4@DA(sg`j> ztn>erV=eLXS=vLvyF}LNPSzxa3f+A^B*mO3gNW-?(Ut68^lwkh#M4SfL1Q9-C$vS- zY&0os#fwwri?`BT^{Vyeo|}1N4dyA+faqP9>7(aNyQ{Qv>Ceo`(=)Jdv?ySatZ@UI zSRz}^1gK$|c68ymPS(I%^f$Uf@vE^D6&Rot19Z&>-exHl#L+RER@1M1t%{IdRA7Jh9sqjjoaW3+ns E7ja?*3;+NC literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ExplodedSystemModules.java b/tests/test_data/std/jdk/internal/module/ExplodedSystemModules.java new file mode 100644 index 00000000..c276647e --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ExplodedSystemModules.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.lang.module.ModuleDescriptor; +import java.util.Map; +import java.util.Set; + +/** + * A dummy SystemModules for use with exploded builds or testing. + */ + +class ExplodedSystemModules implements SystemModules { + @Override + public boolean hasSplitPackages() { + return true; // not known + } + + @Override + public boolean hasIncubatorModules() { + return true; // not known + } + + @Override + public ModuleDescriptor[] moduleDescriptors() { + throw new InternalError(); + } + + @Override + public ModuleTarget[] moduleTargets() { + throw new InternalError(); + } + + @Override + public ModuleHashes[] moduleHashes() { + throw new InternalError(); + } + + @Override + public ModuleResolution[] moduleResolutions() { + throw new InternalError(); + } + + @Override + public Map> moduleReads() { + throw new InternalError(); + } +} diff --git a/tests/test_data/std/jdk/internal/module/ModuleBootstrap$1.class b/tests/test_data/std/jdk/internal/module/ModuleBootstrap$1.class new file mode 100644 index 0000000000000000000000000000000000000000..b4b6407112962aa84bd43496b84943c0df8cc206 GIT binary patch literal 1353 zcma)6ZBG+H5PtS39F)VBiuj6xytM^65%KK^i4ce+1rlrcXtK21vUuHV?za3cO(ed2 zFn;z&8E3CWt`!U)_GWf6^UTaMH~Z`N_a6W@@oESb`fQ{e^kaZw_PF}Nl}d|Hao=qO z)s`>Z-B@e{fsS;@n={J{_6hfA8obGnDIN0@?zXh_-Cf@F4B()HA*30GVy{rtqHe#k z&|Vr2Mr>SjkU^Fq8>9GK)!qHWV^Prz18Y)Az0S~=FB}XbhwC=R9NfS-!$?}vC^sEJUhib&%Q?%KHLU;_6Ua_1TMn_33M4?{Yr?X`TL zANqnJe|h$powG2{#w5eUCHc3ds)~?ds)P2I*aXjpzrq1SYBQ)(;!H^@vDa!Gitt^# zlw2vOaQ}dZ(%d`7ls=L)i22f$X6(`U%CfGwZiSR1RinCkdMxWus`?qj-91u-;tdMS zCHU_IFqD#1{Rd_(5q$BKymcznHpRX6X&|Hd&b;Gl3{MQJy|yc&rprMqtcY!ChC9}? z1WRUoME#bk_(4Q8>}(KQlHKIeUg^0e%l^i&p*&}P5$Z^ zMKcWUiAcW*BH9&aM=23*`aFt6gh|?32MiBjWwYif07%jj(<{+OCxa>Scu3ky^I#ZD zap4rKxOfV?_yxnC$Yf!fz5@gUYXdW+8%Ps8i#d|>bSz}amPdg!1Gh!eA~{<847TtM zqZWSR=2zVQ7(1T>ZpDD(ZRZXkg`tQA0&GJslJ*Eo9cY(sCVf9a+r4l*iTe7x>T{98 a<2d;;o{&so1*>=wTUMxj5GgD!gVaB$q*TBF literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleBootstrap$Counters.class b/tests/test_data/std/jdk/internal/module/ModuleBootstrap$Counters.class new file mode 100644 index 0000000000000000000000000000000000000000..3a0d61a576ec2e2aaf7245436515807b8d0299ea GIT binary patch literal 2847 zcma)8X;Tze6g`i5Gd&C~;)n~V0oNc=#>5zrL1MrSMI;VlV$9OO6Iz?@v8M+mi)P== zzL~@r(=GQ-e_z6G{uBA|g zm;q@bj)Xwn8EewYIF>t>IXZksjRXRTPTRGEE`eCf=AmjNQEeb)q6VhGmNTPgGqxKj z-?f~~gg07rROU$d>h`>#5cpPpLyuR~76qaY9PjSy%^iHa=jieN!F|Va0^(!}wODMR z&cqU=BN61L3W1ssNV=Bm4cZebjNy=uq29zYEEh2IzM8bXVxhDw!o`&)8uVgyA+Y>F zuV|N5CRSq&(MIOtS=<+sj z&!b{OCdREozq-HxsEU)?BWt1)y9J~hPS;nk7icMK;C@m!k4Mfo?9-{#pbHO}=+*#< zF%=wEQwH`%#Sr+mJEjfyn>e5ilQbOC1<_^eHE~GGr`lmD%CmhqVxZr|Q49#IiAXiC z{L`5MKFZ=`v0ZgOGO>MOrE=l!S#rHl@c%@ifckLEL=J-_rl9L1DU|Tk44F8gk4){r zvEKf{xf4)L^*?OlBp#uMrxmiSBnR8e3^3z>J1c8~)IBP&VqTD?fVzveGphU)P9dfr zPnfVUOb)GlUb&+JTW_Dl+#!#^WRsvvta*2{#yYLBDEie=sYgAup>5&}&axhXS6UQ^ zR=+e$awgy!@J!@!uA+lzniN)EC+)c8;dY@9CBZ(jidASUb(^+f_L;U~LFwAijlm_Q{@4)3VAd`Ip)N z_pT|Um-@L`-eJ%SEQbLF`mLAx!~K>=v!2RVGT#+tw}k#bIZk$tIOQ8pkiAsSEBYg9 zzpZJm|Hs|drVk{Q->(Y6L9Y-P_(EWPq(|JIZr)tIuB-eW$0`&Qw@J?5lJT%5qM3JA z6))*H8uew%QKRl4e5dq927%`|uEO*D=5-g&^G@VD9{v)vc!8q~-$Ku{eh={-2UU2H zPrVEo!%G~SB?G*SSNN60tKq74?ttVISTYUc3KreOqEk1p^afVU1Jxo%phhI*D%8m} zc#Y;Uh&tlDj&nrTI2Vbd!&)EWG!bV{(=?WK#U4HG>4@v`K0R)l!NHx0hWJe! zUY?l2gVQ*E1?#5q(2qFv@b`GEAwGl0(<6N7Wi^BG893Mfy2jL3sP0y}t*v-9&wI62 zoVZx_(VWPTlMc2w$Zh20ZgO%Dw#e;hm-pg;+<^z>eK;X^Vp6taO76lX*@0JN7MEow zzL8xaXIvjpUlbVMT$;qaBJGXiQsVSFQ|>(fWhDK>u8i5 zwx%!4;7NY}h>N7|*&Aq_7lN)IWDS!xne-ym%33Uwb!d=FD26misGrku0-IR6O7Uw@ n^*fds=(!c<@hM}d!e{tAd|$_cGb4j%2-}4@gVj{ z+2SPupvhYdk7Gc_6AA_~M1eJMyNr=am&I?@G>hjB1|N}187~I1LJ@Uf9+wnc7F8pyb6dt0DrU#IQv`v^yv|G9;zohTuz;6kEGoE$ zR~X_AuuB!uA}WNli6k1eFQZZ784+_D9M!@QVZ1E zG~heR{?*TZk~}5X>7r^BbzU9InC4ck;!Rtp0X?F83Uv(YIdzG0%`mu?*41j2Q@8ar-|8|xr}5T8)1xAm@g>91;iA-*E0zoJ+A4R6t2zpI6}@eZv>AMfHlvdQp1R5}y3?~pIj#QfAQPOc{IU^qMdBgPZ- zb!-o(8SY~e(o7uY?fEno@2iJ(}v5sq=u7@>36~nB}ibd;U9feO8auWbtS7A(~8Dec5brVj=_qd;!s3w(u>{{dotG8F&- literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleBootstrap.class b/tests/test_data/std/jdk/internal/module/ModuleBootstrap.class new file mode 100644 index 0000000000000000000000000000000000000000..0c163aabc2a5a8d2c37f8ca653ca7fef86996b3d GIT binary patch literal 27634 zcmch=3w%_?*+2d~GiS4#&B=vq0xZ{X5h0L7Km#U#1PBO(O9`Oh1vkkCqPe-7fLOI^ z?MP?<&f z6!KGnO@%a=Y2>H2W(u@5)^3e=L|d4~Oq}!?uw`aLZ3@fGveV`j#GBzV=fMFQ$utD3 zEOlmA+S$G_7HNo<0tcI<*=U=JXbe-<#%RaNSX+BE*0Ggo!bH#5wH>jh){T|k>9|z^ z8V96!pbOLh9mkZPURl4X^n?H%&s5;4k2Ex3QgL}RDgBLEjJylbWTwLOKCx)T=~R-w zGJuO-(B2m7Fc8c7^~2g)@hV7DX_}v=+jOFE*c1T&ES4ERzpYc4D$eAKcSK?xK`N&i zewu01$yC8~+(0m@V)dJvHb)zT@oFMlg;_Lk%rr>|JHVj*IvCcQWz%c|w}-|@;&BkC zsjW4>peY`yYmPQB@p_@*T$`$B9Q>{&_X$@1+Kyc?b10^*EFenphZ;o^{w#8aJ)lBI#_q;MA zoMzMM0zN0w-tKu9r1f-$pU$-DEIQlaBM*x-#p}!FFQ`R*L$tA}HHmI#J($T!a~_*%D~O8YsgmQ-pG9ps1f3ZQ4kin8v0d zX}~T_b{#a=>NW>$edg*V>@nvm40o)8+JK zfPpGXa>Jkmdv|s;HJ8;!JHUAX`if0om8P~)b#CJTeH|9XgUI-%wk^)PRnd4`Ga$5K z4gtE-rmIA07eJb-S{qhHTiP~96WTjS-=u5&bgfO_qU)Fjr6eAL*c^?tV$}9XEFMi3 z2c*UNOf2@>Hr+rsf+^cNp}7hjj5oEFt%ODB0M(+AmdXJAkAvMb@}E#z-`3I+X>F*1 zh$Prxn@!t=4KxrGq+94#Kiwue^t(*Q4@91XCUbDG2-X{%GkaiO_!N!m=?gYNXx z_iWlBT#;?ClOPQkv?*TQ(%!LEW_PzuU1GE|97dF?@7weP>6QmZscmm=>R1`6KQFQ| z8kd*%*>u0W4B_SC*80x6NJm@DC2f!%pq+kt(579q`xvWr7|H42@Gz7~cHH;_E*Pd6 zpL_LQaB(o*dis$~-7>+!P4NYtE$uMswH=X;rg|66GRGd9_R>BqFw)$d1^`y>7{D77iATlJ`=w34qNkWF zVHl=~1Ct6p$_&G;Xcu{oGy`YP(69aUtWCe6--_?luL+p2EmqwekM?oR9H%(VHFK-{ z^gA(|0?D|~X;@tqZH&gEt@SV-zZWMe*=n)tI~$iEKre!slPfH0ZR;p%geL^ieV$$t z5B>ZgJx8zD^eVju-?h1|9^BLh{W3UB=Ox$ar#GN`%xJCAjS zEgCoDY>I4-7Db8@AjQpi+onI!pP^mFt#IT)nDSUwAi2iMNiZwV(O+!(E4_>E4bgag ztf?Kc>GE`P^=UX-kZcC}yib4g)8B3Sfd0WWd>}q_CIo@C9j_oU!85%R^jiI6&D%4s z)5Jwp8j&67#sT=3O&`+#LODaHR=0{@xExg29CdtzKK$bL^NO2W6`+p*11n4L{pLt> zQ-h&rkUpkQ{B+o+BXsl_y32tA+qr42(@(IQ6Nf`u)!gj71a5}9$mnB1CM^!Ym8BxL zD_E$gt+A-Z=z$^$DT*2+P4IVN`dHbl#e`T=6=0t*d1}(e^O#oZkYFCfQY00k$$pyy zoC*C7tJK~ma#S_(jAN0&bs)T0awb#eti*lq=d6TzHS&CFB)$puJ;*`QFf)v(aXaVs zadi?ByIxuhvN@ka5FLb+F|ihXMQ5>FUzx>)JlM}eY#u5a+@m5AO|UlDo#oLBI;8C| zn}_oVps5uVeSPeNir`V{j*N-(f;^IoY#zg7F)u*eG#~2KL=d3Tcm#@7H8mv*suxzR zsaY*;C)j+vtTH2derKdP9$>_BL1|OFu6A|xvH&B3%a!u76${qXRF|x*T79Yzvc%?6 zMwFIiJRk?9OlNz=Wgw(GG)ow4*QHJtKZ|5Rp32kwJl*CK`6P#RJf6K{cosw(Bc071 ztKh_fWevl0b^rq_KHt>(Yuj{oO3qanV1~^z`D7pu!V5u>c*V28`EAY3$az2>Dkp(o z^10IHS>iSN8)0D3UO>#T`4pZD5OL#g0u)woFV@ z^BSAi@@Yag1Y+%&W2qOM`1s!b$vMqO?B3ZDjhQK}vw1zAA+&^LkJQ7lE%E~C-)Yj? ze6o01KKXb}fHyd4hlI8^if?*pn{g@P5)%mfI)3;29I?5M>%m>E(Jk=$oqPml)7Z4J z6MDzk?B>rx^T3Sh)b>^APOVoI(nf#j=i)LE+e?YNJ-DRR<;{hQqZ?X9T(Fr*)l*no(0?<w=NVx`XbZZ z0me<6T4E%Fv?S-Hq#>XDe6jHSCC5}3famabfG?FiXCIqn zh3ZpToQ1B+3G!F?tA75P&0ptld}>zLNn-$4urbg+64E4q46Hal$FdUuDua9#U+w2_ z+I)>5cvQ+wb`4V+Fi5gf9ryFMB#iItR+x@7TPJw@YZ#cPytv%9RvH06Dk5jsUEJWOlRo7QWTbx4|$-{4v~s zOXr0IQv7_oxQWT}JRU8g7{1fy?}>ks*%Sx&#G|bpe!eSVGt7#dA?I~AH6ynZ#;DFR)Ls4U_t)<9K zd3zm78S{rWKOoo(bhJ6pBn-PVz`K~rjs;3grdSnmQ5|X<|5W^$hiv{4cf&P<5Z0fU zmK^vz66n#cjr~lpL@)vFv3akIkd+F6;BM_7Ao+4qsi%oC0(^iE`uP!?ACJ zxCv@s)Z{+U_{TQ?gdc};_C_<%uWP+@aWGJpCI()QY=DJ$41;H65b)3d%P22xmc;pd zq?tNg#S!42+Wa#{=v`>=?B-eAR7NLeIPNoN=wS1gHvftdtY=HybOCmTTnjSH+uu7! zr`t0&|C*l#ODDP^0U>)1Fu5yagMsPT03=z@zeT*pPX!p^xolUZ8SojUk%n_S;~mbh z#(eu35&DT~X2(Ul(@4yDT=uob*G3wnPMza$2Kjk@5m7q-0U@?`QEB}X&M7$T8J?4m z3Bm`<t`XkNK zBohMx{tMj4bFs04fZ|=7-;=~;o)b_k-q_j}i_S+ZCr-oPZ2micfZ-#~_6k#c;`;R- zt{P}@{a^ndSk}`yp@)F0a{i~x&Sx!pz*r?=@DcCisA0l?6Kr+7ng|<>%ur_(V-8KYDt!@x42UX*=1~a!j~URe z^($=P4!Cu?%mm^o%{Dctrl>Ljcmk}1yBss9;LgFmDVoS@ZKj&0ru)^2wmM0bClZd} zuZ7?*$c`kGYNOZzaS|^19_qOQ4lSf++UjIgAsfDu=111ci^YT@@Me(Qx-6BeW(n`k zW~v;Z&j4Lq{HHT`P@SUY`c;*Hf}BkPvZDnR>`i!mjh}wa*b0! zV!Bi4e44FJmsD3qbF_6M4lk(naFWx9g8Lz3VZCR{de7?PV$8T>uS~vPm^f@s2FDg$D%`qEC}BT(f+6)w1dZ$fT=_ zZFPyl7HU2wZ+tE!vfLv9eR8GFkS2fszPij-mn*S}iEe!s*#D%m}tzJkPRI#Clx zMFeqQv(?uX0?okyZCpXur&|$oUAkf~TRUK#;}3mkzFv6ss(uXQoIDArZzgGGY69w7 zs3V7n?sNhQjt`dw)VG13SuI8n&MBMax&d=!vNzi5CWRf>>`s&HU){D+_Hvn)c<1Qy zqz4(ttm!W_l|dC#+ibO6wo9@>@puVlO1DoRUfWrQ5!c{2>s5?+H zn>cVCWX9jK)ee)g7rqn@xZ74;>K>p8_%;|`-R9+iG*#Q5tO ziF<)bllyJ;L-l~eI4(UC*+1hx9CHK@_S`liAMdLNZM91P$~M2tDM&J@hivsDIjJ-9 z)T-JI)yu2q)l_d-UbTAh+UgBe^XFIB)^1o>Q?*E1?y*&m+KWhGO>On6K5d*Vc`fo8 z9^MkWCYaoh*g-vv1eTZ9&fNO(qx1nk%6JED^@xlYUb0~6z{BAriF(XdKb8|wV`N$V zHj=zpmDZ2TRGz^3sZXDZC+0^EJD{EfsY*(s27E~?yu;1W5+{uoP(MQo)FY%$qf)0) zsne)b6zVUa$oV``-oLWdQ|f7WcydzYf)&_pwqOMo3#xu?t7mBp^r({(4JbHHc?pS{ zJ z0W}^_2$@C}#oMFxO^r=ROtc`TDeBl1!A=*pVT(H2it;H}qOM-`M_awA-U0*2Ruy(0 zQjYz6FRs%Zdt)p=J=}KNi(bwNs6T`IR!3qG?xGe1oRTt0POhRTpb(ESg!dBluC3lv z?>l(+-}y_uf%5pf`oORLVXJ?Nvs#cc3#mpRODrm9R)Xq7^}l}gZ(Dt&5E6|C z`TOn1IQ(t0XIQ3eFBhZ^SRn8}4O#^s@Fl(IX)(If-LOk#&V&a)!O4UvSmO~$#F{v| zBF1q~Yq&8@yrRgjdV!);RI>^v0I`?o31yDbOE@BgI<0Ee^2N&+ zRTKraUkCg;)5ci@Y+0JE^s@9+Ie52S&eAlu2DA+hb*QWN%GRSLGS%Q%iM=)j^;kX5ugBZ^I7tZR zrZ8!OVaQlRG>(9!A$bf@&Z2b2gZg+q(XS`jx>zH8NI$jZCfsW`MbNP}S|5wb7Tq9l z@e*VtYmz79WY-&Z&C5)Ea`jct2|5|A#MY&{3>h5{7>DPaMxx_B9hkSZ=xIIG*3Uh`vbu#kgdZw*UmPR2*PdZa}h6HLd zmsG8-+Ay!Gwi@)8cv6CLtb*DbkTnzMns!P&qC?XY{h!LdslWcLjReWK z6VuKHQ`Vmc2R+ff4(T?qif54yt{w9Wio1C!@3G(G2OKPMwoQgh^v?I5GIGK%s7ff7 zHaUBY{2KOH+mIc{#+h-R;5E6s)k%tnV7*bDcCZO7qrkD^tVKyQww%EpmO?;;7lc@qh&7G3il$}lR(3O zNOqXLBsUm>mgo=E*o)+D3p!=Q5dzB=$RKw=z!??-w+VDcV&7Yq{R?M14YD97Kb@E0 zT%=m-qboW)py!YrFeM`cUR~4TU@naYGHp53sjC`z#HDLx0o)RaDFrd70I*Gufl(bU^7=z-Nw2SBjM}}~w zBo^r#Bn?iNx2^37nOo?_2N=`8>M)u5BsiulIisQ8dil|u;Jo>ZUx6Pc-?3)9VYBf!;d31Xe(nHI$G(^v0N z#F=JnK!M2nL?rQ9{eOYgGO%MMNS*G1(}#|q((9`OP{3KGn}9kt)a1H8M-vE6a@R6# zHtr}OPD2xjV&N}v5*i>;2aL5tUEpoufSEK<6hdaT;~EVf;bL9w*ViyD^33kjNM!^> zys80+=?FkZI|$ZR3NoWGgF`F=AE`fKqIxwJR@NF4hU~scYdB`pNa(At9_utOwkSO zgAq?INuL+pidD8_sXmi%VXE`;nls0Kf%AVuA_UwBDiEIZch(j*M@00SovT3Zsg>mp zIf6Lo-`U(CkxZX_{W0cvEDD?PH4Zp}n`6SLd3~@7(gl#Uk-!gceX;1qDA*|%XlvWD zpwrph76!rnlO#JGlNwB|UVNs}(Hr>p&G-Hn#6M$z0bR*X@aTU5J?I94CY;3aGdVh$ z+Z<`BYlw_@obd58<%ouZ9Pbjna}az1&x{mpf!o=0#&P@%?B}`=5>u}908G?fy9ydNgg>_H`#{!*U)JI>R1 z`8{DS(l$Ng=J0A6mMm9_a(((AL3&;P)7JlzBRZK-SGC4{&(r^#I?a&qV+TMQh6a+5 zQmP(+jD2DQZ}(#?519ExFmu?}2latG`g3k3{UVQ^%FVEF+B;w&3G}c&fRZI8pRM=m zeR+BxDgr?((+c{nEZefJ?6j0iQ|soo^P*)nM!$dqBaM-IoB@Z;%4+eJe(7C;+sR?r zQ?U)-9F32!X=^*LGqDru6(SFRrgdBm@7yc9pZ}#Z0J*QkQG<`W|6{g)$psek%kYC*{ATO*b70eycF;sNO(L;r=@q!_CA1E}Rn; z&@f%0%87L)N{W7l@~l*u$DuqsRaO_GJSSD=i721qDHqc)!fj5#8YU-CG-zkB^wFjd4nE^K zhQDzTtOH|iPL6F+5ZCm8O1%ti0>p>O_Tw^ECN9Pg0Dp)Je^`I`mjeD}fN(kBU-6mn zgM>TR?)k2jxX`4i0N@%a2gzKC^x&|w{7EJUl8cWwvF0X+P zE0GImCnofu!Dta$kEapfofYW20R5aNTu#?3^%pR0q2dtIM*zxC$!Rx1$NQ(cyUt?eTORolfiezhsdEpdC)4)(&ctZ58Ygm8_qpM3krkV>6Eaw zmu_d;Mkj@R?$hKE+v)glZa3XkktrYdlxNGwz2!OKj3l_MF1knnR3-sTO#(O`gZ!`} z5Dpxo5r8$++pUKl+C~{xxg8EXNr4{PFG!5xr)4S-jkHQpPpZr|H2;n!z1CmZhF~y z`Fh2m@Sw!YKRPda=q;8e?}WiS?^Wc3LBjca>7R;D%l|h}dx#2w&K~+td8jaS8wK)v zdl+|{fPWx2RG77m4*|P{z5|rMP8Zj%v%;CRJ)BXI37#D4)S_mcHQCe_fak)Q6$Se_ zxNZ;I6@?{-$PO2l?B#3>sLKcI@*%o>D6q+SOcmj9crOcv_z^oY48KMAonVy@?xL_&KBS96R{78_$_^KX zhdHzF>RlZ!s0g|A-%dHj@IHnj-peZ$g$wubYI#0g5wJYJaOgIgBS0p9HjFbp zFwSyebWu=f!WD%fJ{xoeQGt^JOf{p2&#AzQCyAs8`*VX7hk*+j>D7uMySN$a8M2q# zHB}5Av5m%yr1EC7j_}}pywx3VA7A8-7UC}n+a>^BRsmcF!-ISHii#nH!EJPFcyKpg z>Ck^@c&JPNugR04|Fyyu-F%&}0ob;iZ>$&|9ugkDmv2^JkMCBD2#4)EOF!ZlqXz88PH`F=1n7LaJRvtP3Zlg+w%I}5Y7lMPW0$UHIU@Q@zf z?R@MB@jfi8haZ-5H$PS}G{jE`GIQMa0a@dd;h{bJ3;FYOd00Mv6XNFt9ic-sc0WJA zE*#p!FYE@cL*atEDA!aKn5rR0XDk6HEevOtxa)dpAHOVkHN5hQJiV&$=M7<^w+IV= z+ep3$O^DwC!uYR_-YK-VQBh%bVGdT0377Qn`?5MzV7fA~e}spMp|-?esY_rEi1t7; z_rQqmr4a3d8QxE$=wTX12WbK>W|z>TFkFw(DfANypcO;9Q~^H9D6=aP4D5iTi=6v`4p2z3u z8gAC7bBk`^R^0?SYv!14=eUmZX1$d!(U5$g~?Zau?KSkLj#tQYy` z*6aK$>urA8dY7NIKH%S2NBFlsi=Xr5@gID{_$A+1e%V*dulP>nSA8e*YrgsXx^EG` z;akCf^sVPNeP{7IzB>MkubuzyyO2NdeThF57lYr0<8c*@)T`hWW`c7D<0~8HP&W7{ z7tY8W%Arr-R+_hb9R+o*UQG}#_!;6x7N}u#lU@Vgc$j*RX6m)53+rh#!+8RAJM?LQ zG8i;IU!RVrA)s`tUWccl;Dv8FP{0vi)9c~E7wT_dv@`UXG+2Kp`Lu&_c(Fcs?X688fHzV2Hu7l47X0EwYpB%(+F!Ab?OEkrLb=W<>*G4A7%J1(i_F~ zCEK@IZ^9Gu*1k5~gt7H1{K#{~uCED8qESV`$D{!p-)p#upq$72k3gi{Zjvswd!mAPS`8w*Mpm3t#}l z&)3RZnFy>>FN{z4zl2EmCIpq8ahN6|BC!tRyT3l6nlZQmgL_#B*$^>vIV8^yo~(zT z=r||Krns)jDm*xz$?_8MODz2TSA}mf9KnQ3k`c~$k_yAV{GY+g+)g9IaG&4mLQTeF z{NXlO`;15V!?4xO|L*F&SK@JFcF9CyxH2-5kK!BIdTA1T(Q<_Y=t@(yvS^vgpf$=* z8&oFMsi29(=0Nnv(JZ5KESiKHEuwOK2(u>Xi=lEPxSD5Fj+W&ZVZ;NTL|w5FJSX;- znv2}XZ3Y1?K|{cK1bI0IDF%Vx67LLB^<02f`V!z0x9D74{u#Qed6t9Ob%xxF>3<9tgzqUF)j^0aa>2lT`sJ%0R8EP;sP($boYAD5380vZ$eN7Fghtx|pymv^($F;nuGYnd zu71eD&4#X$Q+Xmu*C!mhBL8tfe;KAp843?JVU4^4h23{o;GIP2iz(v>B$Rs%x#vJ* zx+Ikf5k9^tA$*4^3w58+IlX{qdE51+KE4yerT#2v%nS^3X^+Y-)(2E>j~X<&TNNyK zxxvT}L`(u9V9jxE!`41v56=jBAZ~b9ysk%$IBg&B=d{?z3HMjpj(6KioEf(Es^ggU zs7V#R{b~xzVc#BAno2{JLn)Ig0pUtQM8N;)b;tJBLNlrN+)d>Er1uu*eFQu-y9&M-}HI$`JqmVish+0P@)OtEeodKP+o|dY!l88Bp^7NHJVgLcd zTz!?k+AOL0ft_#YcJQo$K0as915K{Aj0o|jjm+q%6>x%cN#i_N(w~>-+#2T8+Tt(ky zQKlgd8Iq)GZUD5PeE*xvzCxG)>aGZ>nx%S{t2>~8 zz$R|(GelSK{Ux#@$5J@Dr=2WyK4qvlDAGYis*}d6Ei^@409~||Rv^87n))K0gXczd zF*T`6ppPy!7&sA_UqOQm?)^x8oX*#Pc{ONrslL%rCIe?;ZvwS&BZoHW|3RIjNd!}- zJy=#7{V|#{j?#FLN_?!tuoiU3Q7SM58}$+ShPyoc9iSE8mFJ+9UI1D}D=d~&>NlKZ zZVG`l#SZeo&U3)ah1N*$@03Donz0FL?QLWmb1O+CFmqS$Ym-yB87uTsNGmFcjk*%| z-ma#>>YKpHHB^PqMe17y2a>})0j{iLF9*|fy$v|PrUK13>rHWnc_+eZ);mgUV-D8Z zi!X!q35$wTY1nfF)|*R=!h4hl*Z%qoUqR2vHF$I+N*ZMGIqlii_FZg43(mog92AXq}j&K;$h zepP1({LB$Jo$!#k&^V1FM}JIyv4L=Z4mg(67(lo^xK-}zruP8fhZ$AsSs``BvMHdu zkP~!A#=f`&y6USI-dt(kh?;QU*&sCNikHJ>3&9ciY2rbtM@Y%#4)qhLvd0nQK7r^K z*=F?%2>&nPg!~Gqe+o{>({!?WHYwJgt?Op4<|aLz9lLYTzt^?UCJ#9sq2MbZ;&jWU&EM%{m==> zmK$A~1z%3BL4Ls7&gJW@a8@@%YM^f&F8(qq9GQVr*sZ<;M-n+%g`DDcnw0bqZxdh8 z@eps9NAV3s=c_xrdaGovUSYGtwkvF3ktbK!vb9Oxi^ydgk;}BobC6;!MiByMCI*4a zOU@^^OJxv!WU_(dYNXcSD*%8rRC~1TCd)KVEz#%;!WDD-hzpEhptqAq3hLO={xFO zx>@~=?ouDXpZW*Ah|3@^tADelK4QQ65AFwl%!Rm!F&vjL#v!{k8MiHFYUVjwaTP96 zEYumi1TwN(XY$#&7*VIQkz>i_Ex6=xp$_rIy1;PhHOQm*;WzC-E+B`4)S@qiVCOP6 z3XKBDrrA7O-vtGbL5q00z7DR1pU&Z7MkxfSkqh+Qc$XevZp z)B}W(FL5OSPmX$!I^BhF6-I7X&jN}z{4XlQfpI(Jz=3gx1H+>-zC!uIc~B8YC|eW- z7apZKuF}xgAEDu}kghbCrX$q==>DY)s zerE1R6cC*QlOsCE1>kkO@4=?w_mjJsseN0uTNH_B-&PNYF~-+dxS9%I84bHfG^lu& z>W1pshtC7hPy2*}oGr{8G$B0+XD5o`9iI_?#=;iOSQx#?s5veM0)A4`|*cEq#Gl zdPKia`jbG2k1342fotFIhaZY-9nOMzF6bg&;^iUr(_?yxN$(IId&$oKe|$uJ3RL!7 z%Fy#@gq~01^#bgQRa3EEM5Rb{EJM0~4X|}Ko*Q%xZG?KiRIf1j6CZI|(nqx54<92=lyed-X^sG1A+wggs_!2yIcKId~S6+VV7P#6H>nsHWJfOn6bTIUD(ov z8QtnR*c$lf);Znk1=*rC_M~rr>do%W(bX+*AFnd}>PB_O{v^?ncoW1I8 zadU%wMK(O$7iIf-V$wkUDK%P1VRNiYvM0twG4=+$v4j_GT}S^A_N6@L3$d|7NNp>9 zHd3)0Xp}yO#_BqntQ+7QG{R}vNT=vckgO&|Zs$@RlFQ97@>_H}eMz5B*XRzq4Qb&6 zdNVx(#r+#3gg=0z@gIF5YyCye&=;_cjf+A0OI)rmHF~&;4kP0@HT+$qD$5BdM8x-E`5Rk)&NF-z7pCg!T)W0w3>Ns#80$k_a4e;c})j5lxyvI7B4MI|Q zJ7YO?geE)sy0n*$GqHd$w(Ac$A0z#^q3MPNV-Xfi>O~-h#HhryiIzb6TnwS~kKjGw z8wnh?r|Fm~7C@O21%YR)g;I_h&X5;~r?Ei-oS8<>%3VO+z(x^`arJuY*bfo~eSzHQ z0pc@gmcSR^NA7k$2`Wtn$m&slE$&u-Lk!Xv#4R2WSqTvGwN4HQ9sv*%!@e4r1()9^gSSKKV_|b-{)EkIx_TePp7^k& zKpaNBG;_Q(u^7(TBjZ5p?*WfHXtchIj??#039RJ|{R4RD_fnOhqVI@Ud&es{F`35x z$e58~*q*^R;JV08l6=29isXgH{%ShO_j*vBsc*#~I3y+a@m&CmU7i`fD=G9LEvi7$ z2*5?R&PW+^lMm4caCq#X2kh`9SbY723wAvyC+NocphxAL-qhFzi^=lrAKjG>Q(Q^f4AE8;IoO1A! zHBQSDX$pE)L^P^ zgmZ|z{Anr9G1^Vd_Ha#}(bDJyr&HvP0TCy6j}1|e901~s&wz+i(tXzm^umZY_n8~E z)l-@`VE9$KWibBbg%NNE#_G{S5x#aQM!}zEI)+wSNbXawEOgH{j7QV zt$t4b-aNga|Da!S>t0RPy^*YYD_Qqvx9(T^ulijV-uwD*?$ZbQL-*<5`Xlr7g8o<^ zaqEuiUZ>8&8BM3o(pH9rEiEdBp~H!4D;Fl}d3@$UYfeEuepDUzT7xn&t$eG%8cgB; E2e=*?tN;K2 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleBootstrap.java b/tests/test_data/std/jdk/internal/module/ModuleBootstrap.java new file mode 100644 index 00000000..b97b0a2d --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModuleBootstrap.java @@ -0,0 +1,1088 @@ +/* + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.File; +import java.io.PrintStream; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.lang.module.ResolvedModule; +import java.net.URI; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.JavaLangModuleAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.loader.BootLoader; +import jdk.internal.loader.BuiltinClassLoader; +import jdk.internal.loader.ClassLoaders; +import jdk.internal.misc.CDS; +import jdk.internal.perf.PerfCounter; + +/** + * Initializes/boots the module system. + * + * The {@link #boot() boot} method is called early in the startup to initialize + * the module system. In summary, the boot method creates a Configuration by + * resolving a set of module names specified via the launcher (or equivalent) + * -m and --add-modules options. The modules are located on a module path that + * is constructed from the upgrade module path, system modules, and application + * module path. The Configuration is instantiated as the boot layer with each + * module in the configuration defined to a class loader. + */ + +public final class ModuleBootstrap { + private ModuleBootstrap() { } + + private static final String JAVA_BASE = "java.base"; + + // the token for "all default modules" + private static final String ALL_DEFAULT = "ALL-DEFAULT"; + + // the token for "all unnamed modules" + private static final String ALL_UNNAMED = "ALL-UNNAMED"; + + // the token for "all system modules" + private static final String ALL_SYSTEM = "ALL-SYSTEM"; + + // the token for "all modules on the module path" + private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; + + // access to java.lang/module + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess(); + + // The ModulePatcher for the initial configuration + private static final ModulePatcher patcher = initModulePatcher(); + + /** + * Returns the ModulePatcher for the initial configuration. + */ + public static ModulePatcher patcher() { + return patcher; + } + + // ModuleFinders for the initial configuration + private static volatile ModuleFinder unlimitedFinder; + private static volatile ModuleFinder limitedFinder; + + /** + * Returns the ModuleFinder for the initial configuration before + * observability is limited by the --limit-modules command line option. + * + * @apiNote Used to support locating modules {@code java.instrument} and + * {@code jdk.management.agent} modules when they are loaded dynamically. + */ + public static ModuleFinder unlimitedFinder() { + ModuleFinder finder = unlimitedFinder; + if (finder == null) { + return ModuleFinder.ofSystem(); + } else { + return finder; + } + } + + /** + * Returns the ModuleFinder for the initial configuration. + * + * @apiNote Used to support "{@code java --list-modules}". + */ + public static ModuleFinder limitedFinder() { + ModuleFinder finder = limitedFinder; + if (finder == null) { + return unlimitedFinder(); + } else { + return finder; + } + } + + /** + * Returns true if the archived boot layer can be used. The system properties + * are checked in the order that they are used by boot2. + */ + private static boolean canUseArchivedBootLayer() { + return getProperty("jdk.module.upgrade.path") == null && + getProperty("jdk.module.path") == null && + getProperty("jdk.module.patch.0") == null && // --patch-module + getProperty("jdk.module.addmods.0") == null && // --add-modules + getProperty("jdk.module.limitmods") == null && // --limit-modules + getProperty("jdk.module.addreads.0") == null && // --add-reads + getProperty("jdk.module.addexports.0") == null && // --add-exports + getProperty("jdk.module.addopens.0") == null; // --add-opens + } + + /** + * Initialize the module system, returning the boot layer. The boot layer + * is obtained from the CDS archive if possible, otherwise it is generated + * from the module graph. + * + * @see java.lang.System#initPhase2(boolean, boolean) + */ + public static ModuleLayer boot() { + Counters.start(); + + ModuleLayer bootLayer; + ArchivedBootLayer archivedBootLayer = ArchivedBootLayer.get(); + if (archivedBootLayer != null) { + assert canUseArchivedBootLayer(); + bootLayer = archivedBootLayer.bootLayer(); + BootLoader.getUnnamedModule(); // trigger of BootLoader. + CDS.defineArchivedModules(ClassLoaders.platformClassLoader(), ClassLoaders.appClassLoader()); + + // assume boot layer has at least one module providing a service + // that is mapped to the application class loader. + JLA.bindToLoader(bootLayer, ClassLoaders.appClassLoader()); + } else { + bootLayer = boot2(); + } + + Counters.publish("jdk.module.boot.totalTime"); + return bootLayer; + } + + private static ModuleLayer boot2() { + // Step 0: Command line options + + ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path"); + ModuleFinder appModulePath = finderFor("jdk.module.path"); + boolean isPatched = patcher.hasPatches(); + String mainModule = System.getProperty("jdk.module.main"); + Set addModules = addModules(); + Set limitModules = limitModules(); + + PrintStream traceOutput = null; + String trace = getAndRemoveProperty("jdk.module.showModuleResolution"); + if (trace != null && Boolean.parseBoolean(trace)) + traceOutput = System.out; + + Counters.add("jdk.module.boot.0.commandLineTime"); + + // Step 1: The observable system modules, either all system modules + // or the system modules pre-generated for the initial module (the + // initial module may be the unnamed module). If the system modules + // are pre-generated for the initial module then resolution can be + // skipped. + + SystemModules systemModules = null; + ModuleFinder systemModuleFinder; + + boolean haveModulePath = (appModulePath != null || upgradeModulePath != null); + boolean needResolution = true; + boolean canArchive = false; + boolean hasSplitPackages; + boolean hasIncubatorModules; + + // If the java heap was archived at CDS dump time and the environment + // at dump time matches the current environment then use the archived + // system modules and finder. + ArchivedModuleGraph archivedModuleGraph = ArchivedModuleGraph.get(mainModule); + if (archivedModuleGraph != null + && !haveModulePath + && addModules.isEmpty() + && limitModules.isEmpty() + && !isPatched) { + systemModuleFinder = archivedModuleGraph.finder(); + hasSplitPackages = archivedModuleGraph.hasSplitPackages(); + hasIncubatorModules = archivedModuleGraph.hasIncubatorModules(); + needResolution = (traceOutput != null); + } else { + if (!haveModulePath && addModules.isEmpty() && limitModules.isEmpty()) { + systemModules = SystemModuleFinders.systemModules(mainModule); + if (systemModules != null && !isPatched) { + needResolution = (traceOutput != null); + if (CDS.isDumpingStaticArchive()) + canArchive = true; + } + } + if (systemModules == null) { + // all system modules are observable + systemModules = SystemModuleFinders.allSystemModules(); + } + if (systemModules != null) { + // images build + systemModuleFinder = SystemModuleFinders.of(systemModules); + } else { + // exploded build or testing + systemModules = new ExplodedSystemModules(); + systemModuleFinder = SystemModuleFinders.ofSystem(); + } + + hasSplitPackages = systemModules.hasSplitPackages(); + hasIncubatorModules = systemModules.hasIncubatorModules(); + // not using the archived module graph - avoid accidental use + archivedModuleGraph = null; + } + + Counters.add("jdk.module.boot.1.systemModulesTime"); + + // Step 2: Define and load java.base. This patches all classes loaded + // to date so that they are members of java.base. Once java.base is + // loaded then resources in java.base are available for error messages + // needed from here on. + + ModuleReference base = systemModuleFinder.find(JAVA_BASE).orElse(null); + if (base == null) + throw new InternalError(JAVA_BASE + " not found"); + URI baseUri = base.location().orElse(null); + if (baseUri == null) + throw new InternalError(JAVA_BASE + " does not have a location"); + BootLoader.loadModule(base); + + Module baseModule = Modules.defineModule(null, base.descriptor(), baseUri); + JLA.addEnableNativeAccess(baseModule); + + // Step 2a: Scan all modules when --validate-modules specified + + if (getAndRemoveProperty("jdk.module.validation") != null) { + int errors = ModulePathValidator.scanAllModules(System.out); + if (errors > 0) { + fail("Validation of module path failed"); + } + } + + Counters.add("jdk.module.boot.2.defineBaseTime"); + + // Step 3: If resolution is needed then create the module finder and + // the set of root modules to resolve. + + ModuleFinder savedModuleFinder = null; + ModuleFinder finder; + Set roots; + if (needResolution) { + + // upgraded modules override the modules in the run-time image + if (upgradeModulePath != null) + systemModuleFinder = ModuleFinder.compose(upgradeModulePath, + systemModuleFinder); + + // The module finder: [--upgrade-module-path] system [--module-path] + if (appModulePath != null) { + finder = ModuleFinder.compose(systemModuleFinder, appModulePath); + } else { + finder = systemModuleFinder; + } + + // The root modules to resolve + roots = new HashSet<>(); + + // launcher -m option to specify the main/initial module + if (mainModule != null) + roots.add(mainModule); + + // additional module(s) specified by --add-modules + boolean addAllDefaultModules = false; + boolean addAllSystemModules = false; + boolean addAllApplicationModules = false; + for (String mod : addModules) { + switch (mod) { + case ALL_DEFAULT: + addAllDefaultModules = true; + break; + case ALL_SYSTEM: + addAllSystemModules = true; + break; + case ALL_MODULE_PATH: + addAllApplicationModules = true; + break; + default: + roots.add(mod); + } + } + + // --limit-modules + savedModuleFinder = finder; + if (!limitModules.isEmpty()) { + finder = limitFinder(finder, limitModules, roots); + } + + // If there is no initial module specified then assume that the initial + // module is the unnamed module of the application class loader. This + // is implemented by resolving all observable modules that export an + // API. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT bit set in + // their ModuleResolution attribute flags are excluded from the + // default set of roots. + if (mainModule == null || addAllDefaultModules) { + roots.addAll(DefaultRoots.compute(systemModuleFinder, finder)); + } + + // If `--add-modules ALL-SYSTEM` is specified then all observable system + // modules will be resolved. + if (addAllSystemModules) { + ModuleFinder f = finder; // observable modules + systemModuleFinder.findAll() + .stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .filter(mn -> f.find(mn).isPresent()) // observable + .forEach(mn -> roots.add(mn)); + } + + // If `--add-modules ALL-MODULE-PATH` is specified then all observable + // modules on the application module path will be resolved. + if (appModulePath != null && addAllApplicationModules) { + ModuleFinder f = finder; // observable modules + appModulePath.findAll() + .stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .filter(mn -> f.find(mn).isPresent()) // observable + .forEach(mn -> roots.add(mn)); + } + } else { + // no resolution case + finder = systemModuleFinder; + roots = null; + } + + Counters.add("jdk.module.boot.3.optionsAndRootsTime"); + + // Step 4: Resolve the root modules, with service binding, to create + // the configuration for the boot layer. If resolution is not needed + // then create the configuration for the boot layer from the + // readability graph created at link time. + + Configuration cf; + if (needResolution) { + cf = Modules.newBootLayerConfiguration(finder, roots, traceOutput); + } else { + if (archivedModuleGraph != null) { + cf = archivedModuleGraph.configuration(); + } else { + Map> map = systemModules.moduleReads(); + cf = JLMA.newConfiguration(systemModuleFinder, map); + } + } + + // check that modules specified to --patch-module are resolved + if (isPatched) { + patcher.patchedModules() + .stream() + .filter(mn -> cf.findModule(mn).isEmpty()) + .forEach(mn -> warnUnknownModule(PATCH_MODULE, mn)); + } + + Counters.add("jdk.module.boot.4.resolveTime"); + + // Step 5: Map the modules in the configuration to class loaders. + // The static configuration provides the mapping of standard and JDK + // modules to the boot and platform loaders. All other modules (JDK + // tool modules, and both explicit and automatic modules on the + // application module path) are defined to the application class + // loader. + + // mapping of modules to class loaders + Function clf; + if (archivedModuleGraph != null) { + clf = archivedModuleGraph.classLoaderFunction(); + } else { + clf = ModuleLoaderMap.mappingFunction(cf); + } + + // check that all modules to be mapped to the boot loader will be + // loaded from the runtime image + if (haveModulePath) { + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + String name = mref.descriptor().name(); + ClassLoader cl = clf.apply(name); + if (cl == null) { + if (upgradeModulePath != null + && upgradeModulePath.find(name).isPresent()) + fail(name + ": cannot be loaded from upgrade module path"); + if (systemModuleFinder.find(name).isEmpty()) + fail(name + ": cannot be loaded from application module path"); + } + } + } + + // check for split packages in the modules mapped to the built-in loaders + if (hasSplitPackages || isPatched || haveModulePath) { + checkSplitPackages(cf, clf); + } + + // load/register the modules with the built-in class loaders + loadModules(cf, clf); + Counters.add("jdk.module.boot.5.loadModulesTime"); + + // Step 6: Define all modules to the VM + + ModuleLayer bootLayer = ModuleLayer.empty().defineModules(cf, clf); + Counters.add("jdk.module.boot.6.layerCreateTime"); + + // Step 7: Miscellaneous + + // check incubating status + if (hasIncubatorModules || haveModulePath) { + checkIncubatingStatus(cf); + } + + // --add-reads, --add-exports/--add-opens + addExtraReads(bootLayer); + boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer); + + // add enable native access + addEnableNativeAccess(bootLayer); + + Counters.add("jdk.module.boot.7.adjustModulesTime"); + + // save module finders for later use + if (savedModuleFinder != null) { + unlimitedFinder = new SafeModuleFinder(savedModuleFinder); + if (savedModuleFinder != finder) + limitedFinder = new SafeModuleFinder(finder); + } + + // If -Xshare:dump and mainModule are specified, check if the mainModule + // is in the runtime image and not on the upgrade module path. If so, + // set canArchive to true so that the module graph can be archived. + if (CDS.isDumpingStaticArchive() && mainModule != null) { + String scheme = systemModuleFinder.find(mainModule) + .stream() + .map(ModuleReference::location) + .flatMap(Optional::stream) + .findAny() + .map(URI::getScheme) + .orElse(null); + if ("jrt".equalsIgnoreCase(scheme)) { + canArchive = true; + } + } + + // Archive module graph and boot layer can be archived at CDS dump time. + if (canArchive) { + ArchivedModuleGraph.archive(hasSplitPackages, + hasIncubatorModules, + systemModuleFinder, + cf, + clf, + mainModule); + if (!hasSplitPackages && !hasIncubatorModules) { + ArchivedBootLayer.archive(bootLayer); + } + } + + return bootLayer; + } + + /** + * Load/register the modules to the built-in class loaders. + */ + private static void loadModules(Configuration cf, + Function clf) { + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + String name = resolvedModule.name(); + ClassLoader loader = clf.apply(name); + if (loader == null) { + // skip java.base as it is already loaded + if (!name.equals(JAVA_BASE)) { + BootLoader.loadModule(mref); + } + } else if (loader instanceof BuiltinClassLoader) { + ((BuiltinClassLoader) loader).loadModule(mref); + } + } + } + + /** + * Checks for split packages between modules defined to the built-in class + * loaders. + */ + private static void checkSplitPackages(Configuration cf, + Function clf) { + Map packageToModule = new HashMap<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); + String name = descriptor.name(); + ClassLoader loader = clf.apply(name); + if (loader == null || loader instanceof BuiltinClassLoader) { + for (String p : descriptor.packages()) { + String other = packageToModule.putIfAbsent(p, name); + if (other != null) { + String msg = "Package " + p + " in both module " + + name + " and module " + other; + throw new LayerInstantiationException(msg); + } + } + } + } + } + + /** + * Returns a ModuleFinder that limits observability to the given root + * modules, their transitive dependences, plus a set of other modules. + */ + private static ModuleFinder limitFinder(ModuleFinder finder, + Set roots, + Set otherMods) + { + // resolve all root modules + Configuration cf = Configuration.empty().resolve(finder, + ModuleFinder.of(), + roots); + + // module name -> reference + Map map = new HashMap<>(); + + // root modules and their transitive dependences + cf.modules().stream() + .map(ResolvedModule::reference) + .forEach(mref -> map.put(mref.descriptor().name(), mref)); + + // additional modules + otherMods.stream() + .map(finder::find) + .flatMap(Optional::stream) + .forEach(mref -> map.putIfAbsent(mref.descriptor().name(), mref)); + + // set of modules that are observable + Set mrefs = new HashSet<>(map.values()); + + return new ModuleFinder() { + @Override + public Optional find(String name) { + return Optional.ofNullable(map.get(name)); + } + @Override + public Set findAll() { + return mrefs; + } + }; + } + + /** + * Creates a finder from the module path that is the value of the given + * system property and optionally patched by --patch-module + */ + private static ModuleFinder finderFor(String prop) { + String s = System.getProperty(prop); + if (s == null) { + return null; + } else { + String[] dirs = s.split(File.pathSeparator); + Path[] paths = new Path[dirs.length]; + int i = 0; + for (String dir: dirs) { + paths[i++] = Path.of(dir); + } + return ModulePath.of(patcher, paths); + } + } + + /** + * Initialize the module patcher for the initial configuration passed on the + * value of the --patch-module options. + */ + private static ModulePatcher initModulePatcher() { + Map> map = decode("jdk.module.patch.", + File.pathSeparator, + false); + return new ModulePatcher(map); + } + + /** + * Returns the set of module names specified by --add-module options. + */ + private static Set addModules() { + String prefix = "jdk.module.addmods."; + int index = 0; + // the system property is removed after decoding + String value = getAndRemoveProperty(prefix + index); + if (value == null) { + return Set.of(); + } else { + Set modules = new HashSet<>(); + while (value != null) { + for (String s : value.split(",")) { + if (!s.isEmpty()) + modules.add(s); + } + index++; + value = getAndRemoveProperty(prefix + index); + } + return modules; + } + } + + /** + * Returns the set of module names specified by --limit-modules. + */ + private static Set limitModules() { + String value = getAndRemoveProperty("jdk.module.limitmods"); + if (value == null) { + return Set.of(); + } else { + Set names = new HashSet<>(); + for (String name : value.split(",")) { + if (name.length() > 0) names.add(name); + } + return names; + } + } + + /** + * Process the --add-reads options to add any additional read edges that + * are specified on the command-line. + */ + private static void addExtraReads(ModuleLayer bootLayer) { + + // decode the command line options + Map> map = decode("jdk.module.addreads."); + if (map.isEmpty()) + return; + + for (Map.Entry> e : map.entrySet()) { + + // the key is $MODULE + String mn = e.getKey(); + Optional om = bootLayer.findModule(mn); + if (om.isEmpty()) { + warnUnknownModule(ADD_READS, mn); + continue; + } + Module m = om.get(); + + // the value is the set of other modules (by name) + for (String name : e.getValue()) { + if (ALL_UNNAMED.equals(name)) { + Modules.addReadsAllUnnamed(m); + } else { + om = bootLayer.findModule(name); + if (om.isPresent()) { + Modules.addReads(m, om.get()); + } else { + warnUnknownModule(ADD_READS, name); + } + } + } + } + } + + /** + * Process the --add-exports and --add-opens options to export/open + * additional packages specified on the command-line. + */ + private static boolean addExtraExportsAndOpens(ModuleLayer bootLayer) { + boolean extraExportsOrOpens = false; + + // --add-exports + String prefix = "jdk.module.addexports."; + Map> extraExports = decode(prefix); + if (!extraExports.isEmpty()) { + addExtraExportsOrOpens(bootLayer, extraExports, false); + extraExportsOrOpens = true; + } + + + // --add-opens + prefix = "jdk.module.addopens."; + Map> extraOpens = decode(prefix); + if (!extraOpens.isEmpty()) { + addExtraExportsOrOpens(bootLayer, extraOpens, true); + extraExportsOrOpens = true; + } + + return extraExportsOrOpens; + } + + private static void addExtraExportsOrOpens(ModuleLayer bootLayer, + Map> map, + boolean opens) + { + String option = opens ? ADD_OPENS : ADD_EXPORTS; + for (Map.Entry> e : map.entrySet()) { + + // the key is $MODULE/$PACKAGE + String key = e.getKey(); + String[] s = key.split("/"); + if (s.length != 2) + fail(unableToParse(option, "/", key)); + + String mn = s[0]; + String pn = s[1]; + if (mn.isEmpty() || pn.isEmpty()) + fail(unableToParse(option, "/", key)); + + // The exporting module is in the boot layer + Module m; + Optional om = bootLayer.findModule(mn); + if (om.isEmpty()) { + warnUnknownModule(option, mn); + continue; + } + + m = om.get(); + + if (!m.getDescriptor().packages().contains(pn)) { + warn("package " + pn + " not in " + mn); + continue; + } + + // the value is the set of modules to export to (by name) + for (String name : e.getValue()) { + boolean allUnnamed = false; + Module other = null; + if (ALL_UNNAMED.equals(name)) { + allUnnamed = true; + } else { + om = bootLayer.findModule(name); + if (om.isPresent()) { + other = om.get(); + } else { + warnUnknownModule(option, name); + continue; + } + } + if (allUnnamed) { + if (opens) { + Modules.addOpensToAllUnnamed(m, pn); + } else { + Modules.addExportsToAllUnnamed(m, pn); + } + } else { + if (opens) { + Modules.addOpens(m, pn, other); + } else { + Modules.addExports(m, pn, other); + } + } + } + } + } + + private static final boolean HAS_ENABLE_NATIVE_ACCESS_FLAG; + private static final Set USER_NATIVE_ACCESS_MODULES; + private static final Set JDK_NATIVE_ACCESS_MODULES; + + public static boolean hasEnableNativeAccessFlag() { + return HAS_ENABLE_NATIVE_ACCESS_FLAG; + } + + static { + USER_NATIVE_ACCESS_MODULES = decodeEnableNativeAccess(); + HAS_ENABLE_NATIVE_ACCESS_FLAG = !USER_NATIVE_ACCESS_MODULES.isEmpty(); + JDK_NATIVE_ACCESS_MODULES = ModuleLoaderMap.nativeAccessModules(); + } + + /** + * Grants native access to modules selected using the --enable-native-access + * command line option, and also to JDK modules that need the access. + */ + private static void addEnableNativeAccess(ModuleLayer layer) { + addEnableNativeAccess(layer, USER_NATIVE_ACCESS_MODULES, true); + addEnableNativeAccess(layer, JDK_NATIVE_ACCESS_MODULES, false); + } + + /** + * Grants native access for the given modules in the given layer. + * Warns optionally about modules that were specified, but not present in the layer. + */ + private static void addEnableNativeAccess(ModuleLayer layer, Set moduleNames, boolean shouldWarn) { + for (String name : moduleNames) { + if (name.equals("ALL-UNNAMED")) { + JLA.addEnableNativeAccessToAllUnnamed(); + } else if (!JLA.addEnableNativeAccess(layer, name) && shouldWarn) { + warnUnknownModule(ENABLE_NATIVE_ACCESS, name); + } + } + } + + /** + * Returns the set of module names specified by --enable-native-access options. + */ + private static Set decodeEnableNativeAccess() { + String prefix = "jdk.module.enable.native.access."; + int index = 0; + // the system property is removed after decoding + String value = getAndRemoveProperty(prefix + index); + Set modules = new HashSet<>(); + if (value == null) { + return modules; + } + while (value != null) { + for (String s : value.split(",")) { + if (!s.isEmpty()) + modules.add(s); + } + index++; + value = getAndRemoveProperty(prefix + index); + } + return modules; + } + + /** + * Decodes the values of --add-reads, -add-exports, --add-opens or + * --patch-modules options that are encoded in system properties. + * + * @param prefix the system property prefix + * @praam regex the regex for splitting the RHS of the option value + */ + private static Map> decode(String prefix, + String regex, + boolean allowDuplicates) { + int index = 0; + // the system property is removed after decoding + String value = getAndRemoveProperty(prefix + index); + if (value == null) + return Map.of(); + + Map> map = new HashMap<>(); + + while (value != null) { + + int pos = value.indexOf('='); + if (pos == -1) + fail(unableToParse(option(prefix), "=", value)); + if (pos == 0) + fail(unableToParse(option(prefix), "=", value)); + + // key is or / + String key = value.substring(0, pos); + + String rhs = value.substring(pos+1); + if (rhs.isEmpty()) + fail(unableToParse(option(prefix), "=", value)); + + // value is (,)* or ()* + if (!allowDuplicates && map.containsKey(key)) + fail(key + " specified more than once to " + option(prefix)); + List values = map.computeIfAbsent(key, k -> new ArrayList<>()); + int ntargets = 0; + for (String s : rhs.split(regex)) { + if (!s.isEmpty()) { + values.add(s); + ntargets++; + } + } + if (ntargets == 0) + fail("Target must be specified: " + option(prefix) + " " + value); + + index++; + value = getAndRemoveProperty(prefix + index); + } + + return map; + } + + /** + * Decodes the values of --add-reads, -add-exports or --add-opens + * which use the "," to separate the RHS of the option value. + */ + private static Map> decode(String prefix) { + return decode(prefix, ",", true); + } + + + /** + * Gets the named system property + */ + private static String getProperty(String key) { + return System.getProperty(key); + } + + /** + * Gets and remove the named system property + */ + private static String getAndRemoveProperty(String key) { + return (String) System.getProperties().remove(key); + } + + /** + * Checks incubating status of modules in the configuration + */ + private static void checkIncubatingStatus(Configuration cf) { + String incubating = null; + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + + // emit warning if the WARN_INCUBATING module resolution bit set + if (ModuleResolution.hasIncubatingWarning(mref)) { + String mn = mref.descriptor().name(); + if (incubating == null) { + incubating = mn; + } else { + incubating += ", " + mn; + } + } + } + if (incubating != null) + warn("Using incubator modules: " + incubating); + } + + /** + * Throws a RuntimeException with the given message + */ + static void fail(String m) { + throw new RuntimeException(m); + } + + static void warn(String m) { + System.err.println("WARNING: " + m); + } + + static void warnUnknownModule(String option, String mn) { + warn("Unknown module: " + mn + " specified to " + option); + } + + static String unableToParse(String option, String text, String value) { + return "Unable to parse " + option + " " + text + ": " + value; + } + + private static final String ADD_MODULES = "--add-modules"; + private static final String ADD_EXPORTS = "--add-exports"; + private static final String ADD_OPENS = "--add-opens"; + private static final String ADD_READS = "--add-reads"; + private static final String PATCH_MODULE = "--patch-module"; + private static final String ENABLE_NATIVE_ACCESS = "--enable-native-access"; + + /* + * Returns the command-line option name corresponds to the specified + * system property prefix. + */ + static String option(String prefix) { + switch (prefix) { + case "jdk.module.addexports.": + return ADD_EXPORTS; + case "jdk.module.addopens.": + return ADD_OPENS; + case "jdk.module.addreads.": + return ADD_READS; + case "jdk.module.patch.": + return PATCH_MODULE; + case "jdk.module.addmods.": + return ADD_MODULES; + default: + throw new IllegalArgumentException(prefix); + } + } + + /** + * Wraps a (potentially not thread safe) ModuleFinder created during startup + * for use after startup. + */ + static class SafeModuleFinder implements ModuleFinder { + private final Set mrefs; + private volatile Map nameToModule; + + SafeModuleFinder(ModuleFinder finder) { + this.mrefs = Collections.unmodifiableSet(finder.findAll()); + } + @Override + public Optional find(String name) { + Objects.requireNonNull(name); + Map nameToModule = this.nameToModule; + if (nameToModule == null) { + this.nameToModule = nameToModule = mrefs.stream() + .collect(Collectors.toMap(m -> m.descriptor().name(), + Function.identity())); + } + return Optional.ofNullable(nameToModule.get(name)); + } + @Override + public Set findAll() { + return mrefs; + } + } + + /** + * Counters for startup performance analysis. + */ + static class Counters { + private static final boolean PUBLISH_COUNTERS; + private static final boolean PRINT_COUNTERS; + private static Map counters; + private static long startTime; + private static long previousTime; + + static { + String s = System.getProperty("jdk.module.boot.usePerfData"); + if (s == null) { + PUBLISH_COUNTERS = false; + PRINT_COUNTERS = false; + } else { + PUBLISH_COUNTERS = true; + PRINT_COUNTERS = s.equals("debug"); + counters = new LinkedHashMap<>(); // preserve insert order + } + } + + /** + * Start counting time. + */ + static void start() { + if (PUBLISH_COUNTERS) { + startTime = previousTime = System.nanoTime(); + } + } + + /** + * Add a counter - storing the time difference between now and the + * previous add or the start. + */ + static void add(String name) { + if (PUBLISH_COUNTERS) { + long current = System.nanoTime(); + long elapsed = current - previousTime; + previousTime = current; + counters.put(name, elapsed); + } + } + + /** + * Publish the counters to the instrumentation buffer or stdout. + */ + static void publish(String totalTimeName) { + if (PUBLISH_COUNTERS) { + long currentTime = System.nanoTime(); + for (Map.Entry e : counters.entrySet()) { + String name = e.getKey(); + long value = e.getValue(); + PerfCounter.newPerfCounter(name).set(value); + if (PRINT_COUNTERS) + System.out.println(name + " = " + value); + } + long elapsedTotal = currentTime - startTime; + PerfCounter.newPerfCounter(totalTimeName).set(elapsedTotal); + if (PRINT_COUNTERS) + System.out.println(totalTimeName + " = " + elapsedTotal); + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/module/ModuleHashes$Builder.class b/tests/test_data/std/jdk/internal/module/ModuleHashes$Builder.class new file mode 100644 index 0000000000000000000000000000000000000000..d3b22263bc1241f65a24c8b449d4cebf0c38498c GIT binary patch literal 1359 zcma)6-%ry}6#niuC@b9tLs4NODBw1b`CD{|xG8~TOp}orocuR%^SwQqNgp#YNau^Xr zCBzgAV2~lXRol*JhOJr#*E3DC=ICl>&0Pe7+MdignqE^a2HD_Eb=?$UhFIY*713m6 z4B?oB;|hjx;*bzeZJQx#sZSlvQj4Zhbab6zI_ZIQ6qQZ=8(u}&OV^l!` zry0UrubY-;H<}Fb4gfDR+mACCmoTB=EY2}R4k@SZwH#{Zd>1htP+k??hSx8 z4$VHmW^OUdFx&;2>_D!_n>E6T6*NOFI?ak|t@Dabk$AzZa=pwgO`QE;$ZlwKm+8V$ zW&QRIQOAT$HLmA*i&r(#9kxo>&>$l%o0exbhNUh7H*@5N|1>BO1)2ucBXDWInPcdw z2=j`*9*slaM@lxYZc~^2V&#(QSXFgd6YUu6oQgT&A%?!9+O}8BHu*%84o zsX>xIHkcrv256!KG;d^9+6{=w1H%P3I)@;wJ;+exBJG|aaQL!n;t? zGp`YUhm*S)dFg(6iJo!F20qa9BcXo6C_dvdMaDf0T)|a3ftUq1b9dKpozyVgz`W1- zkg|n}X!;eDnc01e1@S1oLy-Uki})1*U!dS?2YU1mdK5Q(^eAp2>!L5ICzc zK;OqC!wU=@Ah|*35fR%%dWQ+Npvx9@wR|JC@1**N%cyt=KI5XB%Mz4$hqeJM;jX(T Ok)u_nOY}VH9I)_V<1LROq2Aa^( z%$w2tyl;MfzrF!1(2vm~JeS9_Dr{h9wNW3{u`#UHS6OO*Vn4Y^*3`8r*u{7t3`+f} zmC-g=+kMH0K_x;<_-}d-hV^l12nVTOI{Sm>&^I)LGAVd?ijqGmu1fp> literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleHashes.class b/tests/test_data/std/jdk/internal/module/ModuleHashes.class new file mode 100644 index 0000000000000000000000000000000000000000..cebda888202c7f94ad5e7d89b4ee03bc7bed4ee5 GIT binary patch literal 8192 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 ar)~?Et9F*g9`@c&UI+PmNDZrZq4wvzV>4?2 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleHashes.java b/tests/test_data/std/jdk/internal/module/ModuleHashes.java new file mode 100644 index 00000000..a3eaea5b --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModuleHashes.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Supplier; +import java.util.stream.Stream; + +/** + * The result of hashing the contents of a number of module artifacts. + */ + +public final class ModuleHashes { + + /** + * A supplier of a message digest. + */ + public static interface HashSupplier { + byte[] generate(String algorithm); + } + + private final String algorithm; + private final Map nameToHash; + + /** + * Creates a {@code ModuleHashes}. + * + * @param algorithm the algorithm used to create the hashes + * @param nameToHash the map of module name to hash value + */ + ModuleHashes(String algorithm, Map nameToHash) { + this.algorithm = Objects.requireNonNull(algorithm); + this.nameToHash = Collections.unmodifiableMap(nameToHash); + } + + /** + * Returns the algorithm used to hash the modules ("SHA-256" for example). + */ + public String algorithm() { + return algorithm; + } + + /** + * Returns the set of module names for which hashes are recorded. + */ + public Set names() { + return nameToHash.keySet(); + } + + /** + * Returns the hash for the given module name, {@code null} + * if there is no hash recorded for the module. + */ + public byte[] hashFor(String mn) { + return nameToHash.get(mn); + } + + /** + * Returns unmodifiable map of module name to hash + */ + public Map hashes() { + return nameToHash; + } + + /** + * Computes a hash from the names and content of a module. + * + * @param reader the module reader to access the module content + * @param algorithm the name of the message digest algorithm to use + * @return the hash + * @throws IllegalArgumentException if digest algorithm is not supported + * @throws UncheckedIOException if an I/O error occurs + */ + private static byte[] computeHash(ModuleReader reader, String algorithm) { + MessageDigest md; + try { + md = MessageDigest.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException(e); + } + byte[] buf = new byte[32*1024]; + try (Stream stream = reader.list()) { + stream.sorted().forEach(rn -> { + md.update(rn.getBytes(StandardCharsets.UTF_8)); + try (InputStream in = reader.open(rn).orElseThrow()) { + int n; + while ((n = in.read(buf)) > 0) { + md.update(buf, 0, n); + } + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + }); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + return md.digest(); + } + + /** + * Computes a hash from the names and content of a module. + * + * @param supplier supplies the module reader to access the module content + * @param algorithm the name of the message digest algorithm to use + * @return the hash + * @throws IllegalArgumentException if digest algorithm is not supported + * @throws UncheckedIOException if an I/O error occurs + */ + static byte[] computeHash(Supplier supplier, String algorithm) { + try (ModuleReader reader = supplier.get()) { + return computeHash(reader, algorithm); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + /** + * Computes the hash from the names and content of a set of modules. Returns + * a {@code ModuleHashes} to encapsulate the result. + * + * @param mrefs the set of modules + * @param algorithm the name of the message digest algorithm to use + * @return ModuleHashes that encapsulates the hashes + * @throws IllegalArgumentException if digest algorithm is not supported + * @throws UncheckedIOException if an I/O error occurs + */ + static ModuleHashes generate(Set mrefs, String algorithm) { + Map nameToHash = new TreeMap<>(); + for (ModuleReference mref : mrefs) { + try (ModuleReader reader = mref.open()) { + byte[] hash = computeHash(reader, algorithm); + nameToHash.put(mref.descriptor().name(), hash); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + return new ModuleHashes(algorithm, nameToHash); + } + + @Override + public int hashCode() { + int h = algorithm.hashCode(); + for (Map.Entry e : nameToHash.entrySet()) { + h = h * 31 + e.getKey().hashCode(); + h = h * 31 + Arrays.hashCode(e.getValue()); + } + return h; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ModuleHashes)) + return false; + ModuleHashes other = (ModuleHashes) obj; + if (!algorithm.equals(other.algorithm) + || nameToHash.size() != other.nameToHash.size()) + return false; + for (Map.Entry e : nameToHash.entrySet()) { + String name = e.getKey(); + byte[] hash = e.getValue(); + if (!Arrays.equals(hash, other.nameToHash.get(name))) + return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(algorithm); + sb.append(" "); + nameToHash.entrySet() + .stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> { + sb.append(e.getKey()); + sb.append("="); + byte[] ba = e.getValue(); + for (byte b : ba) { + sb.append(String.format("%02x", b & 0xff)); + } + }); + return sb.toString(); + } + + /** + * This is used by jdk.internal.module.SystemModules class + * generated at link time. + */ + public static class Builder { + final String algorithm; + final Map nameToHash; + + Builder(String algorithm, int initialCapacity) { + this.nameToHash = new HashMap<>(initialCapacity); + this.algorithm = Objects.requireNonNull(algorithm); + } + + /** + * Sets the module hash for the given module name + */ + public Builder hashForModule(String mn, byte[] hash) { + nameToHash.put(mn, hash); + return this; + } + + /** + * Builds a {@code ModuleHashes}. + */ + public ModuleHashes build() { + if (!nameToHash.isEmpty()) { + return new ModuleHashes(algorithm, nameToHash); + } else { + return null; + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/module/ModuleHashesBuilder$Graph$Builder.class b/tests/test_data/std/jdk/internal/module/ModuleHashesBuilder$Graph$Builder.class new file mode 100644 index 0000000000000000000000000000000000000000..be45e1616085d431a697f315c13a3344cf3a6dfd GIT binary patch literal 2536 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 YGj}QfZ5~i3v*VqCYE`Ei6#J+D0KXx2H2?qr literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleHashesBuilder$TopoSorter.class b/tests/test_data/std/jdk/internal/module/ModuleHashesBuilder$TopoSorter.class new file mode 100644 index 0000000000000000000000000000000000000000..753647b73681773642a3c028dd70c0918488f268 GIT binary patch literal 4148 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleHashesBuilder.java b/tests/test_data/std/jdk/internal/module/ModuleHashesBuilder.java new file mode 100644 index 00000000..cebca6fb --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModuleHashesBuilder.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.PrintStream; +import java.lang.module.Configuration; +import java.lang.module.ModuleReference; +import java.lang.module.ResolvedModule; +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.TreeMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Stream; +import static java.util.stream.Collectors.*; + +/** + * A Builder to compute ModuleHashes from a given configuration + */ +public class ModuleHashesBuilder { + private final Configuration configuration; + private final Set hashModuleCandidates; + + /** + * Constructs a ModuleHashesBuilder that finds the packaged modules + * from the location of ModuleReference found from the given Configuration. + * + * @param config Configuration for building module hashes + * @param modules the candidate modules to be hashed + */ + public ModuleHashesBuilder(Configuration config, Set modules) { + this.configuration = config; + this.hashModuleCandidates = modules; + } + + /** + * Returns a map of a module M to ModuleHashes for the modules + * that depend upon M directly or indirectly. + * + * The key for each entry in the returned map is a module M that has + * no outgoing edges to any of the candidate modules to be hashed + * i.e. M is a leaf node in a connected subgraph containing M and + * other candidate modules from the module graph filtering + * the outgoing edges from M to non-candidate modules. + */ + public Map computeHashes(Set roots) { + // build a graph containing the packaged modules and + // its transitive dependences matching --hash-modules + Graph.Builder builder = new Graph.Builder<>(); + Deque todo = new ArrayDeque<>(configuration.modules()); + Set visited = new HashSet<>(); + ResolvedModule rm; + while ((rm = todo.poll()) != null) { + if (visited.add(rm)) { + builder.addNode(rm.name()); + for (ResolvedModule dm : rm.reads()) { + if (!visited.contains(dm)) { + todo.push(dm); + } + builder.addEdge(rm.name(), dm.name()); + } + } + } + + // each node in a transposed graph is a matching packaged module + // in which the hash of the modules that depend upon it is recorded + Graph transposedGraph = builder.build().transpose(); + + // traverse the modules in topological order that will identify + // the modules to record the hashes - it is the first matching + // module and has not been hashed during the traversal. + Set mods = new HashSet<>(); + Map hashes = new TreeMap<>(); + builder.build() + .orderedNodes() + .filter(mn -> roots.contains(mn) && !mods.contains(mn)) + .forEach(mn -> { + // Compute hashes of the modules that depend on mn directly and + // indirectly excluding itself. + Set ns = transposedGraph.dfs(mn) + .stream() + .filter(n -> !n.equals(mn) && hashModuleCandidates.contains(n)) + .collect(toSet()); + mods.add(mn); + mods.addAll(ns); + + if (!ns.isEmpty()) { + Set mrefs = ns.stream() + .map(name -> configuration.findModule(name) + .orElseThrow(InternalError::new)) + .map(ResolvedModule::reference) + .collect(toSet()); + hashes.put(mn, ModuleHashes.generate(mrefs, "SHA-256")); + } + }); + return hashes; + } + + /* + * Utility class + */ + static class Graph { + private final Set nodes; + private final Map> edges; + + public Graph(Set nodes, Map> edges) { + this.nodes = Collections.unmodifiableSet(nodes); + this.edges = Collections.unmodifiableMap(edges); + } + + public Set nodes() { + return nodes; + } + + public Map> edges() { + return edges; + } + + public Set adjacentNodes(T u) { + return edges.get(u); + } + + public boolean contains(T u) { + return nodes.contains(u); + } + + /** + * Returns nodes sorted in topological order. + */ + public Stream orderedNodes() { + TopoSorter sorter = new TopoSorter<>(this); + return sorter.result.stream(); + } + + /** + * Traverses this graph and performs the given action in topological order. + */ + public void ordered(Consumer action) { + TopoSorter sorter = new TopoSorter<>(this); + sorter.ordered(action); + } + + /** + * Traverses this graph and performs the given action in reverse topological order. + */ + public void reverse(Consumer action) { + TopoSorter sorter = new TopoSorter<>(this); + sorter.reverse(action); + } + + /** + * Returns a transposed graph from this graph. + */ + public Graph transpose() { + Builder builder = new Builder<>(); + nodes.forEach(builder::addNode); + // reverse edges + edges.keySet().forEach(u -> { + edges.get(u).forEach(v -> builder.addEdge(v, u)); + }); + return builder.build(); + } + + /** + * Returns all nodes reachable from the given root. + */ + public Set dfs(T root) { + return dfs(Set.of(root)); + } + + /** + * Returns all nodes reachable from the given set of roots. + */ + public Set dfs(Set roots) { + ArrayDeque todo = new ArrayDeque<>(roots); + Set visited = new HashSet<>(); + T u; + while ((u = todo.poll()) != null) { + if (visited.add(u) && contains(u)) { + adjacentNodes(u).stream() + .filter(v -> !visited.contains(v)) + .forEach(todo::push); + } + } + return visited; + } + + public void printGraph(PrintStream out) { + out.println("graph for " + nodes); + nodes + .forEach(u -> adjacentNodes(u) + .forEach(v -> out.format(" %s -> %s%n", u, v))); + } + + static class Builder { + final Set nodes = new HashSet<>(); + final Map> edges = new HashMap<>(); + + public void addNode(T node) { + if (nodes.add(node)) { + edges.computeIfAbsent(node, _e -> new HashSet<>()); + } + } + + public void addEdge(T u, T v) { + addNode(u); + addNode(v); + edges.get(u).add(v); + } + + public Graph build() { + return new Graph(nodes, edges); + } + } + } + + /** + * Topological sort + */ + private static class TopoSorter { + final Deque result = new ArrayDeque<>(); + final Graph graph; + + TopoSorter(Graph graph) { + this.graph = graph; + sort(); + } + + public void ordered(Consumer action) { + result.forEach(action); + } + + public void reverse(Consumer action) { + result.descendingIterator().forEachRemaining(action); + } + + private void sort() { + Set visited = new HashSet<>(); + Deque stack = new ArrayDeque<>(); + graph.nodes.forEach(node -> visit(node, visited, stack)); + } + + private Set children(T node) { + return graph.edges().get(node); + } + + private void visit(T node, Set visited, Deque stack) { + if (visited.add(node)) { + stack.push(node); + children(node).forEach(child -> visit(child, visited, stack)); + stack.pop(); + result.addLast(node); + } + else if (stack.contains(node)) { + throw new IllegalArgumentException( + "Cycle detected: " + node + " -> " + children(node)); + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/module/ModuleInfo$Attributes.class b/tests/test_data/std/jdk/internal/module/ModuleInfo$Attributes.class new file mode 100644 index 0000000000000000000000000000000000000000..236aa9eba66cadfe92c64df2414f8186ecc5a2e3 GIT binary patch literal 1332 zcma)5+iuf95IvhX*SbxcQc408Xw#6mfQ7_c5fTbQtrUt>s=Pb)Hg#}qwBGQ{C-5mC z5h3xw2k=pd*^Na?yZz-Y&ooB!>LxaEgJDf@ zHxeHAj-2>HsmS8bFq(hU#5QixdCbI}@;C}6(vL!hc7}pE?vUYg=Ndz16idd*KqP`Q z5LX0s2Mk6p@;F1S?}z+kayjJU%ozr>QtwBu6AT>TtM6pdkQY83*+EAAg}+Qw?{~V_ z7@MJ`a7*2j%>F-EasUjS%xYIofqeKbnh2M__SM|AxmlkmM>3R8cr1^iSeEdRVQ0BS zH9CWN9EM!<0w<2O$>)y8Q}S<)Zkd6)x-FE|m6>%UbLvPYqgc>S0}M^dJ`qc;G_CJo z*1;4d>(Lae*5fHQtcEeg)>qoi;kLq{Nbe!_a8ZGWHE=TiIT{$@4(&XfRl;5D(3iq1 zB}`{Zi_+IrR|R>UDLn@5ui##y#-^z71?wA1UnrS1F6u>JH<=YIBu(g0aX*E;x=0RE r$(wkPLf%*;N2%m(?52>n7Re%ooX4IXu7!Oa+vrfNQn@nP=%Vol_Qy0_ literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleInfo$ConstantPool$Entry.class b/tests/test_data/std/jdk/internal/module/ModuleInfo$ConstantPool$Entry.class new file mode 100644 index 0000000000000000000000000000000000000000..fe6f05f078147537c1430b52707d442b7748d408 GIT binary patch literal 557 zcmb7BO;5r=5PegMg^Hl4_<r`cZz8D5KCz)G>L`y%Ly(2x1IXq#IwnurNGAqi zmo2t@GRjulMe7S!B(8P)lft-hYfC7qytxj}NkF`~)mP!56 zMBPNy_xmB#r)ITjbY`WthsGqU-?U9{2*ur4$M!2BzZR|^kD!DR4}O4A1cWdDLKx~u zT{nKy#;)2TQ0O>61SmVgVjpgBvKEG{$FfZmDMGmwYjx1QJW=Tnd6FZ6j%6CV zdI;w2d7KfpTmL!O4k2gd8Noj?-L$Q~$4;vJ$D_@Typn{{fy(Tj$*hMt!ovG%gdo&f zrOiZUnaVsY5H{X#`D+#2|8_Hk!qCLgHam9EraISA+@9B7Tu~ zx3#%DP;I^kuU740?3OWs3ZE5sFP=~k&+x@hl*KPhGF}_>VG19)a{SZG@7M>5PJN)6 iLk^#~68Manew@WT$63a!d@jQMnN^O?g^v2feOqXAyxBNFS5uW>%z+;hdg2HFM_`6$h(1RIVB_^s(OBZd;(Czq6Y_kE;0pV(N9?Kw6FY785t`P`PaJLjii5& zLZHrdrKVM4gfhokN0nV=;#)%hcBn$LL&#KvrA8h(R_={mfL|xf)&E8l- z7_E22jqoF(F8rfrN4Crsp;QfihL;*#LQS_>RIGOo2~fSvNc;iA$KSfv#%55Vwy1jdqP4XP)f$N zNF<3&T+9+yewTck4C}uRijeI!)%)x)7I{z(F9BiLjw-!@w_uPXL(ER>W-tycmmfgO ztM_p4m^vu(Ib@%l7i67Rc+MMJfDO~{7{Mqr7GezJY-VpZfwh}p=AeYh6sIu5IK%NW RrZ5M)jAhI-<`@^?eE>3RsdoSX literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleInfo$ConstantPool.class b/tests/test_data/std/jdk/internal/module/ModuleInfo$ConstantPool.class new file mode 100644 index 0000000000000000000000000000000000000000..99cab95706c1c464b07316baec06c94e38929d45 GIT binary patch literal 6614 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleInfo$CountingDataInput.class b/tests/test_data/std/jdk/internal/module/ModuleInfo$CountingDataInput.class new file mode 100644 index 0000000000000000000000000000000000000000..d4c80f2d138f6805d800502030378e83cbaac091 GIT binary patch literal 2930 zcmb7`-%}e^6vw|eEDbD6DJ=y`X^Xa60%KEa)lsNcLTOVev_PYPwq24XENpf$*Wlhf>#wm>(HVUAk8=FpyGz)HgpSNy?(Uv@&gYzS&pkK){QKu7fE4cN zh@l}4%|Ije2<%%n*UY42y7}bf!m^e11@;WvuI;}h(9oaAG@}X4ap(qGU7x7QwEaKPJ7gjS}dhc8#se! zLI+YyW>Hy4NztCEvuRozGz?w!=c`|=jN5(<*hYMa?N=IuV7>=Z;odM z?u|*=sDTR@6VRpcQLnt<1aXbVaY>+OyGEwu_7ha}RZAO_ff(4-&mM-SFN;;IGbJC$6D#r&K1~)g*u3=!7rUo}ZH1DIe+QC`0 zYI8WG%|{&UsW{k!dAvc|o3yEMzQMsh7t)qU(2DH(_YE(50D*H4x}l zSluCu_HYZPilZ9~d}?@z&z>3bZ;;O<2mHeu=!)T-inUkad+$;f-3$vY+9Eo&yyEu- zx)FYsEOuP9BB%J#sM(A|>QtEHP8szE4hsw`s4mlcxSHue*9z#++(>>qL#EEsnuk@D zUpDsIq+`32N+kItmFtogt4O>jYLkxdPP#+VJ0!hZhm==&jAoD5O-Pyvv!`li11Gmg z9T=>czxT*`pL_N}gw-bMq=lMIbz9;L4I;;ZRDi(h` zL|BoyQUaHvah?3RiuEH|cgea}hvi|liuD$X{35&ZS#}!P()GV^advD*83={c@4KY>onJdHLOGb E58YVOAOHXW literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleInfo$DataInputWrapper.class b/tests/test_data/std/jdk/internal/module/ModuleInfo$DataInputWrapper.class new file mode 100644 index 0000000000000000000000000000000000000000..7dbfe63257e317a2292398731c3efd04f3eb9600 GIT binary patch literal 3381 zcmbVONp}=g6#ibSlIm_MQ-?r8LJ}s)0JLa8Bmp4_k%kT^fgs>OC8;EpbXT?A)eMd} zEZw^B7qG#Bb2M<|9N4MHqZ_A%x^md5J9XnBey^%h=_IWuut-%oV8UwQS4XFQBw{j6@MZR6|V1D(C`< z>G7F_WxHn1HqwcVGhRrWi6QTiv?rX+1BPoP?QFq4oinmoGbd0sIx0|~@?dPsN%UQI z&A!6KgqiD!v38Y?YSaisbEYvqSV*TY3ux`<`jW|xkr?8r)391cJ=O@+m8e0IlO{Pg z`CCfDXlM}Fu&~(!KV^@bxrwxM@zA9)GwWK8tzn(OYA=m64;>#2BQdN+vySy>5r`3P z$js-BNt4;_9X_Jx->{pr>`AI>M4NPX19i7AkNdhd>DY`dp6-l6zwJrS?_>;H(XOFG zM<==jsysek`60udVot`g1WmYVi?9r4X1RB;IzQn`R;~e%AT15$ZWt+zenNc%$((qKqQ_h%? z9x-y3d=C~?cgo5O>`dL`nd_1Bajs7S3ZA{PbA24!(5$=$Qt;0bH71XT5vDV;sfhi5 zoD>2m&cp=sll+!8IgpjZt}!+rWf`ymX=_ zoT%V>L>sTbG6+1yzqq_&c}dssuN-H&a*p2y8872A)_DV>v+E;h*ZEe4r}8~1rtX+Q7T^Nh)w2cddd(atWV>-H=v7fQ;X2Pj`4qI_9Y zE*h4L!oVntjj@c%=eSq6CMf(i*UA}b>HH8{SM&N=)SkYI_+IrE8qYMUvuL`3);rg^ z2c%WSdsXp-tdYBvudqt_7FEjEs8PPbdgVKhK{sPHsKf*&S)H{*E-e8Uxi$sMlhlG~ zep4{RObunnG_0*!L^h2K;iU^E)94>sn$c|evq+q7zQ&YdyT6C7 z{6Ka;dhFW#5+SEn*u-b&Q3uE4B#_1Pfj@6CTQ;-Rhj^&B=^be5RW|TiN?OzvIOG{r z%ZZpbC@!TdKd~)8Bd+{{I_1|8KEfX7JkUDAN}Hs;tpO!zL_L&$_#=Bj%<)BNoH>51 zU1Uoh-2q2wi{w}za4f-0R+wkz&){!l_B&_rk8o(BMO^BOxKuzKUJCAFO8_ogC&3#7 z@LJ5hQi6ayD2oaF$*%l`O6Bj6KxGku#>E6uO9>RPr?mQACBT=fzf1LVh_XfVC-7d> zUkKGt1?n4o^}FJamJ%;d^dj-9hE-|=x*84f^&;^Ni^U&ZD*ht&l@`BuCF0c@MATY} zkB8v*BK}e+e#zYJUlDjC!PgPI>At`(W1zJ1gYPasj?3DvZY207f^WVr@E35nH29(S zRs!Bd@NER&eqZ1(B2^kZ`Tk14y9vIF;Jfb&{3YJk{uSKKftQz6>=uU3#E;*=lXv*$ z-?qFc_!HCXA?SWqFvx=c&9wyd6O70T<()Ti;)5ld`-?W02b&juxD>qX<-dYgz2_CY O&S#9}BDjJ#5c?Nt*jT^- literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleInfo.class b/tests/test_data/std/jdk/internal/module/ModuleInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..30c29c383cd33ced6518e02a4268a5d1450a955b GIT binary patch literal 19332 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�Fo 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleInfo.java b/tests/test_data/std/jdk/internal/module/ModuleInfo.java new file mode 100644 index 00000000..26cb12f4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModuleInfo.java @@ -0,0 +1,1227 @@ +/* + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.InvalidModuleDescriptorException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Opens; +import java.nio.ByteBuffer; +import java.nio.BufferUnderflowException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +import jdk.internal.access.JavaLangModuleAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.VM; + +import static jdk.internal.module.ClassFileConstants.*; + + +/** + * Read module information from a {@code module-info} class file. + * + * @implNote The rationale for the hand-coded reader is startup performance + * and fine control over the throwing of InvalidModuleDescriptorException. + */ + +public final class ModuleInfo { + + private static final JavaLangModuleAccess JLMA + = SharedSecrets.getJavaLangModuleAccess(); + + // supplies the set of packages when ModulePackages attribute not present + private final Supplier> packageFinder; + + // indicates if the ModuleHashes attribute should be parsed + private final boolean parseHashes; + + private ModuleInfo(Supplier> pf, boolean ph) { + packageFinder = pf; + parseHashes = ph; + } + + private ModuleInfo(Supplier> pf) { + this(pf, true); + } + + /** + * A holder class for the ModuleDescriptor that is created by reading the + * Module and other standard class file attributes. It also holds the objects + * that represent the non-standard class file attributes that are read from + * the class file. + */ + public static final class Attributes { + private final ModuleDescriptor descriptor; + private final ModuleTarget target; + private final ModuleHashes recordedHashes; + private final ModuleResolution moduleResolution; + Attributes(ModuleDescriptor descriptor, + ModuleTarget target, + ModuleHashes recordedHashes, + ModuleResolution moduleResolution) { + this.descriptor = descriptor; + this.target = target; + this.recordedHashes = recordedHashes; + this.moduleResolution = moduleResolution; + } + public ModuleDescriptor descriptor() { + return descriptor; + } + public ModuleTarget target() { + return target; + } + public ModuleHashes recordedHashes() { + return recordedHashes; + } + public ModuleResolution moduleResolution() { + return moduleResolution; + } + } + + + /** + * Reads a {@code module-info.class} from the given input stream. + * + * @throws InvalidModuleDescriptorException + * @throws IOException + */ + public static Attributes read(InputStream in, Supplier> pf) + throws IOException + { + try { + return new ModuleInfo(pf).doRead(new DataInputStream(in)); + } catch (IllegalArgumentException | IllegalStateException e) { + throw invalidModuleDescriptor(e.getMessage()); + } catch (EOFException x) { + throw truncatedModuleDescriptor(); + } + } + + /** + * Reads a {@code module-info.class} from the given byte buffer. + * + * @throws InvalidModuleDescriptorException + * @throws UncheckedIOException + */ + public static Attributes read(ByteBuffer bb, Supplier> pf) { + try { + return new ModuleInfo(pf).doRead(new DataInputWrapper(bb)); + } catch (IllegalArgumentException | IllegalStateException e) { + throw invalidModuleDescriptor(e.getMessage()); + } catch (EOFException x) { + throw truncatedModuleDescriptor(); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + /** + * Reads a {@code module-info.class} from the given byte buffer + * but ignore the {@code ModuleHashes} attribute. + * + * @throws InvalidModuleDescriptorException + * @throws UncheckedIOException + */ + public static Attributes readIgnoringHashes(ByteBuffer bb, Supplier> pf) { + try { + return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb)); + } catch (IllegalArgumentException | IllegalStateException e) { + throw invalidModuleDescriptor(e.getMessage()); + } catch (EOFException x) { + throw truncatedModuleDescriptor(); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + /** + * Reads the input as a module-info class file. + * + * @throws IOException + * @throws InvalidModuleDescriptorException + * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder + * because an identifier is not a legal Java identifier, duplicate + * exports, and many other reasons + */ + private Attributes doRead(DataInput input) throws IOException { + var in = new CountingDataInput(input); + + int magic = in.readInt(); + if (magic != 0xCAFEBABE) + throw invalidModuleDescriptor("Bad magic number"); + + int minor_version = in.readUnsignedShort(); + int major_version = in.readUnsignedShort(); + if (!VM.isSupportedModuleDescriptorVersion(major_version, minor_version)) { + throw invalidModuleDescriptor("Unsupported major.minor version " + + major_version + "." + minor_version); + } + + ConstantPool cpool = new ConstantPool(in); + + int access_flags = in.readUnsignedShort(); + if (access_flags != ACC_MODULE) + throw invalidModuleDescriptor("access_flags should be ACC_MODULE"); + + int this_class = in.readUnsignedShort(); + String mn = cpool.getClassName(this_class); + if (!"module-info".equals(mn)) + throw invalidModuleDescriptor("this_class should be module-info"); + + int super_class = in.readUnsignedShort(); + if (super_class > 0) + throw invalidModuleDescriptor("bad #super_class"); + + int interfaces_count = in.readUnsignedShort(); + if (interfaces_count > 0) + throw invalidModuleDescriptor("Bad #interfaces"); + + int fields_count = in.readUnsignedShort(); + if (fields_count > 0) + throw invalidModuleDescriptor("Bad #fields"); + + int methods_count = in.readUnsignedShort(); + if (methods_count > 0) + throw invalidModuleDescriptor("Bad #methods"); + + int attributes_count = in.readUnsignedShort(); + + // the names of the attributes found in the class file + Set attributes = new HashSet<>(); + + Builder builder = null; + Set allPackages = null; + String mainClass = null; + ModuleTarget moduleTarget = null; + ModuleHashes moduleHashes = null; + ModuleResolution moduleResolution = null; + + for (int i = 0; i < attributes_count ; i++) { + int name_index = in.readUnsignedShort(); + String attribute_name = cpool.getUtf8(name_index); + int length = in.readInt(); + + boolean added = attributes.add(attribute_name); + if (!added && isAttributeAtMostOnce(attribute_name)) { + throw invalidModuleDescriptor("More than one " + + attribute_name + " attribute"); + } + + long initialPosition = in.count(); + + switch (attribute_name) { + case MODULE : + builder = readModuleAttribute(in, cpool, major_version); + break; + + case MODULE_PACKAGES : + allPackages = readModulePackagesAttribute(in, cpool); + break; + + case MODULE_MAIN_CLASS : + mainClass = readModuleMainClassAttribute(in, cpool); + break; + + case MODULE_TARGET : + moduleTarget = readModuleTargetAttribute(in, cpool); + break; + + case MODULE_HASHES : + if (parseHashes) { + moduleHashes = readModuleHashesAttribute(in, cpool); + } else { + in.skipBytes(length); + } + break; + + case MODULE_RESOLUTION : + moduleResolution = readModuleResolution(in, cpool); + break; + + default: + if (isAttributeDisallowed(attribute_name)) { + throw invalidModuleDescriptor(attribute_name + + " attribute not allowed"); + } else { + in.skipBytes(length); + } + } + + long newPosition = in.count(); + if ((newPosition - initialPosition) != length) { + // attribute length does not match actual attribute size + throw invalidModuleDescriptor("Attribute " + attribute_name + + " does not match its expected length"); + } + + } + + // the Module attribute is required + if (builder == null) { + throw invalidModuleDescriptor(MODULE + " attribute not found"); + } + + // ModuleMainClass attribute + if (mainClass != null) { + builder.mainClass(mainClass); + } + + // If the ModulePackages attribute is not present then the packageFinder + // is used to find the set of packages + boolean usedPackageFinder = false; + if (allPackages == null && packageFinder != null) { + try { + allPackages = packageFinder.get(); + } catch (UncheckedIOException x) { + throw x.getCause(); + } + usedPackageFinder = true; + } + if (allPackages != null) { + Set knownPackages = JLMA.packages(builder); + if (!allPackages.containsAll(knownPackages)) { + Set missingPackages = new HashSet<>(knownPackages); + missingPackages.removeAll(allPackages); + assert !missingPackages.isEmpty(); + String missingPackage = missingPackages.iterator().next(); + String tail; + if (usedPackageFinder) { + tail = " not found in module"; + } else { + tail = " missing from ModulePackages class file attribute"; + } + throw invalidModuleDescriptor("Package " + missingPackage + tail); + + } + builder.packages(allPackages); + } + + ModuleDescriptor descriptor = builder.build(); + return new Attributes(descriptor, + moduleTarget, + moduleHashes, + moduleResolution); + } + + /** + * Reads the Module attribute, returning the ModuleDescriptor.Builder to + * build the corresponding ModuleDescriptor. + */ + private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major) + throws IOException + { + // module_name + int module_name_index = in.readUnsignedShort(); + String mn = cpool.getModuleName(module_name_index); + + int module_flags = in.readUnsignedShort(); + + Set modifiers = new HashSet<>(); + boolean open = ((module_flags & ACC_OPEN) != 0); + if (open) + modifiers.add(ModuleDescriptor.Modifier.OPEN); + if ((module_flags & ACC_SYNTHETIC) != 0) + modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC); + if ((module_flags & ACC_MANDATED) != 0) + modifiers.add(ModuleDescriptor.Modifier.MANDATED); + + Builder builder = JLMA.newModuleBuilder(mn, false, modifiers); + + int module_version_index = in.readUnsignedShort(); + if (module_version_index != 0) { + String vs = cpool.getUtf8(module_version_index); + builder.version(vs); + } + + int requires_count = in.readUnsignedShort(); + boolean requiresJavaBase = false; + for (int i=0; i mods; + if (requires_flags == 0) { + mods = Set.of(); + } else { + mods = new HashSet<>(); + if ((requires_flags & ACC_TRANSITIVE) != 0) + mods.add(Requires.Modifier.TRANSITIVE); + if ((requires_flags & ACC_STATIC_PHASE) != 0) + mods.add(Requires.Modifier.STATIC); + if ((requires_flags & ACC_SYNTHETIC) != 0) + mods.add(Requires.Modifier.SYNTHETIC); + if ((requires_flags & ACC_MANDATED) != 0) + mods.add(Requires.Modifier.MANDATED); + } + + int requires_version_index = in.readUnsignedShort(); + if (requires_version_index == 0) { + builder.requires(mods, dn); + } else { + String vs = cpool.getUtf8(requires_version_index); + JLMA.requires(builder, mods, dn, vs); + } + + if (dn.equals("java.base")) { + if (mods.contains(Requires.Modifier.SYNTHETIC)) { + throw invalidModuleDescriptor("The requires entry for java.base" + + " has ACC_SYNTHETIC set"); + } + if (major >= 54 + && (mods.contains(Requires.Modifier.TRANSITIVE) + || mods.contains(Requires.Modifier.STATIC))) { + String flagName; + if (mods.contains(Requires.Modifier.TRANSITIVE)) { + flagName = "ACC_TRANSITIVE"; + } else { + flagName = "ACC_STATIC_PHASE"; + } + throw invalidModuleDescriptor("The requires entry for java.base" + + " has " + flagName + " set"); + } + requiresJavaBase = true; + } + } + if (mn.equals("java.base")) { + if (requires_count > 0) { + throw invalidModuleDescriptor("The requires table for java.base" + + " must be 0 length"); + } + } else if (!requiresJavaBase) { + throw invalidModuleDescriptor("The requires table must have" + + " an entry for java.base"); + } + + int exports_count = in.readUnsignedShort(); + if (exports_count > 0) { + for (int i=0; i mods; + int exports_flags = in.readUnsignedShort(); + if (exports_flags == 0) { + mods = Set.of(); + } else { + mods = new HashSet<>(); + if ((exports_flags & ACC_SYNTHETIC) != 0) + mods.add(Exports.Modifier.SYNTHETIC); + if ((exports_flags & ACC_MANDATED) != 0) + mods.add(Exports.Modifier.MANDATED); + } + + int exports_to_count = in.readUnsignedShort(); + if (exports_to_count > 0) { + Set targets = HashSet.newHashSet(exports_to_count); + for (int j=0; j 0) { + if (open) { + throw invalidModuleDescriptor("The opens table for an open" + + " module must be 0 length"); + } + for (int i=0; i mods; + int opens_flags = in.readUnsignedShort(); + if (opens_flags == 0) { + mods = Set.of(); + } else { + mods = new HashSet<>(); + if ((opens_flags & ACC_SYNTHETIC) != 0) + mods.add(Opens.Modifier.SYNTHETIC); + if ((opens_flags & ACC_MANDATED) != 0) + mods.add(Opens.Modifier.MANDATED); + } + + int open_to_count = in.readUnsignedShort(); + if (open_to_count > 0) { + Set targets = HashSet.newHashSet(open_to_count); + for (int j=0; j 0) { + for (int i=0; i 0) { + for (int i=0; i providers = new ArrayList<>(with_count); + for (int j=0; j readModulePackagesAttribute(DataInput in, ConstantPool cpool) + throws IOException + { + int package_count = in.readUnsignedShort(); + Set packages = HashSet.newHashSet(package_count); + for (int i=0; i map = HashMap.newHashMap(hash_count); + for (int i=0; i notAllowed = predefinedNotAllowed; + if (notAllowed == null) { + notAllowed = Set.of( + "ConstantValue", + "Code", + "Deprecated", + "StackMapTable", + "Exceptions", + "EnclosingMethod", + "Signature", + "LineNumberTable", + "LocalVariableTable", + "LocalVariableTypeTable", + "RuntimeVisibleParameterAnnotations", + "RuntimeInvisibleParameterAnnotations", + "RuntimeVisibleTypeAnnotations", + "RuntimeInvisibleTypeAnnotations", + "Synthetic", + "AnnotationDefault", + "BootstrapMethods", + "MethodParameters"); + predefinedNotAllowed = notAllowed; + } + return notAllowed.contains(name); + } + + // lazily created set the pre-defined attributes that are not allowed + private static volatile Set predefinedNotAllowed; + + + /** + * The constant pool in a class file. + */ + private static class ConstantPool { + static final int CONSTANT_Utf8 = 1; + static final int CONSTANT_Integer = 3; + static final int CONSTANT_Float = 4; + static final int CONSTANT_Long = 5; + static final int CONSTANT_Double = 6; + static final int CONSTANT_Class = 7; + static final int CONSTANT_String = 8; + static final int CONSTANT_Fieldref = 9; + static final int CONSTANT_Methodref = 10; + static final int CONSTANT_InterfaceMethodref = 11; + static final int CONSTANT_NameAndType = 12; + static final int CONSTANT_MethodHandle = 15; + static final int CONSTANT_MethodType = 16; + static final int CONSTANT_InvokeDynamic = 18; + static final int CONSTANT_Module = 19; + static final int CONSTANT_Package = 20; + + private static class Entry { + protected Entry(int tag) { + this.tag = tag; + } + final int tag; + } + + private static class IndexEntry extends Entry { + IndexEntry(int tag, int index) { + super(tag); + this.index = index; + } + final int index; + } + + private static class Index2Entry extends Entry { + Index2Entry(int tag, int index1, int index2) { + super(tag); + this.index1 = index1; + this.index2 = index2; + } + final int index1, index2; + } + + private static class ValueEntry extends Entry { + ValueEntry(int tag, Object value) { + super(tag); + this.value = value; + } + final Object value; + } + + final Entry[] pool; + + ConstantPool(DataInput in) throws IOException { + int count = in.readUnsignedShort(); + pool = new Entry[count]; + + for (int i = 1; i < count; i++) { + int tag = in.readUnsignedByte(); + switch (tag) { + + case CONSTANT_Utf8: + String svalue = in.readUTF(); + pool[i] = new ValueEntry(tag, svalue); + break; + + case CONSTANT_Class: + case CONSTANT_Package: + case CONSTANT_Module: + case CONSTANT_String: + int index = in.readUnsignedShort(); + pool[i] = new IndexEntry(tag, index); + break; + + case CONSTANT_Double: + double dvalue = in.readDouble(); + pool[i] = new ValueEntry(tag, dvalue); + i++; + break; + + case CONSTANT_Fieldref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_Methodref: + case CONSTANT_InvokeDynamic: + case CONSTANT_NameAndType: + int index1 = in.readUnsignedShort(); + int index2 = in.readUnsignedShort(); + pool[i] = new Index2Entry(tag, index1, index2); + break; + + case CONSTANT_MethodHandle: + int refKind = in.readUnsignedByte(); + index = in.readUnsignedShort(); + pool[i] = new Index2Entry(tag, refKind, index); + break; + + case CONSTANT_MethodType: + index = in.readUnsignedShort(); + pool[i] = new IndexEntry(tag, index); + break; + + case CONSTANT_Float: + float fvalue = in.readFloat(); + pool[i] = new ValueEntry(tag, fvalue); + break; + + case CONSTANT_Integer: + int ivalue = in.readInt(); + pool[i] = new ValueEntry(tag, ivalue); + break; + + case CONSTANT_Long: + long lvalue = in.readLong(); + pool[i] = new ValueEntry(tag, lvalue); + i++; + break; + + default: + throw invalidModuleDescriptor("Bad constant pool entry: " + + i); + } + } + } + + String getClassName(int index) { + checkIndex(index); + Entry e = pool[index]; + if (e.tag != CONSTANT_Class) { + throw invalidModuleDescriptor("CONSTANT_Class expected at entry: " + + index); + } + String value = getUtf8(((IndexEntry) e).index); + checkUnqualifiedName("CONSTANT_Class", index, value); + return value.replace('/', '.'); // internal form -> binary name + } + + String getPackageName(int index) { + checkIndex(index); + Entry e = pool[index]; + if (e.tag != CONSTANT_Package) { + throw invalidModuleDescriptor("CONSTANT_Package expected at entry: " + + index); + } + String value = getUtf8(((IndexEntry) e).index); + checkUnqualifiedName("CONSTANT_Package", index, value); + return value.replace('/', '.'); // internal form -> binary name + } + + String getModuleName(int index) { + checkIndex(index); + Entry e = pool[index]; + if (e.tag != CONSTANT_Module) { + throw invalidModuleDescriptor("CONSTANT_Module expected at entry: " + + index); + } + String value = getUtf8(((IndexEntry) e).index); + return decodeModuleName(index, value); + } + + String getUtf8(int index) { + checkIndex(index); + Entry e = pool[index]; + if (e.tag != CONSTANT_Utf8) { + throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: " + + index); + } + return (String) (((ValueEntry) e).value); + } + + void checkIndex(int index) { + if (index < 1 || index >= pool.length) + throw invalidModuleDescriptor("Index into constant pool out of range"); + } + + void checkUnqualifiedName(String what, int index, String value) { + int len = value.length(); + if (len == 0) { + throw invalidModuleDescriptor(what + " at entry " + index + + " has zero length"); + } + for (int i=0; i= len) { + throw invalidModuleDescriptor("CONSTANT_Module at entry " + + index + " has illegal " + + "escape sequence"); + } + int next = value.codePointAt(j); + if (next != '\\' && next != ':' && next != '@') { + throw invalidModuleDescriptor("CONSTANT_Module at entry " + + index + " has illegal " + + "escape sequence"); + } + sb.appendCodePoint(next); + i += Character.charCount(next); + } else { + sb.appendCodePoint(cp); + } + + i += Character.charCount(cp); + } + return sb.toString(); + } + } + + /** + * A DataInput implementation that reads from a ByteBuffer. + */ + private static class DataInputWrapper implements DataInput { + private final ByteBuffer bb; + + DataInputWrapper(ByteBuffer bb) { + this.bb = bb; + } + + @Override + public void readFully(byte b[]) throws IOException { + readFully(b, 0, b.length); + } + + @Override + public void readFully(byte b[], int off, int len) throws IOException { + try { + bb.get(b, off, len); + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public int skipBytes(int n) { + int skip = Math.min(n, bb.remaining()); + bb.position(bb.position() + skip); + return skip; + } + + @Override + public boolean readBoolean() throws IOException { + try { + int ch = bb.get(); + return (ch != 0); + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public byte readByte() throws IOException { + try { + return bb.get(); + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public int readUnsignedByte() throws IOException { + try { + return ((int) bb.get()) & 0xff; + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public short readShort() throws IOException { + try { + return bb.getShort(); + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public int readUnsignedShort() throws IOException { + try { + return ((int) bb.getShort()) & 0xffff; + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public char readChar() throws IOException { + try { + return bb.getChar(); + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public int readInt() throws IOException { + try { + return bb.getInt(); + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public long readLong() throws IOException { + try { + return bb.getLong(); + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public float readFloat() throws IOException { + try { + return bb.getFloat(); + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public double readDouble() throws IOException { + try { + return bb.getDouble(); + } catch (BufferUnderflowException e) { + throw new EOFException(e.getMessage()); + } + } + + @Override + public String readLine() { + throw new RuntimeException("not implemented"); + } + + @Override + public String readUTF() throws IOException { + // ### Need to measure the performance and feasibility of using + // the UTF-8 decoder instead. + return DataInputStream.readUTF(this); + } + } + + /** + * A DataInput implementation that reads from another DataInput and counts + * the number of bytes read. + */ + private static class CountingDataInput implements DataInput { + private final DataInput delegate; + private long count; + + CountingDataInput(DataInput delegate) { + this.delegate = delegate; + } + + long count() { + return count; + } + + @Override + public void readFully(byte b[]) throws IOException { + delegate.readFully(b, 0, b.length); + count += b.length; + } + + @Override + public void readFully(byte b[], int off, int len) throws IOException { + delegate.readFully(b, off, len); + count += len; + } + + @Override + public int skipBytes(int n) throws IOException { + int skip = delegate.skipBytes(n); + count += skip; + return skip; + } + + @Override + public boolean readBoolean() throws IOException { + boolean b = delegate.readBoolean(); + count++; + return b; + } + + @Override + public byte readByte() throws IOException { + byte b = delegate.readByte(); + count++; + return b; + } + + @Override + public int readUnsignedByte() throws IOException { + int i = delegate.readUnsignedByte(); + count++; + return i; + } + + @Override + public short readShort() throws IOException { + short s = delegate.readShort(); + count += 2; + return s; + } + + @Override + public int readUnsignedShort() throws IOException { + int s = delegate.readUnsignedShort(); + count += 2; + return s; + } + + @Override + public char readChar() throws IOException { + char c = delegate.readChar(); + count += 2; + return c; + } + + @Override + public int readInt() throws IOException { + int i = delegate.readInt(); + count += 4; + return i; + } + + @Override + public long readLong() throws IOException { + long l = delegate.readLong(); + count += 8; + return l; + } + + @Override + public float readFloat() throws IOException { + float f = delegate.readFloat(); + count += 4; + return f; + } + + @Override + public double readDouble() throws IOException { + double d = delegate.readDouble(); + count += 8; + return d; + } + + @Override + public String readLine() { + throw new RuntimeException("not implemented"); + } + + @Override + public String readUTF() throws IOException { + return DataInputStream.readUTF(this); + } + } + + /** + * Returns an InvalidModuleDescriptorException with the given detail + * message + */ + private static InvalidModuleDescriptorException invalidModuleDescriptor(String msg) { + return new InvalidModuleDescriptorException(msg); + } + + /** + * Returns an InvalidModuleDescriptorException with a detail message to + * indicate that the class file is truncated. + */ + private static InvalidModuleDescriptorException truncatedModuleDescriptor() { + return invalidModuleDescriptor("Truncated module-info.class"); + } + +} diff --git a/tests/test_data/std/jdk/internal/module/ModuleInfoExtender.class b/tests/test_data/std/jdk/internal/module/ModuleInfoExtender.class new file mode 100644 index 0000000000000000000000000000000000000000..c01cff7c1f24acb50106bcb614b441379810c10f GIT binary patch literal 8193 zcmcIpd3+S*8GhbP$dK#+Ashh#0~j$EMs6_N2og*J8i?9d>X1y5g}vOJ%W*3$}`uin2$9~`Q-pBXuGp`6wtU>@~2Fgv0LxrGvueIN54O`K{*6n-t+I^0oVs$7Qa@GpU8X9{lF&>o$s!Rl7 z3Ks0`-`5(7I(8yzgTxQSK4c|_6tnX?imQ05UZWvTGtq!X+RtV6JUbZ+Q!h%81;;?huA>>oquE3Y77Bt+ zY~vxv-jGOGhXmyfjlCPI(26q*EHbeeO9WHXmfW6lGNu%aJCF!DHm?o68ykCqScc^W zR+w0cRf0KL-|AEP83@r?w5GQ3jy@6_5X@`vtf&=VU>zB4!)gO-OsrMBPDyj(^C^Kz z*XrL84l6N|ijVasHee$;i(82#iPb9(edfudL?5=pZ8eOMvrKHp7FxvW>$Br@yR+$b zC3$_0KMtg#+LP(j(PS!OC)$G8igp9rOq_!b8oH=SZ8Z9O>GCM309WElk#iDpxWXAF;v5d z7>JsPAuedlQg#{j1R0xAnXjFgn=zSda>#pmG>8O}1{@P9>=!J}LT5cHErr%u0siPS zDQ94%)}vs(-)B53g`F@5cUKxgTjHRJLwG&ePuQ2FLJ5_@YtroNI@J+MI(p@$CN5Je z4f|j`mT;J)dhtdRZ&L5Z#o~5Uzj?EXx2QMesiewdy|~iERhmFN5!)Z?cVAwuGVI$0 zFZ)F(q6fM^i?r)I?FFNth5rm_x%oFV45!rIWT zt}4#vupP0ZnYN)=!AU!_qHv8$mDkdfONC|)d@tT-;Qh)%9}vv;`KcE$ZV6N|AXx0j zE#!k^_E7K-;ll>5R|IYlEcX$}6xn>Wb*5XCOg<7^;3u7Sfh=$7VwR_+<0F&7oA40> zH=DQx9~Df{45oWF*43nL0|m2k;>3O1N*$;kF^G@jRs*-0xLsk?W-)TsDKy5C-Cx75 z_OOXh;FAm{D;^KCjj7AQ&(zB;USZZWK5gPNxRYr!VliK>^i-mm9lODEQT=TW8yf0v z6Zfb_)lP4yhUYT$VjU&GgPVu|0f>M)%p4(Y>D?p}2|szDhJ2k|X@ z+rW2}g1%d#tz9O4%DK>=Dm+{J>c9y&V;(f+dja1!@B(W{-|}G7yD^C0;|~V@sObMm&{B$HD&?qCbY5qk$<0}Y+lrlKtaQKWby{i2 zHo9DQXfSFysRWzOQ+(E=tE_e({h_>;JIXilP^6B}p{U)JitMoyJJnfS9dl!SR=CGX z=(D-^vfLR8F-=jCr5%<8tNak&F0Tiw|8)R(Y0=rod`EOjs=%Zc_#u{9!aROHPe%mhbaH(pslfoRX3L6`FgtR zefbM`PTG7>oxs&N$dGaA?4V9#+cV!V*!tK<)%iR)+XrVlKRR=ukH_h`#g{R-H~H4=zgUp)fOXs*&$Wtkp6*wRugEmM)OjFc z30e!T%}*Yg3P81#^@aE7;Z$Z^n5X767kVjk1m{@AmZsTZJ?nPZ@-WqV!COdCiv*|o z6;*_;@+Z@q`FR~vwabDoC%Q(l-_CpG&kmV9>vc@3GPJ2YSct1L1e-msa?6$Sivoh@ z>(-Z;14C4oH!97;VhnW0Qi(p>9hlX+6~I4fJzWuF{o5FeIY|yg;+?iL6zfk`%P9o) z>&+{djXjgb$*CN3$O2QQOKr9K;~;Une{G(Q74@`z3rd#>w6tkSr9zq&l@?Pb$i!+n z-5sPAP>tSveE2MMwNU#D{QRb6^D*bWA{&c?vP6~|vW&G@mJ3ey*(Y7reJ1B@!4I8H z%~{q9>}so)<)pPriF~Fhvt)L)%;t+VRkBvr8M5A#4Z?AxZ|WC{?vL%WTRU`apxLYe ztB*rw_Bp|b|LIvjJKiSO%I;(^S>F+h?MubIqq)C|`}C2saVP7ge|hO&x+IUi*B=2M z@+K=B?&hSJ(PXwqqjo|Y-DY0j%n@+bAVsnurzYO$osGZl3JqyzUdV3DkswzuhMbdQ z^g>H{Y;%=}MH~PII0iOQqki(>T|oVyz_IC{_5DkH<}U~Op7Vcw<#1nLImy>oPUd-? zz?GaMa_3+8w1rO!x2owuNK^9zFz(fB|H{va?9_n{l%o@s=)&LlG~Hc|zvCZ#;y%p{ z>l3;8C%;peJ2RNgBbe|2rZnBdw`EY6>USRC0yWMog6B&0FRn6)s&-7nOBp#|=G{!Z z!cRqMokz(~oY!hH0Uw!*DX8TmV`SJiw6YZ2bMWs%V6(=6?IT#Y2$<5i0-IMDtZocg zl3-2|Fl9CcR*(PibBvht$ADc%u*-{pDcdWs2E1AbY{3|?D+zX05wQQ#ffN{<1kcnP zJOflVHw}Y-r)Ry#we+>L^mRVC%8UsrMI-f+=yC^ zfEsXwL~hb7HMt}_mdep86=IN$8qAaNQc09r%$6$Rl=;}Kl%OcrRF+vnw^mMC`4Glm z$Pl_9OT0pV@w_JFdUB;3xz$yw^mqU-GP0DMyPJ+;SIZOVy&hdHkE6G%dEqE7;y8a4 ztfS4NU@@kC_l@F`fO>gAfAt3adAa_)LVvzhsFJsh;vE5;e;8HGEu(l(0Lm(E{4Hnv z0}r7Z4^zxXFawX$-5#S#9;Yx*U==49>+mGUi%(%2*Yw~hF2d6pbyf2>s7X?-GsAAJ z8p2_>OcwPMj=Gy7QxTA9ystpu74%e82UJ0K<&|zqt1NyOtvKr_rYh6U8o_lV_@K)) zpQju}i@J>BMxjYRCN$X{%EF&g7QRc++1xUMdo%0nj$*RHsT;wAnU@PZ@CCzocmz*m z-p@aZrE2l~VH|ZYUmC?%6de*ff^YcgjNqH@KBd2M?NVKs!uy+UiN sYmg>csP9^3k*x6UR!W;NL{<18EN96UCfyhCoSa=zDO+WmbYSNH0QbF0)Bpeg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleInfoExtender.java b/tests/test_data/std/jdk/internal/module/ModuleInfoExtender.java new file mode 100644 index 00000000..c9d3fd0a --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModuleInfoExtender.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.constant.ClassDesc; +import java.lang.module.ModuleDescriptor.Version; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.classfile.attribute.ModuleHashInfo; +import java.lang.classfile.attribute.ModuleHashesAttribute; +import java.lang.classfile.attribute.ModuleMainClassAttribute; +import java.lang.classfile.attribute.ModulePackagesAttribute; +import java.lang.classfile.attribute.ModuleResolutionAttribute; +import java.lang.classfile.attribute.ModuleTargetAttribute; +import java.lang.constant.ModuleDesc; +import java.lang.constant.PackageDesc; + + +/** + * Utility class to extend a module-info.class with additional attributes. + */ + +public final class ModuleInfoExtender { + + // the input stream to read the original module-info.class + private final InputStream in; + + // the packages in the ModulePackages attribute + private Set packages; + + // the value for the module version in the Module attribute + private Version version; + + // the value of the ModuleMainClass attribute + private String mainClass; + + // the value for the ModuleTarget attribute + private String targetPlatform; + + // the hashes for the ModuleHashes attribute + private ModuleHashes hashes; + + // the value of the ModuleResolution attribute + private ModuleResolution moduleResolution; + + private ModuleInfoExtender(InputStream in) { + this.in = in; + } + + /** + * Sets the packages for the ModulePackages attribute + * + * @apiNote This method does not check that the package names are legal + * package names or that the set of packages is a super set of the + * packages in the module. + */ + public ModuleInfoExtender packages(Set packages) { + this.packages = Collections.unmodifiableSet(packages); + return this; + } + + /** + * Sets the value for the module version in the Module attribute + */ + public ModuleInfoExtender version(Version version) { + this.version = version; + return this; + } + + /** + * Sets the value of the ModuleMainClass attribute. + * + * @apiNote This method does not check that the main class is a legal + * class name in a named package. + */ + public ModuleInfoExtender mainClass(String mainClass) { + this.mainClass = mainClass; + return this; + } + + /** + * Sets the value for the ModuleTarget attribute. + */ + public ModuleInfoExtender targetPlatform(String targetPlatform) { + this.targetPlatform = targetPlatform; + return this; + } + + /** + * The ModuleHashes attribute will be emitted to the module-info with + * the hashes encapsulated in the given {@code ModuleHashes} + * object. + */ + public ModuleInfoExtender hashes(ModuleHashes hashes) { + this.hashes = hashes; + return this; + } + + /** + * Sets the value for the ModuleResolution attribute. + */ + public ModuleInfoExtender moduleResolution(ModuleResolution mres) { + this.moduleResolution = mres; + return this; + } + + /** + * Outputs the modified module-info.class to the given output stream. + * Once this method has been called then the Extender object should + * be discarded. + */ + public void write(OutputStream out) throws IOException { + // emit to the output stream + out.write(toByteArray()); + } + + /** + * Returns the bytes of the modified module-info.class. + * Once this method has been called then the Extender object should + * be discarded. + */ + public byte[] toByteArray() throws IOException { + var cc = ClassFile.of(); + var cm = cc.parse(in.readAllBytes()); + Version v = ModuleInfoExtender.this.version; + return cc.transform(cm, ClassTransform.endHandler(clb -> { + // ModuleMainClass attribute + if (mainClass != null) { + clb.with(ModuleMainClassAttribute.of(ClassDesc.of(mainClass))); + } + + // ModulePackages attribute + if (packages != null) { + List packageNames = packages.stream() + .sorted() + .map(PackageDesc::of) + .toList(); + clb.with(ModulePackagesAttribute.ofNames(packageNames)); + } + + // ModuleTarget, ModuleResolution and ModuleHashes attributes + if (targetPlatform != null) { + clb.with(ModuleTargetAttribute.of(targetPlatform)); + } + if (moduleResolution != null) { + clb.with(ModuleResolutionAttribute.of(moduleResolution.value())); + } + if (hashes != null) { + clb.with(ModuleHashesAttribute.of( + hashes.algorithm(), + hashes.hashes().entrySet().stream().map(he -> + ModuleHashInfo.of(ModuleDesc.of( + he.getKey()), + he.getValue())).toList())); + } + }).andThen((clb, cle) -> { + if (v != null && cle instanceof ModuleAttribute ma) { + clb.with(ModuleAttribute.of( + ma.moduleName(), + ma.moduleFlagsMask(), + clb.constantPool().utf8Entry(v.toString()), + ma.requires(), + ma.exports(), + ma.opens(), + ma.uses(), + ma.provides())); + } else { + clb.accept(cle); + } + })); + } + + /** + * Returns an {@code Extender} that may be used to add additional + * attributes to the module-info.class read from the given input + * stream. + */ + public static ModuleInfoExtender newExtender(InputStream in) { + return new ModuleInfoExtender(in); + } + +} diff --git a/tests/test_data/std/jdk/internal/module/ModuleLoaderMap$Mapper.class b/tests/test_data/std/jdk/internal/module/ModuleLoaderMap$Mapper.class new file mode 100644 index 0000000000000000000000000000000000000000..bd5ca22a242bf880773efaa3728f2e8ccdceceb9 GIT binary patch literal 2695 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleLoaderMap.class b/tests/test_data/std/jdk/internal/module/ModuleLoaderMap.class new file mode 100644 index 0000000000000000000000000000000000000000..7bbd313afbb4b07f897a6e676dc8690366f9b91f GIT binary patch literal 1525 zcmbtUOK;Oa5dJprq=vLfDW$YfXah+KHKp8A6_rR8h@>2XD#6WhHerLaj{K;^f8qdK zkU&D>%J1OHUqH;-Ze>E$hlu3t%+7u@^UcoAkKbRu0che;0SP3tNNGqT!!SEEjtt#0 z zdz=`wgyaYQsLP#~M%SX9Qp+|C>(Fq7(xc6k_eM}SqwYCD(xh2ix9N$=;!4@1hzx+9NlNZ0Y)Ul;4w(jPd&wbCO1lY6Wc2cU-L+?vb`i iUjp|Dxfw`09?+Vhy&O%pEs{%tyoiTTvu+XFSo#CKX?Z6A literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleLoaderMap.java b/tests/test_data/std/jdk/internal/module/ModuleLoaderMap.java new file mode 100644 index 00000000..ad45399d --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModuleLoaderMap.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.lang.module.Configuration; +import java.lang.module.ResolvedModule; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import jdk.internal.loader.ClassLoaders; + +/** + * Supports the mapping of modules to class loaders. The set of modules mapped + * to the boot and platform class loaders is generated at build time from + * this source file. + */ +public final class ModuleLoaderMap { + + /** + * Maps the system modules to the built-in class loaders. + */ + private static final class Mapper implements Function { + + private static final ClassLoader PLATFORM_CLASSLOADER = + ClassLoaders.platformClassLoader(); + private static final ClassLoader APP_CLASSLOADER = + ClassLoaders.appClassLoader(); + + private static final Integer PLATFORM_LOADER_INDEX = 1; + private static final Integer APP_LOADER_INDEX = 2; + + /** + * Map from module to a class loader index. The index is resolved to the + * actual class loader in {@code apply}. + */ + private final Map map; + + /** + * Creates a Mapper to map module names in the given Configuration to + * built-in classloaders. + * + * As a proxy for the actual classloader, we store an easily archiveable + * index value in the internal map. The index is stored as a boxed value + * so that we can cheaply do identity comparisons during bootstrap. + */ + Mapper(Configuration cf) { + var map = new HashMap(); + for (ResolvedModule resolvedModule : cf.modules()) { + String mn = resolvedModule.name(); + if (!Modules.bootModules.contains(mn)) { + if (Modules.platformModules.contains(mn)) { + map.put(mn, PLATFORM_LOADER_INDEX); + } else { + map.put(mn, APP_LOADER_INDEX); + } + } + } + this.map = map; + } + + @Override + public ClassLoader apply(String name) { + Integer loader = map.get(name); + if (loader == APP_LOADER_INDEX) { + return APP_CLASSLOADER; + } else if (loader == PLATFORM_LOADER_INDEX) { + return PLATFORM_CLASSLOADER; + } else { // BOOT_LOADER_INDEX + return null; + } + } + } + + /** + * Returns the names of the modules defined to the boot loader. + */ + public static Set bootModules() { + return Modules.bootModules; + } + + /** + * Returns the names of the modules defined to the platform loader. + */ + public static Set platformModules() { + return Modules.platformModules; + } + + /** + * Returns the names of the modules defined to the application loader which perform native access. + */ + public static Set nativeAccessModules() { + return Modules.nativeAccessModules; + } + + private static class Modules { + // list of boot modules is generated at build time. + private static final Set bootModules = + Set.of(new String[] { "java.base", + "java.datatransfer", + "java.desktop", + "java.instrument", + "java.logging", + "java.management", + "java.management.rmi", + "java.naming", + "java.prefs", + "java.rmi", + "java.security.sasl", + "java.xml", + "jdk.incubator.vector", + "jdk.internal.vm.ci", + "jdk.jfr", + "jdk.management", + "jdk.management.agent", + "jdk.management.jfr", + "jdk.naming.rmi", + "jdk.net", + "jdk.nio.mapmode", + "jdk.sctp", + "jdk.unsupported" }); + + // list of platform modules is generated at build time. + private static final Set platformModules = + Set.of(new String[] { "java.compiler", + "java.net.http", + "java.scripting", + "java.se", + "java.security.jgss", + "java.smartcardio", + "java.sql", + "java.sql.rowset", + "java.transaction.xa", + "java.xml.crypto", + "jdk.accessibility", + "jdk.charsets", + "jdk.crypto.cryptoki", + "jdk.dynalink", + "jdk.graal.compiler", + "jdk.graal.compiler.management", + "jdk.httpserver", + "jdk.jsobject", + "jdk.localedata", + "jdk.naming.dns", + "jdk.security.auth", + "jdk.security.jgss", + "jdk.xml.dom", + "jdk.zipfs" }); + + // list of jdk modules is generated at build time. + private static final Set nativeAccessModules = + Set.of(new String[] { "java.base", + "java.datatransfer", + "java.desktop", + "java.instrument", + "java.logging", + "java.management", + "java.management.rmi", + "java.naming", + "java.net.http", + "java.prefs", + "java.rmi", + "java.scripting", + "java.se", + "java.security.jgss", + "java.security.sasl", + "java.smartcardio", + "java.sql", + "java.sql.rowset", + "java.transaction.xa", + "java.xml", + "java.xml.crypto", + "jdk.accessibility", + "jdk.charsets", + "jdk.crypto.cryptoki", + "jdk.dynalink", + "jdk.httpserver", + "jdk.incubator.vector", + "jdk.internal.le", + "jdk.internal.vm.ci", + "jdk.jfr", + "jdk.jsobject", + "jdk.localedata", + "jdk.management", + "jdk.management.agent", + "jdk.management.jfr", + "jdk.naming.dns", + "jdk.naming.rmi", + "jdk.net", + "jdk.nio.mapmode", + "jdk.sctp", + "jdk.security.auth", + "jdk.security.jgss", + "jdk.unsupported", + "jdk.xml.dom", + "jdk.zipfs" }); + } + + /** + * Returns a function to map modules in the given configuration to the + * built-in class loaders. + */ + static Function mappingFunction(Configuration cf) { + return new Mapper(cf); + } + + /** + * When defining modules for a configuration, we only allow defining modules + * to the boot or platform classloader if the ClassLoader mapping function + * originate from here. + */ + public static boolean isBuiltinMapper(Function clf) { + return clf instanceof Mapper; + } +} diff --git a/tests/test_data/std/jdk/internal/module/ModulePatcher$ExplodedResourceFinder$1.class b/tests/test_data/std/jdk/internal/module/ModulePatcher$ExplodedResourceFinder$1.class new file mode 100644 index 0000000000000000000000000000000000000000..31b5a072b015e07c49526a40e5b846eb002adc06 GIT binary patch literal 2420 zcmbVNT~`}b6x}xjCQXJAX!x>Ks7;l`wrSN?G^|=cu)**lUuv=HkX*>L!%Ws>DAgBz z^auFtt1o@1Yl+gXr9Z&mUuyOXe4Sv0`}Ts&q4RPimG^k(E_hclO<~oHy+Xmv0Kh z9vfE1Huj{zK4v6lI(fB_r<JZtcLcg7vYQDEVo1ZVjuDKKoX_o) zM}cn7*>FvP)I>I5B)$B`YOxT<1zgnds*cw%CZIQr8=DQY)zbgWN(Bv<1kU@)46V34 z_oOUqp6S>cE(`R9HeA&S<}l;O<&&W>~iq6e-~6BwP?nrQ}1o-GXqz#|mGnnZJVfbWGxX(yg1{v08>ZB4-yg z6a@NxvVP4KS;D*0?PihV`{Uzdfdg8ev9=2h;^AU$3&k(mPHWjsQlDkJ@W@N1EtmH9 zwxzpnY^%~AC^==r+B95KeFuwCuWIser_RhabCap)Q7D-kZ0IxN5GA!Jy{c1LFN*E1Py+X^c}DrsqEYjM*09v9QXlI? zlMINa(zoW18XvcpORX|hCDFNl1>z??N8(AEg^DX=*H(2+r>r2`D@l9TtNK%<$dDEY z+MuFZk|%g-G+tNr$Ag};%a&8;%xk1i! zKEyQ|V1{>_`VHbE%yEC7@BLBWhm`M4c~+0W$GFFTkWkf zU69~dU|gkCo>Mf|o+B;rJ6?HKB92;BH`#a~Uq_eEI!TELcOtz=Mv^D&leAdCC%> z;HgAgM!BeAk?YGHy(V75YnomM>2>HOysqF=GE<4VMGh)a2^H%RGDpa@r|Uu}U5Oxw zRhmR;IL>Dc>jBtpN(H7Xu&zIG;|OoJqm6~o^bTkn*bLAf&;!$o;RdzacgND0`srtA zkzdd~_Ty7-HL@S40V01p^h9wWAP6S9z{5(yy@W+0uoCK(cA5Ddy@Ks3atmzf3{db-E%o{+dN z|H41uix06%lNd`MeX#sBYLyQzc<$|1c<}aBi)%ZdguWdJeaZ zvRkU!rZFXlSsoNuO|O6KcExr}X6c&gyH&4fj$2O2^a!nF(f@suQlVqH#+B!r|rQWa;(b~zDX)UXRG4l-P5xbg@@_Mg?zgTo?xM;JE9%($*c04g+d zl;lj(-r$0YqYQhta%X~4V#V}QA8l@Ks^}Fl6nRw-vxwJ%xxn*XyRudS=Ng^1zg~J)`4UoTI9za-_0mIGeC>^Dq#?UosIp%b=ykvUwe95Mr?n$@E?FH^xVjXR!gH?+% z_`-iLPD;(9?fRr3y-W?1VjGzjcauDi7ytG~L$Z$Kvb(v|C9bf)V=myu^(kJFrmL7E zmm144?6ca~?V>4**H=M=gf&ZTd}5}4LSYSDO5(I_iTpd#kbjN2!jPG>RvaEwJu<@B z`Q}Ko?UxE9Fo`Jw6~=f-3zayW z`x4b2u`&jCGJoW&`a}V)2@GbHR9^$N+ zJ*{9%v2QhFjXV#}pPY4VM%CWHS}#b2HSx*i9tx-TA;LFW?4lvj0o={ks>lE69w(LEptPxA&C_xPNvRN23(q* z#u5oDD54}s6Du@|+W}d$iZztw%s~Y{-lMZVV!RC|-lyd2p|$uKrS%7`8a~9w_!Ni! E0jJ(wlmGw# literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModulePatcher$JarResourceFinder$1.class b/tests/test_data/std/jdk/internal/module/ModulePatcher$JarResourceFinder$1.class new file mode 100644 index 0000000000000000000000000000000000000000..cba27cb531ebbc81c04a83407ab8c7153730606a GIT binary patch literal 2699 zcmbVO+jA3D9R5z4cGIw>X(=tpU8}SyutF)fBA3)6t!Y6DRp_8@lhby~b`y6u6z~Fg zneh+s*;ikDz!@lv%s9^Y;0)@E5BlJP{vnR_JG+}SY3itSx_i!^^E=<~`(00-{Pp!W z0EX~MGh%4a5ZBR&CV_$Z{58XJeCax-Z7dY>C0iO}!EoO6b92(|9yQ$y(kqnQoIGPW zd9LgiNL)AVZpU1Z0`1v(^SWu+rZa0y_^##54k{%H9nDAzG%HEz`0h=CO`&MXw`^nH zbPYletDWG0uA>F(1)BUh%j6x+*yxoU!;!wRxVUJXH(gI&B5{GFbaI8fq<`iFcK6hqf2Fs6 zO~Y0JJ@Ax*ymTR}VY@)rYTso_mQ9LDY(rZDy9DBN)G_t>oQ`fhPs(PoD4o2(-ZfO$ zYmNZv;@#-c(5oYjK7sxkzx=nr3pD0DG8b4M8W>qZpKrrnMQ`6KR_CVYWzHY`XI2R? z(6L>HLO7tK9|xIRej&^wfsUT~qtvzqhg5hEGe&FqU{b?Tf$bG%kD2yN!CjDfav#2t zlSSVuI7#N{ppN5siRR2of5a)4eCn0v0>e_)YZZ*D4XQqgQyNa|$Y4ldL!hEohEXO) z{|&C{vo5kuD_{U9%{#xo0X9nO!Rp#PC%e zS&Y$X^E2cb#-X~P&RDi2&vQ7h;WcI71$rsqxmrrVh`bl<+_H+s6{{E)WTd~=G{RoQ zB@L50UdI~(oprFmVF8W)oUm@OIk2ooHCz#B3uJ>PF~W8;E8RvmB-~zJUKW@pkN@9? z2J5S=-W`!Sll1Noi&mgDYdLbfv@k8*i{`W)G_XR>v?op1Qs2>HTy-IV!%su3d;g$7 zYE1fbg*^KPyCnN7!IWFZgPz&MSx`u+a-x+>iS_MDuVniIg4}kl6xy0uOhxO$c0^68 zAGJ*QX71XUSq$vZz+_IXxV~IhDe715mz@&vs)yY^XfmJ!kCNLc)c5EucW>_gG zPeZAk*(z_&Rdz@r(8sttepWiOiYPOKg%J0GG!dgj3dyMa<)u<{2klc9Fm%IC&MtVo zVM5>P_yD(wF~e&~;J{j~pf-G~+CQC_7?+-Zw&3|1J`~vXuUW|I9&sG$4%w#Xsp@X4 zyB@KVoh8NGZb+rnB@1xmRTzxC;kcvm*?_B*dy})X9OE22(t932r1w66mhO9ib?Jv_ z{fg@`yv27D1R%b}+njfDjq)%t%~8!1u0W3SmImMs)l;c@1oAk@w^C$qBnTSQ_aW|a zQjPpwfUJiC5wd{9Omz4jIT9L2)ZvCl*qD8cEtel-+vSJY(Y|vD&vIkkeY~)QJ?#cR z`}izj|3eIn?YTEbef%vzDg!t|9A!}_y#w(*n#B|Jiytr`e#9a1Q@|rlZT;joi$1;& z@tK3gH}yx{nrY5_;FW7!ZHHJUbWBtKHiSkw0jI+L0Kb&!iHPKC>wm7YK2fp0fFgA& z*A4Tu(%zC@!m%Zs$o4(L%PS!2GJ*I73Gr(H6b7gz0!q-(ciz|?1-LyLWZ#vPx2NnK$G zLf*fV_a9ZfyDGd}aRWEWO}RLM*q`W#pRTqdj$7P`;a$APG0vYD@8eFeau*+QZ0Fu? N+{MRCf8{>@{S5$ukO}|* literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModulePatcher$JarResourceFinder.class b/tests/test_data/std/jdk/internal/module/ModulePatcher$JarResourceFinder.class new file mode 100644 index 0000000000000000000000000000000000000000..73014a42f2ce35835dde96d11050649d5f839cdd GIT binary patch literal 2569 zcmbVOYgZdZ7=8v47Q#Xx+*+!=P+CcVZZA@+L99g(YJf^0O0Ad4W&#^FyK#4et-p$@ z1>0(m-#o|T|L{+EJifELluZMzHs>U>GxP3ydERH9$shkbc?Mt>_Y-JAtAdz{INBI` zDtw1)Cbu@Vm10Hc9z)x-VHw^GL+e<&prD;$z&EOUhN)G!quu7tykUw?B+#iqRndiR zhLmq)8MaoYP3;c%wiwzyJMTG$waL&wmd+gp3s$oUDCm)?^iq_u=KXY`1AXXMFrZ=( zLk!m{rESfyJmFZ})T(x=PO+B!fgDR!KMvEtN9EP~iT>GP1Ic zlPZRBiXraV>yAON93*QAPg`GIq(tAuX$5CgoW(f?H7GXN3|?E!HNBS0%Iwdp7{vuL z(%p4w)E(pzc+U9{yrp7Hb|bEvwksqk85QH0VCdWw9u+iadCmidiK8HDF3Y#hD!9Zj z^%{7MUP)jQmt|Y7Fcc}~|HnKVWaSep?DcVZrVFy*YbxHx6tU0s9Kov$rw&@+H!N7y z$Q5m7Q^e(WRNTP3gc+~ZOv2_&gMGPf>7HR*+I;vxZO&p^!TTy^@By*mkkbvmiS|`q zW4IAQ?MH9+7IOKB+!TDsaQW4cy~xp_Fkr(8%BBkpv01w$7?L@|63g{!Q8;V7Xwph5 zXY1T7aL17Ia53g>87?*cwYo;ZYW~6P4@nw5&RK@U+40hnSWtwR#jAd4OA6z*uwwzuoGW7WjhmxdSD9@IqC{J(DoAz%J( z6p7IDEH}-(;R)h`x@cL#nKilV3Oa(lN8Ci+2UHKPCIv*m3r)Zsg@J+{hSM)MCHV{h zqg$$vE_#NW^qZ1bCn;u1-a|CT=o`l^+L@&%o#rhxp3m%qWu8LW7=MfohJ7R-A(f%Y z35Gqq@dzUi$*ct*(QisRVY`U2hZtZ#V1)gMIa(hKTwxv`(~O*A0gIHzZF-K;_z8XK zrVB$~rx~N2_RLR6?cw5~fB7#3Y#$2y+4rjkcA?*>wW zk_y%u>MCH0-jpL1_6R?(t`aJsV>!2-Dke_=Y-sb|8y5$ t_~Si%MWe*Tpom|CV-q!686nF)+{3r@k7knQ@^h2sPFn&l>i7;P{{`#bt9Sqa literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModulePatcher$PatchedModuleReader$1.class b/tests/test_data/std/jdk/internal/module/ModulePatcher$PatchedModuleReader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..e797464b546fba827f38c4fe658a4259f82c207d GIT binary patch literal 2139 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModulePatcher$ResourceFinder.class b/tests/test_data/std/jdk/internal/module/ModulePatcher$ResourceFinder.class new file mode 100644 index 0000000000000000000000000000000000000000..d30ada878ae225f90275038608b1a74a8e93ea52 GIT binary patch literal 514 zcmZ`$O-}+b5Pd~tVMXM_kAo)@4|uW0E5^%4BMFL;Ur?5c#nPI#Yy52<`~m(bpf{Vw&(r^qC^L&uew*mP^?G<;9b4`Zojr8HldNN|0;b3L4zf5JQ_l=P*(ZYM_85)bd zzg(^W3~O}O>90!Uc!VlNHHylFF=gu5L}{5pBd^33v6{uLg?51*>=4GpA_uWsi9Z2R CCyFWn literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModulePatcher.class b/tests/test_data/std/jdk/internal/module/ModulePatcher.class new file mode 100644 index 0000000000000000000000000000000000000000..b552d1354eb73d7688c6065c172d71c1880d60ab GIT binary patch literal 13680 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 QeBQw4PCk2;#VRKHU+Bu&)Bpeg literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModulePatcher.java b/tests/test_data/std/jdk/internal/module/ModulePatcher.java new file mode 100644 index 00000000..ce837027 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModulePatcher.java @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.module; + +import java.io.Closeable; +import java.io.File; +import java.io.IOError; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Stream; + +import jdk.internal.loader.Resource; +import jdk.internal.access.JavaLangModuleAccess; +import jdk.internal.access.SharedSecrets; +import sun.net.www.ParseUtil; + + +/** + * Provides support for patching modules, mostly the boot layer. + */ + +public final class ModulePatcher { + + private static final JavaLangModuleAccess JLMA + = SharedSecrets.getJavaLangModuleAccess(); + + // module name -> sequence of patches (directories or JAR files) + private final Map> map; + + /** + * Initialize the module patcher with the given map. The map key is + * the module name, the value is a list of path strings. + */ + public ModulePatcher(Map> input) { + if (input.isEmpty()) { + this.map = Map.of(); + } else { + Map> map = new HashMap<>(); + for (Map.Entry> e : input.entrySet()) { + String mn = e.getKey(); + List paths = e.getValue().stream() + .map(Paths::get) + .toList(); + map.put(mn, paths); + } + this.map = map; + } + } + + /** + * Returns a module reference that interposes on the given module if + * needed. If there are no patches for the given module then the module + * reference is simply returned. Otherwise the patches for the module + * are scanned (to find any new packages) and a new module reference is + * returned. + * + * @throws UncheckedIOException if an I/O error is detected + */ + public ModuleReference patchIfNeeded(ModuleReference mref) { + // if there are no patches for the module then nothing to do + ModuleDescriptor descriptor = mref.descriptor(); + String mn = descriptor.name(); + List paths = map.get(mn); + if (paths == null) + return mref; + + // Scan the JAR file or directory tree to get the set of packages. + // For automatic modules then packages that do not contain class files + // must be ignored. + Set packages = new HashSet<>(); + boolean isAutomatic = descriptor.isAutomatic(); + try { + for (Path file : paths) { + if (Files.isRegularFile(file)) { + + // JAR file - do not open as a multi-release JAR as this + // is not supported by the boot class loader + try (JarFile jf = new JarFile(file.toString())) { + jf.stream() + .filter(e -> !e.isDirectory() + && (!isAutomatic || e.getName().endsWith(".class"))) + .map(e -> toPackageName(file, e)) + .filter(Checks::isPackageName) + .forEach(packages::add); + } + + } else if (Files.isDirectory(file)) { + + // exploded directory without following sym links + Path top = file; + try (Stream stream = Files.find(top, Integer.MAX_VALUE, + ((path, attrs) -> attrs.isRegularFile()))) { + stream.filter(path -> (!isAutomatic + || path.toString().endsWith(".class")) + && !isHidden(path)) + .map(path -> toPackageName(top, path)) + .filter(Checks::isPackageName) + .forEach(packages::add); + } + + } + } + + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + + // if there are new packages then we need a new ModuleDescriptor + packages.removeAll(descriptor.packages()); + if (!packages.isEmpty()) { + Builder builder = JLMA.newModuleBuilder(descriptor.name(), + /*strict*/ descriptor.isAutomatic(), + descriptor.modifiers()); + if (!descriptor.isAutomatic()) { + descriptor.requires().forEach(builder::requires); + descriptor.exports().forEach(builder::exports); + descriptor.opens().forEach(builder::opens); + descriptor.uses().forEach(builder::uses); + } + descriptor.provides().forEach(builder::provides); + + descriptor.version().ifPresent(builder::version); + descriptor.mainClass().ifPresent(builder::mainClass); + + // original + new packages + builder.packages(descriptor.packages()); + builder.packages(packages); + + descriptor = builder.build(); + } + + // return a module reference to the patched module + URI location = mref.location().orElse(null); + + ModuleTarget target = null; + ModuleHashes recordedHashes = null; + ModuleHashes.HashSupplier hasher = null; + ModuleResolution mres = null; + if (mref instanceof ModuleReferenceImpl) { + ModuleReferenceImpl impl = (ModuleReferenceImpl)mref; + target = impl.moduleTarget(); + recordedHashes = impl.recordedHashes(); + hasher = impl.hasher(); + mres = impl.moduleResolution(); + } + + return new ModuleReferenceImpl(descriptor, + location, + () -> new PatchedModuleReader(paths, mref), + this, + target, + recordedHashes, + hasher, + mres); + + } + + /** + * Returns true is this module patcher has patches. + */ + public boolean hasPatches() { + return !map.isEmpty(); + } + + /* + * Returns the names of the patched modules. + */ + Set patchedModules() { + return map.keySet(); + } + + /** + * A ModuleReader that reads resources from a patched module. + * + * This class is public so as to expose the findResource method to the + * built-in class loaders and avoid locating the resource twice during + * class loading (once to locate the resource, the second to gets the + * URL for the CodeSource). + */ + public static class PatchedModuleReader implements ModuleReader { + private final List finders; + private final ModuleReference mref; + private final URL delegateCodeSourceURL; + private volatile ModuleReader delegate; + + /** + * Creates the ModuleReader to reads resources in a patched module. + */ + PatchedModuleReader(List patches, ModuleReference mref) { + List finders = new ArrayList<>(); + boolean initialized = false; + try { + for (Path file : patches) { + if (Files.isRegularFile(file)) { + finders.add(new JarResourceFinder(file)); + } else { + finders.add(new ExplodedResourceFinder(file)); + } + } + initialized = true; + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } finally { + // close all ResourceFinder in the event of an error + if (!initialized) closeAll(finders); + } + + this.finders = finders; + this.mref = mref; + this.delegateCodeSourceURL = codeSourceURL(mref); + } + + /** + * Closes all resource finders. + */ + private static void closeAll(List finders) { + for (ResourceFinder finder : finders) { + try { finder.close(); } catch (IOException ioe) { } + } + } + + /** + * Returns the code source URL for the given module. + */ + private static URL codeSourceURL(ModuleReference mref) { + try { + Optional ouri = mref.location(); + if (ouri.isPresent()) + return ouri.get().toURL(); + } catch (MalformedURLException e) { } + return null; + } + + /** + * Returns the ModuleReader to delegate to when the resource is not + * found in a patch location. + */ + private ModuleReader delegate() throws IOException { + ModuleReader r = delegate; + if (r == null) { + synchronized (this) { + r = delegate; + if (r == null) { + delegate = r = mref.open(); + } + } + } + return r; + } + + /** + * Finds a resources in the patch locations. Returns null if not found + * or the name is "module-info.class" as that cannot be overridden. + */ + private Resource findResourceInPatch(String name) throws IOException { + if (!name.equals("module-info.class")) { + for (ResourceFinder finder : finders) { + Resource r = finder.find(name); + if (r != null) + return r; + } + } + return null; + } + + /** + * Finds a resource of the given name in the patched module. + */ + public Resource findResource(String name) throws IOException { + + // patch locations + Resource r = findResourceInPatch(name); + if (r != null) + return r; + + // original module + ByteBuffer bb = delegate().read(name).orElse(null); + if (bb == null) + return null; + + return new Resource() { + private T shouldNotGetHere(Class type) { + throw new InternalError("should not get here"); + } + @Override + public String getName() { + return shouldNotGetHere(String.class); + } + @Override + public URL getURL() { + return shouldNotGetHere(URL.class); + } + @Override + public URL getCodeSourceURL() { + return delegateCodeSourceURL; + } + @Override + public ByteBuffer getByteBuffer() throws IOException { + return bb; + } + @Override + public InputStream getInputStream() throws IOException { + return shouldNotGetHere(InputStream.class); + } + @Override + public int getContentLength() throws IOException { + return shouldNotGetHere(int.class); + } + }; + } + + @Override + public Optional find(String name) throws IOException { + Resource r = findResourceInPatch(name); + if (r != null) { + URI uri = URI.create(r.getURL().toString()); + return Optional.of(uri); + } else { + return delegate().find(name); + } + } + + @Override + public Optional open(String name) throws IOException { + Resource r = findResourceInPatch(name); + if (r != null) { + return Optional.of(r.getInputStream()); + } else { + return delegate().open(name); + } + } + + @Override + public Optional read(String name) throws IOException { + Resource r = findResourceInPatch(name); + if (r != null) { + ByteBuffer bb = r.getByteBuffer(); + assert !bb.isDirect(); + return Optional.of(bb); + } else { + return delegate().read(name); + } + } + + @Override + public void release(ByteBuffer bb) { + if (bb.isDirect()) { + try { + delegate().release(bb); + } catch (IOException ioe) { + throw new InternalError(ioe); + } + } + } + + @Override + public Stream list() throws IOException { + Stream s = delegate().list(); + for (ResourceFinder finder : finders) { + s = Stream.concat(s, finder.list()); + } + return s.distinct(); + } + + @Override + public void close() throws IOException { + closeAll(finders); + delegate().close(); + } + } + + + /** + * A resource finder that find resources in a patch location. + */ + private static interface ResourceFinder extends Closeable { + Resource find(String name) throws IOException; + Stream list() throws IOException; + } + + + /** + * A ResourceFinder that finds resources in a JAR file. + */ + private static class JarResourceFinder implements ResourceFinder { + private final JarFile jf; + private final URL csURL; + + JarResourceFinder(Path path) throws IOException { + this.jf = new JarFile(path.toString()); + this.csURL = path.toUri().toURL(); + } + + @Override + public void close() throws IOException { + jf.close(); + } + + @Override + public Resource find(String name) throws IOException { + JarEntry entry = jf.getJarEntry(name); + if (entry == null) + return null; + + return new Resource() { + @Override + public String getName() { + return name; + } + @Override + public URL getURL() { + String encodedPath = ParseUtil.encodePath(name, false); + try { + @SuppressWarnings("deprecation") + var result = new URL("jar:" + csURL + "!/" + encodedPath); + return result; + } catch (MalformedURLException e) { + return null; + } + } + @Override + public URL getCodeSourceURL() { + return csURL; + } + @Override + public ByteBuffer getByteBuffer() throws IOException { + byte[] bytes = getInputStream().readAllBytes(); + return ByteBuffer.wrap(bytes); + } + @Override + public InputStream getInputStream() throws IOException { + return jf.getInputStream(entry); + } + @Override + public int getContentLength() throws IOException { + long size = entry.getSize(); + return (size > Integer.MAX_VALUE) ? -1 : (int) size; + } + }; + } + + @Override + public Stream list() throws IOException { + return jf.stream().map(JarEntry::getName); + } + } + + + /** + * A ResourceFinder that finds resources on the file system. + */ + private static class ExplodedResourceFinder implements ResourceFinder { + private final Path dir; + + ExplodedResourceFinder(Path dir) { + this.dir = dir; + } + + @Override + public void close() { } + + @Override + public Resource find(String name) throws IOException { + Path file = Resources.toFilePath(dir, name); + if (file != null) { + return newResource(name, dir, file); + } else { + return null; + } + } + + private Resource newResource(String name, Path top, Path file) { + return new Resource() { + @Override + public String getName() { + return name; + } + @Override + public URL getURL() { + try { + return file.toUri().toURL(); + } catch (IOException | IOError e) { + return null; + } + } + @Override + public URL getCodeSourceURL() { + try { + return top.toUri().toURL(); + } catch (IOException | IOError e) { + return null; + } + } + @Override + public ByteBuffer getByteBuffer() throws IOException { + return ByteBuffer.wrap(Files.readAllBytes(file)); + } + @Override + public InputStream getInputStream() throws IOException { + return Files.newInputStream(file); + } + @Override + public int getContentLength() throws IOException { + long size = Files.size(file); + return (size > Integer.MAX_VALUE) ? -1 : (int)size; + } + }; + } + + @Override + public Stream list() throws IOException { + return Files.walk(dir, Integer.MAX_VALUE) + .map(f -> Resources.toResourceName(dir, f)) + .filter(s -> !s.isEmpty()); + } + } + + + /** + * Derives a package name from the file path of an entry in an exploded patch + */ + private static String toPackageName(Path top, Path file) { + Path entry = top.relativize(file); + Path parent = entry.getParent(); + if (parent == null) { + return warnIfModuleInfo(top, entry.toString()); + } else { + return parent.toString().replace(File.separatorChar, '.'); + } + } + + /** + * Returns true if the given file exists and is a hidden file + */ + private boolean isHidden(Path file) { + try { + return Files.isHidden(file); + } catch (IOException ioe) { + return false; + } + } + + /** + * Derives a package name from the name of an entry in a JAR file. + */ + private static String toPackageName(Path file, JarEntry entry) { + String name = entry.getName(); + int index = name.lastIndexOf("/"); + if (index == -1) { + return warnIfModuleInfo(file, name); + } else { + return name.substring(0, index).replace('/', '.'); + } + } + + private static String warnIfModuleInfo(Path file, String e) { + if (e.equals("module-info.class")) + System.err.println("WARNING: " + e + " ignored in patch: " + file); + return ""; + } +} diff --git a/tests/test_data/std/jdk/internal/module/ModulePath$Patterns.class b/tests/test_data/std/jdk/internal/module/ModulePath$Patterns.class new file mode 100644 index 0000000000000000000000000000000000000000..e53b7523c4dbe5812f6381cc795fd76cf2c94456 GIT binary patch literal 878 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 Z%aQoR;Ua|}##3(ry53VCs1GUh{{TOlDyskh literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModulePath.java b/tests/test_data/std/jdk/internal/module/ModulePath.java new file mode 100644 index 00000000..2804079c --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModulePath.java @@ -0,0 +1,789 @@ +/* + * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; +import java.lang.module.FindException; +import java.lang.module.InvalidModuleDescriptorException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import sun.nio.cs.UTF_8; + +import jdk.internal.jmod.JmodFile; +import jdk.internal.jmod.JmodFile.Section; +import jdk.internal.perf.PerfCounter; + +/** + * A {@code ModuleFinder} that locates modules on the file system by searching + * a sequence of directories or packaged modules. The ModuleFinder can be + * created to work in either the run-time or link-time phases. In both cases it + * locates modular JAR and exploded modules. When created for link-time then it + * additionally locates modules in JMOD files. The ModuleFinder can also + * optionally patch any modules that it locates with a ModulePatcher. + */ + +public class ModulePath implements ModuleFinder { + private static final String MODULE_INFO = "module-info.class"; + + // the version to use for multi-release modular JARs + private final Runtime.Version releaseVersion; + + // true for the link phase (supports modules packaged in JMOD format) + private final boolean isLinkPhase; + + // for patching modules, can be null + private final ModulePatcher patcher; + + // the entries on this module path + private final Path[] entries; + private int next; + + // map of module name to module reference map for modules already located + private final Map cachedModules = new HashMap<>(); + + + private ModulePath(Runtime.Version version, + boolean isLinkPhase, + ModulePatcher patcher, + Path... entries) { + this.releaseVersion = version; + this.isLinkPhase = isLinkPhase; + this.patcher = patcher; + this.entries = entries.clone(); + for (Path entry : this.entries) { + Objects.requireNonNull(entry); + } + } + + /** + * Returns a ModuleFinder that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. The modules + * may be patched by the given ModulePatcher. + */ + public static ModuleFinder of(ModulePatcher patcher, Path... entries) { + return new ModulePath(JarFile.runtimeVersion(), false, patcher, entries); + } + + /** + * Returns a ModuleFinder that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. + */ + public static ModuleFinder of(Path... entries) { + return of((ModulePatcher)null, entries); + } + + /** + * Returns a ModuleFinder that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. + * + * @param version The release version to use for multi-release JAR files + * @param isLinkPhase {@code true} if the link phase to locate JMOD files + */ + public static ModuleFinder of(Runtime.Version version, + boolean isLinkPhase, + Path... entries) { + return new ModulePath(version, isLinkPhase, null, entries); + } + + + @Override + public Optional find(String name) { + Objects.requireNonNull(name); + + // try cached modules + ModuleReference m = cachedModules.get(name); + if (m != null) + return Optional.of(m); + + // the module may not have been encountered yet + while (hasNextEntry()) { + scanNextEntry(); + m = cachedModules.get(name); + if (m != null) + return Optional.of(m); + } + return Optional.empty(); + } + + @Override + public Set findAll() { + // need to ensure that all entries have been scanned + while (hasNextEntry()) { + scanNextEntry(); + } + return cachedModules.values().stream().collect(Collectors.toSet()); + } + + /** + * Returns {@code true} if there are additional entries to scan + */ + private boolean hasNextEntry() { + return next < entries.length; + } + + /** + * Scans the next entry on the module path. A no-op if all entries have + * already been scanned. + * + * @throws FindException if an error occurs scanning the next entry + */ + private void scanNextEntry() { + if (hasNextEntry()) { + + long t0 = System.nanoTime(); + + Path entry = entries[next]; + Map modules = scan(entry); + next++; + + // update cache, ignoring duplicates + int initialSize = cachedModules.size(); + for (Map.Entry e : modules.entrySet()) { + cachedModules.putIfAbsent(e.getKey(), e.getValue()); + } + + // update counters + int added = cachedModules.size() - initialSize; + moduleCount.add(added); + + scanTime.addElapsedTimeFrom(t0); + } + } + + + /** + * Scan the given module path entry. If the entry is a directory then it is + * a directory of modules or an exploded module. If the entry is a regular + * file then it is assumed to be a packaged module. + * + * @throws FindException if an error occurs scanning the entry + */ + private Map scan(Path entry) { + + BasicFileAttributes attrs; + try { + attrs = Files.readAttributes(entry, BasicFileAttributes.class); + } catch (NoSuchFileException e) { + return Map.of(); + } catch (IOException ioe) { + throw new FindException(ioe); + } + + try { + + if (attrs.isDirectory()) { + Path mi = entry.resolve(MODULE_INFO); + if (!Files.exists(mi)) { + // assume a directory of modules + return scanDirectory(entry); + } + } + + // packaged or exploded module + ModuleReference mref = readModule(entry, attrs); + if (mref != null) { + String name = mref.descriptor().name(); + return Map.of(name, mref); + } + + // not recognized + String msg; + if (!isLinkPhase && entry.toString().endsWith(".jmod")) { + msg = "JMOD format not supported at execution time"; + } else { + msg = "Module format not recognized"; + } + throw new FindException(msg + ": " + entry); + + } catch (IOException ioe) { + throw new FindException(ioe); + } + } + + + /** + * Scans the given directory for packaged or exploded modules. + * + * @return a map of module name to ModuleReference for the modules found + * in the directory + * + * @throws IOException if an I/O error occurs + * @throws FindException if an error occurs scanning the entry or the + * directory contains two or more modules with the same name + */ + private Map scanDirectory(Path dir) + throws IOException + { + // The map of name -> mref of modules found in this directory. + Map nameToReference = new HashMap<>(); + + try (DirectoryStream stream = Files.newDirectoryStream(dir)) { + for (Path entry : stream) { + BasicFileAttributes attrs; + try { + attrs = Files.readAttributes(entry, BasicFileAttributes.class); + } catch (NoSuchFileException ignore) { + // file has been removed or moved, ignore for now + continue; + } + + ModuleReference mref = readModule(entry, attrs); + + // module found + if (mref != null) { + // can have at most one version of a module in the directory + String name = mref.descriptor().name(); + ModuleReference previous = nameToReference.put(name, mref); + if (previous != null) { + String fn1 = fileName(mref); + String fn2 = fileName(previous); + throw new FindException("Two versions of module " + + name + " found in " + dir + + " (" + fn1 + " and " + fn2 + ")"); + } + } + } + } + + return nameToReference; + } + + + /** + * Reads a packaged or exploded module, returning a {@code ModuleReference} + * to the module. Returns {@code null} if the entry is not recognized. + * + * @throws IOException if an I/O error occurs + * @throws FindException if an error occurs parsing its module descriptor + */ + private ModuleReference readModule(Path entry, BasicFileAttributes attrs) + throws IOException + { + try { + + // exploded module + if (attrs.isDirectory()) { + return readExplodedModule(entry); // may return null + } + + // JAR or JMOD file + if (attrs.isRegularFile()) { + String fn = entry.getFileName().toString(); + boolean isDefaultFileSystem = isDefaultFileSystem(entry); + + // JAR file + if (fn.endsWith(".jar")) { + if (isDefaultFileSystem) { + return readJar(entry); + } else { + // the JAR file is in a custom file system so + // need to copy it to the local file system + Path tmpdir = Files.createTempDirectory("mlib"); + Path target = Files.copy(entry, tmpdir.resolve(fn)); + return readJar(target); + } + } + + // JMOD file + if (isDefaultFileSystem && isLinkPhase && fn.endsWith(".jmod")) { + return readJMod(entry); + } + } + + return null; + + } catch (InvalidModuleDescriptorException e) { + throw new FindException("Error reading module: " + entry, e); + } + } + + /** + * Returns a string with the file name of the module if possible. + * If the module location is not a file URI then return the URI + * as a string. + */ + private String fileName(ModuleReference mref) { + URI uri = mref.location().orElse(null); + if (uri != null) { + if (uri.getScheme().equalsIgnoreCase("file")) { + Path file = Path.of(uri); + return file.getFileName().toString(); + } else { + return uri.toString(); + } + } else { + return ""; + } + } + + // -- JMOD files -- + + private Set jmodPackages(JmodFile jf) { + return jf.stream() + .filter(e -> e.section() == Section.CLASSES) + .map(JmodFile.Entry::name) + .map(this::toPackageName) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); + } + + /** + * Returns a {@code ModuleReference} to a module in JMOD file on the + * file system. + * + * @throws IOException + * @throws InvalidModuleDescriptorException + */ + private ModuleReference readJMod(Path file) throws IOException { + try (JmodFile jf = new JmodFile(file)) { + ModuleInfo.Attributes attrs; + try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) { + attrs = ModuleInfo.read(in, () -> jmodPackages(jf)); + } + return ModuleReferences.newJModModule(attrs, file); + } + } + + + // -- JAR files -- + + private static final String SERVICES_PREFIX = "META-INF/services/"; + + private static final Attributes.Name AUTOMATIC_MODULE_NAME + = new Attributes.Name("Automatic-Module-Name"); + + /** + * Returns the service type corresponding to the name of a services + * configuration file if it is a legal type name. + * + * For example, if called with "META-INF/services/p.S" then this method + * returns a container with the value "p.S". + */ + private Optional toServiceName(String cf) { + assert cf.startsWith(SERVICES_PREFIX); + int index = cf.lastIndexOf("/") + 1; + if (index < cf.length()) { + String prefix = cf.substring(0, index); + if (prefix.equals(SERVICES_PREFIX)) { + String sn = cf.substring(index); + if (Checks.isClassName(sn)) + return Optional.of(sn); + } + } + return Optional.empty(); + } + + /** + * Reads the next line from the given reader and trims it of comments and + * leading/trailing white space. + * + * Returns null if the reader is at EOF. + */ + private String nextLine(BufferedReader reader) throws IOException { + String ln = reader.readLine(); + if (ln != null) { + int ci = ln.indexOf('#'); + if (ci >= 0) + ln = ln.substring(0, ci); + ln = ln.trim(); + } + return ln; + } + + /** + * Treat the given JAR file as a module as follows: + * + * 1. The value of the Automatic-Module-Name attribute is the module name + * 2. The version, and the module name when the Automatic-Module-Name + * attribute is not present, is derived from the file ame of the JAR file + * 3. All packages are derived from the .class files in the JAR file + * 4. The contents of any META-INF/services configuration files are mapped + * to "provides" declarations + * 5. The Main-Class attribute in the main attributes of the JAR manifest + * is mapped to the module descriptor mainClass if possible + */ + private ModuleDescriptor deriveModuleDescriptor(JarFile jf) + throws IOException + { + // Read Automatic-Module-Name attribute if present + Manifest man = jf.getManifest(); + Attributes attrs = null; + String moduleName = null; + if (man != null) { + attrs = man.getMainAttributes(); + if (attrs != null) { + moduleName = attrs.getValue(AUTOMATIC_MODULE_NAME); + } + } + + // Derive the version, and the module name if needed, from JAR file name + String fn = jf.getName(); + int i = fn.lastIndexOf(File.separator); + if (i != -1) + fn = fn.substring(i + 1); + + // drop ".jar" + String name = fn.substring(0, fn.length() - 4); + String vs = null; + + // find first occurrence of -${NUMBER}. or -${NUMBER}$ + Matcher matcher = Patterns.DASH_VERSION.matcher(name); + if (matcher.find()) { + int start = matcher.start(); + + // attempt to parse the tail as a version string + try { + String tail = name.substring(start + 1); + ModuleDescriptor.Version.parse(tail); + vs = tail; + } catch (IllegalArgumentException ignore) { } + + name = name.substring(0, start); + } + + // Create builder, using the name derived from file name when + // Automatic-Module-Name not present + Builder builder; + if (moduleName != null) { + try { + builder = ModuleDescriptor.newAutomaticModule(moduleName); + } catch (IllegalArgumentException e) { + throw new FindException(AUTOMATIC_MODULE_NAME + ": " + e.getMessage()); + } + } else { + builder = ModuleDescriptor.newAutomaticModule(cleanModuleName(name)); + } + + // module version if present + if (vs != null) + builder.version(vs); + + // scan the names of the entries in the JAR file + Map> map = jf.versionedStream() + .filter(e -> !e.isDirectory()) + .map(JarEntry::getName) + .filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX))) + .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX), + Collectors.toSet())); + + Set classFiles = map.get(Boolean.FALSE); + Set configFiles = map.get(Boolean.TRUE); + + // the packages containing class files + Set packages = classFiles.stream() + .map(this::toPackageName) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); + + // all packages are exported and open + builder.packages(packages); + + // map names of service configuration files to service names + Set serviceNames = configFiles.stream() + .map(this::toServiceName) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); + + // parse each service configuration file + for (String sn : serviceNames) { + JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn); + List providerClasses = new ArrayList<>(); + try (InputStream in = jf.getInputStream(entry)) { + BufferedReader reader + = new BufferedReader(new InputStreamReader(in, UTF_8.INSTANCE)); + String cn; + while ((cn = nextLine(reader)) != null) { + if (!cn.isEmpty()) { + String pn = packageName(cn); + if (!packages.contains(pn)) { + String msg = "Provider class " + cn + " not in JAR file " + fn; + throw new InvalidModuleDescriptorException(msg); + } + providerClasses.add(cn); + } + } + } + if (!providerClasses.isEmpty()) + builder.provides(sn, providerClasses); + } + + // Main-Class attribute if it exists + if (attrs != null) { + String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS); + if (mainClass != null) { + mainClass = mainClass.replace('/', '.'); + if (Checks.isClassName(mainClass)) { + String pn = packageName(mainClass); + if (packages.contains(pn)) { + builder.mainClass(mainClass); + } + } + } + } + + return builder.build(); + } + + /** + * Patterns used to derive the module name from a JAR file name. + */ + private static class Patterns { + static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))"); + static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]"); + static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+"); + static final Pattern LEADING_DOTS = Pattern.compile("^\\."); + static final Pattern TRAILING_DOTS = Pattern.compile("\\.$"); + } + + /** + * Clean up candidate module name derived from a JAR file name. + */ + private static String cleanModuleName(String mn) { + // replace non-alphanumeric + mn = Patterns.NON_ALPHANUM.matcher(mn).replaceAll("."); + + // collapse repeating dots + mn = Patterns.REPEATING_DOTS.matcher(mn).replaceAll("."); + + // drop leading dots + if (!mn.isEmpty() && mn.charAt(0) == '.') + mn = Patterns.LEADING_DOTS.matcher(mn).replaceAll(""); + + // drop trailing dots + int len = mn.length(); + if (len > 0 && mn.charAt(len-1) == '.') + mn = Patterns.TRAILING_DOTS.matcher(mn).replaceAll(""); + + return mn; + } + + private Set jarPackages(JarFile jf) { + return jf.versionedStream() + .filter(e -> !e.isDirectory()) + .map(JarEntry::getName) + .map(this::toPackageName) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); + } + + /** + * Returns a {@code ModuleReference} to a module in modular JAR file on + * the file system. + * + * @throws IOException + * @throws FindException + * @throws InvalidModuleDescriptorException + */ + private ModuleReference readJar(Path file) throws IOException { + try (JarFile jf = new JarFile(file.toFile(), + true, // verify + ZipFile.OPEN_READ, + releaseVersion)) + { + ModuleInfo.Attributes attrs; + JarEntry entry = jf.getJarEntry(MODULE_INFO); + if (entry == null) { + + // no module-info.class so treat it as automatic module + try { + ModuleDescriptor md = deriveModuleDescriptor(jf); + attrs = new ModuleInfo.Attributes(md, null, null, null); + } catch (RuntimeException e) { + throw new FindException("Unable to derive module descriptor for " + + jf.getName(), e); + } + + } else { + attrs = ModuleInfo.read(jf.getInputStream(entry), + () -> jarPackages(jf)); + } + + return ModuleReferences.newJarModule(attrs, patcher, file); + } catch (ZipException e) { + throw new FindException("Error reading " + file, e); + } + } + + + // -- exploded directories -- + + private Set explodedPackages(Path dir) { + String separator = dir.getFileSystem().getSeparator(); + try (Stream stream = Files.find(dir, Integer.MAX_VALUE, + (path, attrs) -> attrs.isRegularFile() && !isHidden(path))) { + return stream.map(dir::relativize) + .map(path -> toPackageName(path, separator)) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } + + /** + * Returns a {@code ModuleReference} to an exploded module on the file + * system or {@code null} if {@code module-info.class} not found. + * + * @throws IOException + * @throws InvalidModuleDescriptorException + */ + private ModuleReference readExplodedModule(Path dir) throws IOException { + Path mi = dir.resolve(MODULE_INFO); + ModuleInfo.Attributes attrs; + try (InputStream in = Files.newInputStream(mi)) { + attrs = ModuleInfo.read(new BufferedInputStream(in), + () -> explodedPackages(dir)); + } catch (NoSuchFileException e) { + // for now + return null; + } + return ModuleReferences.newExplodedModule(attrs, patcher, dir); + } + + /** + * Maps a type name to its package name. + */ + private static String packageName(String cn) { + int index = cn.lastIndexOf('.'); + return (index == -1) ? "" : cn.substring(0, index); + } + + /** + * Maps the name of an entry in a JAR or ZIP file to a package name. + * + * @throws InvalidModuleDescriptorException if the name is a class file in + * the top-level directory of the JAR/ZIP file (and it's not + * module-info.class) + */ + private Optional toPackageName(String name) { + assert !name.endsWith("/"); + int index = name.lastIndexOf("/"); + if (index == -1) { + if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { + String msg = name + " found in top-level directory" + + " (unnamed package not allowed in module)"; + throw new InvalidModuleDescriptorException(msg); + } + return Optional.empty(); + } + + String pn = name.substring(0, index).replace('/', '.'); + if (Checks.isPackageName(pn)) { + return Optional.of(pn); + } else { + // not a valid package name + return Optional.empty(); + } + } + + /** + * Maps the relative path of an entry in an exploded module to a package + * name. + * + * @throws InvalidModuleDescriptorException if the name is a class file in + * the top-level directory (and it's not module-info.class) + */ + private Optional toPackageName(Path file, String separator) { + assert file.getRoot() == null; + + Path parent = file.getParent(); + if (parent == null) { + String name = file.toString(); + if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { + String msg = name + " found in top-level directory" + + " (unnamed package not allowed in module)"; + throw new InvalidModuleDescriptorException(msg); + } + return Optional.empty(); + } + + String pn = parent.toString().replace(separator, "."); + if (Checks.isPackageName(pn)) { + return Optional.of(pn); + } else { + // not a valid package name + return Optional.empty(); + } + } + + /** + * Returns true if the given file exists and is a hidden file + */ + private boolean isHidden(Path file) { + try { + return Files.isHidden(file); + } catch (IOException ioe) { + return false; + } + } + + + /** + * Return true if a path locates a path in the default file system + */ + private boolean isDefaultFileSystem(Path path) { + return path.getFileSystem().provider() + .getScheme().equalsIgnoreCase("file"); + } + + + private static final PerfCounter scanTime + = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime"); + private static final PerfCounter moduleCount + = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules"); +} diff --git a/tests/test_data/std/jdk/internal/module/ModulePathValidator.class b/tests/test_data/std/jdk/internal/module/ModulePathValidator.class new file mode 100644 index 0000000000000000000000000000000000000000..ef756a91c48df35853185cce66be16d2442cf20b GIT binary patch literal 9040 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 k2Dx4C@Y?S5#@#Ik=AiP9!JGr0W;ikCjbBd literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModulePathValidator.java b/tests/test_data/std/jdk/internal/module/ModulePathValidator.java new file mode 100644 index 00000000..cea54ce4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModulePathValidator.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.module.FindException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * A validator to check for errors and conflicts between modules. + */ + +class ModulePathValidator { + private static final String MODULE_INFO = "module-info.class"; + private static final String INDENT = " "; + + private final Map nameToModule; + private final Map packageToModule; + private final PrintStream out; + + private int errorCount; + + private ModulePathValidator(PrintStream out) { + this.nameToModule = new HashMap<>(); + this.packageToModule = new HashMap<>(); + this.out = out; + } + + /** + * Scans and the validates all modules on the module path. The module path + * comprises the upgrade module path, system modules, and the application + * module path. + * + * @param out the print stream for output messages + * @return the number of errors found + */ + static int scanAllModules(PrintStream out) { + ModulePathValidator validator = new ModulePathValidator(out); + + // upgrade module path + String value = System.getProperty("jdk.module.upgrade.path"); + if (value != null) { + Stream.of(value.split(File.pathSeparator)) + .map(Path::of) + .forEach(validator::scan); + } + + // system modules + ModuleFinder.ofSystem().findAll().stream() + .sorted(Comparator.comparing(ModuleReference::descriptor)) + .forEach(validator::process); + + // application module path + value = System.getProperty("jdk.module.path"); + if (value != null) { + Stream.of(value.split(File.pathSeparator)) + .map(Path::of) + .forEach(validator::scan); + } + + return validator.errorCount; + } + + /** + * Prints the module location and name. + */ + private void printModule(ModuleReference mref) { + mref.location() + .filter(uri -> !isJrt(uri)) + .ifPresent(uri -> out.print(uri + " ")); + ModuleDescriptor descriptor = mref.descriptor(); + out.print(descriptor.name()); + if (descriptor.isAutomatic()) + out.print(" automatic"); + out.println(); + } + + /** + * Prints the module location and name, checks if the module is + * shadowed by a previously seen module, and finally checks for + * package conflicts with previously seen modules. + */ + private void process(ModuleReference mref) { + String name = mref.descriptor().name(); + ModuleReference previous = nameToModule.putIfAbsent(name, mref); + if (previous != null) { + printModule(mref); + out.print(INDENT + "shadowed by "); + printModule(previous); + } else { + boolean first = true; + + // check for package conflicts when not shadowed + for (String pkg : mref.descriptor().packages()) { + previous = packageToModule.putIfAbsent(pkg, mref); + if (previous != null) { + if (first) { + printModule(mref); + first = false; + errorCount++; + } + String mn = previous.descriptor().name(); + out.println(INDENT + "contains " + pkg + + " conflicts with module " + mn); + } + } + } + } + + /** + * Scan an element on a module path. The element is a directory + * of modules, an exploded module, or a JAR file. + */ + private void scan(Path entry) { + BasicFileAttributes attrs; + try { + attrs = Files.readAttributes(entry, BasicFileAttributes.class); + } catch (NoSuchFileException ignore) { + return; + } catch (IOException ioe) { + out.println(entry + " " + ioe); + errorCount++; + return; + } + + String fn = entry.getFileName().toString(); + if (attrs.isRegularFile() && fn.endsWith(".jar")) { + // JAR file, explicit or automatic module + scanModule(entry).ifPresent(this::process); + } else if (attrs.isDirectory()) { + Path mi = entry.resolve(MODULE_INFO); + if (Files.exists(mi)) { + // exploded module + scanModule(entry).ifPresent(this::process); + } else { + // directory of modules + scanDirectory(entry); + } + } + } + + /** + * Scan the JAR files and exploded modules in a directory. + */ + private void scanDirectory(Path dir) { + try (DirectoryStream stream = Files.newDirectoryStream(dir)) { + Map moduleToEntry = new HashMap<>(); + + for (Path entry : stream) { + BasicFileAttributes attrs; + try { + attrs = Files.readAttributes(entry, BasicFileAttributes.class); + } catch (IOException ioe) { + out.println(entry + " " + ioe); + errorCount++; + continue; + } + + ModuleReference mref = null; + + String fn = entry.getFileName().toString(); + if (attrs.isRegularFile() && fn.endsWith(".jar")) { + mref = scanModule(entry).orElse(null); + } else if (attrs.isDirectory()) { + Path mi = entry.resolve(MODULE_INFO); + if (Files.exists(mi)) { + mref = scanModule(entry).orElse(null); + } + } + + if (mref != null) { + String name = mref.descriptor().name(); + Path previous = moduleToEntry.putIfAbsent(name, entry); + if (previous != null) { + // same name as other module in the directory + printModule(mref); + out.println(INDENT + "contains same module as " + + previous.getFileName()); + errorCount++; + } else { + process(mref); + } + } + } + } catch (IOException ioe) { + out.println(dir + " " + ioe); + errorCount++; + } + } + + /** + * Scan a JAR file or exploded module. + */ + private Optional scanModule(Path entry) { + ModuleFinder finder = ModuleFinder.of(entry); + try { + return finder.findAll().stream().findFirst(); + } catch (FindException e) { + out.println(entry); + out.println(INDENT + e.getMessage()); + Throwable cause = e.getCause(); + if (cause != null) { + out.println(INDENT + cause); + } + errorCount++; + return Optional.empty(); + } + } + + /** + * Returns true if the given URI is a jrt URI + */ + private static boolean isJrt(URI uri) { + return (uri != null && uri.getScheme().equalsIgnoreCase("jrt")); + } +} diff --git a/tests/test_data/std/jdk/internal/module/ModuleReferenceImpl$CachedHash.class b/tests/test_data/std/jdk/internal/module/ModuleReferenceImpl$CachedHash.class new file mode 100644 index 0000000000000000000000000000000000000000..9ca31f4c50ec867250d369e105553947241baf02 GIT binary patch literal 1735 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleReferenceImpl.java b/tests/test_data/std/jdk/internal/module/ModuleReferenceImpl.java new file mode 100644 index 00000000..e460b0fc --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModuleReferenceImpl.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.util.Objects; +import java.util.function.Supplier; + +/** + * A ModuleReference implementation that supports referencing a module that + * is patched and/or can be tied to other modules by means of hashes. + */ + +public class ModuleReferenceImpl extends ModuleReference { + + // location of module + private final URI location; + + // the module reader + private final Supplier readerSupplier; + + // non-null if the module is patched + private final ModulePatcher patcher; + + // ModuleTarget if the module is OS/architecture specific + private final ModuleTarget target; + + // the hashes of other modules recorded in this module + private final ModuleHashes recordedHashes; + + // the function that computes the hash of this module + private final ModuleHashes.HashSupplier hasher; + + // ModuleResolution flags + private final ModuleResolution moduleResolution; + + // Single-slot cache of this module's hash to avoid needing to compute + // it many times. For correctness under concurrent updates, we need to + // wrap the fields updated at the same time with a record. + private record CachedHash(byte[] hash, String algorithm) {} + private CachedHash cachedHash; + + /** + * Constructs a new instance of this class. + */ + public ModuleReferenceImpl(ModuleDescriptor descriptor, + URI location, + Supplier readerSupplier, + ModulePatcher patcher, + ModuleTarget target, + ModuleHashes recordedHashes, + ModuleHashes.HashSupplier hasher, + ModuleResolution moduleResolution) + { + super(descriptor, Objects.requireNonNull(location)); + this.location = location; + this.readerSupplier = readerSupplier; + this.patcher = patcher; + this.target = target; + this.recordedHashes = recordedHashes; + this.hasher = hasher; + this.moduleResolution = moduleResolution; + } + + @Override + public ModuleReader open() throws IOException { + try { + return readerSupplier.get(); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + /** + * Returns {@code true} if this module has been patched via --patch-module. + */ + public boolean isPatched() { + return (patcher != null); + } + + /** + * Returns the ModuleTarget or {@code null} if the no target platform. + */ + public ModuleTarget moduleTarget() { + return target; + } + + /** + * Returns the hashes recorded in this module or {@code null} if there + * are no hashes recorded. + */ + public ModuleHashes recordedHashes() { + return recordedHashes; + } + + /** + * Returns the supplier that computes the hash of this module. + */ + ModuleHashes.HashSupplier hasher() { + return hasher; + } + + /** + * Returns the ModuleResolution flags. + */ + public ModuleResolution moduleResolution() { + return moduleResolution; + } + + /** + * Computes the hash of this module. Returns {@code null} if the hash + * cannot be computed. + * + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public byte[] computeHash(String algorithm) { + CachedHash ch = cachedHash; + if (ch != null && ch.algorithm().equals(algorithm)) { + return ch.hash(); + } + + if (hasher == null) { + return null; + } + byte[] hash = hasher.generate(algorithm); + cachedHash = new CachedHash(hash, algorithm); + return hash; + } + + @Override + public int hashCode() { + int hc = hash; + if (hc == 0) { + hc = descriptor().hashCode(); + hc = 43 * hc + Objects.hashCode(location); + hc = 43 * hc + Objects.hashCode(patcher); + if (hc == 0) + hc = -1; + hash = hc; + } + return hc; + } + + private int hash; + + @Override + public boolean equals(Object ob) { + if (!(ob instanceof ModuleReferenceImpl)) + return false; + ModuleReferenceImpl that = (ModuleReferenceImpl)ob; + + // assume module content, recorded hashes, etc. are the same + // when the modules have equal module descriptors, are at the + // same location, and are patched by the same patcher. + return Objects.equals(this.descriptor(), that.descriptor()) + && Objects.equals(this.location, that.location) + && Objects.equals(this.patcher, that.patcher); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[module "); + sb.append(descriptor().name()); + sb.append(", location="); + sb.append(location); + if (isPatched()) sb.append(" (patched)"); + sb.append("]"); + return sb.toString(); + } + +} diff --git a/tests/test_data/std/jdk/internal/module/ModuleReferences$ExplodedModuleReader.class b/tests/test_data/std/jdk/internal/module/ModuleReferences$ExplodedModuleReader.class new file mode 100644 index 0000000000000000000000000000000000000000..f2a9e180bf8aa73b60d2040732d2f0dff03c5c21 GIT binary patch literal 4407 zcmbtX`+FQ!8Gg@ZlSwv{CfSy>CA}mV+9VBZK~!){frQoua;Z&;l6sr$PLgRRGt2C3 z+bE?1iZ?Fe4O%X0DWXudC~cP_)Svvp$3Mx(_?|PfyEEHut@=FKoyoa;-}}Aa_r2%r z-~V;x698klnnD6i8j?Di(IU`w)Hr5jY{Oa1OwS)RbG|^!9?P-(y#h^xL$hsYMVp3{ zj&|q*_Z`hIXDr7zJ;$&!D{j7Io0&=VIAkuEp6TSw;=sNW1>4P=`O1WmH$9rmTm0TI zp*%X4n^~~9`Jmx1Wm8y(P7Pf;x{;27nprLS=88ai(e!7`T*rTc1_z3pS>( z9Ro6Lw+q}7LJ0!*JK778ix#U}RCP<)R3nbhHfx##jK@n%ex`-`jLF^IeR3HM@J2eCjTJbG;loRwd)%0}O@(SyXCpl<&}^<0eAY!zWo^B?{nyl= zOh>K$4(J%iBLeFj^Z2+^DETwKXBw>b{S8^Kue6%6O1v_xnjM1e!Gw-UObO_;oPWr+ zM^}BB_Iw;UK=K;gF6Q9Ih0p>{hvPw6wq`7f2rWjDo=C!6Ty~)A1FgdRCxY zQLP9Zr)02Yn@+8*t!a2%7NOLgstU-0o3)CTUnA#;j<4XW(wAW`3mj|+c)XsIIzts= zRA!2b-Aq7oHcdVJx{hzaU?z=1!Dc4s=;VJDxR|Sjl9Q7vli44>WZRKLUW2J)0gJ3J z75}xcD3dFa+Iz!r)rxDaMeDmhECEZ$QINAFQ%yndi`8e<*g?!Cd3m}L=E4nRGJ#DJFkLcX=B5}8e;t>$9RZQF{tR~RB2`2^bSi6pcYNI zIm4bcJWKu`4krC2i;b22KPrfVR%G}0M&&hr=4AysW_%;JJZTh^Uk%T(4{ME9cL-9= zt7i+rB^NA*2T)8g*$(RT2%N?xjAs?Y?GC1Dnn@H%N2Mnng&G**TtOWjZ8O%QWB5FT zYULcwPPBk3lD;RfS2+XrN>45|Q{aIxO*d(wP6?GEseu2rp*mqxhHOi=Rd1}V;$0|^ zx&CYzWHb_KwpktXOt5XN%;${(>1E)q>zws-ObrtnTf4iK+5gxY+|HvjHKPuFDVp?C zxpq|Uad*nH;;A@A6*=G*eGP934BU)Bvgt=%*C!`NVbb)M+_<2256;S2}~Ls~707lOiLrjfYnY zW_0<@PX;b;yf-R;q2)2dwr4ErJ5T>{$1%Mz+b9<0>A#`T4PC=W0=L(~iQ$V!t>I&V zZ8u&@l@BOFAJdb7z&H7wmcJu-@{Y>2*pcm~hX)pt0WhFGI1{v>MEuv;SpaE4cCeoIK>v?AoX;SbPz8XX^D`{U{U%lOpQ z8WQ=N3gQI4uPV>di?kegmR@M18{gwgl2hCH`96NYLFwQ;Hz)ZV9KM7dbfWDlV@Sr_ zGx8xa0%d&W!qgp?aQ|Pi{c0HxUEuC+BJSnIH6UUeG`c@YBAy}%rwHR|^onP&MLdfE z@tlG*OdngAhacic+(mC8IQjNGUZBkmT6~cN1+?@avBrUbmM6#zgobQuB!-u0C4nDv z=gZYtPI5$A@2`)gbA4)G%AQn7JHa}i029Z1%iK(;9tU4@p2@C{Z**_Rj3;x zP+KAXiLDZ1jo<*>PYCX(Rd7#+;QH#pts5!h(K4p5gY6Y!dzIKu6WbY*`g#OgUlm(l z72EoHY+D*(`x&wQ9KQ&Qz~EEX%+3n7^p{B3m&=$NzJjj-A7Va%D_D|mb^;d^_p%8B z`py#KTi7Vhp9ekG!5R~E05Mn(!uh8MEEc2lA?jbo6K+ACQB6?+MCsdOKrTs3N z#d{H(ErHFhl+@hN!YH58LI*=Aya_G&4w6mhIS>@7bOeH{0qekPEIg<#Y(}E}LD7|v zdLP=mp9t7iXbXGdSS{$l);VR1g(??S^U#JjRp3edlH&>d3cps*vpC16T>U-~y^VM9 cu6lb9zbBn#&ZRlminC<6l~n%)pJ4O90fkhBH~;_u literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleReferences$JModModuleReader.class b/tests/test_data/std/jdk/internal/module/ModuleReferences$JModModuleReader.class new file mode 100644 index 0000000000000000000000000000000000000000..7ad82d66e90f94c8a219309e41b4116f96504da2 GIT binary patch literal 4639 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 TM`NrIYxo6q{t~~&Z_)ifiVmWk literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleReferences$SafeCloseModuleReader.class b/tests/test_data/std/jdk/internal/module/ModuleReferences$SafeCloseModuleReader.class new file mode 100644 index 0000000000000000000000000000000000000000..57dec6c239e7a888e9f103a321142d2884b9d526 GIT binary patch literal 2375 zcmbtU-%}e^6#j0KviY&KG&EQ&ErDVUp>zdXS{tM)7Ksg@gi`TsNiK9DY?#f)`linK z7x<=+PCK2cFJ~eO2wFwTsx-i&PcO(!?9eM<9-wxf)T`^YdEaqIUEtVyj)x{EZdciZI+DH zaEzf_KsYWH{yT}W!^R!yTm zUHiaR)z!h%I(qRUg)6AO6$J!Uj^QO8DfE$!wYpXsw`@96sTw{{@4V|+_EN@AaC*(P z%2bEV>q5VdvkF2>)mF{da897jgJYGA?DW--3epP?<7I(%zg$VHlB{8gVgN&G)Ls!t zG%G%*kY3O+yoYppP1z!0a3p8ha;mzzAe~urp~RgyJ8YKbOvh5+_05ob)2axJ#Lh`kY9tJdyNnbNDP z?umWKn;>>7U#>a@Ic_OM5{)ryycg$GK@Q23thf{9imTy zkZAh!gpwSr00c%6LR`IMd`IKzwtJR0mNuX+AZ>&{KC6s=ovR{(Tmk9yHbnX%wE1mB zHW5vyHxS)HtH37O>mMEJqjR0n0ldNgcIE*-W6h6Q@e_37Q}prsP44QotbEPi0t3`7 z=c%jogyS$cSbnB_^fqj-l|f*zyWv<$&TGHBnyDL%*> z==l=I(*0XFGg;eB3!J_G5CijZV;h6JQ+vAuyDS+YwSK1P=HsGl(4*UfFxOwvdmF8| z!1XBw=)CF*Qk4|YseAqB-a`O-B}G&KJ4{Q@X3AmU>wf>Zw~9^ z@C`YzLD(UO4RY8bhaGZw@a!BW$l*O|R@31N+8`+pKcz!kdJ7kGdkydR$>1YalOcgL zGb9O3S-%Xsr0^Xne2)Yk;S_BWKQQVM&f`bl1P<3_s5d{^wE0;ApW#RayaD>0Rw+0{ zjGev#($k?$^bmcf=HLw7<%7KU(Z9P+l_Tizu2~K28GZvl^Zyru{gq&UqyI5_@H?X( s!=N3+A3nfCKEPoFJFanBV!m++BF~Hg%;LId=kPvll$B$c!+a?G7f3S?z5oCK literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleReferences.class b/tests/test_data/std/jdk/internal/module/ModuleReferences.class new file mode 100644 index 0000000000000000000000000000000000000000..f1f7990f4f53a9917b8434fb6684c030e7bff473 GIT binary patch literal 5303 zcmcInYj+z*8Ggo=ytcfFT@fcJ5R;^8YfDyD>J+G*x+HE>JGIDu*{XWEv)Tr7&NB=u-`r%J^!Ar8z9 z;dCHkNw0WuYkfJG(P+I`ZCPbyytv(JHtVKz_%SjLPa9sj7B3QpDn>~diaSbVmEbU_ zdg3yFDTR08xP}utPU3EX6L)k*;6PKkwO-wnlKB)k7a7n_)h8Q0itCFYmHmlIVG*Y^Jf!12crV)`Isu(fv3n*g`Fy|( z0{KzCWTwO%k$5i)vzw`P_(5Ux6ad_ewWtpq;hFPaeqj0y$!anI@GbWDR62yV}{dj ztAr;7603}>z|@9m$<0<{M>-dbojO<28+O^KUosq1&BMinS2J1M_r}z7*S%%Zfx)AV z8}cz5_BR0ep`|F~VCa8H@oaH7WORXJv3((+`3xv|gx(!vxy}AOHf!q8qj)h!d{DzM zfDK1h1y1(VLSx{?fZ;gYAJc2ic3fBD{5c)1TJ^#53N;_t_Kfmg$!PkC(!c~BkGMH> z5=4^PHg_${WEx?V{t%5^n-N?>Uy8s9dmaCttfPgioPATxUeV$B-(FL*Z|P{_#DsciyMA{(J7;9l=&*U#>h2#XXh*2YlVoyz-Qq=dwQjhsWL^A3U^cog)Y-{$>pmbg z{9K?Ay9F;g1n~fdAEJ;8ASxza9u+8y7fBsmnd3 z)aJi)Hpa1V3)zK$d2o6*Hds`;K|3_}%9ZSi=KQLLyBwxquQZkeLGdCoBBeQ(U z0_!wT!ZbENAWDR z&teMC;bZjE;A-H2lHZ|xnJeQE|3OYe1y#;Qu*;PiOzKr`{nU>SkX`sIvV0{i6mAj^ zmJ*r7P2A5P$y_0m$Y+vo;6dfhsPB!snv$%piTGw#Q z_iB{;4*6asxO>v~rRzcPZHHFIQAZ=h`YN#|sp~}E$6CrS+{F8UO+tQHLC!4{L?$r+ z=q}CH7$y@(2txrq6)5TeJ>kRS6%j{$cq5cf`|w7&Cl!Xe9pK>G4udfcs}o9>I#pO^ z2y2P3azRK7dC><+)g<83l;=aq1)DlhW;!vOfgQ%|UqKPl--W0FR$owaXt z)?Ve>kGOM*g^MCN}P Ca>!i( literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleReferences.java b/tests/test_data/std/jdk/internal/module/ModuleReferences.java new file mode 100644 index 00000000..346838b4 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModuleReferences.java @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.File; +import java.io.IOError; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Supplier; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Stream; +import java.util.zip.ZipFile; + +import jdk.internal.jmod.JmodFile; +import jdk.internal.module.ModuleHashes.HashSupplier; +import sun.net.www.ParseUtil; + + +/** + * A factory for creating ModuleReference implementations where the modules are + * packaged as modular JAR file, JMOD files or where the modules are exploded + * on the file system. + */ + +class ModuleReferences { + private ModuleReferences() { } + + /** + * Creates a ModuleReference to a possibly-patched module + */ + private static ModuleReference newModule(ModuleInfo.Attributes attrs, + URI uri, + Supplier supplier, + ModulePatcher patcher, + HashSupplier hasher) { + ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(), + uri, + supplier, + null, + attrs.target(), + attrs.recordedHashes(), + hasher, + attrs.moduleResolution()); + if (patcher != null) + mref = patcher.patchIfNeeded(mref); + + return mref; + } + + /** + * Creates a ModuleReference to a possibly-patched module in a modular JAR. + */ + static ModuleReference newJarModule(ModuleInfo.Attributes attrs, + ModulePatcher patcher, + Path file) { + URI uri = file.toUri(); + Supplier supplier = () -> new JarModuleReader(file, uri); + HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a); + return newModule(attrs, uri, supplier, patcher, hasher); + } + + /** + * Creates a ModuleReference to a module in a JMOD file. + */ + static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) { + URI uri = file.toUri(); + Supplier supplier = () -> new JModModuleReader(file, uri); + HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a); + return newModule(attrs, uri, supplier, null, hasher); + } + + /** + * Creates a ModuleReference to a possibly-patched exploded module. + */ + static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, + ModulePatcher patcher, + Path dir) { + Supplier supplier = () -> new ExplodedModuleReader(dir); + return newModule(attrs, dir.toUri(), supplier, patcher, null); + } + + + /** + * A base module reader that encapsulates machinery required to close the + * module reader safely. + */ + abstract static class SafeCloseModuleReader implements ModuleReader { + + // RW lock to support safe close + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final Lock readLock = lock.readLock(); + private final Lock writeLock = lock.writeLock(); + private boolean closed; + + SafeCloseModuleReader() { } + + /** + * Returns a URL to resource. This method is invoked by the find + * method to do the actual work of finding the resource. + */ + abstract Optional implFind(String name) throws IOException; + + /** + * Returns an input stream for reading a resource. This method is + * invoked by the open method to do the actual work of opening + * an input stream to the resource. + */ + abstract Optional implOpen(String name) throws IOException; + + /** + * Returns a stream of the names of resources in the module. This + * method is invoked by the list method to do the actual work of + * creating the stream. + */ + abstract Stream implList() throws IOException; + + /** + * Closes the module reader. This method is invoked by close to do the + * actual work of closing the module reader. + */ + abstract void implClose() throws IOException; + + @Override + public final Optional find(String name) throws IOException { + readLock.lock(); + try { + if (!closed) { + return implFind(name); + } else { + throw new IOException("ModuleReader is closed"); + } + } finally { + readLock.unlock(); + } + } + + + @Override + public final Optional open(String name) throws IOException { + readLock.lock(); + try { + if (!closed) { + return implOpen(name); + } else { + throw new IOException("ModuleReader is closed"); + } + } finally { + readLock.unlock(); + } + } + + @Override + public final Stream list() throws IOException { + readLock.lock(); + try { + if (!closed) { + return implList(); + } else { + throw new IOException("ModuleReader is closed"); + } + } finally { + readLock.unlock(); + } + } + + @Override + public final void close() throws IOException { + writeLock.lock(); + try { + if (!closed) { + closed = true; + implClose(); + } + } finally { + writeLock.unlock(); + } + } + } + + + /** + * A ModuleReader for a modular JAR file. + */ + static class JarModuleReader extends SafeCloseModuleReader { + private final JarFile jf; + private final URI uri; + + static JarFile newJarFile(Path path) { + try { + return new JarFile(new File(path.toString()), + true, // verify + ZipFile.OPEN_READ, + JarFile.runtimeVersion()); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + JarModuleReader(Path path, URI uri) { + this.jf = newJarFile(path); + this.uri = uri; + } + + private JarEntry getEntry(String name) { + return jf.getJarEntry(Objects.requireNonNull(name)); + } + + @Override + Optional implFind(String name) throws IOException { + JarEntry je = getEntry(name); + if (je != null) { + if (jf.isMultiRelease()) + name = je.getRealName(); + if (je.isDirectory() && !name.endsWith("/")) + name += "/"; + String encodedPath = ParseUtil.encodePath(name, false); + String uris = "jar:" + uri + "!/" + encodedPath; + return Optional.of(URI.create(uris)); + } else { + return Optional.empty(); + } + } + + @Override + Optional implOpen(String name) throws IOException { + JarEntry je = getEntry(name); + if (je != null) { + return Optional.of(jf.getInputStream(je)); + } else { + return Optional.empty(); + } + } + + @Override + Stream implList() throws IOException { + // take snapshot to avoid async close + List names = jf.versionedStream() + .map(JarEntry::getName) + .toList(); + return names.stream(); + } + + @Override + void implClose() throws IOException { + jf.close(); + } + } + + + /** + * A ModuleReader for a JMOD file. + */ + static class JModModuleReader extends SafeCloseModuleReader { + private final JmodFile jf; + private final URI uri; + + static JmodFile newJmodFile(Path path) { + try { + return new JmodFile(path); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + JModModuleReader(Path path, URI uri) { + this.jf = newJmodFile(path); + this.uri = uri; + } + + private JmodFile.Entry getEntry(String name) { + Objects.requireNonNull(name); + return jf.getEntry(JmodFile.Section.CLASSES, name); + } + + @Override + Optional implFind(String name) { + JmodFile.Entry je = getEntry(name); + if (je != null) { + if (je.isDirectory() && !name.endsWith("/")) + name += "/"; + String encodedPath = ParseUtil.encodePath(name, false); + String uris = "jmod:" + uri + "!/" + encodedPath; + return Optional.of(URI.create(uris)); + } else { + return Optional.empty(); + } + } + + @Override + Optional implOpen(String name) throws IOException { + JmodFile.Entry je = getEntry(name); + if (je != null) { + return Optional.of(jf.getInputStream(je)); + } else { + return Optional.empty(); + } + } + + @Override + Stream implList() throws IOException { + // take snapshot to avoid async close + List names = jf.stream() + .filter(e -> e.section() == JmodFile.Section.CLASSES) + .map(JmodFile.Entry::name) + .toList(); + return names.stream(); + } + + @Override + void implClose() throws IOException { + jf.close(); + } + } + + + /** + * A ModuleReader for an exploded module. + */ + static class ExplodedModuleReader implements ModuleReader { + private final Path dir; + private volatile boolean closed; + + ExplodedModuleReader(Path dir) { + this.dir = dir; + + // when running with a security manager then check that the caller + // has access to the directory. + @SuppressWarnings("removal") + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + boolean unused = Files.isDirectory(dir); + } + } + + /** + * Throws IOException if the module reader is closed; + */ + private void ensureOpen() throws IOException { + if (closed) throw new IOException("ModuleReader is closed"); + } + + @Override + public Optional find(String name) throws IOException { + ensureOpen(); + Path path = Resources.toFilePath(dir, name); + if (path != null) { + try { + return Optional.of(path.toUri()); + } catch (IOError e) { + throw (IOException) e.getCause(); + } + } else { + return Optional.empty(); + } + } + + @Override + public Optional open(String name) throws IOException { + ensureOpen(); + Path path = Resources.toFilePath(dir, name); + if (path != null) { + return Optional.of(Files.newInputStream(path)); + } else { + return Optional.empty(); + } + } + + @Override + public Optional read(String name) throws IOException { + ensureOpen(); + Path path = Resources.toFilePath(dir, name); + if (path != null) { + return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path))); + } else { + return Optional.empty(); + } + } + + @Override + public Stream list() throws IOException { + ensureOpen(); + return Files.walk(dir, Integer.MAX_VALUE) + .map(f -> Resources.toResourceName(dir, f)) + .filter(s -> s.length() > 0); + } + + @Override + public void close() { + closed = true; + } + } + +} diff --git a/tests/test_data/std/jdk/internal/module/ModuleResolution.class b/tests/test_data/std/jdk/internal/module/ModuleResolution.class new file mode 100644 index 0000000000000000000000000000000000000000..e6cbb6982bd2e18ec728766b93f367b433502b9f GIT binary patch literal 2476 zcma)6T~pge6g`V=WV^z49ftr(Qxg)fO%o?g3u(z$!H~E$(1w%_q?xI(77&poSC;AI zrPIHWU(lC4v@vrlV$If@CND0STBEUKn0&#u8m?x!jX1)HC>T_sAj**1)AqHZsaZS4)vY~V zbr}Zl8kXVSX9(r;>oLUfjsjK15E2Ymdyy=ATu*qzHk+G1iGbNLe{$ucJ(E(?hF87@)8r#goz|#r?r^Kh%eA^0$24xJDB>n*!52-ikvWk}4_zH^IVBj!hbnI4BT7)WS8UgV z+2`{wOMF{vnj|dJ)28s7Q86q0GP_!%+z$O4&9Nv0q0jLsK4nmzc`CXW#a&X;bJEX( zt&^yd6~p2y&Ds`so@!erS<)4|s+sGWV~B5Q4729TWT^^hRa>%CEI!8x2f$g`h(%_mU`DC;qA3S8AiGd9XJNhw^J;VN>D{| z+FM~(LCtJ|wx;`rm?hkzK8ES`A=QYR zfmY&AV@{TPv|7Rd{eXDk5TU}w-x2$jz6Nlgo(Y8LIZ5ZI5JL_R=xf;b#zTBYUv$nx zrM}a9USbyM&1f%D_zkhwwD92uJ>#?oqxudKCPtUzO|po9#ywIXc7*sw=n%}T6_oJL2!{k~C~)X@fHf&uOXL&5z|cbx?P71lNMFR+w;?X| zMpXJD&bw9tW(jxkPiZosqVBBUfPe^b-zPx7KKcRx_ia^NftlYy@dc^ zLIN^8ZlioJQD(frR0?eT2^h5-!)%)k4RpR zNqFS|>r5bx5Lk|aF8862AE%${ORw~zUncq$qF+6o{_{4yBeS3NvL8H7pYKbbiuU4P zBmSqv|8;R*-X5X8cukVjf0DW|QI4F5=1C&u=XfF5@k5it_aM%dB0lqc%gTtYhP@4EOrBA#9KFJOroe%rtJq{@X@YgbhK9DYU7a6H CW@F6& literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ModuleTarget.java b/tests/test_data/std/jdk/internal/module/ModuleTarget.java new file mode 100644 index 00000000..ffd50704 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ModuleTarget.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +/** + * Represents the module target. + * + * For now, this is a single value for the target platform, e.g. "linux-x64". + */ +public final class ModuleTarget { + + private final String targetPlatform; + + public ModuleTarget(String targetPlatform) { + this.targetPlatform = targetPlatform; + } + + public String targetPlatform() { + return targetPlatform; + } + +} diff --git a/tests/test_data/std/jdk/internal/module/Modules.class b/tests/test_data/std/jdk/internal/module/Modules.class new file mode 100644 index 0000000000000000000000000000000000000000..21dd5adc41ea08452103a4c0a14ffba4a7fdaf71 GIT binary patch literal 12016 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 EA6#bMUH||9 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/Modules.java b/tests/test_data/std/jdk/internal/module/Modules.java new file mode 100644 index 00000000..be3f8b63 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/Modules.java @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.PrintStream; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.lang.module.ResolvedModule; +import java.net.URI; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import jdk.internal.access.JavaLangModuleAccess; +import jdk.internal.loader.BootLoader; +import jdk.internal.loader.BuiltinClassLoader; +import jdk.internal.loader.ClassLoaders; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + +/** + * A helper class for creating and updating modules. This class is intended to + * support command-line options, tests, and the instrumentation API. It is also + * used by the VM to load modules or add read edges when agents are instrumenting + * code that need to link to supporting classes. + * + * The parameters that are package names in this API are the fully-qualified + * names of the packages as defined in section 6.5.3 of The Java + * Language Specification , for example, {@code "java.lang"}. + */ + +public class Modules { + private Modules() { } + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess(); + + /** + * Creates a new Module. The module has the given ModuleDescriptor and + * is defined to the given class loader. + * + * The resulting Module is in a larval state in that it does not read + * any other module and does not have any exports. + * + * The URI is for information purposes only. + */ + public static Module defineModule(ClassLoader loader, + ModuleDescriptor descriptor, + URI uri) + { + return JLA.defineModule(loader, descriptor, uri); + } + + /** + * Updates m1 to read m2. + * Same as m1.addReads(m2) but without a caller check. + */ + public static void addReads(Module m1, Module m2) { + JLA.addReads(m1, m2); + } + + /** + * Update module m to read all unnamed modules. + */ + public static void addReadsAllUnnamed(Module m) { + JLA.addReadsAllUnnamed(m); + } + + /** + * Updates module m1 to export a package to module m2. + * Same as m1.addExports(pn, m2) but without a caller check + */ + public static void addExports(Module m1, String pn, Module m2) { + JLA.addExports(m1, pn, m2); + } + + /** + * Updates module m to export a package unconditionally. + */ + public static void addExports(Module m, String pn) { + JLA.addExports(m, pn); + } + + /** + * Updates module m to export a package to all unnamed modules. + */ + public static void addExportsToAllUnnamed(Module m, String pn) { + JLA.addExportsToAllUnnamed(m, pn); + } + + /** + * Updates module m1 to open a package to module m2. + * Same as m1.addOpens(pn, m2) but without a caller check. + */ + public static void addOpens(Module m1, String pn, Module m2) { + JLA.addOpens(m1, pn, m2); + } + + /** + * Updates module m to open a package to all unnamed modules. + */ + public static void addOpensToAllUnnamed(Module m, String pn) { + JLA.addOpensToAllUnnamed(m, pn); + } + + /** + * Adds native access to all unnamed modules. + */ + public static void addEnableNativeAccessToAllUnnamed() { + JLA.addEnableNativeAccessToAllUnnamed(); + } + + /** + * Updates module m to use a service. + * Same as m2.addUses(service) but without a caller check. + */ + public static void addUses(Module m, Class service) { + JLA.addUses(m, service); + } + + /** + * Updates module m to provide a service + */ + public static void addProvides(Module m, Class service, Class impl) { + ModuleLayer layer = m.getLayer(); + + PrivilegedAction pa = m::getClassLoader; + @SuppressWarnings("removal") + ClassLoader loader = AccessController.doPrivileged(pa); + + ClassLoader platformClassLoader = ClassLoaders.platformClassLoader(); + if (layer == null || loader == null || loader == platformClassLoader) { + // update ClassLoader catalog + ServicesCatalog catalog; + if (loader == null) { + catalog = BootLoader.getServicesCatalog(); + } else { + catalog = ServicesCatalog.getServicesCatalog(loader); + } + catalog.addProvider(m, service, impl); + } + + if (layer != null) { + // update Layer catalog + JLA.getServicesCatalog(layer).addProvider(m, service, impl); + } + } + + /** + * Resolves a collection of root modules, with service binding and the empty + * Configuration as the parent to create a Configuration for the boot layer. + * + * This method is intended to be used to create the Configuration for the + * boot layer during startup or at a link-time. + */ + public static Configuration newBootLayerConfiguration(ModuleFinder finder, + Collection roots, + PrintStream traceOutput) + { + return JLMA.resolveAndBind(finder, roots, traceOutput); + } + + /** + * Called by the VM when code in the given Module has been transformed by + * an agent and so may have been instrumented to call into supporting + * classes on the boot class path or application class path. + */ + public static void transformedByAgent(Module m) { + addReads(m, BootLoader.getUnnamedModule()); + addReads(m, ClassLoaders.appClassLoader().getUnnamedModule()); + } + + /** + * Called by the VM to load a system module, typically "java.instrument" or + * "jdk.management.agent". If the module is not loaded then it is resolved + * and loaded (along with any dependences that weren't previously loaded) + * into a child layer. + */ + public static synchronized Module loadModule(String name) { + ModuleLayer top = topLayer; + if (top == null) + top = ModuleLayer.boot(); + + Module module = top.findModule(name).orElse(null); + if (module != null) { + // module already loaded + return module; + } + + // resolve the module with the top-most layer as the parent + ModuleFinder empty = ModuleFinder.of(); + ModuleFinder finder = ModuleBootstrap.unlimitedFinder(); + Set roots = Set.of(name); + Configuration cf = top.configuration().resolveAndBind(empty, finder, roots); + + // create the child layer + Function clf = ModuleLoaderMap.mappingFunction(cf); + ModuleLayer newLayer = top.defineModules(cf, clf); + + // add qualified exports/opens to give access to modules in child layer + Map map = newLayer.modules().stream() + .collect(Collectors.toMap(Module::getName, + Function.identity())); + ModuleLayer layer = top; + while (layer != null) { + for (Module m : layer.modules()) { + // qualified exports + m.getDescriptor().exports().stream() + .filter(ModuleDescriptor.Exports::isQualified) + .forEach(e -> e.targets().forEach(target -> { + Module other = map.get(target); + if (other != null) { + addExports(m, e.source(), other); + }})); + + // qualified opens + m.getDescriptor().opens().stream() + .filter(ModuleDescriptor.Opens::isQualified) + .forEach(o -> o.targets().forEach(target -> { + Module other = map.get(target); + if (other != null) { + addOpens(m, o.source(), other); + }})); + } + + List parents = layer.parents(); + assert parents.size() <= 1; + layer = parents.isEmpty() ? null : parents.get(0); + } + + // update security manager before making types visible + JLA.addNonExportedPackages(newLayer); + + // update the built-in class loaders to make the types visible + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + String mn = mref.descriptor().name(); + ClassLoader cl = clf.apply(mn); + if (cl == null) { + BootLoader.loadModule(mref); + } else { + ((BuiltinClassLoader) cl).loadModule(mref); + } + } + + // new top layer + topLayer = newLayer; + + // return module + return newLayer.findModule(name) + .orElseThrow(() -> new InternalError("module not loaded")); + + } + + /** + * Finds the module with the given name in the boot layer or any child + * layers created to load the "java.instrument" or "jdk.management.agent" + * modules into a running VM. + */ + public static Optional findLoadedModule(String name) { + ModuleLayer top = topLayer; + if (top == null) + top = ModuleLayer.boot(); + return top.findModule(name); + } + + // the top-most layer + private static volatile ModuleLayer topLayer; + +} diff --git a/tests/test_data/std/jdk/internal/module/Resources.class b/tests/test_data/std/jdk/internal/module/Resources.class new file mode 100644 index 0000000000000000000000000000000000000000..ba0b68e93c4d09e8b1ac39d6c4d51ed41c7baf10 GIT binary patch literal 3762 zcma)9YgZfB72Q|TFhUv(#ykQ7$Dz~)$)MV<(;8uHBRh>+3=a5FliFdB1{e@CvSy%= z=FvFr`~9xnrXfvQ+SKi$`9L6D?ZEK;5jqsK>LqH60(BoHf#}KvlnKneKpqzpMLt2tib<2x$mI z+a*5c=1psw;#tF*c4s{CR1gO^)0@ufjw83$X*h^_fuLb!oExSTYwQ}@u~|@(=pGND z0gWn}G&JK0f%e(VT->x=BX8;1_`IE2$Qtoc!?73gX~PkyaqTO5dQP7fmG+{brCS)*AYB++Y1j3BYO<5UZX=F+u(3R?D+#eHw z6#BS^qc|o|?JP_>MTnZZQmO7r-UQLDA&QuQnm2M;Jx{}EX!eR8FS4CXICvZZb z-owx`?f8^QXs+lI+ECue>aMwHzDPaMA|$(H5=G6sC#CLF8a|2B%#>?yXSSiMf*;lR z6h5uujD|iW1T@bNy73I%AZU(})APD(=aVyfUO*%zCTBGa;2eWAolEmMciH30xQYt` zPwb9k$h780a;|AxA(Hi?ic1=v!Dj>x?Us|)n4_@iTr~4!t(~XRlNBR=z5skF;vEyD zor;t|v!~mufkNnm3uZQB%Ii4lqahlp$9Oi67h>dD+ItdG}vA z@VtgENOF;kj-6dJRNNMb?M7aAN$SZ3*N6}5j+vH*E^JS+FxP^?Q&p8#W)2DXFF>H@5q-Ui2mzL5-k#a%IXfQD= zsk&X?iY(rggg>ic9u_%2uPz2b}Bj=kdkbzsqWu@da+yU#Lx>Oe|-LjC2{ZAH& zt6>3)EWosFxw>hQ-jQ<6vY^I{I}3)DHoS(pgk=>kYWNafdaRCi^3PC6vjR;L<@$=I zi*T2*zjBXI@rpplZVXe_qMkJ~Qh5nPN$@Xgcnx<8mPc)yXG+s!)b^4u$#$8#iN2(b=!&xhfe=Kgf5k^ z7iWb&${v_8$&7|Qoc81y{S=u=e;8B9wPiZxg1~+@|7Q*b6j?IV*|W#${*}Zm7)v>} z*|KIU#_43PaO{+l@2GfdyI1o}NR5)hi*B{nf(zA5_Kx<_`0-;@Yg z#u9nsx2IU<{=96Zn&awu@4|6W(l0dTT^!^t=5afVPOqdhPO!9nyc_{4-@Fw;;A{Mf z^UXsYO7wk*KXc&2*ZGvoKsUa@r&bWaH}NfgRpZ;J=ZxGuOKGX}aC9ANf26MJ9UO?( z*Q}%VJ{14M=mrjLpyeSY{GQf&1UNoH^C#)fDKz1ZrQ>k3-%U3`x=zRxdu zvV|r#7kOtY+I6W<+C3Jni?8Ewf5i7DY9i8!KxPG1^&M+be`FnTwDkz~!sBAaY_&M%#mPrzI1YK&s9g~)8 z&$iu1ZOk9@z#>LN(M^o<0NlX!;hw+aOtfbc<398SS_1XA3IV*(r?e=WNDDl`!O|$y z_5f8afwfgAeTrD4H*s9YIE*6JCrKPyWlS&dT0Oz^O`-#7UK}%&oJK!pcvmnP;Vf=o zj)(HR7wZ7M?MH;RenBe4*=c30k~p_Z@!$3`#oo)Ezr-7iw1azoMLEBRL>rVXG>Z?> zucF8M-FgJypbFy={d|+U0(`IVF3YP1M-r#ExHrg^d;Wn~UA%oA(>KqOSCO{%%+rBb zdt+b&a}U5s+X52?Dw**bI&qh5 zd7W6@!x^4436^S-#hPLnjgiOKh{*&|%o0FQR{FZMylEuo)DVDKH8?q7H#qT)s(~oQTJx2jr?JVkZ$ZMIO zDlb2$5&kzfh>!ReMNzRt&I%!bN2uDuAyE_FLWpz2Dqh}_f8=@&oack-;?<;(E_^^k zk`(9Kl(&%}7iGg?(Z62TyTU#|6#WBj0p_CJ>qTwK3K}^)7>xubic;JW*lA8jSv6pM z3L~s$OkqY7VH}-!mz@0rQGLj|`;&)Sl%^x(+`B|kwt;iS&LKw<1BSwpY+{AVtbr1) SInU}0i$`ocg6d?aefS^2L5lzY literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/Resources.java b/tests/test_data/std/jdk/internal/module/Resources.java new file mode 100644 index 00000000..2bd26e47 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/Resources.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.module; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; + +/** + * A helper class to support working with resources in modules. Also provides + * support for translating resource names to file paths. + */ +public final class Resources { + private Resources() { } + + /** + * Return true if a resource can be encapsulated. Resource with names + * ending in ".class" or "/" cannot be encapsulated. Resource names + * that map to a legal package name can be encapsulated. + */ + public static boolean canEncapsulate(String name) { + int len = name.length(); + if (len > 6 && name.endsWith(".class")) { + return false; + } else { + return Checks.isPackageName(toPackageName(name)); + } + } + + /** + * Derive a package name for a resource. The package name + * returned by this method may not be a legal package name. This method + * returns null if the resource name ends with a "/" (a directory) + * or the resource name does not contain a "/". + */ + public static String toPackageName(String name) { + int index = name.lastIndexOf('/'); + if (index == -1 || index == name.length()-1) { + return ""; + } else { + return name.substring(0, index).replace('/', '.'); + } + } + + /** + * Returns a resource name corresponding to the relative file path + * between {@code dir} and {@code file}. If the file is a directory + * then the name will end with a "/", except the top-level directory + * where the empty string is returned. + */ + public static String toResourceName(Path dir, Path file) { + String s = dir.relativize(file) + .toString() + .replace(File.separatorChar, '/'); + if (!s.isEmpty() && Files.isDirectory(file)) + s += "/"; + return s; + } + + /** + * Returns a file path to a resource in a file tree. If the resource + * name has a trailing "/" then the file path will locate a directory. + * Returns {@code null} if the resource does not map to a file in the + * tree file. + */ + public static Path toFilePath(Path dir, String name) throws IOException { + boolean expectDirectory = name.endsWith("/"); + if (expectDirectory) { + name = name.substring(0, name.length() - 1); // drop trailing "/" + } + Path path = toSafeFilePath(dir.getFileSystem(), name); + if (path != null) { + Path file = dir.resolve(path); + try { + BasicFileAttributes attrs; + attrs = Files.readAttributes(file, BasicFileAttributes.class); + if (attrs.isDirectory() + || (!attrs.isDirectory() && !expectDirectory)) + return file; + } catch (NoSuchFileException ignore) { } + } + return null; + } + + /** + * Map a resource name to a "safe" file path. Returns {@code null} if + * the resource name cannot be converted into a "safe" file path. + * + * Resource names with empty elements, or elements that are "." or ".." + * are rejected, as are resource names that translates to a file path + * with a root component. + */ + private static Path toSafeFilePath(FileSystem fs, String name) { + // scan elements of resource name + int next; + int off = 0; + while ((next = name.indexOf('/', off)) != -1) { + int len = next - off; + if (!mayTranslate(name, off, len)) { + return null; + } + off = next + 1; + } + int rem = name.length() - off; + if (!mayTranslate(name, off, rem)) { + return null; + } + + // map resource name to a file path string + String pathString; + if (File.separatorChar == '/') { + pathString = name; + } else { + // not allowed to embed file separators + if (name.contains(File.separator)) + return null; + pathString = name.replace('/', File.separatorChar); + } + + // try to convert to a Path + Path path; + try { + path = fs.getPath(pathString); + } catch (InvalidPathException e) { + // not a valid file path + return null; + } + + // file path not allowed to have root component + return (path.getRoot() == null) ? path : null; + } + + /** + * Returns {@code true} if the element in a resource name is a candidate + * to translate to the element of a file path. + */ + private static boolean mayTranslate(String name, int off, int len) { + if (len <= 2) { + if (len == 0) + return false; + boolean starsWithDot = (name.charAt(off) == '.'); + if (len == 1 && starsWithDot) + return false; + if (len == 2 && starsWithDot && (name.charAt(off+1) == '.')) + return false; + } + return true; + } + +} diff --git a/tests/test_data/std/jdk/internal/module/ServicesCatalog$ServiceProvider.class b/tests/test_data/std/jdk/internal/module/ServicesCatalog$ServiceProvider.class new file mode 100644 index 0000000000000000000000000000000000000000..2ed0867c87a664ea0b69302cf6536dfc5ea26a45 GIT binary patch literal 1260 zcmbVMTTc@~6#izn?Y3o0p+XhBOO;-LmKfuuYA{WR#I~5!kf2Y~c0w1HUEJOBM|{#h z;0q6$NF*j2ef2jPCfL^z5%FVISCEAfryDHVhj`8e4m$X z?rfFU+uNcOFvK2Ojukv+(DQ|j1mZ{-NSYXf$#8qSyHmEDKzI(f%e!v3Z;NtEc>7jI z_%$AI+uh2k`*Y9Tx4Ockj)O#oO#LrhBP^~;fN>LPOfZ;xs-($x#mVee;91UAHHi$) z8JIFLjV!}t*sdQ~wqoxyM0(usF=X?vhQJ2es)aS#;DU)6%n~i}y3cJYna`h2Jsl~$ z9LZD)hB6h)!UoZ(xn0tbu3L_1_IKODd%@dwsLJhddxLwHysKa&=vhSMPW?aptujpI z3qvdvuhFm~#}Jne4d~GmuQ5!Yp{NSnU2L_fH=Keu24aS<|2(M;y-xp+4dSt?|Ohcs6d~5W&G^cdR z$cdso3P#_Hv|ggyrW}6S)5XtV#nK^+;=&5hf2tsH_fk%N|pi!A;fejk2p!`hoa6MD>Hx zcf=dA>jHg`aQ-c(Wplcv!kZC!kBBaD^w7^)#OVAC2I}NzgZyj~*L4!v9P+ht>}v(L tFi+^?WJjL7)=;4OG3be3$Qg*Q(7zIjp^Oq1!hMmN0ZA%~V-Xe1`~iUe0iFN= literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ServicesCatalog.class b/tests/test_data/std/jdk/internal/module/ServicesCatalog.class new file mode 100644 index 0000000000000000000000000000000000000000..a4802fba786a8ba3e10ec3c56275553a1cbef4df GIT binary patch literal 4747 zcmbVP`*#z^75>JOy|T2%pkRW476=%yY~ut7AvS@!h9oYsoW|7D;IvswYa=5|%1Uwr zd9?{?`hL=;kEBi0CbUT(2@r$hhUBN@oc<5}M|#rI@6N8Qm24k#@{2S(bLZage)lmm z|N7tiHvtUb!!Q~UFc37+h$e-#)7GrjleKbFJ;M{zcB-V%bU2gCl#VC__H>LI2r2B+ zLgi8>+mp)YQf0@nbETev#o@zN@$8UQ2*W^F^hOkddj>m3o6&+b23k$5#X5x@)9G_P znOwnK8_MBO2qhnMMZ#Qulb|^#&<D4iRI-_Tzwodrcg~eHDc|C__5(j3485%r2&!Orex_M6W+iUVga3 zRWa(lAH4?pOdQ4o3fpzKwB8kVD1-`5em0Y~>BPE<4Gna}F7-ul6kjmVZ{mv>s7WfW zaxWw9SQ_7kn!SVGJQWCBzQZi`F#A%!%+G6H{t(_P&@R-8>+bHRsUWt1s9ntr7DdEQ@7YF?@cUw@Ofr*-g zaWRK6j=>1{F=gT`G72WMzk-3Dp75*iHn4_QZ&CIB^of~s z$Qqb2krVD)t05c6T16T&nCeMu#uncTCY})58}gIV9*QPP(jH8T3_Hi{NvoVKN#~q3 z@eMplvIi2QY-_d9vUw|QJ3U%`LXStSY}sa9FW@NyPYb`#DD159XN64)oqjHSI+tsl zLg{lRzKL(KC8QkND(QGIjH^?p;k_XJ@S?&4D;f0#(o2YCbL86!cUFlW^v;#zj+1x7 zco6}iBEak($xP*}QrRKQXmD7fF~u&S*uq;X4N*##BsQk$ASK7L}w|YV;oVg9L&z?#f*_tbmynE`flPqV+ z!V$mWy3V~a(9mMidhF#;pj>bZ>u#( zOhSiKS?^5{9?6%Tl>J~v8qfMVTYIG)Gx?Hsu{2~$hax(2Fqg9(O^wu2$UA~LZ1uKR z4rScKqosk*lmaXu%lN^PM-`|J4V)%aH%nvAW3_*^7X#6@LV_RV9Do?6r0bpu_lfH)G=0QMrnaheX>kD#ZSW6z)$&!QjC z;RGX|=KnOK>EH#FaZ%GX&RjUg7uIj_3P*9?>xHC7?(N5`q^5})4&irP<-38iLR^Rz zhDrYKHNmrs1kd6%{DHhQ^3wM@{zy87R>?e9+n=aS$UKVRf6;0PpT}?E0Kx`Z4D5F& z3?vO$WLg<`gZcL#wBI7be8+n-RG{!CE>pb}#6`lEIB$uQ{OKU691Cdjy7?)jktv}m zpfgH}3Ea1tUs4uvckiMLTRa!2k3{@gOK-tnII8A|yY|-N+FM+6i}!6J`z!wDAv?}_ zv9?av!wux;;pmEx3TyCH*d+}`(vQN6P}X_r>Z<-b-TVjMp#gFFUdl>sMy{Y7pTqf& z&{D7T6|K}Q`v~5}6^b|G>Y|F5h)&wX?y8DJ=O>8Wz_SUNVm?1lwL@JWqp>T|De7Gc zH!+I98!U-8(aJE~L2|Z|qISHkO>U#yR?1vsrxA~Kd&VQA^gYfgodY4LPtnex64V^n z%d}rlc%Wi+2qFu3k-h1q537-k>d0MTdR=7$y@ricBM}wz;M2qPSVpcjEy&+;^^`EC&7EaGvVtIoE*qvA}=n#^d-WM^Vlt*_J+_$#E*a HiP--Epsm(I literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/ServicesCatalog.java b/tests/test_data/std/jdk/internal/module/ServicesCatalog.java new file mode 100644 index 00000000..730bbe63 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/ServicesCatalog.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Provides; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import jdk.internal.loader.ClassLoaderValue; + +/** + * A services catalog. Each {@code ClassLoader} and {@code Layer} has + * an optional {@code ServicesCatalog} for modules that provide services. + * + * @apiNote This class will be replaced once the ServiceLoader is further + * specified + */ +public final class ServicesCatalog { + + /** + * Represents a service provider in the services catalog. + */ + public static final class ServiceProvider { + private final Module module; + private final String providerName; + + public ServiceProvider(Module module, String providerName) { + this.module = module; + this.providerName = providerName; + } + + public Module module() { + return module; + } + + public String providerName() { + return providerName; + } + + @Override + public int hashCode() { + return Objects.hash(module, providerName); + } + + @Override + public boolean equals(Object ob) { + if (!(ob instanceof ServiceProvider)) + return false; + ServiceProvider that = (ServiceProvider)ob; + return Objects.equals(this.module, that.module) + && Objects.equals(this.providerName, that.providerName); + } + } + + // service name -> list of providers + private final Map> map = new ConcurrentHashMap<>(32); + + private ServicesCatalog() { } + + /** + * Creates a ServicesCatalog that supports concurrent registration + * and lookup + */ + public static ServicesCatalog create() { + return new ServicesCatalog(); + } + + /** + * Adds service providers for the given service type. + */ + private void addProviders(String service, ServiceProvider ... providers) { + List list = map.get(service); + if (list == null) { + list = new CopyOnWriteArrayList<>(providers); + List prev = map.putIfAbsent(service, list); + if (prev != null) { + // someone else got there + prev.addAll(list); + } + } else { + if (providers.length == 1) { + list.add(providers[0]); + } else { + list.addAll(Arrays.asList(providers)); + } + } + } + + /** + * Registers the providers in the given module in this services catalog. + */ + public void register(Module module) { + ModuleDescriptor descriptor = module.getDescriptor(); + for (Provides provides : descriptor.provides()) { + String service = provides.service(); + List providerNames = provides.providers(); + int count = providerNames.size(); + ServiceProvider[] providers = new ServiceProvider[count]; + for (int i = 0; i < count; i++) { + providers[i] = new ServiceProvider(module, providerNames.get(i)); + } + addProviders(service, providers); + } + } + + /** + * Adds a provider in the given module to this services catalog. + * + * @apiNote This method is for use by java.lang.instrument + */ + public void addProvider(Module module, Class service, Class impl) { + addProviders(service.getName(), new ServiceProvider(module, impl.getName())); + } + + /** + * Returns the (possibly empty) list of service providers that implement + * the given service type. + */ + public List findServices(String service) { + return map.getOrDefault(service, List.of()); + } + + /** + * Returns the ServicesCatalog for the given class loader or {@code null} + * if there is none. + */ + public static ServicesCatalog getServicesCatalogOrNull(ClassLoader loader) { + return CLV.get(loader); + } + + /** + * Returns the ServicesCatalog for the given class loader, creating it if + * needed. + */ + public static ServicesCatalog getServicesCatalog(ClassLoader loader) { + // CLV.computeIfAbsent(loader, (cl, clv) -> create()); + ServicesCatalog catalog = CLV.get(loader); + if (catalog == null) { + catalog = create(); + ServicesCatalog previous = CLV.putIfAbsent(loader, catalog); + if (previous != null) catalog = previous; + } + return catalog; + } + + /** + * Associates the given ServicesCatalog with the given class loader. + */ + public static void putServicesCatalog(ClassLoader loader, ServicesCatalog catalog) { + ServicesCatalog previous = CLV.putIfAbsent(loader, catalog); + if (previous != null) { + throw new InternalError(); + } + } + + // the ServicesCatalog registered to a class loader + private static final ClassLoaderValue CLV = new ClassLoaderValue<>(); +} diff --git a/tests/test_data/std/jdk/internal/module/SystemModuleFinders$1.class b/tests/test_data/std/jdk/internal/module/SystemModuleFinders$1.class new file mode 100644 index 0000000000000000000000000000000000000000..25d944f6b65aba7ecaaa2d22538739a373977b61 GIT binary patch literal 2504 zcmb7F-**#56#gbnyJ@nJG++T0D40T;AOQsxQ>$sD6irhkr3n6XMV*KYZyC^hz6PjuJhWW}&r!f|ug876nRnQJqguWj>PUNX7W>3c-? zmXkGt3OYk(uzP)LTQog}sYSywyd{Q-{K96Ih#l9FMuz5&Z!t9TM<7I&8=hlW zo$^9xaz)d33~#S=&oOolQ*=bD()0}5B2rnL&~Q@6E0|?CCrQ27UTHRk>sD>cb8OQT z4ujsZ2Qe6KC`vCp28#+nF_5Z+=PYYD&5)HyzGs-F^V9`iI2(M+ zBulntH@UgV9V3`4W88aUkfz1j*u_pfrW;1b;-2qN)VRgFGWg)M>JSXE9w*61KD)<9_%4R)LpmwjLEZ0*ws3^i6y+uQG1Q`J9wPi$0U5L)ot2;-XY#6gBrhrq z0(aLe?{2ktE+Cz|#&9Pp#;DQ?`Aby~(TW%`YJFF%Bj_?A1gs zQ5UYaYP-~GGt0K^xt_y&A-bEvCk!Wtf~a0q`J}B@6r4y zr;zn3w_2ufb2Z!E@q6Wid5Tzu95?7Yi*6r(F@!waH`;(zk3!HR}Aw9G#Pa~4d3)HD4F9S&PoZoLqjbvM;S{{*PjQ=WP(ebuG2U@DHLd>NN+c2 zjM11Z6n_FM{0!{}n#FL1{-?+j_ycd!zb@aCxQY_ZuF(^dHfr?r7DVdMI6>oy!jE9Z zeH;VUt~|xeuQ>HRnI~k(poDLVaXZS@fJa)i1yo(+)dgafQOcM$Ug*s zmuysD3Y^mzL_QUOKYEHY5BG5%s1+rFi!T%Si!Q;xC4t${O%X^dSZXT@HnhA?U?FTd zlMFrpng?fIRIrIc@fYM`2ymj>J&#}{uq5>dVT6aA#D{YKN2t&k$1*;~9cfv{DvbfR d4HD=sK1E%<-9rOk&{|d@(<{Ej*Z3A^{sph#uN?pY literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModuleFinders$2.class b/tests/test_data/std/jdk/internal/module/SystemModuleFinders$2.class new file mode 100644 index 0000000000000000000000000000000000000000..235f2dc94e8d85cf82d7caf6a05edb7cd219f94a GIT binary patch literal 1403 zcma)6?M@Rx6g^YgF0CtUD=LB?AXVD(v5NkYB8fo>Bn3^2B>r65p$u+k$?hzPZ>0%H zqKOaSQ}`stJKZI2wE>!JXZOyXbI&<*XMX&TAXRKAd%nuZ-Vkwc!r z(0QRR7)GK*$(8-Sv02N*#B~EBCPrZ~SbtI8?j7=$q7o}Y3bo2GRIcnAC^9Txm0*%| zgF8ezj{?SYt(y!p<^MVNldJ6JNyBXuKudMT&K=<+!_!FZ6dDOsfMCFwE7j zs(Y!%FxJO2GLyo&rszmVg+3K~mk<&sM3KR?R}$%ibgvS8zUhU2i?0hUW<2SC+%${Y z7gGL4wp=fuHre9pz-t>QGt6F5pNT5w7z)Ze_kExHT(+p>ujHQgk$laAmM@N!=hp`M z7(wkgKJD^F85>S;z=O*(N;>g;$1h56@W6A)aZlDR=&V>FSv0LwW#Sf?e1@%FUVV05Z z%~{`3_)t9|q!Sotxbd0tk~l9DI97yXy&|0H7{{hj*T_`A;?}>5lO!@Ri3}e0O3a|t l8z12@jcLrHg85!#77H{^kjfN|`d6UYMe@SNQ#{M&{s4u#c)9=p literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModuleFinders$3.class b/tests/test_data/std/jdk/internal/module/SystemModuleFinders$3.class new file mode 100644 index 0000000000000000000000000000000000000000..3482d30537627980edcd3159f3b89cbc315525bd GIT binary patch literal 875 zcma)4U2hUW6g@+M1-i9}iuI#f6)n){KIn_V_yDn~3Dl%(c;RV)2@DRiWM{UC|4I{$ zi4Xn&f0XggmV_o<6E~SXckY~f?wxz*_n)7?0Q7KJMh;sZ@;(YEGPD-cPl41{#G0#M z8BG%d~CyKs4n<94;0t4;KO(! zCYGW2Mrvu_GHf+lLl4&&o@Zsd$a6xv!ZaL&$!evfh#3maQMWZ@$oHbDVA$@mtZbQg>oAll2QPAblQrS6rKMXry)v9}n^g462wy{fCCF>QT^HkbL-@)2H;C)Rw*XduRNU#-Z zWc$uW1vhY$@D{CH>Z{{6oj9e}gifi@{s#6XC2T}YDpJ27tVM{5J=~$NJnp9ad$>=S Z$37n7aq8K}6T%wBIcfLppn+$_@?Ss4*L?s0 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModuleFinders$ModuleContentSpliterator.class b/tests/test_data/std/jdk/internal/module/SystemModuleFinders$ModuleContentSpliterator.class new file mode 100644 index 0000000000000000000000000000000000000000..8f295a146570f2237af21a035b80fbfbed57235d GIT binary patch literal 3758 zcmb7HYgZe`8GdFYu^^TJ0y{W1HrNCMMkonR8(Y{h7gN&!j!i;p+N55jH7tmgvRXMN zZkx2HJx+Q}?=@|DOIvzzS~rPtT=z8n)DQg|{T1!WiTli~KoVfP)j3-2%)HlUp7)*6 zKR^1*-vA8bMideu17Q;pR0%XJSQo8C#&YKpr)L-JlrK;<;JA)|Tp-ldJ#C;`;K7p6 zl1EFfv3e+T)vgty`&L`AdorwofPfJ!VXS->Ec-Q!56Upu^Q$?#u zWunnU3{3*nel~C^(A>3EC0T zl0qfz;cO(`O9M)+}gQLVNHegc}?O^m^g(o!d_xxa~W+mWNYyh#tlrE zm{fqqN}kt61dMqrKWSg`mF&|d&fqN5aXGQMh>H2BO?t+}v#Q{XIoqGKmTbl2=S+MG z=ZJfUmCxIrPHM!-TeBIPMJ>1~pB8A*5$FywxGr_l^Rny?GYCcT0zPZtya@}l742rd ztgAA%JLeN=wwo~}o;G3Q0((lnFq_xyM(x7bHpQ>@aNdNYfH0i=Nd>l=TQrf;Ip??; zDmm9g7CG{Y$qmo5cX_r;>?(F++{ydNT6oAC@YQB;Umqx;tCpk0wFd3?dZD<)o5B-~wcccI{F5+&H8@`WW; zOV-#P-*9?5!#5WYU zL3L=G!x?fxU}xISv)IxbTR!Dmet`=$Q_h^rSC4(;NEv~3RSn#)O$ANkcv66(>SU@Y zl>b9LJghrc{kY@WlZB;O+j~aQR(14j%F0Yzo}W;IcxX`S{(|ip1I+PJL?L@~jkFH4EKI5p&b#%aY~WQ_jnTkL~G` z^gfWv6t73e%JM2U(lQ*%qPdI5=v21grR-5h(XwTmOG=-r0J@xHAg8i5n(i_`x0-24eF-Cxo`4a;#++36xtZS(a@q! z0L~ix@-(H)xB2!jS_tts({mG|=QfOUH&GLduE9LS?;09zpqbMTaeB`Uw7!q_p7+qa zhJzEm|3I{N4e=GU-$wtrqH3^e#vTu}Z{p)0aH_TU7LH2vypIz%F#2cu3*kF_cA|#C zMiG{^*ey+T%6dF18!#XnF(YG0%O)(!W_*{jZ9$y)9=^{JBgPMyx8Q9gi67!e%;zd+ zn;`FCK;4UX7K8z%%) z6MV$4BF@a2?ZL@+Fuj6UTqj<88#4svGdjh%PH`2Dy#WT#htIDeb$#{DTMB?%m{ay6 z;(9Pz2s{MVl#3OVtZ}?_3oi-~tkpXy#u&gg#7&0W15>tQm)wiJavvU+?TE|$7?KAt zE<12qcH(*2h4Zop8F>hKST|4 zG>i50YcBo1}kYaSbXu<@d1G1R7&k*6{iYjPNSLp?5K@ zin2VBh{hrUX`bMrRYc)!{85Yj2|?ahpw#$ZiT&sb-huivbOrD7w~v2P-V4|K7q_*( ATL1t6 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModuleFinders$SystemImage.class b/tests/test_data/std/jdk/internal/module/SystemModuleFinders$SystemImage.class new file mode 100644 index 0000000000000000000000000000000000000000..659af512c3ae874ee467b24015fa5b67663f9a3a GIT binary patch literal 734 zcma)4OD_Xa6#hsBuK+;0WK^M9SnVPr~t}lYBds41RPZPSgRiN|^ zA(>k}??D~ z_ILO8ON51DM}AG2xZ6~fq~OFY8~qrtkZ~}GEMfT%eL;9SjIIg&RjJ$R5EgT*e>Nke z@?nJs94M+l9yjV`8J&r;&rG%$dcr>!kutbNru2o137egT|F?xLUPILUM?!kr^IJQ% zPs2v!$$~OX$A8%5x;YT19LrcAgt4|TOIYbx%kKjaoWmfHQQjAEEP3?aw!2`SZ=2v( z!Hvyz*-J9!XTi)6BbP0)?OJ;VJ+PC&Fn>)Lbb}H0oi71KF~%s(g|f_;edd|D_vXJ>fByqu4bL)2AZZ|FB8?$|i396b ztK?Yjerap>K-L3+p%vS;gH?fKVQFUsmoRJ~V`2oRz-YL=9oSB(Cb>7^H3a4h&no>e zXE4C4kSOiUsxaQ|TMmy+!U(swPV)b#e+jx5zWtw1(6!^wv2?n%Ejf7&LH zZu+v(5*Y7`F@h;vF_1Iy7N&d1Zd!)|!(L0Q|s)<>= zEnvDfWlR6d+Yv~ud3!v=c*S;QwcXs6{9sj0IB#UnktiWXCHwJy*xXIU9OcgJua-Xe_@?37;=fXGZ)WGm9)K& zrmXh7=-U$yH$c?YKAgDA8$3Q0J=I{H863) z1J5X6C~^-}Et)LE*(fCiKI*rf6E#!w+J0Sb*s82dpY9f|JF0jHT&l`e@W^YiqJ7V@ ze9n|%(SPi^(qD6|R!jAb?CA&weiXQTQu0_obTeUYg-r!{_PzvoM*dEy{>Sf6*p3tU zlyml$ubr`q&p9IuzQ6+pQ(s^5-#`Li@!LGMtka^2ZP1>^!-&RR zmj6OAfq(Jt5lX*tB@qgv{_Q~ALRu_@OmvLgu^>5og9?##j7@%3u|*#hqr{owktY1; u3FMG6iscYaE0>PoG|0Eq{JW6A6V$?S8#^4cgdM{+o+5)E*kykj8vY;Kpo{nb literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModuleFinders$SystemModuleReader.class b/tests/test_data/std/jdk/internal/module/SystemModuleFinders$SystemModuleReader.class new file mode 100644 index 0000000000000000000000000000000000000000..51b38d5fb93abd0ed74a499c90696ad07010af75 GIT binary patch literal 5803 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModuleFinders.class b/tests/test_data/std/jdk/internal/module/SystemModuleFinders.class new file mode 100644 index 0000000000000000000000000000000000000000..8c19d4d0d4f3245a5ad5d6b915a13761d77769a7 GIT binary patch literal 11983 zcmc&)dwdktz5o8QkJ)S{Jc2=%mmpC{LI?t)ZV(|nB#=ZT0STaVlT66MW;gC`P{g;? zsl_}d9%@y7Wn5y zo6=GHBh(RkWO#v`%Hjznu$%&2VGmP#8Pb>@$y(Rizo zObH5CH!Rt>bYVl|#+3^jmkDHD5W_HB!w4NCQ6wlimZ(%+q>~CpVln3c6n)aP(%NHo zu2RDtr=wVnbzG~_7U_zmU4m4D<8_QdNKjx+r9RSOaDd`zrR!_^fN4l4qw!4?I1b}A zOwchAC%BNa8W1_-!mdcn6yWG?;aXK{0x(&}iE6-LODvK~nd1dff|E3ytYa#s35NF# zyhybXXl;q4YN=-KkZY?&EV3pvJ5bRQl<6qPbiuGqMtV^qo=PXXTGEN6VD>cU)T|Cp z5lN#hMjBK)I#J*ZRBD*1;}pyiOz0ahM{9x^H!iB-kdb%`b)M=PFaw4|Y5S3eIfBW@ zw5x`>f>C`MEV;PF=uAfwaSf*nj_-R>W3zNgGMPvQaT>yk@>PN{P7oX0lZlHW%`u~@ zbWH(f<4hg%ah71DMTo^lswEliByzOF$!=QM?6-K|*RV>7S*W9$-iAV}QDY=YJ5U6v zOZap6kR`=xXG&P2V=2xS=$3?KkyN{)<}n0V%}fC`I+kNab|$NgR3g@;fTEPrq1EVX zTcx2+FsTn!OPfkd-Bm`Lku+#!4d-Nx!XaXn^xTpq@pN)qkm2K89jnkFDB5JijbtQk zC@wc9l&XR`iXDUEVNb{AXGS#nxEgCToTpve3v`GmWjYBh9qcE+Lxy=9fnmF&<1dsE;s^e<7<$jGGf0c_OqB}8bObfO=Uf_I$s z9ArLKLyT#2Xowazs>f{M)_aKN4!$_ybt#|a3dz}mRt<)ZHf*AcnD)p3EbtkMID#rC z4t9)ipzjVOneG6E@FatuJ|>`oa~s|PYo-5#&smX zOg5$^($a3U4jfHzf@5N?5iAwSnIuvg(mJ{n;U~FfW)9krj-;b4E0c*%Bbg?80fp+a zM28W;Ma<-}XmbF3tXa}i1=x;DHC(3Sa$G^zG;I)%CMw&aOz0~kX}V@!qOG45Y=5yQ zYZeXeB;=AnD_q4{yG7SV<6F)#<8=_%V26e;>$nzQ$wZH=fTh%ffvPZ?T4ikNibay@ zfnb(RiflWjYL%@}_F>;3X4Va0xN^E1)MURZSWFo?Jl1KKRMnt7&RQgZuj#l6H&e+( zTb)__)Wq8oRC=;2$mF)?HMm8`t!m;0(bVE-k|{Tl+!ny?f+?%xDj`iuCnmKTX}*}0 zZZ{?+yW$n;XooQ=+7a1gsC@PfMbJA{wc=n;#vW^exEnh)+@s^0xR*k6P1(}AI*~}H z(n(cpX`PWYIm*B{SdC?MA?m6bd3hi1*YJQsc9&q{;DcC{YRV10TWEi4nkGJ$Jv4lq zX)V|IPP=A2{*)jd#CH{by9FmY@ylhcQs$cPFbHx$D`Q8 z`s$17VChw(tjWqTX+&5z(@y^jQQg(XT7p5lA475qvB{wPy?R^P?n}|n;yDdJ((ycgJR}*FpRy!S zmFxy`KfzBKhdaBt zz&hQD=CLxHV`;`29>Gf*ex~DP{Cp6)=Tw3eV1!8|Ta8vL`E&WzpJ*=T+a*E}ui`Zg zuj_aNzv!QLa&%z!R&^F*;K)o2w6c?tCJt}nEe*fY@oW6XmG&D9f)a>wQ5i9pD5G6{ zYwYI~@HT#{;deUT!9QklmMK2dgaNEQlBzc@raUfQ*Qp-w>iB2;iz)!k$L<2q2ET|) z}72ebFpZEipc`bv)K%gSLLA(!-s=Gea@n6c40kg>Bn*!A1zjgdYLFA`Dt}wQ# zM<4061U*6gatP88XS+J#bI{cSS$DEALUI854H4IPVu zb{)%s#iNT?d|Yx{;`_=?!L%W1+}BdkPc&TuYU%EYw6?Ou6YgsGq(CKXhqn_H+ps3= z4D(zXavMYnbr~kZ$)x4=s~2)L=#BxAmKGzGs$5Pe>W%d3WOSkVpei6EIpF4GIv}Gs z|4Qy6NU<)X<#-~|l87_Js+HxSRB~2X1rn06nvBzByiDl7gEEK$Y7_>#w4v5o14kM7 zBokbXbmi(*HC37rurHigX9Z=VaF4?$C#qaFP`dRbZVP8-m6AbrmFmorD!Xi`>FA6F zWr}c{#3xfl3Z23Sqn&#+>zCV^vLW4VO_#t-wKGJM|K~;5nxK?QnI`4BOqU9^A|5n7 z*^^-a?o>rwOpn$%V0)dUOU0O*uu~Rp~NM&ZK8CK=tz<_sYUHE-N&t z)um4A``gC$+J^Q>l1oE_uBx_)MsZgCBT0@}H;BtK=B#9Ea$rWv+?t(X(Rqd{>Wt)! z)@VvCFqTGAX;oVXWtB8&(x}U76_gx1!d8jOB?{HaEGS#8SjY?H= zL{*TnHIZag{k9)^)9q2BmAe|tQTKE6uaFDnmMvtUEuzpu$O<-;by_YP=5&0g{1hd7 zt^HN!Qa+huFO@lf(R_W;8J0dzAl*hG}V*qPH z{kIYc!jzoS`{P~ESB21SCC-VvBs;1QGS;d+*kKAg3>qZuaDI$d)=a7J)S+ZKYLM(X z!=gl&s`z{g6kC_vCDf|S4l76Tbf_izXnUfWU}^7okszw_&TOj=w{XrhV(;3V{pLCB zF>qby!m&@4`4o4Odw?8r)>kXCY}e#6O)l5u3QexoWCu&iM4M$wMs_P8ksa;asp2t> zB{aK_qoR|Vcx#l=RoXQ9hU@UbrJl94XX99+WdMb8t|C>f&t)3%FCT&m{g-nlhX*B2 zmJ)d#bY$DhGgio&YJ_E~zC|Llf?EZr!uG0PMa8}y2vwyrs#=2T%u-3v=xD$YXN{M` zH14rnF!rCWvUR;%?EhWhY==Nj#3|6FjGJ;x9KAR@XRrSSbv5CZkGno{f}Po@Fe#MV zCtU%B0c}t+WTS{x2a&@n3X*UAmJa>qoH?ga%vY#qylqyAmybf*%2UFZbh_gyD$nE@w=%#oi-Ib)@F8@0Yah#*t=2H=^o(cBs-ac$$4%vAFl!n(Gr4^&{_lhXCo zj9*(A`{uR8?89~6R<*1qs14@+m$kh;#+l@-h?bh6oSvDZ-bkhE3{?`PGZc)-JWPojgT{k`{f1hw#!d+>5<+M zvWyRo1mz|9nI5KfLk`{7xjAD?UZg%{Ao?V^UK8h8sCoLX z0)lUeI`h)x4M9aNvkuB$N>V)Riv&dj89*qlhxT4`(3y9}48{(Yp-xej$u;>0rv3re z%Vh{neyjFivmw-lu5B|`0G8GGT|t1~r2rm`Rhull8>>Dz;dQw>Jma;1@A<_FcaS#n zS0(6By!y)aK_25xo_vXa`I>*vmk9srRs(647XAvTk525)r`*$Ya{s69O_tvzRsFF&{oi^|8( zsxPbP#@M@YN)INDpB46oygiuWIe?OGl!kpFA8+%zQE>>f_k?}>aavQzw-0ALvm;M- zA3Z>o$OfE^WjGaHb9!NZu>u|e`mvR&UBq9Pa8lce)usF<Rk05*+#;JRC;kPrqp87EgKIVV{brNSo z`2?p^$j&#F^UiODyPg-WvBTc-gL8ewz5}QY`_-jBtX1@2WjNrOn_rw? z?AwK<<;D54y3rU8h615r57vbX)RXD_SHXXwf{>S&9$XOCL;m9Yklql|cnOB|9yB-X z$S35z`_bMM@`tp2*sSm*hwnhO9S19vv5B_ ze*ouV7oylr(mq79+(%P9Y=Xaovs{KbSW5tdY*mg8vX!)sVw7AY7Zc9YvD}0_U!g&= zZR1tr5#c4WolpTdR|udsT4eJ2W)qZHk?4|hD% zgS*&hdy}Vv(!Ukl)4<%nKUpGV4 zFkC9P(7LQIY1M6VD{)?rO1X`99`+8(?QG{YaSp-vDN&X?KEoW-KelUpaH2+U4XRUR z3);L72rQ$ZlG6$j^fJ<2zVy}OXADE7??`=^KeMcv)# z32W0sS~s4S9vlh>%1G@%FAjTfUMSFw7sL6X{KE)`^1Ja$FMdfc3xmHR~f`P@{KLkGGgPkC;zf@+CBj}!2QG^L`N z%@{-@@w_E8Q;8{xmf1n4y&w%zv2D(4-;QRwx`$Jm#&+6=hpA!9r0rIc( z)sG1L$GC;EyZ|L?j!f^!wrlC_mg`M z@k@*c_||Ls{~VIalCdi*nOwO`R#1a@7SzuhW{ug!Ou8g{=Zj+cVcuDOHkl` zXvY5UYB-|dRSj>eHe~}legxm=n4sZJv-8`Z@VlFU`ZUU-KYmYVP|>iaOhtCzUeQO% zh*44$@^#B`y)wpwuz$ZyWZn$<_sOKNwqK?+DV}pHe7Z@9lfnT;3B{mk;Xo+R7Z}EJ z>X6g;4eaUM(G2s;%Y`(_3TC}J(}WwWf$^z4L^|b=#^9RV7lt_ z<%gk_?}ooePVaM)S!Q%;4ns`9A9#dokzaG5+GpWxR45U@kOk~!gR@zK- z$~f1tY_XR}5J#*v6B0`(tg&h6MWZ}U>3P{&!Foq}*|maplo`>l@(Z&HFN#Q?Vj}r6 z>=OjZ46Rzdd4l5eh zZ$wb7bZo{hCIpHQ{<89JS)zb;R;C|0M)sTj&jtk08ku+U6m`fWLH6^hRq9?vofPdV zd!*)ZEDP-GA-?|=6X$ch{+id{$lLNeg#HHB_-#=D literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModuleFinders.java b/tests/test_data/std/jdk/internal/module/SystemModuleFinders.java new file mode 100644 index 00000000..74af7570 --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/SystemModuleFinders.java @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.module; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.lang.reflect.Constructor; +import java.net.URI; +import java.net.URLConnection; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import jdk.internal.jimage.ImageLocation; +import jdk.internal.jimage.ImageReader; +import jdk.internal.jimage.ImageReaderFactory; +import jdk.internal.access.JavaNetUriAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.util.StaticProperty; +import jdk.internal.module.ModuleHashes.HashSupplier; + +/** + * The factory for SystemModules objects and for creating ModuleFinder objects + * that find modules in the runtime image. + * + * This class supports initializing the module system when the runtime is an + * images build, an exploded build, or an images build with java.base patched + * by an exploded java.base. It also supports a testing mode that re-parses + * the module-info.class resources in the run-time image. + */ + +public final class SystemModuleFinders { + private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess(); + + private static final boolean USE_FAST_PATH; + static { + String value = System.getProperty("jdk.system.module.finder.disableFastPath"); + if (value == null) { + USE_FAST_PATH = true; + } else { + USE_FAST_PATH = !value.isEmpty() && !Boolean.parseBoolean(value); + } + } + + // cached ModuleFinder returned from ofSystem + private static volatile ModuleFinder cachedSystemModuleFinder; + + private SystemModuleFinders() { } + + /** + * Returns the SystemModules object to reconstitute all modules. Returns + * null if this is an exploded build or java.base is patched by an exploded + * build. + */ + static SystemModules allSystemModules() { + if (USE_FAST_PATH) { + return SystemModulesMap.allSystemModules(); + } else { + return null; + } + } + + /** + * Returns a SystemModules object to reconstitute the modules for the + * given initial module. If the initial module is null then return the + * SystemModules object to reconstitute the default modules. + * + * Return null if there is no SystemModules class for the initial module, + * this is an exploded build, or java.base is patched by an exploded build. + */ + static SystemModules systemModules(String initialModule) { + if (USE_FAST_PATH) { + if (initialModule == null) { + return SystemModulesMap.defaultSystemModules(); + } + + String[] initialModules = SystemModulesMap.moduleNames(); + for (int i = 0; i < initialModules.length; i++) { + String moduleName = initialModules[i]; + if (initialModule.equals(moduleName)) { + String cn = SystemModulesMap.classNames()[i]; + try { + // one-arg Class.forName as java.base may not be defined + Constructor ctor = Class.forName(cn).getConstructor(); + return (SystemModules) ctor.newInstance(); + } catch (Exception e) { + throw new InternalError(e); + } + } + } + } + return null; + } + + /** + * Returns a ModuleFinder that is backed by the given SystemModules object. + * + * @apiNote The returned ModuleFinder is thread safe. + */ + static ModuleFinder of(SystemModules systemModules) { + ModuleDescriptor[] descriptors = systemModules.moduleDescriptors(); + ModuleTarget[] targets = systemModules.moduleTargets(); + ModuleHashes[] recordedHashes = systemModules.moduleHashes(); + ModuleResolution[] moduleResolutions = systemModules.moduleResolutions(); + + int moduleCount = descriptors.length; + ModuleReference[] mrefs = new ModuleReference[moduleCount]; + @SuppressWarnings(value = {"rawtypes", "unchecked"}) + Map.Entry[] map + = (Map.Entry[])new Map.Entry[moduleCount]; + + Map nameToHash = generateNameToHash(recordedHashes); + + for (int i = 0; i < moduleCount; i++) { + String name = descriptors[i].name(); + HashSupplier hashSupplier = hashSupplier(nameToHash, name); + ModuleReference mref = toModuleReference(descriptors[i], + targets[i], + recordedHashes[i], + hashSupplier, + moduleResolutions[i]); + mrefs[i] = mref; + map[i] = Map.entry(name, mref); + } + + return new SystemModuleFinder(mrefs, map); + } + + /** + * Returns the ModuleFinder to find all system modules. Supports both + * images and exploded builds. + * + * @apiNote Used by ModuleFinder.ofSystem() + */ + public static ModuleFinder ofSystem() { + ModuleFinder finder = cachedSystemModuleFinder; + if (finder != null) { + return finder; + } + + // probe to see if this is an images build + String home = StaticProperty.javaHome(); + Path modules = Path.of(home, "lib", "modules"); + if (Files.isRegularFile(modules)) { + if (USE_FAST_PATH) { + SystemModules systemModules = allSystemModules(); + if (systemModules != null) { + finder = of(systemModules); + } + } + + // fall back to parsing the module-info.class files in image + if (finder == null) { + finder = ofModuleInfos(); + } + + cachedSystemModuleFinder = finder; + return finder; + + } + + // exploded build (do not cache module finder) + Path dir = Path.of(home, "modules"); + if (!Files.isDirectory(dir)) + throw new InternalError("Unable to detect the run-time image"); + ModuleFinder f = ModulePath.of(ModuleBootstrap.patcher(), dir); + return new ModuleFinder() { + @SuppressWarnings("removal") + @Override + public Optional find(String name) { + PrivilegedAction> pa = () -> f.find(name); + return AccessController.doPrivileged(pa); + } + @SuppressWarnings("removal") + @Override + public Set findAll() { + PrivilegedAction> pa = f::findAll; + return AccessController.doPrivileged(pa); + } + }; + } + + /** + * Parses the module-info.class of all module in the runtime image and + * returns a ModuleFinder to find the modules. + * + * @apiNote The returned ModuleFinder is thread safe. + */ + private static ModuleFinder ofModuleInfos() { + // parse the module-info.class in every module + Map nameToAttributes = new HashMap<>(); + Map nameToHash = new HashMap<>(); + ImageReader reader = SystemImage.reader(); + for (String mn : reader.getModuleNames()) { + ImageLocation loc = reader.findLocation(mn, "module-info.class"); + ModuleInfo.Attributes attrs + = ModuleInfo.read(reader.getResourceBuffer(loc), null); + + nameToAttributes.put(mn, attrs); + ModuleHashes hashes = attrs.recordedHashes(); + if (hashes != null) { + for (String name : hashes.names()) { + nameToHash.computeIfAbsent(name, k -> hashes.hashFor(name)); + } + } + } + + // create a ModuleReference for each module + Set mrefs = new HashSet<>(); + Map nameToModule = new HashMap<>(); + for (Map.Entry e : nameToAttributes.entrySet()) { + String mn = e.getKey(); + ModuleInfo.Attributes attrs = e.getValue(); + HashSupplier hashSupplier = hashSupplier(nameToHash, mn); + ModuleReference mref = toModuleReference(attrs.descriptor(), + attrs.target(), + attrs.recordedHashes(), + hashSupplier, + attrs.moduleResolution()); + mrefs.add(mref); + nameToModule.put(mn, mref); + } + + return new SystemModuleFinder(mrefs, nameToModule); + } + + /** + * A ModuleFinder that finds module in an array or set of modules. + */ + private static class SystemModuleFinder implements ModuleFinder { + final Set mrefs; + final Map nameToModule; + + SystemModuleFinder(ModuleReference[] array, + Map.Entry[] map) { + this.mrefs = Set.of(array); + this.nameToModule = Map.ofEntries(map); + } + + SystemModuleFinder(Set mrefs, + Map nameToModule) { + this.mrefs = Set.copyOf(mrefs); + this.nameToModule = Map.copyOf(nameToModule); + } + + @Override + public Optional find(String name) { + Objects.requireNonNull(name); + return Optional.ofNullable(nameToModule.get(name)); + } + + @Override + public Set findAll() { + return mrefs; + } + } + + /** + * Creates a ModuleReference to the system module. + */ + static ModuleReference toModuleReference(ModuleDescriptor descriptor, + ModuleTarget target, + ModuleHashes recordedHashes, + HashSupplier hasher, + ModuleResolution mres) { + String mn = descriptor.name(); + URI uri = JNUA.create("jrt", "/".concat(mn)); + + Supplier readerSupplier = new Supplier<>() { + @Override + public ModuleReader get() { + return new SystemModuleReader(mn, uri); + } + }; + + ModuleReference mref = new ModuleReferenceImpl(descriptor, + uri, + readerSupplier, + null, + target, + recordedHashes, + hasher, + mres); + + // may need a reference to a patched module if --patch-module specified + mref = ModuleBootstrap.patcher().patchIfNeeded(mref); + + return mref; + } + + /** + * Generates a map of module name to hash value. + */ + static Map generateNameToHash(ModuleHashes[] recordedHashes) { + Map nameToHash = null; + + boolean secondSeen = false; + // record the hashes to build HashSupplier + for (ModuleHashes mh : recordedHashes) { + if (mh != null) { + // if only one module contain ModuleHashes, use it + if (nameToHash == null) { + nameToHash = mh.hashes(); + } else { + if (!secondSeen) { + nameToHash = new HashMap<>(nameToHash); + secondSeen = true; + } + nameToHash.putAll(mh.hashes()); + } + } + } + return (nameToHash != null) ? nameToHash : Map.of(); + } + + /** + * Returns a HashSupplier that returns the hash of the given module. + */ + static HashSupplier hashSupplier(Map nameToHash, String name) { + byte[] hash = nameToHash.get(name); + if (hash != null) { + // avoid lambda here + return new HashSupplier() { + @Override + public byte[] generate(String algorithm) { + return hash; + } + }; + } else { + return null; + } + } + + /** + * Holder class for the ImageReader + * + * @apiNote This class must be loaded before a security manager is set. + */ + private static class SystemImage { + static final ImageReader READER = ImageReaderFactory.getImageReader(); + static ImageReader reader() { + return READER; + } + } + + /** + * A ModuleReader for reading resources from a module linked into the + * run-time image. + */ + private static class SystemModuleReader implements ModuleReader { + private final String module; + private volatile boolean closed; + + /** + * If there is a security manager set then check permission to + * connect to the run-time image. + */ + private static void checkPermissionToConnect(URI uri) { + @SuppressWarnings("removal") + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + URLConnection uc = uri.toURL().openConnection(); + sm.checkPermission(uc.getPermission()); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + } + + SystemModuleReader(String module, URI uri) { + checkPermissionToConnect(uri); + this.module = module; + } + + /** + * Returns the ImageLocation for the given resource, {@code null} + * if not found. + */ + private ImageLocation findImageLocation(String name) throws IOException { + Objects.requireNonNull(name); + if (closed) + throw new IOException("ModuleReader is closed"); + ImageReader imageReader = SystemImage.reader(); + if (imageReader != null) { + return imageReader.findLocation(module, name); + } else { + // not an images build + return null; + } + } + + /** + * Returns {@code true} if the given resource exists, {@code false} + * if not found. + */ + private boolean containsImageLocation(String name) throws IOException { + Objects.requireNonNull(name); + if (closed) + throw new IOException("ModuleReader is closed"); + ImageReader imageReader = SystemImage.reader(); + if (imageReader != null) { + return imageReader.verifyLocation(module, name); + } else { + // not an images build + return false; + } + } + + @Override + public Optional find(String name) throws IOException { + if (containsImageLocation(name)) { + URI u = JNUA.create("jrt", "/" + module + "/" + name); + return Optional.of(u); + } else { + return Optional.empty(); + } + } + + @Override + public Optional open(String name) throws IOException { + return read(name).map(this::toInputStream); + } + + private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer? + try { + int rem = bb.remaining(); + byte[] bytes = new byte[rem]; + bb.get(bytes); + return new ByteArrayInputStream(bytes); + } finally { + release(bb); + } + } + + @Override + public Optional read(String name) throws IOException { + ImageLocation location = findImageLocation(name); + if (location != null) { + return Optional.of(SystemImage.reader().getResourceBuffer(location)); + } else { + return Optional.empty(); + } + } + + @Override + public void release(ByteBuffer bb) { + Objects.requireNonNull(bb); + ImageReader.releaseByteBuffer(bb); + } + + @Override + public Stream list() throws IOException { + if (closed) + throw new IOException("ModuleReader is closed"); + + Spliterator s = new ModuleContentSpliterator(module); + return StreamSupport.stream(s, false); + } + + @Override + public void close() { + // nothing else to do + closed = true; + } + } + + /** + * A Spliterator for traversing the resources of a module linked into the + * run-time image. + */ + private static class ModuleContentSpliterator implements Spliterator { + final String moduleRoot; + final Deque stack; + Iterator iterator; + + ModuleContentSpliterator(String module) throws IOException { + moduleRoot = "/modules/" + module; + stack = new ArrayDeque<>(); + + // push the root node to the stack to get started + ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot); + if (dir == null || !dir.isDirectory()) + throw new IOException(moduleRoot + " not a directory"); + stack.push(dir); + iterator = Collections.emptyIterator(); + } + + /** + * Returns the name of the next non-directory node or {@code null} if + * there are no remaining nodes to visit. + */ + private String next() throws IOException { + for (;;) { + while (iterator.hasNext()) { + ImageReader.Node node = iterator.next(); + String name = node.getName(); + if (node.isDirectory()) { + // build node + ImageReader.Node dir = SystemImage.reader().findNode(name); + assert dir.isDirectory(); + stack.push(dir); + } else { + // strip /modules/$MODULE/ prefix + return name.substring(moduleRoot.length() + 1); + } + } + + if (stack.isEmpty()) { + return null; + } else { + ImageReader.Node dir = stack.poll(); + assert dir.isDirectory(); + iterator = dir.getChildren().iterator(); + } + } + } + + @Override + public boolean tryAdvance(Consumer action) { + String next; + try { + next = next(); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + if (next != null) { + action.accept(next); + return true; + } else { + return false; + } + } + + @Override + public Spliterator trySplit() { + return null; + } + + @Override + public int characteristics() { + return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE; + } + + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } + } +} diff --git a/tests/test_data/std/jdk/internal/module/SystemModules$0.class b/tests/test_data/std/jdk/internal/module/SystemModules$0.class new file mode 100644 index 0000000000000000000000000000000000000000..fa550fd65e8c169e0a6baaec92b5935d60d94c30 GIT binary patch literal 69880 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

    Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a + * single element_value by definition), this ByteVector is initially empty when passed to the + * constructor, and {@link #numElementValuePairsOffset} is set to -1. + */ + private final ByteVector annotation; + + /** + * The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for + * the case of AnnotationDefault attributes). + */ + private final int numElementValuePairsOffset; + + /** The number of element value pairs visited so far. */ + private int numElementValuePairs; + + /** + * The previous AnnotationWriter. This field is used to store the list of annotations of a + * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations + * (annotation values of annotation type), or for AnnotationDefault attributes. + */ + private final AnnotationWriter previousAnnotation; + + /** + * The next AnnotationWriter. This field is used to store the list of annotations of a + * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations + * (annotation values of annotation type), or for AnnotationDefault attributes. + */ + private AnnotationWriter nextAnnotation; + + // ----------------------------------------------------------------------------------------------- + // Constructors and factories + // ----------------------------------------------------------------------------------------------- + + /** + * Constructs a new {@link AnnotationWriter}. + * + * @param symbolTable where the constants used in this AnnotationWriter must be stored. + * @param useNamedValues whether values are named or not. AnnotationDefault and annotation arrays + * use unnamed values. + * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to + * the visited content must be stored. This ByteVector must already contain all the fields of + * the structure except the last one (the element_value_pairs array). + * @param previousAnnotation the previously visited annotation of the + * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or + * {@literal null} in other cases (e.g. nested or array annotations). + */ + AnnotationWriter( + final SymbolTable symbolTable, + final boolean useNamedValues, + final ByteVector annotation, + final AnnotationWriter previousAnnotation) { + super(/* latest api = */ Opcodes.ASM9); + this.symbolTable = symbolTable; + this.useNamedValues = useNamedValues; + this.annotation = annotation; + // By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'. + this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2; + this.previousAnnotation = previousAnnotation; + if (previousAnnotation != null) { + previousAnnotation.nextAnnotation = this; + } + } + + /** + * Creates a new {@link AnnotationWriter} using named values. + * + * @param symbolTable where the constants used in this AnnotationWriter must be stored. + * @param descriptor the class descriptor of the annotation class. + * @param previousAnnotation the previously visited annotation of the + * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or + * {@literal null} in other cases (e.g. nested or array annotations). + * @return a new {@link AnnotationWriter} for the given annotation descriptor. + */ + static AnnotationWriter create( + final SymbolTable symbolTable, + final String descriptor, + final AnnotationWriter previousAnnotation) { + // Create a ByteVector to hold an 'annotation' JVMS structure. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. + ByteVector annotation = new ByteVector(); + // Write type_index and reserve space for num_element_value_pairs. + annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); + return new AnnotationWriter( + symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation); + } + + /** + * Creates a new {@link AnnotationWriter} using named values. + * + * @param symbolTable where the constants used in this AnnotationWriter must be stored. + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link + * TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See + * {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param descriptor the class descriptor of the annotation class. + * @param previousAnnotation the previously visited annotation of the + * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or + * {@literal null} in other cases (e.g. nested or array annotations). + * @return a new {@link AnnotationWriter} for the given type annotation reference and descriptor. + */ + static AnnotationWriter create( + final SymbolTable symbolTable, + final int typeRef, + final TypePath typePath, + final String descriptor, + final AnnotationWriter previousAnnotation) { + // Create a ByteVector to hold a 'type_annotation' JVMS structure. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. + ByteVector typeAnnotation = new ByteVector(); + // Write target_type, target_info, and target_path. + TypeReference.putTarget(typeRef, typeAnnotation); + TypePath.put(typePath, typeAnnotation); + // Write type_index and reserve space for num_element_value_pairs. + typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); + return new AnnotationWriter( + symbolTable, /* useNamedValues = */ true, typeAnnotation, previousAnnotation); + } + + // ----------------------------------------------------------------------------------------------- + // Implementation of the AnnotationVisitor abstract class + // ----------------------------------------------------------------------------------------------- + + @Override + public void visit(final String name, final Object value) { + // Case of an element_value with a const_value_index, class_info_index or array_index field. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. + ++numElementValuePairs; + if (useNamedValues) { + annotation.putShort(symbolTable.addConstantUtf8(name)); + } + if (value instanceof String) { + annotation.put12('s', symbolTable.addConstantUtf8((String) value)); + } else if (value instanceof Byte) { + annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index); + } else if (value instanceof Boolean) { + int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0; + annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index); + } else if (value instanceof Character) { + annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index); + } else if (value instanceof Short) { + annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index); + } else if (value instanceof Type) { + annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor())); + } else if (value instanceof byte[]) { + byte[] byteArray = (byte[]) value; + annotation.put12('[', byteArray.length); + for (byte byteValue : byteArray) { + annotation.put12('B', symbolTable.addConstantInteger(byteValue).index); + } + } else if (value instanceof boolean[]) { + boolean[] booleanArray = (boolean[]) value; + annotation.put12('[', booleanArray.length); + for (boolean booleanValue : booleanArray) { + annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index); + } + } else if (value instanceof short[]) { + short[] shortArray = (short[]) value; + annotation.put12('[', shortArray.length); + for (short shortValue : shortArray) { + annotation.put12('S', symbolTable.addConstantInteger(shortValue).index); + } + } else if (value instanceof char[]) { + char[] charArray = (char[]) value; + annotation.put12('[', charArray.length); + for (char charValue : charArray) { + annotation.put12('C', symbolTable.addConstantInteger(charValue).index); + } + } else if (value instanceof int[]) { + int[] intArray = (int[]) value; + annotation.put12('[', intArray.length); + for (int intValue : intArray) { + annotation.put12('I', symbolTable.addConstantInteger(intValue).index); + } + } else if (value instanceof long[]) { + long[] longArray = (long[]) value; + annotation.put12('[', longArray.length); + for (long longValue : longArray) { + annotation.put12('J', symbolTable.addConstantLong(longValue).index); + } + } else if (value instanceof float[]) { + float[] floatArray = (float[]) value; + annotation.put12('[', floatArray.length); + for (float floatValue : floatArray) { + annotation.put12('F', symbolTable.addConstantFloat(floatValue).index); + } + } else if (value instanceof double[]) { + double[] doubleArray = (double[]) value; + annotation.put12('[', doubleArray.length); + for (double doubleValue : doubleArray) { + annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index); + } + } else { + Symbol symbol = symbolTable.addConstant(value); + annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index); + } + } + + @Override + public void visitEnum(final String name, final String descriptor, final String value) { + // Case of an element_value with an enum_const_value field. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. + ++numElementValuePairs; + if (useNamedValues) { + annotation.putShort(symbolTable.addConstantUtf8(name)); + } + annotation + .put12('e', symbolTable.addConstantUtf8(descriptor)) + .putShort(symbolTable.addConstantUtf8(value)); + } + + @Override + public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { + // Case of an element_value with an annotation_value field. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. + ++numElementValuePairs; + if (useNamedValues) { + annotation.putShort(symbolTable.addConstantUtf8(name)); + } + // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs. + annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0); + return new AnnotationWriter(symbolTable, /* useNamedValues = */ true, annotation, null); + } + + @Override + public AnnotationVisitor visitArray(final String name) { + // Case of an element_value with an array_value field. + // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1 + ++numElementValuePairs; + if (useNamedValues) { + annotation.putShort(symbolTable.addConstantUtf8(name)); + } + // Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the + // end of an element_value of array type is similar to the end of an 'annotation' structure: an + // unsigned short num_values followed by num_values element_value, versus an unsigned short + // num_element_value_pairs, followed by num_element_value_pairs { element_name_index, + // element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to + // visit the array elements. Its num_element_value_pairs will correspond to the number of array + // elements and will be stored in what is in fact num_values. + annotation.put12('[', 0); + return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null); + } + + @Override + public void visitEnd() { + if (numElementValuePairsOffset != -1) { + byte[] data = annotation.data; + data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8); + data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs; + } + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the size of a Runtime[In]Visible[Type]Annotations attribute containing this annotation + * and all its predecessors (see {@link #previousAnnotation}. Also adds the attribute name + * to the constant pool of the class (if not null). + * + * @param attributeName one of "Runtime[In]Visible[Type]Annotations", or {@literal null}. + * @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this + * annotation and all its predecessors. This includes the size of the attribute_name_index and + * attribute_length fields. + */ + int computeAnnotationsSize(final String attributeName) { + if (attributeName != null) { + symbolTable.addConstantUtf8(attributeName); + } + // The attribute_name_index, attribute_length and num_annotations fields use 8 bytes. + int attributeSize = 8; + AnnotationWriter annotationWriter = this; + while (annotationWriter != null) { + attributeSize += annotationWriter.annotation.length; + annotationWriter = annotationWriter.previousAnnotation; + } + return attributeSize; + } + + /** + * Returns the size of the Runtime[In]Visible[Type]Annotations attributes containing the given + * annotations and all their predecessors (see {@link #previousAnnotation}. Also adds the + * attribute names to the constant pool of the class (if not null). + * + * @param lastRuntimeVisibleAnnotation The last runtime visible annotation of a field, method or + * class. The previous ones can be accessed with the {@link #previousAnnotation} field. May be + * {@literal null}. + * @param lastRuntimeInvisibleAnnotation The last runtime invisible annotation of this a field, + * method or class. The previous ones can be accessed with the {@link #previousAnnotation} + * field. May be {@literal null}. + * @param lastRuntimeVisibleTypeAnnotation The last runtime visible type annotation of this a + * field, method or class. The previous ones can be accessed with the {@link + * #previousAnnotation} field. May be {@literal null}. + * @param lastRuntimeInvisibleTypeAnnotation The last runtime invisible type annotation of a + * field, method or class field. The previous ones can be accessed with the {@link + * #previousAnnotation} field. May be {@literal null}. + * @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing the + * given annotations and all their predecessors. This includes the size of the + * attribute_name_index and attribute_length fields. + */ + static int computeAnnotationsSize( + final AnnotationWriter lastRuntimeVisibleAnnotation, + final AnnotationWriter lastRuntimeInvisibleAnnotation, + final AnnotationWriter lastRuntimeVisibleTypeAnnotation, + final AnnotationWriter lastRuntimeInvisibleTypeAnnotation) { + int size = 0; + if (lastRuntimeVisibleAnnotation != null) { + size += + lastRuntimeVisibleAnnotation.computeAnnotationsSize( + Constants.RUNTIME_VISIBLE_ANNOTATIONS); + } + if (lastRuntimeInvisibleAnnotation != null) { + size += + lastRuntimeInvisibleAnnotation.computeAnnotationsSize( + Constants.RUNTIME_INVISIBLE_ANNOTATIONS); + } + if (lastRuntimeVisibleTypeAnnotation != null) { + size += + lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + } + if (lastRuntimeInvisibleTypeAnnotation != null) { + size += + lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + } + return size; + } + + /** + * Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its + * predecessors (see {@link #previousAnnotation} in the given ByteVector. Annotations are + * put in the same order they have been visited. + * + * @param attributeNameIndex the constant pool index of the attribute name (one of + * "Runtime[In]Visible[Type]Annotations"). + * @param output where the attribute must be put. + */ + void putAnnotations(final int attributeNameIndex, final ByteVector output) { + int attributeLength = 2; // For num_annotations. + int numAnnotations = 0; + AnnotationWriter annotationWriter = this; + AnnotationWriter firstAnnotation = null; + while (annotationWriter != null) { + // In case the user forgot to call visitEnd(). + annotationWriter.visitEnd(); + attributeLength += annotationWriter.annotation.length; + numAnnotations++; + firstAnnotation = annotationWriter; + annotationWriter = annotationWriter.previousAnnotation; + } + output.putShort(attributeNameIndex); + output.putInt(attributeLength); + output.putShort(numAnnotations); + annotationWriter = firstAnnotation; + while (annotationWriter != null) { + output.putByteArray(annotationWriter.annotation.data, 0, annotationWriter.annotation.length); + annotationWriter = annotationWriter.nextAnnotation; + } + } + + /** + * Puts the Runtime[In]Visible[Type]Annotations attributes containing the given annotations and + * all their predecessors (see {@link #previousAnnotation} in the given ByteVector. + * Annotations are put in the same order they have been visited. + * + * @param symbolTable where the constants used in the AnnotationWriter instances are stored. + * @param lastRuntimeVisibleAnnotation The last runtime visible annotation of a field, method or + * class. The previous ones can be accessed with the {@link #previousAnnotation} field. May be + * {@literal null}. + * @param lastRuntimeInvisibleAnnotation The last runtime invisible annotation of this a field, + * method or class. The previous ones can be accessed with the {@link #previousAnnotation} + * field. May be {@literal null}. + * @param lastRuntimeVisibleTypeAnnotation The last runtime visible type annotation of this a + * field, method or class. The previous ones can be accessed with the {@link + * #previousAnnotation} field. May be {@literal null}. + * @param lastRuntimeInvisibleTypeAnnotation The last runtime invisible type annotation of a + * field, method or class field. The previous ones can be accessed with the {@link + * #previousAnnotation} field. May be {@literal null}. + * @param output where the attributes must be put. + */ + static void putAnnotations( + final SymbolTable symbolTable, + final AnnotationWriter lastRuntimeVisibleAnnotation, + final AnnotationWriter lastRuntimeInvisibleAnnotation, + final AnnotationWriter lastRuntimeVisibleTypeAnnotation, + final AnnotationWriter lastRuntimeInvisibleTypeAnnotation, + final ByteVector output) { + if (lastRuntimeVisibleAnnotation != null) { + lastRuntimeVisibleAnnotation.putAnnotations( + symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output); + } + if (lastRuntimeInvisibleAnnotation != null) { + lastRuntimeInvisibleAnnotation.putAnnotations( + symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output); + } + if (lastRuntimeVisibleTypeAnnotation != null) { + lastRuntimeVisibleTypeAnnotation.putAnnotations( + symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output); + } + if (lastRuntimeInvisibleTypeAnnotation != null) { + lastRuntimeInvisibleTypeAnnotation.putAnnotations( + symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output); + } + } + + /** + * Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the + * annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the + * constant pool of the class. + * + * @param attributeName one of "Runtime[In]VisibleParameterAnnotations". + * @param annotationWriters an array of AnnotationWriter lists (designated by their last + * element). + * @param annotableParameterCount the number of elements in annotationWriters to take into account + * (elements [0..annotableParameterCount[ are taken into account). + * @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding + * to the given sub-array of AnnotationWriter lists. This includes the size of the + * attribute_name_index and attribute_length fields. + */ + static int computeParameterAnnotationsSize( + final String attributeName, + final AnnotationWriter[] annotationWriters, + final int annotableParameterCount) { + // Note: attributeName is added to the constant pool by the call to computeAnnotationsSize + // below. This assumes that there is at least one non-null element in the annotationWriters + // sub-array (which is ensured by the lazy instantiation of this array in MethodWriter). + // The attribute_name_index, attribute_length and num_parameters fields use 7 bytes, and each + // element of the parameter_annotations array uses 2 bytes for its num_annotations field. + int attributeSize = 7 + 2 * annotableParameterCount; + for (int i = 0; i < annotableParameterCount; ++i) { + AnnotationWriter annotationWriter = annotationWriters[i]; + attributeSize += + annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(attributeName) - 8; + } + return attributeSize; + } + + /** + * Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists + * from the given AnnotationWriter sub-array in the given ByteVector. + * + * @param attributeNameIndex constant pool index of the attribute name (one of + * Runtime[In]VisibleParameterAnnotations). + * @param annotationWriters an array of AnnotationWriter lists (designated by their last + * element). + * @param annotableParameterCount the number of elements in annotationWriters to put (elements + * [0..annotableParameterCount[ are put). + * @param output where the attribute must be put. + */ + static void putParameterAnnotations( + final int attributeNameIndex, + final AnnotationWriter[] annotationWriters, + final int annotableParameterCount, + final ByteVector output) { + // The num_parameters field uses 1 byte, and each element of the parameter_annotations array + // uses 2 bytes for its num_annotations field. + int attributeLength = 1 + 2 * annotableParameterCount; + for (int i = 0; i < annotableParameterCount; ++i) { + AnnotationWriter annotationWriter = annotationWriters[i]; + attributeLength += + annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8; + } + output.putShort(attributeNameIndex); + output.putInt(attributeLength); + output.putByte(annotableParameterCount); + for (int i = 0; i < annotableParameterCount; ++i) { + AnnotationWriter annotationWriter = annotationWriters[i]; + AnnotationWriter firstAnnotation = null; + int numAnnotations = 0; + while (annotationWriter != null) { + // In case user the forgot to call visitEnd(). + annotationWriter.visitEnd(); + numAnnotations++; + firstAnnotation = annotationWriter; + annotationWriter = annotationWriter.previousAnnotation; + } + output.putShort(numAnnotations); + annotationWriter = firstAnnotation; + while (annotationWriter != null) { + output.putByteArray( + annotationWriter.annotation.data, 0, annotationWriter.annotation.length); + annotationWriter = annotationWriter.nextAnnotation; + } + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Attribute$Set.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Attribute$Set.class new file mode 100644 index 0000000000000000000000000000000000000000..29fe87c1b0db16bfde6da9037767cf7a159363a8 GIT binary patch literal 1679 zcmb7FO>Y}j6g}7Dcw%?rnuZ3GxM?YE6Mr;@@=fAGaD%WE2MI@!2n+gbkHVzROqdx{ z!U8r$d%fRq-5M3*f16|DIQ2vN=(yH;9t;Vz!vyKnBh=bU@*d;ask z-);h^Vkw0f3=?q+BS;7`o9Z1^?kIPo{AzR4ZiRxxg5x^jX@N1DUo$Z(C~daSl^r*< zeOGnLp1)D{BH#0Nv#f%x@?seJPO}@@#~OBMA|;p|_CyjUEDK{u3*v1RDnap$%aA%un2ljY2SW$O_`7NMmqGaJD=I(@#9M~=P+g;UR&JW%LJHIYS zH)`ukZ`M|-uPxP=R#us!s^F&%>DmU{l6@GjdTmnJzwEg7N_VSi`>U$iiAZ@Z z)mc-%qwW4?JbcR`x*)3E29{fz5A?P_@q0)pj4#48292 zY26+9`)E<7$hU)ThvCH$n67>POw{M8hS&95_REfznI6!Z(-mYluh>EOilnPtyXP!9+jO`}EYs%N6UTKaeeyZeag67}fK5 zX%`RGuipAw$2Fq3lSnY`M~KPCEcYk8?w?{@KEsrJ9^oA6#Tww`@GO-HF(&aGM-0z1 zRtmQ!Y-yLX_@mrqiAUJR~#<>#BV))X^kUa@KyVg*Zr#q zd!l!?k3EVED$Jb5=DX5I_>h)XJ7ZLGI_ecnYmD5fT^uiR+(7;kM&j2l#N_I&zl>{i z?FpaI1(2`#C|<-NxrD=9AD3?jqGP<+r&%yfe`X+mCK4@sL`&|UNF-mWKBbGaHKmH? zqsiR7jHA(UwRIZYQBoVxjd`;dT12$Io8JRIzb)g}#F&mywk#I3eGoC_i99 tejJd^VjM3pH=1l^K(?}ntN|&K)r)k9VG%DybCQ2Nx_InN{#z{Pg0c49AA`Qm4 zY2v1ClfKhsc5SlAri=Fb2=3Q3ZCCl4v|kt9_Oo+hk$yOd<~CYfooKwIAzJ^A_VHqnYU0lnZdGlwNa=Ef3u5PNi_OmxWa zGIhd@m#j+VtZgmWWq}6@^6BYf$sSu_d-);}L;a-`tpAey@o>qy-ur z`?^;{KxU$jZ?JRlA0wSm5 zl)!;HV4qnnxC?egRyuCtG@fFmOSU&@U2)4ZcDYh?9o50~_Duc0-3F*)AV)RlHym%- z_KF1qUzLx=CCBpC%C^SgL71illBey}vR$w|dqDy>ZQ^;Hr3R^-s&E8estaHZ<-TZk zfM0q>cEmXo=P@H-Fm`^~Ewld*_2tq#@FTr^&BO)iB~C9n$CK2|nYbipM|8pRENSzi ziI;F$z@&|&@sw2sXyk+O-RV^6KE%-dzvH*#LO1*Av(_y{wciB_Azw_zB#qOPEr;KPiWE zxw-M&eTJxuPgn%A@q2%J9^YT@2RV^KcX6>|QwGVxvQ_p+xO^v!3+$Fn69zgH*u_io zWkbMv@3R)dY}LH!q*ED&v4VeXQ1+A7 zYCw9nE)})ClV;!Us#GWNeN4>S?G!+TV_wHM>rd&LnJ2|xPhquTVn^lzfQE2VFuMeF_*I#YVpeG9Pxeo9P#MvUJ<58hRw&id{`lzLIZipsAS4xUsP z_R2GZLbw+$R+Xn-yv((jOa*0B5U1x3c*L5geR-@25?&1{0Y19XO+@k-${^CgzGmLio=Vdl%+=S zb^79OoX-&zI*dj%@l^Xtki<=Tm!-FgNo^!D7>x|ZGW`QuB(jA}RW$7i#J|$l-{|-6 zgzq2p_|F>!(evAP7a8Kp=L4aK!V zJu_sajE|7*PZ<=_7LLuf=}qyJk%|v=w?*4xTR5?alb0_K>eArAkn!H#zqIL9^!6+1 ze99U>qvy{_#2w;t7oAl1Q6cbz&{P$d{J3Eiqd^tSB_wt+fJ(DG*yxT?K3)UXd=PSa@6VZ znHmu`$}zw{FK$wUpK=lz*z@&JkMv+sY vBBw${P6di&zN%(lkuhj{+uK;k_gF{--^UMljk3TW;>Wy8syhR3Vb6a6Z(|}| literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Attribute.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/Attribute.java new file mode 100644 index 00000000..9c5ce91e --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/Attribute.java @@ -0,0 +1,424 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A non standard class, field, method or Code attribute, as defined in the Java Virtual Machine + * Specification (JVMS). + * + * @see JVMS + * 4.7 + * @see JVMS + * 4.7.3 + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class Attribute { + + /** The type of this attribute, also called its name in the JVMS. */ + public final String type; + + /** + * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}). + * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are not + * included. + */ + private byte[] content; + + /** + * The next attribute in this attribute list (Attribute instances can be linked via this field to + * store a list of class, field, method or Code attributes). May be {@literal null}. + */ + Attribute nextAttribute; + + /** + * Constructs a new empty attribute. + * + * @param type the type of the attribute. + */ + protected Attribute(final String type) { + this.type = type; + } + + /** + * Returns {@literal true} if this type of attribute is unknown. This means that the attribute + * content can't be parsed to extract constant pool references, labels, etc. Instead, the + * attribute content is read as an opaque byte array, and written back as is. This can lead to + * invalid attributes, if the content actually contains constant pool references, labels, or other + * symbolic references that need to be updated when there are changes to the constant pool, the + * method bytecode, etc. The default implementation of this method always returns {@literal true}. + * + * @return {@literal true} if this type of attribute is unknown. + */ + public boolean isUnknown() { + return true; + } + + /** + * Returns {@literal true} if this type of attribute is a Code attribute. + * + * @return {@literal true} if this type of attribute is a Code attribute. + */ + public boolean isCodeAttribute() { + return false; + } + + /** + * Returns the labels corresponding to this attribute. + * + * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not + * a Code attribute that contains labels. + */ + protected Label[] getLabels() { + return new Label[0]; + } + + /** + * Reads a {@link #type} attribute. This method must return a new {@link Attribute} object, + * of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given + * ClassReader. + * + * @param classReader the class that contains the attribute to be read. + * @param offset index of the first byte of the attribute's content in {@link ClassReader}. The 6 + * attribute header bytes (attribute_name_index and attribute_length) are not taken into + * account here. + * @param length the length of the attribute's content (excluding the 6 attribute header bytes). + * @param charBuffer the buffer to be used to call the ClassReader methods requiring a + * 'charBuffer' parameter. + * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute + * in {@link ClassReader}, or -1 if the attribute to be read is not a Code attribute. The 6 + * attribute header bytes (attribute_name_index and attribute_length) are not taken into + * account here. + * @param labels the labels of the method's code, or {@literal null} if the attribute to be read + * is not a Code attribute. + * @return a new {@link Attribute} object corresponding to the specified bytes. + */ + protected Attribute read( + final ClassReader classReader, + final int offset, + final int length, + final char[] charBuffer, + final int codeAttributeOffset, + final Label[] labels) { + Attribute attribute = new Attribute(type); + attribute.content = new byte[length]; + System.arraycopy(classReader.classFileBuffer, offset, attribute.content, 0, length); + return attribute; + } + + /** + * Returns the byte array form of the content of this attribute. The 6 header bytes + * (attribute_name_index and attribute_length) must not be added in the returned + * ByteVector. + * + * @param classWriter the class to which this attribute must be added. This parameter can be used + * to add the items that corresponds to this attribute to the constant pool of this class. + * @param code the bytecode of the method corresponding to this Code attribute, or {@literal null} + * if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code + * attribute. + * @param codeLength the length of the bytecode of the method corresponding to this code + * attribute, or 0 if this attribute is not a Code attribute. Corresponds to the 'code_length' + * field of the Code attribute. + * @param maxStack the maximum stack size of the method corresponding to this Code attribute, or + * -1 if this attribute is not a Code attribute. + * @param maxLocals the maximum number of local variables of the method corresponding to this code + * attribute, or -1 if this attribute is not a Code attribute. + * @return the byte array form of this attribute. + */ + protected ByteVector write( + final ClassWriter classWriter, + final byte[] code, + final int codeLength, + final int maxStack, + final int maxLocals) { + return new ByteVector(content); + } + + /** + * Returns the number of attributes of the attribute list that begins with this attribute. + * + * @return the number of attributes of the attribute list that begins with this attribute. + */ + final int getAttributeCount() { + int count = 0; + Attribute attribute = this; + while (attribute != null) { + count += 1; + attribute = attribute.nextAttribute; + } + return count; + } + + /** + * Returns the total size in bytes of all the attributes in the attribute list that begins with + * this attribute. This size includes the 6 header bytes (attribute_name_index and + * attribute_length) per attribute. Also adds the attribute type names to the constant pool. + * + * @param symbolTable where the constants used in the attributes must be stored. + * @return the size of all the attributes in this attribute list. This size includes the size of + * the attribute headers. + */ + final int computeAttributesSize(final SymbolTable symbolTable) { + final byte[] code = null; + final int codeLength = 0; + final int maxStack = -1; + final int maxLocals = -1; + return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals); + } + + /** + * Returns the total size in bytes of all the attributes in the attribute list that begins with + * this attribute. This size includes the 6 header bytes (attribute_name_index and + * attribute_length) per attribute. Also adds the attribute type names to the constant pool. + * + * @param symbolTable where the constants used in the attributes must be stored. + * @param code the bytecode of the method corresponding to these Code attributes, or {@literal + * null} if they are not Code attributes. Corresponds to the 'code' field of the Code + * attribute. + * @param codeLength the length of the bytecode of the method corresponding to these code + * attributes, or 0 if they are not Code attributes. Corresponds to the 'code_length' field of + * the Code attribute. + * @param maxStack the maximum stack size of the method corresponding to these Code attributes, or + * -1 if they are not Code attributes. + * @param maxLocals the maximum number of local variables of the method corresponding to these + * Code attributes, or -1 if they are not Code attribute. + * @return the size of all the attributes in this attribute list. This size includes the size of + * the attribute headers. + */ + final int computeAttributesSize( + final SymbolTable symbolTable, + final byte[] code, + final int codeLength, + final int maxStack, + final int maxLocals) { + final ClassWriter classWriter = symbolTable.classWriter; + int size = 0; + Attribute attribute = this; + while (attribute != null) { + symbolTable.addConstantUtf8(attribute.type); + size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length; + attribute = attribute.nextAttribute; + } + return size; + } + + /** + * Returns the total size in bytes of all the attributes that correspond to the given field, + * method or class access flags and signature. This size includes the 6 header bytes + * (attribute_name_index and attribute_length) per attribute. Also adds the attribute type names + * to the constant pool. + * + * @param symbolTable where the constants used in the attributes must be stored. + * @param accessFlags some field, method or class access flags. + * @param signatureIndex the constant pool index of a field, method of class signature. + * @return the size of all the attributes in bytes. This size includes the size of the attribute + * headers. + */ + static int computeAttributesSize( + final SymbolTable symbolTable, final int accessFlags, final int signatureIndex) { + int size = 0; + // Before Java 1.5, synthetic fields are represented with a Synthetic attribute. + if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 + && symbolTable.getMajorVersion() < Opcodes.V1_5) { + // Synthetic attributes always use 6 bytes. + symbolTable.addConstantUtf8(Constants.SYNTHETIC); + size += 6; + } + if (signatureIndex != 0) { + // Signature attributes always use 8 bytes. + symbolTable.addConstantUtf8(Constants.SIGNATURE); + size += 8; + } + // ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead. + if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { + // Deprecated attributes always use 6 bytes. + symbolTable.addConstantUtf8(Constants.DEPRECATED); + size += 6; + } + return size; + } + + /** + * Puts all the attributes of the attribute list that begins with this attribute, in the given + * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per + * attribute. + * + * @param symbolTable where the constants used in the attributes must be stored. + * @param output where the attributes must be written. + */ + final void putAttributes(final SymbolTable symbolTable, final ByteVector output) { + final byte[] code = null; + final int codeLength = 0; + final int maxStack = -1; + final int maxLocals = -1; + putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output); + } + + /** + * Puts all the attributes of the attribute list that begins with this attribute, in the given + * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per + * attribute. + * + * @param symbolTable where the constants used in the attributes must be stored. + * @param code the bytecode of the method corresponding to these Code attributes, or {@literal + * null} if they are not Code attributes. Corresponds to the 'code' field of the Code + * attribute. + * @param codeLength the length of the bytecode of the method corresponding to these code + * attributes, or 0 if they are not Code attributes. Corresponds to the 'code_length' field of + * the Code attribute. + * @param maxStack the maximum stack size of the method corresponding to these Code attributes, or + * -1 if they are not Code attributes. + * @param maxLocals the maximum number of local variables of the method corresponding to these + * Code attributes, or -1 if they are not Code attribute. + * @param output where the attributes must be written. + */ + final void putAttributes( + final SymbolTable symbolTable, + final byte[] code, + final int codeLength, + final int maxStack, + final int maxLocals, + final ByteVector output) { + final ClassWriter classWriter = symbolTable.classWriter; + Attribute attribute = this; + while (attribute != null) { + ByteVector attributeContent = + attribute.write(classWriter, code, codeLength, maxStack, maxLocals); + // Put attribute_name_index and attribute_length. + output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length); + output.putByteArray(attributeContent.data, 0, attributeContent.length); + attribute = attribute.nextAttribute; + } + } + + /** + * Puts all the attributes that correspond to the given field, method or class access flags and + * signature, in the given byte vector. This includes the 6 header bytes (attribute_name_index and + * attribute_length) per attribute. + * + * @param symbolTable where the constants used in the attributes must be stored. + * @param accessFlags some field, method or class access flags. + * @param signatureIndex the constant pool index of a field, method of class signature. + * @param output where the attributes must be written. + */ + static void putAttributes( + final SymbolTable symbolTable, + final int accessFlags, + final int signatureIndex, + final ByteVector output) { + // Before Java 1.5, synthetic fields are represented with a Synthetic attribute. + if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 + && symbolTable.getMajorVersion() < Opcodes.V1_5) { + output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); + } + if (signatureIndex != 0) { + output + .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) + .putInt(2) + .putShort(signatureIndex); + } + if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { + output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); + } + } + + /** A set of attribute prototypes (attributes with the same type are considered equal). */ + static final class Set { + + private static final int SIZE_INCREMENT = 6; + + private int size; + private Attribute[] data = new Attribute[SIZE_INCREMENT]; + + void addAttributes(final Attribute attributeList) { + Attribute attribute = attributeList; + while (attribute != null) { + if (!contains(attribute)) { + add(attribute); + } + attribute = attribute.nextAttribute; + } + } + + Attribute[] toArray() { + Attribute[] result = new Attribute[size]; + System.arraycopy(data, 0, result, 0, size); + return result; + } + + private boolean contains(final Attribute attribute) { + for (int i = 0; i < size; ++i) { + if (data[i].type.equals(attribute.type)) { + return true; + } + } + return false; + } + + private void add(final Attribute attribute) { + if (size >= data.length) { + Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT]; + System.arraycopy(data, 0, newData, 0, size); + data = newData; + } + data[size++] = attribute; + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ByteVector.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/ByteVector.class new file mode 100644 index 0000000000000000000000000000000000000000..30f683a15685841f6fc0a9069b000ea50f68d2af GIT binary patch literal 5036 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 K+(tKi$o&^;D!$GD literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ByteVector.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/ByteVector.java new file mode 100644 index 00000000..33a66b2c --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/ByteVector.java @@ -0,0 +1,405 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream + * on top of a ByteArrayOutputStream, but is more efficient. + * + * @author Eric Bruneton + */ +public class ByteVector { + + /** The content of this vector. Only the first {@link #length} bytes contain real data. */ + byte[] data; + + /** The actual number of bytes in this vector. */ + int length; + + /** Constructs a new {@link ByteVector} with a default initial capacity. */ + public ByteVector() { + data = new byte[64]; + } + + /** + * Constructs a new {@link ByteVector} with the given initial capacity. + * + * @param initialCapacity the initial capacity of the byte vector to be constructed. + */ + public ByteVector(final int initialCapacity) { + data = new byte[initialCapacity]; + } + + /** + * Constructs a new {@link ByteVector} from the given initial data. + * + * @param data the initial data of the new byte vector. + */ + ByteVector(final byte[] data) { + this.data = data; + this.length = data.length; + } + + /** + * Returns the actual number of bytes in this vector. + * + * @return the actual number of bytes in this vector. + */ + public int size() { + return length; + } + + /** + * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param byteValue a byte. + * @return this byte vector. + */ + public ByteVector putByte(final int byteValue) { + int currentLength = length; + if (currentLength + 1 > data.length) { + enlarge(1); + } + data[currentLength++] = (byte) byteValue; + length = currentLength; + return this; + } + + /** + * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param byteValue1 a byte. + * @param byteValue2 another byte. + * @return this byte vector. + */ + final ByteVector put11(final int byteValue1, final int byteValue2) { + int currentLength = length; + if (currentLength + 2 > data.length) { + enlarge(2); + } + byte[] currentData = data; + currentData[currentLength++] = (byte) byteValue1; + currentData[currentLength++] = (byte) byteValue2; + length = currentLength; + return this; + } + + /** + * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param shortValue a short. + * @return this byte vector. + */ + public ByteVector putShort(final int shortValue) { + int currentLength = length; + if (currentLength + 2 > data.length) { + enlarge(2); + } + byte[] currentData = data; + currentData[currentLength++] = (byte) (shortValue >>> 8); + currentData[currentLength++] = (byte) shortValue; + length = currentLength; + return this; + } + + /** + * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if + * necessary. + * + * @param byteValue a byte. + * @param shortValue a short. + * @return this byte vector. + */ + final ByteVector put12(final int byteValue, final int shortValue) { + int currentLength = length; + if (currentLength + 3 > data.length) { + enlarge(3); + } + byte[] currentData = data; + currentData[currentLength++] = (byte) byteValue; + currentData[currentLength++] = (byte) (shortValue >>> 8); + currentData[currentLength++] = (byte) shortValue; + length = currentLength; + return this; + } + + /** + * Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if + * necessary. + * + * @param byteValue1 a byte. + * @param byteValue2 another byte. + * @param shortValue a short. + * @return this byte vector. + */ + final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) { + int currentLength = length; + if (currentLength + 4 > data.length) { + enlarge(4); + } + byte[] currentData = data; + currentData[currentLength++] = (byte) byteValue1; + currentData[currentLength++] = (byte) byteValue2; + currentData[currentLength++] = (byte) (shortValue >>> 8); + currentData[currentLength++] = (byte) shortValue; + length = currentLength; + return this; + } + + /** + * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param intValue an int. + * @return this byte vector. + */ + public ByteVector putInt(final int intValue) { + int currentLength = length; + if (currentLength + 4 > data.length) { + enlarge(4); + } + byte[] currentData = data; + currentData[currentLength++] = (byte) (intValue >>> 24); + currentData[currentLength++] = (byte) (intValue >>> 16); + currentData[currentLength++] = (byte) (intValue >>> 8); + currentData[currentLength++] = (byte) intValue; + length = currentLength; + return this; + } + + /** + * Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged + * if necessary. + * + * @param byteValue a byte. + * @param shortValue1 a short. + * @param shortValue2 another short. + * @return this byte vector. + */ + final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) { + int currentLength = length; + if (currentLength + 5 > data.length) { + enlarge(5); + } + byte[] currentData = data; + currentData[currentLength++] = (byte) byteValue; + currentData[currentLength++] = (byte) (shortValue1 >>> 8); + currentData[currentLength++] = (byte) shortValue1; + currentData[currentLength++] = (byte) (shortValue2 >>> 8); + currentData[currentLength++] = (byte) shortValue2; + length = currentLength; + return this; + } + + /** + * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary. + * + * @param longValue a long. + * @return this byte vector. + */ + public ByteVector putLong(final long longValue) { + int currentLength = length; + if (currentLength + 8 > data.length) { + enlarge(8); + } + byte[] currentData = data; + int intValue = (int) (longValue >>> 32); + currentData[currentLength++] = (byte) (intValue >>> 24); + currentData[currentLength++] = (byte) (intValue >>> 16); + currentData[currentLength++] = (byte) (intValue >>> 8); + currentData[currentLength++] = (byte) intValue; + intValue = (int) longValue; + currentData[currentLength++] = (byte) (intValue >>> 24); + currentData[currentLength++] = (byte) (intValue >>> 16); + currentData[currentLength++] = (byte) (intValue >>> 8); + currentData[currentLength++] = (byte) intValue; + length = currentLength; + return this; + } + + /** + * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if + * necessary. + * + * @param stringValue a String whose UTF8 encoded length must be less than 65536. + * @return this byte vector. + */ + // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). + public ByteVector putUTF8(final String stringValue) { + int charLength = stringValue.length(); + if (charLength > 65535) { + throw new IllegalArgumentException("UTF8 string too large"); + } + int currentLength = length; + if (currentLength + 2 + charLength > data.length) { + enlarge(2 + charLength); + } + byte[] currentData = data; + // Optimistic algorithm: instead of computing the byte length and then serializing the string + // (which requires two loops), we assume the byte length is equal to char length (which is the + // most frequent case), and we start serializing the string right away. During the + // serialization, if we find that this assumption is wrong, we continue with the general method. + currentData[currentLength++] = (byte) (charLength >>> 8); + currentData[currentLength++] = (byte) charLength; + for (int i = 0; i < charLength; ++i) { + char charValue = stringValue.charAt(i); + if (charValue >= '\u0001' && charValue <= '\u007F') { + currentData[currentLength++] = (byte) charValue; + } else { + length = currentLength; + return encodeUtf8(stringValue, i, 65535); + } + } + length = currentLength; + return this; + } + + /** + * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if + * necessary. The string length is encoded in two bytes before the encoded characters, if there is + * space for that (i.e. if this.length - offset - 2 >= 0). + * + * @param stringValue the String to encode. + * @param offset the index of the first character to encode. The previous characters are supposed + * to have already been encoded, using only one byte per character. + * @param maxByteLength the maximum byte length of the encoded string, including the already + * encoded characters. + * @return this byte vector. + */ + final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength) { + int charLength = stringValue.length(); + int byteLength = offset; + for (int i = offset; i < charLength; ++i) { + char charValue = stringValue.charAt(i); + if (charValue >= 0x0001 && charValue <= 0x007F) { + byteLength++; + } else if (charValue <= 0x07FF) { + byteLength += 2; + } else { + byteLength += 3; + } + } + if (byteLength > maxByteLength) { + throw new IllegalArgumentException("UTF8 string too large"); + } + // Compute where 'byteLength' must be stored in 'data', and store it at this location. + int byteLengthOffset = length - offset - 2; + if (byteLengthOffset >= 0) { + data[byteLengthOffset] = (byte) (byteLength >>> 8); + data[byteLengthOffset + 1] = (byte) byteLength; + } + if (length + byteLength - offset > data.length) { + enlarge(byteLength - offset); + } + int currentLength = length; + for (int i = offset; i < charLength; ++i) { + char charValue = stringValue.charAt(i); + if (charValue >= 0x0001 && charValue <= 0x007F) { + data[currentLength++] = (byte) charValue; + } else if (charValue <= 0x07FF) { + data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F); + data[currentLength++] = (byte) (0x80 | charValue & 0x3F); + } else { + data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF); + data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F); + data[currentLength++] = (byte) (0x80 | charValue & 0x3F); + } + } + length = currentLength; + return this; + } + + /** + * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if + * necessary. + * + * @param byteArrayValue an array of bytes. May be {@literal null} to put {@code byteLength} null + * bytes into this byte vector. + * @param byteOffset index of the first byte of byteArrayValue that must be copied. + * @param byteLength number of bytes of byteArrayValue that must be copied. + * @return this byte vector. + */ + public ByteVector putByteArray( + final byte[] byteArrayValue, final int byteOffset, final int byteLength) { + if (length + byteLength > data.length) { + enlarge(byteLength); + } + if (byteArrayValue != null) { + System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength); + } + length += byteLength; + return this; + } + + /** + * Enlarges this byte vector so that it can receive 'size' more bytes. + * + * @param size number of additional bytes that this byte vector should be able to receive. + */ + private void enlarge(final int size) { + if (length > data.length) { + throw new AssertionError("Internal error"); + } + int doubleCapacity = 2 * data.length; + int minimalCapacity = length + size; + byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity]; + System.arraycopy(data, 0, newData, 0, length); + data = newData; + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ClassReader.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/ClassReader.class new file mode 100644 index 0000000000000000000000000000000000000000..01cea9853e9975ead42882f1e5046bdbdc0cefc4 GIT binary patch literal 50442 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ClassReader.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/ClassReader.java new file mode 100644 index 00000000..1e31e41e --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/ClassReader.java @@ -0,0 +1,3900 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * A parser to make a {@link ClassVisitor} visit a ClassFile structure, as defined in the Java + * Virtual Machine Specification (JVMS). This class parses the ClassFile content and calls the + * appropriate visit methods of a given {@link ClassVisitor} for each field, method and bytecode + * instruction encountered. + * + * @see JVMS 4 + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class ClassReader { + + /** + * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed + * nor visited. + */ + public static final int SKIP_CODE = 1; + + /** + * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, + * LocalVariableTypeTable, LineNumberTable and MethodParameters attributes. If this flag is set + * these attributes are neither parsed nor visited (i.e. {@link ClassVisitor#visitSource}, {@link + * MethodVisitor#visitLocalVariable}, {@link MethodVisitor#visitLineNumber} and {@link + * MethodVisitor#visitParameter} are not called). + */ + public static final int SKIP_DEBUG = 2; + + /** + * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes + * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag + * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames + * that will be ignored and recomputed from scratch. + */ + public static final int SKIP_FRAMES = 4; + + /** + * A flag to expand the stack map frames. By default stack map frames are visited in their + * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed" + * for the other classes). If this flag is set, stack map frames are always visited in expanded + * format (this option adds a decompression/compression step in ClassReader and ClassWriter which + * degrades performance quite a lot). + */ + public static final int EXPAND_FRAMES = 8; + + /** + * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode + * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset + * reserved for it is not sufficient to store the bytecode offset. In this case the jump + * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes + * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing + * such instructions, in order to replace them with standard instructions. In addition, when this + * flag is used, goto_w and jsr_w are not converted into goto and jsr, to make sure that + * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a + * goto_w in ClassWriter cannot occur. + */ + static final int EXPAND_ASM_INSNS = 256; + + /** The maximum size of array to allocate. */ + private static final int MAX_BUFFER_SIZE = 1024 * 1024; + + /** The size of the temporary byte array used to read class input streams chunk by chunk. */ + private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096; + + /** + * A byte array containing the JVMS ClassFile structure to be parsed. + * + * @deprecated Use {@link #readByte(int)} and the other read methods instead. This field will + * eventually be deleted. + */ + @Deprecated + // DontCheck(MemberName): can't be renamed (for backward binary compatibility). + public final byte[] b; + + /** The offset in bytes of the ClassFile's access_flags field. */ + public final int header; + + /** + * A byte array containing the JVMS ClassFile structure to be parsed. The content of this array + * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally + * not needed by class visitors. + * + *

    NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not + * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct + * ClassFile element offsets within this byte array. + */ + final byte[] classFileBuffer; + + /** + * The offset in bytes, in {@link #classFileBuffer}, of each cp_info entry of the ClassFile's + * constant_pool array, plus one. In other words, the offset of constant pool entry i is + * given by cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - + * 1]. + */ + private final int[] cpInfoOffsets; + + /** + * The String objects corresponding to the CONSTANT_Utf8 constant pool items. This cache avoids + * multiple parsing of a given CONSTANT_Utf8 constant pool item. + */ + private final String[] constantUtf8Values; + + /** + * The ConstantDynamic objects corresponding to the CONSTANT_Dynamic constant pool items. This + * cache avoids multiple parsing of a given CONSTANT_Dynamic constant pool item. + */ + private final ConstantDynamic[] constantDynamicValues; + + /** + * The start offsets in {@link #classFileBuffer} of each element of the bootstrap_methods array + * (in the BootstrapMethods attribute). + * + * @see JVMS + * 4.7.23 + */ + private final int[] bootstrapMethodOffsets; + + /** + * A conservative estimate of the maximum length of the strings contained in the constant pool of + * the class. + */ + private final int maxStringLength; + + // ----------------------------------------------------------------------------------------------- + // Constructors + // ----------------------------------------------------------------------------------------------- + + /** + * Constructs a new {@link ClassReader} object. + * + * @param classFile the JVMS ClassFile structure to be read. + */ + public ClassReader(final byte[] classFile) { + this(classFile, 0, classFile.length); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. + * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. + * @param classFileLength the length in bytes of the ClassFile to be read. + */ + @SuppressWarnings("this-escape") + public ClassReader( + final byte[] classFileBuffer, + final int classFileOffset, + final int classFileLength) { // NOPMD(UnusedFormalParameter) used for backward compatibility. + this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true); + } + + /** + * Constructs a new {@link ClassReader} object. This internal constructor must not be exposed + * as a public API. + * + * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. + * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. + * @param checkClassVersion whether to check the class version or not. + */ + ClassReader( + final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) { + this.classFileBuffer = classFileBuffer; + this.b = classFileBuffer; + // Check the class' major_version. This field is after the magic and minor_version fields, which + // use 4 and 2 bytes respectively. + if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V23) { + throw new IllegalArgumentException( + "Unsupported class file major version " + readShort(classFileOffset + 6)); + } + // Create the constant pool arrays. The constant_pool_count field is after the magic, + // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively. + int constantPoolCount = readUnsignedShort(classFileOffset + 8); + cpInfoOffsets = new int[constantPoolCount]; + constantUtf8Values = new String[constantPoolCount]; + // Compute the offset of each constant pool entry, as well as a conservative estimate of the + // maximum length of the constant pool strings. The first constant pool entry is after the + // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2 + // bytes respectively. + int currentCpInfoIndex = 1; + int currentCpInfoOffset = classFileOffset + 10; + int currentMaxStringLength = 0; + boolean hasBootstrapMethods = false; + boolean hasConstantDynamic = false; + // The offset of the other entries depend on the total size of all the previous entries. + while (currentCpInfoIndex < constantPoolCount) { + cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1; + int cpInfoSize; + switch (classFileBuffer[currentCpInfoOffset]) { + case Symbol.CONSTANT_FIELDREF_TAG: + case Symbol.CONSTANT_METHODREF_TAG: + case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: + case Symbol.CONSTANT_INTEGER_TAG: + case Symbol.CONSTANT_FLOAT_TAG: + case Symbol.CONSTANT_NAME_AND_TYPE_TAG: + cpInfoSize = 5; + break; + case Symbol.CONSTANT_DYNAMIC_TAG: + cpInfoSize = 5; + hasBootstrapMethods = true; + hasConstantDynamic = true; + break; + case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: + cpInfoSize = 5; + hasBootstrapMethods = true; + break; + case Symbol.CONSTANT_LONG_TAG: + case Symbol.CONSTANT_DOUBLE_TAG: + cpInfoSize = 9; + currentCpInfoIndex++; + break; + case Symbol.CONSTANT_UTF8_TAG: + cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1); + if (cpInfoSize > currentMaxStringLength) { + // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate + // of the length in characters of the corresponding string, and is much cheaper to + // compute than this exact length. + currentMaxStringLength = cpInfoSize; + } + break; + case Symbol.CONSTANT_METHOD_HANDLE_TAG: + cpInfoSize = 4; + break; + case Symbol.CONSTANT_CLASS_TAG: + case Symbol.CONSTANT_STRING_TAG: + case Symbol.CONSTANT_METHOD_TYPE_TAG: + case Symbol.CONSTANT_PACKAGE_TAG: + case Symbol.CONSTANT_MODULE_TAG: + cpInfoSize = 3; + break; + default: + throw new IllegalArgumentException(); + } + currentCpInfoOffset += cpInfoSize; + } + maxStringLength = currentMaxStringLength; + // The Classfile's access_flags field is just after the last constant pool entry. + header = currentCpInfoOffset; + + // Allocate the cache of ConstantDynamic values, if there is at least one. + constantDynamicValues = hasConstantDynamic ? new ConstantDynamic[constantPoolCount] : null; + + // Read the BootstrapMethods attribute, if any (only get the offset of each method). + bootstrapMethodOffsets = + hasBootstrapMethods ? readBootstrapMethodsAttribute(currentMaxStringLength) : null; + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input + * stream must contain nothing more than the ClassFile structure itself. It is read from its + * current position to its end. + * @throws IOException if a problem occurs during reading. + */ + public ClassReader(final InputStream inputStream) throws IOException { + this(readStream(inputStream, false)); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param className the fully qualified name of the class to be read. The ClassFile structure is + * retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}. + * @throws IOException if an exception occurs during reading. + */ + public ClassReader(final String className) throws IOException { + this( + readStream( + ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true)); + } + + /** + * Reads the given input stream and returns its content as a byte array. + * + * @param inputStream an input stream. + * @param close true to close the input stream after reading. + * @return the content of the given input stream. + * @throws IOException if a problem occurs during reading. + */ + @SuppressWarnings("PMD.UseTryWithResources") + private static byte[] readStream(final InputStream inputStream, final boolean close) + throws IOException { + if (inputStream == null) { + throw new IOException("Class not found"); + } + int bufferSize = computeBufferSize(inputStream); + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] data = new byte[bufferSize]; + int bytesRead; + int readCount = 0; + while ((bytesRead = inputStream.read(data, 0, bufferSize)) != -1) { + outputStream.write(data, 0, bytesRead); + readCount++; + } + outputStream.flush(); + if (readCount == 1) { + return data; + } + return outputStream.toByteArray(); + } finally { + if (close) { + inputStream.close(); + } + } + } + + private static int computeBufferSize(final InputStream inputStream) throws IOException { + int expectedLength = inputStream.available(); + /* + * Some implementations can return 0 while holding available data (e.g. new + * FileInputStream("/proc/a_file")). Also in some pathological cases a very small number might + * be returned, and in this case we use a default size. + */ + if (expectedLength < 256) { + return INPUT_STREAM_DATA_CHUNK_SIZE; + } + return Math.min(expectedLength, MAX_BUFFER_SIZE); + } + + // ----------------------------------------------------------------------------------------------- + // Accessors + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated + * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes. + * + * @return the class access flags. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public int getAccess() { + return readUnsignedShort(header); + } + + /** + * Returns the internal name of the class (see {@link Type#getInternalName()}). + * + * @return the internal class name. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getClassName() { + // this_class is just after the access_flags field (using 2 bytes). + return readClass(header + 2, new char[maxStringLength]); + } + + /** + * Returns the internal name of the super class (see {@link Type#getInternalName()}). For + * interfaces, the super class is {@link Object}. + * + * @return the internal name of the super class, or {@literal null} for {@link Object} class. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getSuperName() { + // super_class is after the access_flags and this_class fields (2 bytes each). + return readClass(header + 4, new char[maxStringLength]); + } + + /** + * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}). + * + * @return the internal names of the directly implemented interfaces. Inherited implemented + * interfaces are not returned. + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String[] getInterfaces() { + // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each). + int currentOffset = header + 6; + int interfacesCount = readUnsignedShort(currentOffset); + String[] interfaces = new String[interfacesCount]; + if (interfacesCount > 0) { + char[] charBuffer = new char[maxStringLength]; + for (int i = 0; i < interfacesCount; ++i) { + currentOffset += 2; + interfaces[i] = readClass(currentOffset, charBuffer); + } + } + return interfaces; + } + + // ----------------------------------------------------------------------------------------------- + // Public methods + // ----------------------------------------------------------------------------------------------- + + /** + * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this + * {@link ClassReader}. + * + * @param classVisitor the visitor that must visit this class. + * @param parsingOptions the options to use to parse this class. One or more of {@link + * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. + */ + public void accept(final ClassVisitor classVisitor, final int parsingOptions) { + accept(classVisitor, new Attribute[0], parsingOptions); + } + + /** + * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this + * {@link ClassReader}. + * + * @param classVisitor the visitor that must visit this class. + * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of + * the class. Any attribute whose type is not equal to the type of one the prototypes will not + * be parsed: its byte array value will be passed unchanged to the ClassWriter. This may + * corrupt it if this value contains references to the constant pool, or has syntactic or + * semantic links with a class element that has been transformed by a class adapter between + * the reader and the writer. + * @param parsingOptions the options to use to parse this class. One or more of {@link + * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. + */ + public void accept( + final ClassVisitor classVisitor, + final Attribute[] attributePrototypes, + final int parsingOptions) { + Context context = new Context(); + context.attributePrototypes = attributePrototypes; + context.parsingOptions = parsingOptions; + context.charBuffer = new char[maxStringLength]; + + // Read the access_flags, this_class, super_class, interface_count and interfaces fields. + char[] charBuffer = context.charBuffer; + int currentOffset = header; + int accessFlags = readUnsignedShort(currentOffset); + String thisClass = readClass(currentOffset + 2, charBuffer); + String superClass = readClass(currentOffset + 4, charBuffer); + String[] interfaces = new String[readUnsignedShort(currentOffset + 6)]; + currentOffset += 8; + for (int i = 0; i < interfaces.length; ++i) { + interfaces[i] = readClass(currentOffset, charBuffer); + currentOffset += 2; + } + + // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS). + // Attribute offsets exclude the attribute_name_index and attribute_length fields. + // - The offset of the InnerClasses attribute, or 0. + int innerClassesOffset = 0; + // - The offset of the EnclosingMethod attribute, or 0. + int enclosingMethodOffset = 0; + // - The string corresponding to the Signature attribute, or null. + String signature = null; + // - The string corresponding to the SourceFile attribute, or null. + String sourceFile = null; + // - The string corresponding to the SourceDebugExtension attribute, or null. + String sourceDebugExtension = null; + // - The offset of the RuntimeVisibleAnnotations attribute, or 0. + int runtimeVisibleAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. + int runtimeInvisibleAnnotationsOffset = 0; + // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. + int runtimeVisibleTypeAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. + int runtimeInvisibleTypeAnnotationsOffset = 0; + // - The offset of the Module attribute, or 0. + int moduleOffset = 0; + // - The offset of the ModulePackages attribute, or 0. + int modulePackagesOffset = 0; + // - The string corresponding to the ModuleMainClass attribute, or null. + String moduleMainClass = null; + // - The string corresponding to the NestHost attribute, or null. + String nestHostClass = null; + // - The offset of the NestMembers attribute, or 0. + int nestMembersOffset = 0; + // - The offset of the PermittedSubclasses attribute, or 0 + int permittedSubclassesOffset = 0; + // - The offset of the Record attribute, or 0. + int recordOffset = 0; + // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). + // This list in the reverse order or their order in the ClassFile structure. + Attribute attributes = null; + + int currentAttributeOffset = getFirstAttributeOffset(); + for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentAttributeOffset, charBuffer); + int attributeLength = readInt(currentAttributeOffset + 2); + currentAttributeOffset += 6; + // The tests are sorted in decreasing frequency order (based on frequencies observed on + // typical classes). + if (Constants.SOURCE_FILE.equals(attributeName)) { + sourceFile = readUTF8(currentAttributeOffset, charBuffer); + } else if (Constants.INNER_CLASSES.equals(attributeName)) { + innerClassesOffset = currentAttributeOffset; + } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) { + enclosingMethodOffset = currentAttributeOffset; + } else if (Constants.NEST_HOST.equals(attributeName)) { + nestHostClass = readClass(currentAttributeOffset, charBuffer); + } else if (Constants.NEST_MEMBERS.equals(attributeName)) { + nestMembersOffset = currentAttributeOffset; + } else if (Constants.PERMITTED_SUBCLASSES.equals(attributeName)) { + permittedSubclassesOffset = currentAttributeOffset; + } else if (Constants.SIGNATURE.equals(attributeName)) { + signature = readUTF8(currentAttributeOffset, charBuffer); + } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleAnnotationsOffset = currentAttributeOffset; + } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset; + } else if (Constants.DEPRECATED.equals(attributeName)) { + accessFlags |= Opcodes.ACC_DEPRECATED; + } else if (Constants.SYNTHETIC.equals(attributeName)) { + accessFlags |= Opcodes.ACC_SYNTHETIC; + } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) { + if (attributeLength > classFileBuffer.length - currentAttributeOffset) { + throw new IllegalArgumentException(); + } + sourceDebugExtension = + readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]); + } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleAnnotationsOffset = currentAttributeOffset; + } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset; + } else if (Constants.RECORD.equals(attributeName)) { + recordOffset = currentAttributeOffset; + accessFlags |= Opcodes.ACC_RECORD; + } else if (Constants.MODULE.equals(attributeName)) { + moduleOffset = currentAttributeOffset; + } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) { + moduleMainClass = readClass(currentAttributeOffset, charBuffer); + } else if (Constants.MODULE_PACKAGES.equals(attributeName)) { + modulePackagesOffset = currentAttributeOffset; + } else if (!Constants.BOOTSTRAP_METHODS.equals(attributeName)) { + // The BootstrapMethods attribute is read in the constructor. + Attribute attribute = + readAttribute( + attributePrototypes, + attributeName, + currentAttributeOffset, + attributeLength, + charBuffer, + -1, + null); + attribute.nextAttribute = attributes; + attributes = attribute; + } + currentAttributeOffset += attributeLength; + } + + // Visit the class declaration. The minor_version and major_version fields start 6 bytes before + // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition). + classVisitor.visit( + readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces); + + // Visit the SourceFile and SourceDebugExtenstion attributes. + if ((parsingOptions & SKIP_DEBUG) == 0 + && (sourceFile != null || sourceDebugExtension != null)) { + classVisitor.visitSource(sourceFile, sourceDebugExtension); + } + + // Visit the Module, ModulePackages and ModuleMainClass attributes. + if (moduleOffset != 0) { + readModuleAttributes( + classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass); + } + + // Visit the NestHost attribute. + if (nestHostClass != null) { + classVisitor.visitNestHost(nestHostClass); + } + + // Visit the EnclosingMethod attribute. + if (enclosingMethodOffset != 0) { + String className = readClass(enclosingMethodOffset, charBuffer); + int methodIndex = readUnsignedShort(enclosingMethodOffset + 2); + String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer); + String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer); + classVisitor.visitOuterClass(className, name, type); + } + + // Visit the RuntimeVisibleAnnotations attribute. + if (runtimeVisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleAnnotations attribute. + if (runtimeInvisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeVisibleTypeAnnotations attribute. + if (runtimeVisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + classVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleTypeAnnotations attribute. + if (runtimeInvisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + classVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the non standard attributes. + while (attributes != null) { + // Copy and reset the nextAttribute field so that it can also be used in ClassWriter. + Attribute nextAttribute = attributes.nextAttribute; + attributes.nextAttribute = null; + classVisitor.visitAttribute(attributes); + attributes = nextAttribute; + } + + // Visit the NestedMembers attribute. + if (nestMembersOffset != 0) { + int numberOfNestMembers = readUnsignedShort(nestMembersOffset); + int currentNestMemberOffset = nestMembersOffset + 2; + while (numberOfNestMembers-- > 0) { + classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer)); + currentNestMemberOffset += 2; + } + } + + // Visit the PermittedSubclasses attribute. + if (permittedSubclassesOffset != 0) { + int numberOfPermittedSubclasses = readUnsignedShort(permittedSubclassesOffset); + int currentPermittedSubclassesOffset = permittedSubclassesOffset + 2; + while (numberOfPermittedSubclasses-- > 0) { + classVisitor.visitPermittedSubclass( + readClass(currentPermittedSubclassesOffset, charBuffer)); + currentPermittedSubclassesOffset += 2; + } + } + + // Visit the InnerClasses attribute. + if (innerClassesOffset != 0) { + int numberOfClasses = readUnsignedShort(innerClassesOffset); + int currentClassesOffset = innerClassesOffset + 2; + while (numberOfClasses-- > 0) { + classVisitor.visitInnerClass( + readClass(currentClassesOffset, charBuffer), + readClass(currentClassesOffset + 2, charBuffer), + readUTF8(currentClassesOffset + 4, charBuffer), + readUnsignedShort(currentClassesOffset + 6)); + currentClassesOffset += 8; + } + } + + // Visit Record components. + if (recordOffset != 0) { + int recordComponentsCount = readUnsignedShort(recordOffset); + recordOffset += 2; + while (recordComponentsCount-- > 0) { + recordOffset = readRecordComponent(classVisitor, context, recordOffset); + } + } + + // Visit the fields and methods. + int fieldsCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (fieldsCount-- > 0) { + currentOffset = readField(classVisitor, context, currentOffset); + } + int methodsCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (methodsCount-- > 0) { + currentOffset = readMethod(classVisitor, context, currentOffset); + } + + // Visit the end of the class. + classVisitor.visitEnd(); + } + + // ---------------------------------------------------------------------------------------------- + // Methods to parse modules, fields and methods + // ---------------------------------------------------------------------------------------------- + + /** + * Reads the Module, ModulePackages and ModuleMainClass attributes and visit them. + * + * @param classVisitor the current class visitor + * @param context information about the class being parsed. + * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's + * attribute_name_index and attribute_length fields). + * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the + * attribute_info's attribute_name_index and attribute_length fields), or 0. + * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or {@literal + * null}. + */ + private void readModuleAttributes( + final ClassVisitor classVisitor, + final Context context, + final int moduleOffset, + final int modulePackagesOffset, + final String moduleMainClass) { + char[] buffer = context.charBuffer; + + // Read the module_name_index, module_flags and module_version_index fields and visit them. + int currentOffset = moduleOffset; + String moduleName = readModule(currentOffset, buffer); + int moduleFlags = readUnsignedShort(currentOffset + 2); + String moduleVersion = readUTF8(currentOffset + 4, buffer); + currentOffset += 6; + ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion); + if (moduleVisitor == null) { + return; + } + + // Visit the ModuleMainClass attribute. + if (moduleMainClass != null) { + moduleVisitor.visitMainClass(moduleMainClass); + } + + // Visit the ModulePackages attribute. + if (modulePackagesOffset != 0) { + int packageCount = readUnsignedShort(modulePackagesOffset); + int currentPackageOffset = modulePackagesOffset + 2; + while (packageCount-- > 0) { + moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer)); + currentPackageOffset += 2; + } + } + + // Read the 'requires_count' and 'requires' fields. + int requiresCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (requiresCount-- > 0) { + // Read the requires_index, requires_flags and requires_version fields and visit them. + String requires = readModule(currentOffset, buffer); + int requiresFlags = readUnsignedShort(currentOffset + 2); + String requiresVersion = readUTF8(currentOffset + 4, buffer); + currentOffset += 6; + moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion); + } + + // Read the 'exports_count' and 'exports' fields. + int exportsCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (exportsCount-- > 0) { + // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields + // and visit them. + String exports = readPackage(currentOffset, buffer); + int exportsFlags = readUnsignedShort(currentOffset + 2); + int exportsToCount = readUnsignedShort(currentOffset + 4); + currentOffset += 6; + String[] exportsTo = null; + if (exportsToCount != 0) { + exportsTo = new String[exportsToCount]; + for (int i = 0; i < exportsToCount; ++i) { + exportsTo[i] = readModule(currentOffset, buffer); + currentOffset += 2; + } + } + moduleVisitor.visitExport(exports, exportsFlags, exportsTo); + } + + // Reads the 'opens_count' and 'opens' fields. + int opensCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (opensCount-- > 0) { + // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them. + String opens = readPackage(currentOffset, buffer); + int opensFlags = readUnsignedShort(currentOffset + 2); + int opensToCount = readUnsignedShort(currentOffset + 4); + currentOffset += 6; + String[] opensTo = null; + if (opensToCount != 0) { + opensTo = new String[opensToCount]; + for (int i = 0; i < opensToCount; ++i) { + opensTo[i] = readModule(currentOffset, buffer); + currentOffset += 2; + } + } + moduleVisitor.visitOpen(opens, opensFlags, opensTo); + } + + // Read the 'uses_count' and 'uses' fields. + int usesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (usesCount-- > 0) { + moduleVisitor.visitUse(readClass(currentOffset, buffer)); + currentOffset += 2; + } + + // Read the 'provides_count' and 'provides' fields. + int providesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (providesCount-- > 0) { + // Read the provides_index, provides_with_count and provides_with_index fields and visit them. + String provides = readClass(currentOffset, buffer); + int providesWithCount = readUnsignedShort(currentOffset + 2); + currentOffset += 4; + String[] providesWith = new String[providesWithCount]; + for (int i = 0; i < providesWithCount; ++i) { + providesWith[i] = readClass(currentOffset, buffer); + currentOffset += 2; + } + moduleVisitor.visitProvide(provides, providesWith); + } + + // Visit the end of the module attributes. + moduleVisitor.visitEnd(); + } + + /** + * Reads a record component and visit it. + * + * @param classVisitor the current class visitor + * @param context information about the class being parsed. + * @param recordComponentOffset the offset of the current record component. + * @return the offset of the first byte following the record component. + */ + private int readRecordComponent( + final ClassVisitor classVisitor, final Context context, final int recordComponentOffset) { + char[] charBuffer = context.charBuffer; + + int currentOffset = recordComponentOffset; + String name = readUTF8(currentOffset, charBuffer); + String descriptor = readUTF8(currentOffset + 2, charBuffer); + currentOffset += 4; + + // Read the record component attributes (the variables are ordered as in Section 4.7 of the + // JVMS). + + // Attribute offsets exclude the attribute_name_index and attribute_length fields. + // - The string corresponding to the Signature attribute, or null. + String signature = null; + // - The offset of the RuntimeVisibleAnnotations attribute, or 0. + int runtimeVisibleAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. + int runtimeInvisibleAnnotationsOffset = 0; + // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. + int runtimeVisibleTypeAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. + int runtimeInvisibleTypeAnnotationsOffset = 0; + // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). + // This list in the reverse order or their order in the ClassFile structure. + Attribute attributes = null; + + int attributesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (attributesCount-- > 0) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentOffset, charBuffer); + int attributeLength = readInt(currentOffset + 2); + currentOffset += 6; + // The tests are sorted in decreasing frequency order (based on frequencies observed on + // typical classes). + if (Constants.SIGNATURE.equals(attributeName)) { + signature = readUTF8(currentOffset, charBuffer); + } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleTypeAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleTypeAnnotationsOffset = currentOffset; + } else { + Attribute attribute = + readAttribute( + context.attributePrototypes, + attributeName, + currentOffset, + attributeLength, + charBuffer, + -1, + null); + attribute.nextAttribute = attributes; + attributes = attribute; + } + currentOffset += attributeLength; + } + + RecordComponentVisitor recordComponentVisitor = + classVisitor.visitRecordComponent(name, descriptor, signature); + if (recordComponentVisitor == null) { + return currentOffset; + } + + // Visit the RuntimeVisibleAnnotations attribute. + if (runtimeVisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + recordComponentVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleAnnotations attribute. + if (runtimeInvisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + recordComponentVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeVisibleTypeAnnotations attribute. + if (runtimeVisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + recordComponentVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleTypeAnnotations attribute. + if (runtimeInvisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + recordComponentVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the non standard attributes. + while (attributes != null) { + // Copy and reset the nextAttribute field so that it can also be used in FieldWriter. + Attribute nextAttribute = attributes.nextAttribute; + attributes.nextAttribute = null; + recordComponentVisitor.visitAttribute(attributes); + attributes = nextAttribute; + } + + // Visit the end of the field. + recordComponentVisitor.visitEnd(); + return currentOffset; + } + + /** + * Reads a JVMS field_info structure and makes the given visitor visit it. + * + * @param classVisitor the visitor that must visit the field. + * @param context information about the class being parsed. + * @param fieldInfoOffset the start offset of the field_info structure. + * @return the offset of the first byte following the field_info structure. + */ + private int readField( + final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) { + char[] charBuffer = context.charBuffer; + + // Read the access_flags, name_index and descriptor_index fields. + int currentOffset = fieldInfoOffset; + int accessFlags = readUnsignedShort(currentOffset); + String name = readUTF8(currentOffset + 2, charBuffer); + String descriptor = readUTF8(currentOffset + 4, charBuffer); + currentOffset += 6; + + // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS). + // Attribute offsets exclude the attribute_name_index and attribute_length fields. + // - The value corresponding to the ConstantValue attribute, or null. + Object constantValue = null; + // - The string corresponding to the Signature attribute, or null. + String signature = null; + // - The offset of the RuntimeVisibleAnnotations attribute, or 0. + int runtimeVisibleAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. + int runtimeInvisibleAnnotationsOffset = 0; + // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. + int runtimeVisibleTypeAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. + int runtimeInvisibleTypeAnnotationsOffset = 0; + // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). + // This list in the reverse order or their order in the ClassFile structure. + Attribute attributes = null; + + int attributesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (attributesCount-- > 0) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentOffset, charBuffer); + int attributeLength = readInt(currentOffset + 2); + currentOffset += 6; + // The tests are sorted in decreasing frequency order (based on frequencies observed on + // typical classes). + if (Constants.CONSTANT_VALUE.equals(attributeName)) { + int constantvalueIndex = readUnsignedShort(currentOffset); + constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer); + } else if (Constants.SIGNATURE.equals(attributeName)) { + signature = readUTF8(currentOffset, charBuffer); + } else if (Constants.DEPRECATED.equals(attributeName)) { + accessFlags |= Opcodes.ACC_DEPRECATED; + } else if (Constants.SYNTHETIC.equals(attributeName)) { + accessFlags |= Opcodes.ACC_SYNTHETIC; + } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleTypeAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleTypeAnnotationsOffset = currentOffset; + } else { + Attribute attribute = + readAttribute( + context.attributePrototypes, + attributeName, + currentOffset, + attributeLength, + charBuffer, + -1, + null); + attribute.nextAttribute = attributes; + attributes = attribute; + } + currentOffset += attributeLength; + } + + // Visit the field declaration. + FieldVisitor fieldVisitor = + classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue); + if (fieldVisitor == null) { + return currentOffset; + } + + // Visit the RuntimeVisibleAnnotations attribute. + if (runtimeVisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleAnnotations attribute. + if (runtimeInvisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeVisibleTypeAnnotations attribute. + if (runtimeVisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + fieldVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleTypeAnnotations attribute. + if (runtimeInvisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + fieldVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the non standard attributes. + while (attributes != null) { + // Copy and reset the nextAttribute field so that it can also be used in FieldWriter. + Attribute nextAttribute = attributes.nextAttribute; + attributes.nextAttribute = null; + fieldVisitor.visitAttribute(attributes); + attributes = nextAttribute; + } + + // Visit the end of the field. + fieldVisitor.visitEnd(); + return currentOffset; + } + + /** + * Reads a JVMS method_info structure and makes the given visitor visit it. + * + * @param classVisitor the visitor that must visit the method. + * @param context information about the class being parsed. + * @param methodInfoOffset the start offset of the method_info structure. + * @return the offset of the first byte following the method_info structure. + */ + private int readMethod( + final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) { + char[] charBuffer = context.charBuffer; + + // Read the access_flags, name_index and descriptor_index fields. + int currentOffset = methodInfoOffset; + context.currentMethodAccessFlags = readUnsignedShort(currentOffset); + context.currentMethodName = readUTF8(currentOffset + 2, charBuffer); + context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer); + currentOffset += 6; + + // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS). + // Attribute offsets exclude the attribute_name_index and attribute_length fields. + // - The offset of the Code attribute, or 0. + int codeOffset = 0; + // - The offset of the Exceptions attribute, or 0. + int exceptionsOffset = 0; + // - The strings corresponding to the Exceptions attribute, or null. + String[] exceptions = null; + // - Whether the method has a Synthetic attribute. + boolean synthetic = false; + // - The constant pool index contained in the Signature attribute, or 0. + int signatureIndex = 0; + // - The offset of the RuntimeVisibleAnnotations attribute, or 0. + int runtimeVisibleAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. + int runtimeInvisibleAnnotationsOffset = 0; + // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0. + int runtimeVisibleParameterAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0. + int runtimeInvisibleParameterAnnotationsOffset = 0; + // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. + int runtimeVisibleTypeAnnotationsOffset = 0; + // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. + int runtimeInvisibleTypeAnnotationsOffset = 0; + // - The offset of the AnnotationDefault attribute, or 0. + int annotationDefaultOffset = 0; + // - The offset of the MethodParameters attribute, or 0. + int methodParametersOffset = 0; + // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). + // This list in the reverse order or their order in the ClassFile structure. + Attribute attributes = null; + + int attributesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (attributesCount-- > 0) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentOffset, charBuffer); + int attributeLength = readInt(currentOffset + 2); + currentOffset += 6; + // The tests are sorted in decreasing frequency order (based on frequencies observed on + // typical classes). + if (Constants.CODE.equals(attributeName)) { + if ((context.parsingOptions & SKIP_CODE) == 0) { + codeOffset = currentOffset; + } + } else if (Constants.EXCEPTIONS.equals(attributeName)) { + exceptionsOffset = currentOffset; + exceptions = new String[readUnsignedShort(exceptionsOffset)]; + int currentExceptionOffset = exceptionsOffset + 2; + for (int i = 0; i < exceptions.length; ++i) { + exceptions[i] = readClass(currentExceptionOffset, charBuffer); + currentExceptionOffset += 2; + } + } else if (Constants.SIGNATURE.equals(attributeName)) { + signatureIndex = readUnsignedShort(currentOffset); + } else if (Constants.DEPRECATED.equals(attributeName)) { + context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED; + } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleTypeAnnotationsOffset = currentOffset; + } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) { + annotationDefaultOffset = currentOffset; + } else if (Constants.SYNTHETIC.equals(attributeName)) { + synthetic = true; + context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC; + } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleTypeAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { + runtimeVisibleParameterAnnotationsOffset = currentOffset; + } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { + runtimeInvisibleParameterAnnotationsOffset = currentOffset; + } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) { + methodParametersOffset = currentOffset; + } else { + Attribute attribute = + readAttribute( + context.attributePrototypes, + attributeName, + currentOffset, + attributeLength, + charBuffer, + -1, + null); + attribute.nextAttribute = attributes; + attributes = attribute; + } + currentOffset += attributeLength; + } + + // Visit the method declaration. + MethodVisitor methodVisitor = + classVisitor.visitMethod( + context.currentMethodAccessFlags, + context.currentMethodName, + context.currentMethodDescriptor, + signatureIndex == 0 ? null : readUtf(signatureIndex, charBuffer), + exceptions); + if (methodVisitor == null) { + return currentOffset; + } + + // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method + // adapter between the reader and the writer. In this case, it might be possible to copy + // the method attributes directly into the writer. If so, return early without visiting + // the content of these attributes. + if (methodVisitor instanceof MethodWriter) { + MethodWriter methodWriter = (MethodWriter) methodVisitor; + if (methodWriter.canCopyMethodAttributes( + this, + synthetic, + (context.currentMethodAccessFlags & Opcodes.ACC_DEPRECATED) != 0, + readUnsignedShort(methodInfoOffset + 4), + signatureIndex, + exceptionsOffset)) { + methodWriter.setMethodAttributesSource(methodInfoOffset, currentOffset - methodInfoOffset); + return currentOffset; + } + } + + // Visit the MethodParameters attribute. + if (methodParametersOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) { + int parametersCount = readByte(methodParametersOffset); + int currentParameterOffset = methodParametersOffset + 1; + while (parametersCount-- > 0) { + // Read the name_index and access_flags fields and visit them. + methodVisitor.visitParameter( + readUTF8(currentParameterOffset, charBuffer), + readUnsignedShort(currentParameterOffset + 2)); + currentParameterOffset += 4; + } + } + + // Visit the AnnotationDefault attribute. + if (annotationDefaultOffset != 0) { + AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault(); + readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer); + if (annotationVisitor != null) { + annotationVisitor.visitEnd(); + } + } + + // Visit the RuntimeVisibleAnnotations attribute. + if (runtimeVisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleAnnotations attribute. + if (runtimeInvisibleAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeVisibleTypeAnnotations attribute. + if (runtimeVisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + methodVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeInvisibleTypeAnnotations attribute. + if (runtimeInvisibleTypeAnnotationsOffset != 0) { + int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); + int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; + while (numAnnotations-- > 0) { + // Parse the target_type, target_info and target_path fields. + currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentAnnotationOffset = + readElementValues( + methodVisitor.visitTypeAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + } + + // Visit the RuntimeVisibleParameterAnnotations attribute. + if (runtimeVisibleParameterAnnotationsOffset != 0) { + readParameterAnnotations( + methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true); + } + + // Visit the RuntimeInvisibleParameterAnnotations attribute. + if (runtimeInvisibleParameterAnnotationsOffset != 0) { + readParameterAnnotations( + methodVisitor, + context, + runtimeInvisibleParameterAnnotationsOffset, + /* visible = */ false); + } + + // Visit the non standard attributes. + while (attributes != null) { + // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. + Attribute nextAttribute = attributes.nextAttribute; + attributes.nextAttribute = null; + methodVisitor.visitAttribute(attributes); + attributes = nextAttribute; + } + + // Visit the Code attribute. + if (codeOffset != 0) { + methodVisitor.visitCode(); + readCode(methodVisitor, context, codeOffset); + } + + // Visit the end of the method. + methodVisitor.visitEnd(); + return currentOffset; + } + + // ---------------------------------------------------------------------------------------------- + // Methods to parse a Code attribute + // ---------------------------------------------------------------------------------------------- + + /** + * Reads a JVMS 'Code' attribute and makes the given visitor visit it. + * + * @param methodVisitor the visitor that must visit the Code attribute. + * @param context information about the class being parsed. + * @param codeOffset the start offset in {@link #classFileBuffer} of the Code attribute, excluding + * its attribute_name_index and attribute_length fields. + */ + private void readCode( + final MethodVisitor methodVisitor, final Context context, final int codeOffset) { + int currentOffset = codeOffset; + + // Read the max_stack, max_locals and code_length fields. + final byte[] classBuffer = classFileBuffer; + final char[] charBuffer = context.charBuffer; + final int maxStack = readUnsignedShort(currentOffset); + final int maxLocals = readUnsignedShort(currentOffset + 2); + final int codeLength = readInt(currentOffset + 4); + currentOffset += 8; + if (codeLength > classFileBuffer.length - currentOffset) { + throw new IllegalArgumentException(); + } + + // Read the bytecode 'code' array to create a label for each referenced instruction. + final int bytecodeStartOffset = currentOffset; + final int bytecodeEndOffset = currentOffset + codeLength; + final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1]; + while (currentOffset < bytecodeEndOffset) { + final int bytecodeOffset = currentOffset - bytecodeStartOffset; + final int opcode = classBuffer[currentOffset] & 0xFF; + switch (opcode) { + case Opcodes.NOP: + case Opcodes.ACONST_NULL: + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.IALOAD: + case Opcodes.LALOAD: + case Opcodes.FALOAD: + case Opcodes.DALOAD: + case Opcodes.AALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + case Opcodes.IASTORE: + case Opcodes.LASTORE: + case Opcodes.FASTORE: + case Opcodes.DASTORE: + case Opcodes.AASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.POP: + case Opcodes.POP2: + case Opcodes.DUP: + case Opcodes.DUP_X1: + case Opcodes.DUP_X2: + case Opcodes.DUP2: + case Opcodes.DUP2_X1: + case Opcodes.DUP2_X2: + case Opcodes.SWAP: + case Opcodes.IADD: + case Opcodes.LADD: + case Opcodes.FADD: + case Opcodes.DADD: + case Opcodes.ISUB: + case Opcodes.LSUB: + case Opcodes.FSUB: + case Opcodes.DSUB: + case Opcodes.IMUL: + case Opcodes.LMUL: + case Opcodes.FMUL: + case Opcodes.DMUL: + case Opcodes.IDIV: + case Opcodes.LDIV: + case Opcodes.FDIV: + case Opcodes.DDIV: + case Opcodes.IREM: + case Opcodes.LREM: + case Opcodes.FREM: + case Opcodes.DREM: + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + case Opcodes.ISHL: + case Opcodes.LSHL: + case Opcodes.ISHR: + case Opcodes.LSHR: + case Opcodes.IUSHR: + case Opcodes.LUSHR: + case Opcodes.IAND: + case Opcodes.LAND: + case Opcodes.IOR: + case Opcodes.LOR: + case Opcodes.IXOR: + case Opcodes.LXOR: + case Opcodes.I2L: + case Opcodes.I2F: + case Opcodes.I2D: + case Opcodes.L2I: + case Opcodes.L2F: + case Opcodes.L2D: + case Opcodes.F2I: + case Opcodes.F2L: + case Opcodes.F2D: + case Opcodes.D2I: + case Opcodes.D2L: + case Opcodes.D2F: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + case Opcodes.LCMP: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.ARETURN: + case Opcodes.RETURN: + case Opcodes.ARRAYLENGTH: + case Opcodes.ATHROW: + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + case Constants.ILOAD_0: + case Constants.ILOAD_1: + case Constants.ILOAD_2: + case Constants.ILOAD_3: + case Constants.LLOAD_0: + case Constants.LLOAD_1: + case Constants.LLOAD_2: + case Constants.LLOAD_3: + case Constants.FLOAD_0: + case Constants.FLOAD_1: + case Constants.FLOAD_2: + case Constants.FLOAD_3: + case Constants.DLOAD_0: + case Constants.DLOAD_1: + case Constants.DLOAD_2: + case Constants.DLOAD_3: + case Constants.ALOAD_0: + case Constants.ALOAD_1: + case Constants.ALOAD_2: + case Constants.ALOAD_3: + case Constants.ISTORE_0: + case Constants.ISTORE_1: + case Constants.ISTORE_2: + case Constants.ISTORE_3: + case Constants.LSTORE_0: + case Constants.LSTORE_1: + case Constants.LSTORE_2: + case Constants.LSTORE_3: + case Constants.FSTORE_0: + case Constants.FSTORE_1: + case Constants.FSTORE_2: + case Constants.FSTORE_3: + case Constants.DSTORE_0: + case Constants.DSTORE_1: + case Constants.DSTORE_2: + case Constants.DSTORE_3: + case Constants.ASTORE_0: + case Constants.ASTORE_1: + case Constants.ASTORE_2: + case Constants.ASTORE_3: + currentOffset += 1; + break; + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + case Opcodes.GOTO: + case Opcodes.JSR: + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + createLabel(bytecodeOffset + readShort(currentOffset + 1), labels); + currentOffset += 3; + break; + case Constants.ASM_IFEQ: + case Constants.ASM_IFNE: + case Constants.ASM_IFLT: + case Constants.ASM_IFGE: + case Constants.ASM_IFGT: + case Constants.ASM_IFLE: + case Constants.ASM_IF_ICMPEQ: + case Constants.ASM_IF_ICMPNE: + case Constants.ASM_IF_ICMPLT: + case Constants.ASM_IF_ICMPGE: + case Constants.ASM_IF_ICMPGT: + case Constants.ASM_IF_ICMPLE: + case Constants.ASM_IF_ACMPEQ: + case Constants.ASM_IF_ACMPNE: + case Constants.ASM_GOTO: + case Constants.ASM_JSR: + case Constants.ASM_IFNULL: + case Constants.ASM_IFNONNULL: + createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels); + currentOffset += 3; + break; + case Constants.GOTO_W: + case Constants.JSR_W: + case Constants.ASM_GOTO_W: + createLabel(bytecodeOffset + readInt(currentOffset + 1), labels); + currentOffset += 5; + break; + case Constants.WIDE: + switch (classBuffer[currentOffset + 1] & 0xFF) { + case Opcodes.ILOAD: + case Opcodes.FLOAD: + case Opcodes.ALOAD: + case Opcodes.LLOAD: + case Opcodes.DLOAD: + case Opcodes.ISTORE: + case Opcodes.FSTORE: + case Opcodes.ASTORE: + case Opcodes.LSTORE: + case Opcodes.DSTORE: + case Opcodes.RET: + currentOffset += 4; + break; + case Opcodes.IINC: + currentOffset += 6; + break; + default: + throw new IllegalArgumentException(); + } + break; + case Opcodes.TABLESWITCH: + // Skip 0 to 3 padding bytes. + currentOffset += 4 - (bytecodeOffset & 3); + // Read the default label and the number of table entries. + createLabel(bytecodeOffset + readInt(currentOffset), labels); + int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1; + currentOffset += 12; + // Read the table labels. + while (numTableEntries-- > 0) { + createLabel(bytecodeOffset + readInt(currentOffset), labels); + currentOffset += 4; + } + break; + case Opcodes.LOOKUPSWITCH: + // Skip 0 to 3 padding bytes. + currentOffset += 4 - (bytecodeOffset & 3); + // Read the default label and the number of switch cases. + createLabel(bytecodeOffset + readInt(currentOffset), labels); + int numSwitchCases = readInt(currentOffset + 4); + currentOffset += 8; + // Read the switch labels. + while (numSwitchCases-- > 0) { + createLabel(bytecodeOffset + readInt(currentOffset + 4), labels); + currentOffset += 8; + } + break; + case Opcodes.ILOAD: + case Opcodes.LLOAD: + case Opcodes.FLOAD: + case Opcodes.DLOAD: + case Opcodes.ALOAD: + case Opcodes.ISTORE: + case Opcodes.LSTORE: + case Opcodes.FSTORE: + case Opcodes.DSTORE: + case Opcodes.ASTORE: + case Opcodes.RET: + case Opcodes.BIPUSH: + case Opcodes.NEWARRAY: + case Opcodes.LDC: + currentOffset += 2; + break; + case Opcodes.SIPUSH: + case Constants.LDC_W: + case Constants.LDC2_W: + case Opcodes.GETSTATIC: + case Opcodes.PUTSTATIC: + case Opcodes.GETFIELD: + case Opcodes.PUTFIELD: + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.NEW: + case Opcodes.ANEWARRAY: + case Opcodes.CHECKCAST: + case Opcodes.INSTANCEOF: + case Opcodes.IINC: + currentOffset += 3; + break; + case Opcodes.INVOKEINTERFACE: + case Opcodes.INVOKEDYNAMIC: + currentOffset += 5; + break; + case Opcodes.MULTIANEWARRAY: + currentOffset += 4; + break; + default: + throw new IllegalArgumentException(); + } + } + + // Read the 'exception_table_length' and 'exception_table' field to create a label for each + // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks. + int exceptionTableLength = readUnsignedShort(currentOffset); + currentOffset += 2; + while (exceptionTableLength-- > 0) { + Label start = createLabel(readUnsignedShort(currentOffset), labels); + Label end = createLabel(readUnsignedShort(currentOffset + 2), labels); + Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels); + String catchType = readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer); + currentOffset += 8; + methodVisitor.visitTryCatchBlock(start, end, handler, catchType); + } + + // Read the Code attributes to create a label for each referenced instruction (the variables + // are ordered as in Section 4.7 of the JVMS). Attribute offsets exclude the + // attribute_name_index and attribute_length fields. + // - The offset of the current 'stack_map_frame' in the StackMap[Table] attribute, or 0. + // Initially, this is the offset of the first 'stack_map_frame' entry. Then this offset is + // updated after each stack_map_frame is read. + int stackMapFrameOffset = 0; + // - The end offset of the StackMap[Table] attribute, or 0. + int stackMapTableEndOffset = 0; + // - Whether the stack map frames are compressed (i.e. in a StackMapTable) or not. + boolean compressedFrames = true; + // - The offset of the LocalVariableTable attribute, or 0. + int localVariableTableOffset = 0; + // - The offset of the LocalVariableTypeTable attribute, or 0. + int localVariableTypeTableOffset = 0; + // - The offset of each 'type_annotation' entry in the RuntimeVisibleTypeAnnotations + // attribute, or null. + int[] visibleTypeAnnotationOffsets = null; + // - The offset of each 'type_annotation' entry in the RuntimeInvisibleTypeAnnotations + // attribute, or null. + int[] invisibleTypeAnnotationOffsets = null; + // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). + // This list in the reverse order or their order in the ClassFile structure. + Attribute attributes = null; + + int attributesCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (attributesCount-- > 0) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentOffset, charBuffer); + int attributeLength = readInt(currentOffset + 2); + currentOffset += 6; + if (Constants.LOCAL_VARIABLE_TABLE.equals(attributeName)) { + if ((context.parsingOptions & SKIP_DEBUG) == 0) { + localVariableTableOffset = currentOffset; + // Parse the attribute to find the corresponding (debug only) labels. + int currentLocalVariableTableOffset = currentOffset; + int localVariableTableLength = readUnsignedShort(currentLocalVariableTableOffset); + currentLocalVariableTableOffset += 2; + while (localVariableTableLength-- > 0) { + int startPc = readUnsignedShort(currentLocalVariableTableOffset); + createDebugLabel(startPc, labels); + int length = readUnsignedShort(currentLocalVariableTableOffset + 2); + createDebugLabel(startPc + length, labels); + // Skip the name_index, descriptor_index and index fields (2 bytes each). + currentLocalVariableTableOffset += 10; + } + } + } else if (Constants.LOCAL_VARIABLE_TYPE_TABLE.equals(attributeName)) { + localVariableTypeTableOffset = currentOffset; + // Here we do not extract the labels corresponding to the attribute content. We assume they + // are the same or a subset of those of the LocalVariableTable attribute. + } else if (Constants.LINE_NUMBER_TABLE.equals(attributeName)) { + if ((context.parsingOptions & SKIP_DEBUG) == 0) { + // Parse the attribute to find the corresponding (debug only) labels. + int currentLineNumberTableOffset = currentOffset; + int lineNumberTableLength = readUnsignedShort(currentLineNumberTableOffset); + currentLineNumberTableOffset += 2; + while (lineNumberTableLength-- > 0) { + int startPc = readUnsignedShort(currentLineNumberTableOffset); + int lineNumber = readUnsignedShort(currentLineNumberTableOffset + 2); + currentLineNumberTableOffset += 4; + createDebugLabel(startPc, labels); + labels[startPc].addLineNumber(lineNumber); + } + } + } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + visibleTypeAnnotationOffsets = + readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ true); + // Here we do not extract the labels corresponding to the attribute content. This would + // require a full parsing of the attribute, which would need to be repeated when parsing + // the bytecode instructions (see below). Instead, the content of the attribute is read one + // type annotation at a time (i.e. after a type annotation has been visited, the next type + // annotation is read), and the labels it contains are also extracted one annotation at a + // time. This assumes that type annotations are ordered by increasing bytecode offset. + } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { + invisibleTypeAnnotationOffsets = + readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ false); + // Same comment as above for the RuntimeVisibleTypeAnnotations attribute. + } else if (Constants.STACK_MAP_TABLE.equals(attributeName)) { + if ((context.parsingOptions & SKIP_FRAMES) == 0) { + stackMapFrameOffset = currentOffset + 2; + stackMapTableEndOffset = currentOffset + attributeLength; + } + // Here we do not extract the labels corresponding to the attribute content. This would + // require a full parsing of the attribute, which would need to be repeated when parsing + // the bytecode instructions (see below). Instead, the content of the attribute is read one + // frame at a time (i.e. after a frame has been visited, the next frame is read), and the + // labels it contains are also extracted one frame at a time. Thanks to the ordering of + // frames, having only a "one frame lookahead" is not a problem, i.e. it is not possible to + // see an offset smaller than the offset of the current instruction and for which no Label + // exist. Except for UNINITIALIZED type offsets. We solve this by parsing the stack map + // table without a full decoding (see below). + } else if ("StackMap".equals(attributeName)) { + if ((context.parsingOptions & SKIP_FRAMES) == 0) { + stackMapFrameOffset = currentOffset + 2; + stackMapTableEndOffset = currentOffset + attributeLength; + compressedFrames = false; + } + // IMPORTANT! Here we assume that the frames are ordered, as in the StackMapTable attribute, + // although this is not guaranteed by the attribute format. This allows an incremental + // extraction of the labels corresponding to this attribute (see the comment above for the + // StackMapTable attribute). + } else { + Attribute attribute = + readAttribute( + context.attributePrototypes, + attributeName, + currentOffset, + attributeLength, + charBuffer, + codeOffset, + labels); + attribute.nextAttribute = attributes; + attributes = attribute; + } + currentOffset += attributeLength; + } + + // Initialize the context fields related to stack map frames, and generate the first + // (implicit) stack map frame, if needed. + final boolean expandFrames = (context.parsingOptions & EXPAND_FRAMES) != 0; + if (stackMapFrameOffset != 0) { + // The bytecode offset of the first explicit frame is not offset_delta + 1 but only + // offset_delta. Setting the implicit frame offset to -1 allows us to use of the + // "offset_delta + 1" rule in all cases. + context.currentFrameOffset = -1; + context.currentFrameType = 0; + context.currentFrameLocalCount = 0; + context.currentFrameLocalCountDelta = 0; + context.currentFrameLocalTypes = new Object[maxLocals]; + context.currentFrameStackCount = 0; + context.currentFrameStackTypes = new Object[maxStack]; + if (expandFrames) { + computeImplicitFrame(context); + } + // Find the labels for UNINITIALIZED frame types. Instead of decoding each element of the + // stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED type + // (tag ITEM_Uninitialized, offset within bytecode bounds, NEW instruction at this offset). + // We may find false positives (i.e. not real UNINITIALIZED types), but this should be rare, + // and the only consequence will be the creation of an unneeded label. This is better than + // creating a label for each NEW instruction, and faster than fully decoding the whole stack + // map table. + for (int offset = stackMapFrameOffset; offset < stackMapTableEndOffset - 2; ++offset) { + if (classBuffer[offset] == Frame.ITEM_UNINITIALIZED) { + int potentialBytecodeOffset = readUnsignedShort(offset + 1); + if (potentialBytecodeOffset >= 0 + && potentialBytecodeOffset < codeLength + && (classBuffer[bytecodeStartOffset + potentialBytecodeOffset] & 0xFF) + == Opcodes.NEW) { + createLabel(potentialBytecodeOffset, labels); + } + } + } + } + if (expandFrames && (context.parsingOptions & EXPAND_ASM_INSNS) != 0) { + // Expanding the ASM specific instructions can introduce F_INSERT frames, even if the method + // does not currently have any frame. These inserted frames must be computed by simulating the + // effect of the bytecode instructions, one by one, starting from the implicit first frame. + // For this, MethodWriter needs to know maxLocals before the first instruction is visited. To + // ensure this, we visit the implicit first frame here (passing only maxLocals - the rest is + // computed in MethodWriter). + methodVisitor.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null); + } + + // Visit the bytecode instructions. First, introduce state variables for the incremental parsing + // of the type annotations. + + // Index of the next runtime visible type annotation to read (in the + // visibleTypeAnnotationOffsets array). + int currentVisibleTypeAnnotationIndex = 0; + // The bytecode offset of the next runtime visible type annotation to read, or -1. + int currentVisibleTypeAnnotationBytecodeOffset = + getTypeAnnotationBytecodeOffset(visibleTypeAnnotationOffsets, 0); + // Index of the next runtime invisible type annotation to read (in the + // invisibleTypeAnnotationOffsets array). + int currentInvisibleTypeAnnotationIndex = 0; + // The bytecode offset of the next runtime invisible type annotation to read, or -1. + int currentInvisibleTypeAnnotationBytecodeOffset = + getTypeAnnotationBytecodeOffset(invisibleTypeAnnotationOffsets, 0); + + // Whether a F_INSERT stack map frame must be inserted before the current instruction. + boolean insertFrame = false; + + // The delta to subtract from a goto_w or jsr_w opcode to get the corresponding goto or jsr + // opcode, or 0 if goto_w and jsr_w must be left unchanged (i.e. when expanding ASM specific + // instructions). + final int wideJumpOpcodeDelta = + (context.parsingOptions & EXPAND_ASM_INSNS) == 0 ? Constants.WIDE_JUMP_OPCODE_DELTA : 0; + + currentOffset = bytecodeStartOffset; + while (currentOffset < bytecodeEndOffset) { + final int currentBytecodeOffset = currentOffset - bytecodeStartOffset; + readBytecodeInstructionOffset(currentBytecodeOffset); + + // Visit the label and the line number(s) for this bytecode offset, if any. + Label currentLabel = labels[currentBytecodeOffset]; + if (currentLabel != null) { + currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0); + } + + // Visit the stack map frame for this bytecode offset, if any. + while (stackMapFrameOffset != 0 + && (context.currentFrameOffset == currentBytecodeOffset + || context.currentFrameOffset == -1)) { + // If there is a stack map frame for this offset, make methodVisitor visit it, and read the + // next stack map frame if there is one. + if (context.currentFrameOffset != -1) { + if (!compressedFrames || expandFrames) { + methodVisitor.visitFrame( + Opcodes.F_NEW, + context.currentFrameLocalCount, + context.currentFrameLocalTypes, + context.currentFrameStackCount, + context.currentFrameStackTypes); + } else { + methodVisitor.visitFrame( + context.currentFrameType, + context.currentFrameLocalCountDelta, + context.currentFrameLocalTypes, + context.currentFrameStackCount, + context.currentFrameStackTypes); + } + // Since there is already a stack map frame for this bytecode offset, there is no need to + // insert a new one. + insertFrame = false; + } + if (stackMapFrameOffset < stackMapTableEndOffset) { + stackMapFrameOffset = + readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context); + } else { + stackMapFrameOffset = 0; + } + } + + // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to + // true during the previous iteration. The actual frame content is computed in MethodWriter. + if (insertFrame) { + if ((context.parsingOptions & EXPAND_FRAMES) != 0) { + methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null); + } + insertFrame = false; + } + + // Visit the instruction at this bytecode offset. + int opcode = classBuffer[currentOffset] & 0xFF; + switch (opcode) { + case Opcodes.NOP: + case Opcodes.ACONST_NULL: + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.IALOAD: + case Opcodes.LALOAD: + case Opcodes.FALOAD: + case Opcodes.DALOAD: + case Opcodes.AALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + case Opcodes.IASTORE: + case Opcodes.LASTORE: + case Opcodes.FASTORE: + case Opcodes.DASTORE: + case Opcodes.AASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.POP: + case Opcodes.POP2: + case Opcodes.DUP: + case Opcodes.DUP_X1: + case Opcodes.DUP_X2: + case Opcodes.DUP2: + case Opcodes.DUP2_X1: + case Opcodes.DUP2_X2: + case Opcodes.SWAP: + case Opcodes.IADD: + case Opcodes.LADD: + case Opcodes.FADD: + case Opcodes.DADD: + case Opcodes.ISUB: + case Opcodes.LSUB: + case Opcodes.FSUB: + case Opcodes.DSUB: + case Opcodes.IMUL: + case Opcodes.LMUL: + case Opcodes.FMUL: + case Opcodes.DMUL: + case Opcodes.IDIV: + case Opcodes.LDIV: + case Opcodes.FDIV: + case Opcodes.DDIV: + case Opcodes.IREM: + case Opcodes.LREM: + case Opcodes.FREM: + case Opcodes.DREM: + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + case Opcodes.ISHL: + case Opcodes.LSHL: + case Opcodes.ISHR: + case Opcodes.LSHR: + case Opcodes.IUSHR: + case Opcodes.LUSHR: + case Opcodes.IAND: + case Opcodes.LAND: + case Opcodes.IOR: + case Opcodes.LOR: + case Opcodes.IXOR: + case Opcodes.LXOR: + case Opcodes.I2L: + case Opcodes.I2F: + case Opcodes.I2D: + case Opcodes.L2I: + case Opcodes.L2F: + case Opcodes.L2D: + case Opcodes.F2I: + case Opcodes.F2L: + case Opcodes.F2D: + case Opcodes.D2I: + case Opcodes.D2L: + case Opcodes.D2F: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + case Opcodes.LCMP: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.ARETURN: + case Opcodes.RETURN: + case Opcodes.ARRAYLENGTH: + case Opcodes.ATHROW: + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + methodVisitor.visitInsn(opcode); + currentOffset += 1; + break; + case Constants.ILOAD_0: + case Constants.ILOAD_1: + case Constants.ILOAD_2: + case Constants.ILOAD_3: + case Constants.LLOAD_0: + case Constants.LLOAD_1: + case Constants.LLOAD_2: + case Constants.LLOAD_3: + case Constants.FLOAD_0: + case Constants.FLOAD_1: + case Constants.FLOAD_2: + case Constants.FLOAD_3: + case Constants.DLOAD_0: + case Constants.DLOAD_1: + case Constants.DLOAD_2: + case Constants.DLOAD_3: + case Constants.ALOAD_0: + case Constants.ALOAD_1: + case Constants.ALOAD_2: + case Constants.ALOAD_3: + opcode -= Constants.ILOAD_0; + methodVisitor.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); + currentOffset += 1; + break; + case Constants.ISTORE_0: + case Constants.ISTORE_1: + case Constants.ISTORE_2: + case Constants.ISTORE_3: + case Constants.LSTORE_0: + case Constants.LSTORE_1: + case Constants.LSTORE_2: + case Constants.LSTORE_3: + case Constants.FSTORE_0: + case Constants.FSTORE_1: + case Constants.FSTORE_2: + case Constants.FSTORE_3: + case Constants.DSTORE_0: + case Constants.DSTORE_1: + case Constants.DSTORE_2: + case Constants.DSTORE_3: + case Constants.ASTORE_0: + case Constants.ASTORE_1: + case Constants.ASTORE_2: + case Constants.ASTORE_3: + opcode -= Constants.ISTORE_0; + methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); + currentOffset += 1; + break; + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + case Opcodes.GOTO: + case Opcodes.JSR: + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + methodVisitor.visitJumpInsn( + opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]); + currentOffset += 3; + break; + case Constants.GOTO_W: + case Constants.JSR_W: + methodVisitor.visitJumpInsn( + opcode - wideJumpOpcodeDelta, + labels[currentBytecodeOffset + readInt(currentOffset + 1)]); + currentOffset += 5; + break; + case Constants.ASM_IFEQ: + case Constants.ASM_IFNE: + case Constants.ASM_IFLT: + case Constants.ASM_IFGE: + case Constants.ASM_IFGT: + case Constants.ASM_IFLE: + case Constants.ASM_IF_ICMPEQ: + case Constants.ASM_IF_ICMPNE: + case Constants.ASM_IF_ICMPLT: + case Constants.ASM_IF_ICMPGE: + case Constants.ASM_IF_ICMPGT: + case Constants.ASM_IF_ICMPLE: + case Constants.ASM_IF_ACMPEQ: + case Constants.ASM_IF_ACMPNE: + case Constants.ASM_GOTO: + case Constants.ASM_JSR: + case Constants.ASM_IFNULL: + case Constants.ASM_IFNONNULL: + { + // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO + // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx with IFNOTxxx GOTO_W L:..., + // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and + // where designates the instruction just after the GOTO_W. + // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and + // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL. + opcode = + opcode < Constants.ASM_IFNULL + ? opcode - Constants.ASM_OPCODE_DELTA + : opcode - Constants.ASM_IFNULL_OPCODE_DELTA; + Label target = labels[currentBytecodeOffset + readUnsignedShort(currentOffset + 1)]; + if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { + // Replace GOTO with GOTO_W and JSR with JSR_W. + methodVisitor.visitJumpInsn(opcode + Constants.WIDE_JUMP_OPCODE_DELTA, target); + } else { + // Compute the "opposite" of opcode. This can be done by flipping the least + // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ + // (with a pre and post offset by 1). + opcode = opcode < Opcodes.GOTO ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1; + Label endif = createLabel(currentBytecodeOffset + 3, labels); + methodVisitor.visitJumpInsn(opcode, endif); + methodVisitor.visitJumpInsn(Constants.GOTO_W, target); + // endif designates the instruction just after GOTO_W, and is visited as part of the + // next instruction. Since it is a jump target, we need to insert a frame here. + insertFrame = true; + } + currentOffset += 3; + break; + } + case Constants.ASM_GOTO_W: + // Replace ASM_GOTO_W with GOTO_W. + methodVisitor.visitJumpInsn( + Constants.GOTO_W, labels[currentBytecodeOffset + readInt(currentOffset + 1)]); + // The instruction just after is a jump target (because ASM_GOTO_W is used in patterns + // IFNOTxxx ASM_GOTO_W L:..., see MethodWriter), so we need to insert a frame + // here. + insertFrame = true; + currentOffset += 5; + break; + case Constants.WIDE: + opcode = classBuffer[currentOffset + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + methodVisitor.visitIincInsn( + readUnsignedShort(currentOffset + 2), readShort(currentOffset + 4)); + currentOffset += 6; + } else { + methodVisitor.visitVarInsn(opcode, readUnsignedShort(currentOffset + 2)); + currentOffset += 4; + } + break; + case Opcodes.TABLESWITCH: + { + // Skip 0 to 3 padding bytes. + currentOffset += 4 - (currentBytecodeOffset & 3); + // Read the instruction. + Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; + int low = readInt(currentOffset + 4); + int high = readInt(currentOffset + 8); + currentOffset += 12; + Label[] table = new Label[high - low + 1]; + for (int i = 0; i < table.length; ++i) { + table[i] = labels[currentBytecodeOffset + readInt(currentOffset)]; + currentOffset += 4; + } + methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table); + break; + } + case Opcodes.LOOKUPSWITCH: + { + // Skip 0 to 3 padding bytes. + currentOffset += 4 - (currentBytecodeOffset & 3); + // Read the instruction. + Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; + int numPairs = readInt(currentOffset + 4); + currentOffset += 8; + int[] keys = new int[numPairs]; + Label[] values = new Label[numPairs]; + for (int i = 0; i < numPairs; ++i) { + keys[i] = readInt(currentOffset); + values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)]; + currentOffset += 8; + } + methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values); + break; + } + case Opcodes.ILOAD: + case Opcodes.LLOAD: + case Opcodes.FLOAD: + case Opcodes.DLOAD: + case Opcodes.ALOAD: + case Opcodes.ISTORE: + case Opcodes.LSTORE: + case Opcodes.FSTORE: + case Opcodes.DSTORE: + case Opcodes.ASTORE: + case Opcodes.RET: + methodVisitor.visitVarInsn(opcode, classBuffer[currentOffset + 1] & 0xFF); + currentOffset += 2; + break; + case Opcodes.BIPUSH: + case Opcodes.NEWARRAY: + methodVisitor.visitIntInsn(opcode, classBuffer[currentOffset + 1]); + currentOffset += 2; + break; + case Opcodes.SIPUSH: + methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1)); + currentOffset += 3; + break; + case Opcodes.LDC: + methodVisitor.visitLdcInsn(readConst(classBuffer[currentOffset + 1] & 0xFF, charBuffer)); + currentOffset += 2; + break; + case Constants.LDC_W: + case Constants.LDC2_W: + methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer)); + currentOffset += 3; + break; + case Opcodes.GETSTATIC: + case Opcodes.PUTSTATIC: + case Opcodes.GETFIELD: + case Opcodes.PUTFIELD: + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.INVOKEINTERFACE: + { + int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; + int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; + String owner = readClass(cpInfoOffset, charBuffer); + String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); + String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); + if (opcode < Opcodes.INVOKEVIRTUAL) { + methodVisitor.visitFieldInsn(opcode, owner, name, descriptor); + } else { + boolean isInterface = + classBuffer[cpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; + methodVisitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + } + if (opcode == Opcodes.INVOKEINTERFACE) { + currentOffset += 5; + } else { + currentOffset += 3; + } + break; + } + case Opcodes.INVOKEDYNAMIC: + { + int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; + int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; + String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); + String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); + int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; + Handle handle = + (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); + Object[] bootstrapMethodArguments = + new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; + bootstrapMethodOffset += 4; + for (int i = 0; i < bootstrapMethodArguments.length; i++) { + bootstrapMethodArguments[i] = + readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); + bootstrapMethodOffset += 2; + } + methodVisitor.visitInvokeDynamicInsn( + name, descriptor, handle, bootstrapMethodArguments); + currentOffset += 5; + break; + } + case Opcodes.NEW: + case Opcodes.ANEWARRAY: + case Opcodes.CHECKCAST: + case Opcodes.INSTANCEOF: + methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer)); + currentOffset += 3; + break; + case Opcodes.IINC: + methodVisitor.visitIincInsn( + classBuffer[currentOffset + 1] & 0xFF, classBuffer[currentOffset + 2]); + currentOffset += 3; + break; + case Opcodes.MULTIANEWARRAY: + methodVisitor.visitMultiANewArrayInsn( + readClass(currentOffset + 1, charBuffer), classBuffer[currentOffset + 3] & 0xFF); + currentOffset += 4; + break; + default: + throw new AssertionError(); + } + + // Visit the runtime visible instruction annotations, if any. + while (visibleTypeAnnotationOffsets != null + && currentVisibleTypeAnnotationIndex < visibleTypeAnnotationOffsets.length + && currentVisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { + if (currentVisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { + // Parse the target_type, target_info and target_path fields. + int currentAnnotationOffset = + readTypeAnnotationTarget( + context, visibleTypeAnnotationOffsets[currentVisibleTypeAnnotationIndex]); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + readElementValues( + methodVisitor.visitInsnAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ true), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + currentVisibleTypeAnnotationBytecodeOffset = + getTypeAnnotationBytecodeOffset( + visibleTypeAnnotationOffsets, ++currentVisibleTypeAnnotationIndex); + } + + // Visit the runtime invisible instruction annotations, if any. + while (invisibleTypeAnnotationOffsets != null + && currentInvisibleTypeAnnotationIndex < invisibleTypeAnnotationOffsets.length + && currentInvisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { + if (currentInvisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { + // Parse the target_type, target_info and target_path fields. + int currentAnnotationOffset = + readTypeAnnotationTarget( + context, invisibleTypeAnnotationOffsets[currentInvisibleTypeAnnotationIndex]); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); + currentAnnotationOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + readElementValues( + methodVisitor.visitInsnAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + annotationDescriptor, + /* visible = */ false), + currentAnnotationOffset, + /* named = */ true, + charBuffer); + } + currentInvisibleTypeAnnotationBytecodeOffset = + getTypeAnnotationBytecodeOffset( + invisibleTypeAnnotationOffsets, ++currentInvisibleTypeAnnotationIndex); + } + } + if (labels[codeLength] != null) { + methodVisitor.visitLabel(labels[codeLength]); + } + + // Visit LocalVariableTable and LocalVariableTypeTable attributes. + if (localVariableTableOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) { + // The (start_pc, index, signature_index) fields of each entry of the LocalVariableTypeTable. + int[] typeTable = null; + if (localVariableTypeTableOffset != 0) { + typeTable = new int[readUnsignedShort(localVariableTypeTableOffset) * 3]; + currentOffset = localVariableTypeTableOffset + 2; + int typeTableIndex = typeTable.length; + while (typeTableIndex > 0) { + // Store the offset of 'signature_index', and the value of 'index' and 'start_pc'. + typeTable[--typeTableIndex] = currentOffset + 6; + typeTable[--typeTableIndex] = readUnsignedShort(currentOffset + 8); + typeTable[--typeTableIndex] = readUnsignedShort(currentOffset); + currentOffset += 10; + } + } + int localVariableTableLength = readUnsignedShort(localVariableTableOffset); + currentOffset = localVariableTableOffset + 2; + while (localVariableTableLength-- > 0) { + int startPc = readUnsignedShort(currentOffset); + int length = readUnsignedShort(currentOffset + 2); + String name = readUTF8(currentOffset + 4, charBuffer); + String descriptor = readUTF8(currentOffset + 6, charBuffer); + int index = readUnsignedShort(currentOffset + 8); + currentOffset += 10; + String signature = null; + if (typeTable != null) { + for (int i = 0; i < typeTable.length; i += 3) { + if (typeTable[i] == startPc && typeTable[i + 1] == index) { + signature = readUTF8(typeTable[i + 2], charBuffer); + break; + } + } + } + methodVisitor.visitLocalVariable( + name, descriptor, signature, labels[startPc], labels[startPc + length], index); + } + } + + // Visit the local variable type annotations of the RuntimeVisibleTypeAnnotations attribute. + if (visibleTypeAnnotationOffsets != null) { + for (int typeAnnotationOffset : visibleTypeAnnotationOffsets) { + int targetType = readByte(typeAnnotationOffset); + if (targetType == TypeReference.LOCAL_VARIABLE + || targetType == TypeReference.RESOURCE_VARIABLE) { + // Parse the target_type, target_info and target_path fields. + currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentOffset, charBuffer); + currentOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + readElementValues( + methodVisitor.visitLocalVariableAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + context.currentLocalVariableAnnotationRangeStarts, + context.currentLocalVariableAnnotationRangeEnds, + context.currentLocalVariableAnnotationRangeIndices, + annotationDescriptor, + /* visible = */ true), + currentOffset, + /* named = */ true, + charBuffer); + } + } + } + + // Visit the local variable type annotations of the RuntimeInvisibleTypeAnnotations attribute. + if (invisibleTypeAnnotationOffsets != null) { + for (int typeAnnotationOffset : invisibleTypeAnnotationOffsets) { + int targetType = readByte(typeAnnotationOffset); + if (targetType == TypeReference.LOCAL_VARIABLE + || targetType == TypeReference.RESOURCE_VARIABLE) { + // Parse the target_type, target_info and target_path fields. + currentOffset = readTypeAnnotationTarget(context, typeAnnotationOffset); + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentOffset, charBuffer); + currentOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + readElementValues( + methodVisitor.visitLocalVariableAnnotation( + context.currentTypeAnnotationTarget, + context.currentTypeAnnotationTargetPath, + context.currentLocalVariableAnnotationRangeStarts, + context.currentLocalVariableAnnotationRangeEnds, + context.currentLocalVariableAnnotationRangeIndices, + annotationDescriptor, + /* visible = */ false), + currentOffset, + /* named = */ true, + charBuffer); + } + } + } + + // Visit the non standard attributes. + while (attributes != null) { + // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. + Attribute nextAttribute = attributes.nextAttribute; + attributes.nextAttribute = null; + methodVisitor.visitAttribute(attributes); + attributes = nextAttribute; + } + + // Visit the max stack and max locals values. + methodVisitor.visitMaxs(maxStack, maxLocals); + } + + /** + * Handles the bytecode offset of the next instruction to be visited in {@link + * #accept(ClassVisitor,int)}. This method is called just before the instruction and before its + * associated label and stack map frame, if any. The default implementation of this method does + * nothing. Subclasses can override this method to store the argument in a mutable field, for + * instance, so that {@link MethodVisitor} instances can get the bytecode offset of each visited + * instruction (if so, the usual concurrency issues related to mutable data should be addressed). + * + * @param bytecodeOffset the bytecode offset of the next instruction to be visited. + */ + protected void readBytecodeInstructionOffset(final int bytecodeOffset) { + // Do nothing by default. + } + + /** + * Returns the label corresponding to the given bytecode offset. The default implementation of + * this method creates a label for the given offset if it has not been already created. + * + * @param bytecodeOffset a bytecode offset in a method. + * @param labels the already created labels, indexed by their offset. If a label already exists + * for bytecodeOffset this method must not create a new one. Otherwise it must store the new + * label in this array. + * @return a non null Label, which must be equal to labels[bytecodeOffset]. + */ + protected Label readLabel(final int bytecodeOffset, final Label[] labels) { + if (labels[bytecodeOffset] == null) { + labels[bytecodeOffset] = new Label(); + } + return labels[bytecodeOffset]; + } + + /** + * Creates a label without the {@link Label#FLAG_DEBUG_ONLY} flag set, for the given bytecode + * offset. The label is created with a call to {@link #readLabel} and its {@link + * Label#FLAG_DEBUG_ONLY} flag is cleared. + * + * @param bytecodeOffset a bytecode offset in a method. + * @param labels the already created labels, indexed by their offset. + * @return a Label without the {@link Label#FLAG_DEBUG_ONLY} flag set. + */ + private Label createLabel(final int bytecodeOffset, final Label[] labels) { + Label label = readLabel(bytecodeOffset, labels); + label.flags &= ~Label.FLAG_DEBUG_ONLY; + return label; + } + + /** + * Creates a label with the {@link Label#FLAG_DEBUG_ONLY} flag set, if there is no already + * existing label for the given bytecode offset (otherwise does nothing). The label is created + * with a call to {@link #readLabel}. + * + * @param bytecodeOffset a bytecode offset in a method. + * @param labels the already created labels, indexed by their offset. + */ + private void createDebugLabel(final int bytecodeOffset, final Label[] labels) { + if (labels[bytecodeOffset] == null) { + readLabel(bytecodeOffset, labels).flags |= Label.FLAG_DEBUG_ONLY; + } + } + + // ---------------------------------------------------------------------------------------------- + // Methods to parse annotations, type annotations and parameter annotations + // ---------------------------------------------------------------------------------------------- + + /** + * Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation + * entry it contains, to find the corresponding labels, and to visit the try catch block + * annotations. + * + * @param methodVisitor the method visitor to be used to visit the try catch block annotations. + * @param context information about the class being parsed. + * @param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations + * attribute, excluding the attribute_info's attribute_name_index and attribute_length fields. + * @param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute, + * false it is a RuntimeInvisibleTypeAnnotations attribute. + * @return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's + * 'annotations' array field. + */ + private int[] readTypeAnnotations( + final MethodVisitor methodVisitor, + final Context context, + final int runtimeTypeAnnotationsOffset, + final boolean visible) { + char[] charBuffer = context.charBuffer; + int currentOffset = runtimeTypeAnnotationsOffset; + // Read the num_annotations field and create an array to store the type_annotation offsets. + int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)]; + currentOffset += 2; + // Parse the 'annotations' array field. + for (int i = 0; i < typeAnnotationsOffsets.length; ++i) { + typeAnnotationsOffsets[i] = currentOffset; + // Parse the type_annotation's target_type and the target_info fields. The size of the + // target_info field depends on the value of target_type. + int targetType = readInt(currentOffset); + switch (targetType >>> 24) { + case TypeReference.LOCAL_VARIABLE: + case TypeReference.RESOURCE_VARIABLE: + // A localvar_target has a variable size, which depends on the value of their table_length + // field. It also references bytecode offsets, for which we need labels. + int tableLength = readUnsignedShort(currentOffset + 1); + currentOffset += 3; + while (tableLength-- > 0) { + int startPc = readUnsignedShort(currentOffset); + int length = readUnsignedShort(currentOffset + 2); + // Skip the index field (2 bytes). + currentOffset += 6; + createLabel(startPc, context.currentMethodLabels); + createLabel(startPc + length, context.currentMethodLabels); + } + break; + case TypeReference.CAST: + case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: + case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: + case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: + currentOffset += 4; + break; + case TypeReference.CLASS_EXTENDS: + case TypeReference.CLASS_TYPE_PARAMETER_BOUND: + case TypeReference.METHOD_TYPE_PARAMETER_BOUND: + case TypeReference.THROWS: + case TypeReference.EXCEPTION_PARAMETER: + case TypeReference.INSTANCEOF: + case TypeReference.NEW: + case TypeReference.CONSTRUCTOR_REFERENCE: + case TypeReference.METHOD_REFERENCE: + currentOffset += 3; + break; + case TypeReference.CLASS_TYPE_PARAMETER: + case TypeReference.METHOD_TYPE_PARAMETER: + case TypeReference.METHOD_FORMAL_PARAMETER: + case TypeReference.FIELD: + case TypeReference.METHOD_RETURN: + case TypeReference.METHOD_RECEIVER: + default: + // TypeReference type which can't be used in Code attribute, or which is unknown. + throw new IllegalArgumentException(); + } + // Parse the rest of the type_annotation structure, starting with the target_path structure + // (whose size depends on its path_length field). + int pathLength = readByte(currentOffset); + if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) { + // Parse the target_path structure and create a corresponding TypePath. + TypePath path = pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); + currentOffset += 1 + 2 * pathLength; + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentOffset, charBuffer); + currentOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentOffset = + readElementValues( + methodVisitor.visitTryCatchAnnotation( + targetType & 0xFFFFFF00, path, annotationDescriptor, visible), + currentOffset, + /* named = */ true, + charBuffer); + } else { + // We don't want to visit the other target_type annotations, so we just skip them (which + // requires some parsing because the element_value_pairs array has a variable size). First, + // skip the target_path structure: + currentOffset += 3 + 2 * pathLength; + // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them + // with a null AnnotationVisitor). + currentOffset = + readElementValues( + /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer); + } + } + return typeAnnotationsOffsets; + } + + /** + * Returns the bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or + * -1 if there is no such type_annotation of if it does not have a bytecode offset. + * + * @param typeAnnotationOffsets the offset of each 'type_annotation' entry in a + * Runtime[In]VisibleTypeAnnotations attribute, or {@literal null}. + * @param typeAnnotationIndex the index a 'type_annotation' entry in typeAnnotationOffsets. + * @return bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or -1 + * if there is no such type_annotation of if it does not have a bytecode offset. + */ + private int getTypeAnnotationBytecodeOffset( + final int[] typeAnnotationOffsets, final int typeAnnotationIndex) { + if (typeAnnotationOffsets == null + || typeAnnotationIndex >= typeAnnotationOffsets.length + || readByte(typeAnnotationOffsets[typeAnnotationIndex]) < TypeReference.INSTANCEOF) { + return -1; + } + return readUnsignedShort(typeAnnotationOffsets[typeAnnotationIndex] + 1); + } + + /** + * Parses the header of a JVMS type_annotation structure to extract its target_type, target_info + * and target_path (the result is stored in the given context), and returns the start offset of + * the rest of the type_annotation structure. + * + * @param context information about the class being parsed. This is where the extracted + * target_type and target_path must be stored. + * @param typeAnnotationOffset the start offset of a type_annotation structure. + * @return the start offset of the rest of the type_annotation structure. + */ + private int readTypeAnnotationTarget(final Context context, final int typeAnnotationOffset) { + int currentOffset = typeAnnotationOffset; + // Parse and store the target_type structure. + int targetType = readInt(typeAnnotationOffset); + switch (targetType >>> 24) { + case TypeReference.CLASS_TYPE_PARAMETER: + case TypeReference.METHOD_TYPE_PARAMETER: + case TypeReference.METHOD_FORMAL_PARAMETER: + targetType &= 0xFFFF0000; + currentOffset += 2; + break; + case TypeReference.FIELD: + case TypeReference.METHOD_RETURN: + case TypeReference.METHOD_RECEIVER: + targetType &= 0xFF000000; + currentOffset += 1; + break; + case TypeReference.LOCAL_VARIABLE: + case TypeReference.RESOURCE_VARIABLE: + targetType &= 0xFF000000; + int tableLength = readUnsignedShort(currentOffset + 1); + currentOffset += 3; + context.currentLocalVariableAnnotationRangeStarts = new Label[tableLength]; + context.currentLocalVariableAnnotationRangeEnds = new Label[tableLength]; + context.currentLocalVariableAnnotationRangeIndices = new int[tableLength]; + for (int i = 0; i < tableLength; ++i) { + int startPc = readUnsignedShort(currentOffset); + int length = readUnsignedShort(currentOffset + 2); + int index = readUnsignedShort(currentOffset + 4); + currentOffset += 6; + context.currentLocalVariableAnnotationRangeStarts[i] = + createLabel(startPc, context.currentMethodLabels); + context.currentLocalVariableAnnotationRangeEnds[i] = + createLabel(startPc + length, context.currentMethodLabels); + context.currentLocalVariableAnnotationRangeIndices[i] = index; + } + break; + case TypeReference.CAST: + case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: + case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: + case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: + targetType &= 0xFF0000FF; + currentOffset += 4; + break; + case TypeReference.CLASS_EXTENDS: + case TypeReference.CLASS_TYPE_PARAMETER_BOUND: + case TypeReference.METHOD_TYPE_PARAMETER_BOUND: + case TypeReference.THROWS: + case TypeReference.EXCEPTION_PARAMETER: + targetType &= 0xFFFFFF00; + currentOffset += 3; + break; + case TypeReference.INSTANCEOF: + case TypeReference.NEW: + case TypeReference.CONSTRUCTOR_REFERENCE: + case TypeReference.METHOD_REFERENCE: + targetType &= 0xFF000000; + currentOffset += 3; + break; + default: + throw new IllegalArgumentException(); + } + context.currentTypeAnnotationTarget = targetType; + // Parse and store the target_path structure. + int pathLength = readByte(currentOffset); + context.currentTypeAnnotationTargetPath = + pathLength == 0 ? null : new TypePath(classFileBuffer, currentOffset); + // Return the start offset of the rest of the type_annotation structure. + return currentOffset + 1 + 2 * pathLength; + } + + /** + * Reads a Runtime[In]VisibleParameterAnnotations attribute and makes the given visitor visit it. + * + * @param methodVisitor the visitor that must visit the parameter annotations. + * @param context information about the class being parsed. + * @param runtimeParameterAnnotationsOffset the start offset of a + * Runtime[In]VisibleParameterAnnotations attribute, excluding the attribute_info's + * attribute_name_index and attribute_length fields. + * @param visible true if the attribute to parse is a RuntimeVisibleParameterAnnotations + * attribute, false it is a RuntimeInvisibleParameterAnnotations attribute. + */ + private void readParameterAnnotations( + final MethodVisitor methodVisitor, + final Context context, + final int runtimeParameterAnnotationsOffset, + final boolean visible) { + int currentOffset = runtimeParameterAnnotationsOffset; + int numParameters = classFileBuffer[currentOffset++] & 0xFF; + methodVisitor.visitAnnotableParameterCount(numParameters, visible); + char[] charBuffer = context.charBuffer; + for (int i = 0; i < numParameters; ++i) { + int numAnnotations = readUnsignedShort(currentOffset); + currentOffset += 2; + while (numAnnotations-- > 0) { + // Parse the type_index field. + String annotationDescriptor = readUTF8(currentOffset, charBuffer); + currentOffset += 2; + // Parse num_element_value_pairs and element_value_pairs and visit these values. + currentOffset = + readElementValues( + methodVisitor.visitParameterAnnotation(i, annotationDescriptor, visible), + currentOffset, + /* named = */ true, + charBuffer); + } + } + } + + /** + * Reads the element values of a JVMS 'annotation' structure and makes the given visitor visit + * them. This method can also be used to read the values of the JVMS 'array_value' field of an + * annotation's 'element_value'. + * + * @param annotationVisitor the visitor that must visit the values. + * @param annotationOffset the start offset of an 'annotation' structure (excluding its type_index + * field) or of an 'array_value' structure. + * @param named if the annotation values are named or not. This should be true to parse the values + * of a JVMS 'annotation' structure, and false to parse the JVMS 'array_value' of an + * annotation's element_value. + * @param charBuffer the buffer used to read strings in the constant pool. + * @return the end offset of the JVMS 'annotation' or 'array_value' structure. + */ + private int readElementValues( + final AnnotationVisitor annotationVisitor, + final int annotationOffset, + final boolean named, + final char[] charBuffer) { + int currentOffset = annotationOffset; + // Read the num_element_value_pairs field (or num_values field for an array_value). + int numElementValuePairs = readUnsignedShort(currentOffset); + currentOffset += 2; + if (named) { + // Parse the element_value_pairs array. + while (numElementValuePairs-- > 0) { + String elementName = readUTF8(currentOffset, charBuffer); + currentOffset = + readElementValue(annotationVisitor, currentOffset + 2, elementName, charBuffer); + } + } else { + // Parse the array_value array. + while (numElementValuePairs-- > 0) { + currentOffset = + readElementValue(annotationVisitor, currentOffset, /* elementName= */ null, charBuffer); + } + } + if (annotationVisitor != null) { + annotationVisitor.visitEnd(); + } + return currentOffset; + } + + /** + * Reads a JVMS 'element_value' structure and makes the given visitor visit it. + * + * @param annotationVisitor the visitor that must visit the element_value structure. + * @param elementValueOffset the start offset in {@link #classFileBuffer} of the element_value + * structure to be read. + * @param elementName the name of the element_value structure to be read, or {@literal null}. + * @param charBuffer the buffer used to read strings in the constant pool. + * @return the end offset of the JVMS 'element_value' structure. + */ + private int readElementValue( + final AnnotationVisitor annotationVisitor, + final int elementValueOffset, + final String elementName, + final char[] charBuffer) { + int currentOffset = elementValueOffset; + if (annotationVisitor == null) { + switch (classFileBuffer[currentOffset] & 0xFF) { + case 'e': // enum_const_value + return currentOffset + 5; + case '@': // annotation_value + return readElementValues(null, currentOffset + 3, /* named = */ true, charBuffer); + case '[': // array_value + return readElementValues(null, currentOffset + 1, /* named = */ false, charBuffer); + default: + return currentOffset + 3; + } + } + switch (classFileBuffer[currentOffset++] & 0xFF) { + case 'B': // const_value_index, CONSTANT_Integer + annotationVisitor.visit( + elementName, (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); + currentOffset += 2; + break; + case 'C': // const_value_index, CONSTANT_Integer + annotationVisitor.visit( + elementName, (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); + currentOffset += 2; + break; + case 'D': // const_value_index, CONSTANT_Double + case 'F': // const_value_index, CONSTANT_Float + case 'I': // const_value_index, CONSTANT_Integer + case 'J': // const_value_index, CONSTANT_Long + annotationVisitor.visit( + elementName, readConst(readUnsignedShort(currentOffset), charBuffer)); + currentOffset += 2; + break; + case 'S': // const_value_index, CONSTANT_Integer + annotationVisitor.visit( + elementName, (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); + currentOffset += 2; + break; + + case 'Z': // const_value_index, CONSTANT_Integer + annotationVisitor.visit( + elementName, + readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]) == 0 + ? Boolean.FALSE + : Boolean.TRUE); + currentOffset += 2; + break; + case 's': // const_value_index, CONSTANT_Utf8 + annotationVisitor.visit(elementName, readUTF8(currentOffset, charBuffer)); + currentOffset += 2; + break; + case 'e': // enum_const_value + annotationVisitor.visitEnum( + elementName, + readUTF8(currentOffset, charBuffer), + readUTF8(currentOffset + 2, charBuffer)); + currentOffset += 4; + break; + case 'c': // class_info + annotationVisitor.visit(elementName, Type.getType(readUTF8(currentOffset, charBuffer))); + currentOffset += 2; + break; + case '@': // annotation_value + currentOffset = + readElementValues( + annotationVisitor.visitAnnotation(elementName, readUTF8(currentOffset, charBuffer)), + currentOffset + 2, + true, + charBuffer); + break; + case '[': // array_value + int numValues = readUnsignedShort(currentOffset); + currentOffset += 2; + if (numValues == 0) { + return readElementValues( + annotationVisitor.visitArray(elementName), + currentOffset - 2, + /* named = */ false, + charBuffer); + } + switch (classFileBuffer[currentOffset] & 0xFF) { + case 'B': + byte[] byteValues = new byte[numValues]; + for (int i = 0; i < numValues; i++) { + byteValues[i] = (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, byteValues); + break; + case 'Z': + boolean[] booleanValues = new boolean[numValues]; + for (int i = 0; i < numValues; i++) { + booleanValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]) != 0; + currentOffset += 3; + } + annotationVisitor.visit(elementName, booleanValues); + break; + case 'S': + short[] shortValues = new short[numValues]; + for (int i = 0; i < numValues; i++) { + shortValues[i] = (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, shortValues); + break; + case 'C': + char[] charValues = new char[numValues]; + for (int i = 0; i < numValues; i++) { + charValues[i] = (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, charValues); + break; + case 'I': + int[] intValues = new int[numValues]; + for (int i = 0; i < numValues; i++) { + intValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, intValues); + break; + case 'J': + long[] longValues = new long[numValues]; + for (int i = 0; i < numValues; i++) { + longValues[i] = readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); + currentOffset += 3; + } + annotationVisitor.visit(elementName, longValues); + break; + case 'F': + float[] floatValues = new float[numValues]; + for (int i = 0; i < numValues; i++) { + floatValues[i] = + Float.intBitsToFloat( + readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); + currentOffset += 3; + } + annotationVisitor.visit(elementName, floatValues); + break; + case 'D': + double[] doubleValues = new double[numValues]; + for (int i = 0; i < numValues; i++) { + doubleValues[i] = + Double.longBitsToDouble( + readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); + currentOffset += 3; + } + annotationVisitor.visit(elementName, doubleValues); + break; + default: + currentOffset = + readElementValues( + annotationVisitor.visitArray(elementName), + currentOffset - 2, + /* named = */ false, + charBuffer); + break; + } + break; + default: + throw new IllegalArgumentException(); + } + return currentOffset; + } + + // ---------------------------------------------------------------------------------------------- + // Methods to parse stack map frames + // ---------------------------------------------------------------------------------------------- + + /** + * Computes the implicit frame of the method currently being parsed (as defined in the given + * {@link Context}) and stores it in the given context. + * + * @param context information about the class being parsed. + */ + private void computeImplicitFrame(final Context context) { + String methodDescriptor = context.currentMethodDescriptor; + Object[] locals = context.currentFrameLocalTypes; + int numLocal = 0; + if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) { + if ("".equals(context.currentMethodName)) { + locals[numLocal++] = Opcodes.UNINITIALIZED_THIS; + } else { + locals[numLocal++] = readClass(header + 2, context.charBuffer); + } + } + // Parse the method descriptor, one argument type descriptor at each iteration. Start by + // skipping the first method descriptor character, which is always '('. + int currentMethodDescritorOffset = 1; + while (true) { + int currentArgumentDescriptorStartOffset = currentMethodDescritorOffset; + switch (methodDescriptor.charAt(currentMethodDescritorOffset++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + locals[numLocal++] = Opcodes.INTEGER; + break; + case 'F': + locals[numLocal++] = Opcodes.FLOAT; + break; + case 'J': + locals[numLocal++] = Opcodes.LONG; + break; + case 'D': + locals[numLocal++] = Opcodes.DOUBLE; + break; + case '[': + while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') { + ++currentMethodDescritorOffset; + } + if (methodDescriptor.charAt(currentMethodDescritorOffset) == 'L') { + ++currentMethodDescritorOffset; + while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { + ++currentMethodDescritorOffset; + } + } + locals[numLocal++] = + methodDescriptor.substring( + currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset); + break; + case 'L': + while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { + ++currentMethodDescritorOffset; + } + locals[numLocal++] = + methodDescriptor.substring( + currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++); + break; + default: + context.currentFrameLocalCount = numLocal; + return; + } + } + } + + /** + * Reads a JVMS 'stack_map_frame' structure and stores the result in the given {@link Context} + * object. This method can also be used to read a full_frame structure, excluding its frame_type + * field (this is used to parse the legacy StackMap attributes). + * + * @param stackMapFrameOffset the start offset in {@link #classFileBuffer} of the + * stack_map_frame_value structure to be read, or the start offset of a full_frame structure + * (excluding its frame_type field). + * @param compressed true to read a 'stack_map_frame' structure, false to read a 'full_frame' + * structure without its frame_type field. + * @param expand if the stack map frame must be expanded. See {@link #EXPAND_FRAMES}. + * @param context where the parsed stack map frame must be stored. + * @return the end offset of the JVMS 'stack_map_frame' or 'full_frame' structure. + */ + private int readStackMapFrame( + final int stackMapFrameOffset, + final boolean compressed, + final boolean expand, + final Context context) { + int currentOffset = stackMapFrameOffset; + final char[] charBuffer = context.charBuffer; + final Label[] labels = context.currentMethodLabels; + int frameType; + if (compressed) { + // Read the frame_type field. + frameType = classFileBuffer[currentOffset++] & 0xFF; + } else { + frameType = Frame.FULL_FRAME; + context.currentFrameOffset = -1; + } + int offsetDelta; + context.currentFrameLocalCountDelta = 0; + if (frameType < Frame.SAME_LOCALS_1_STACK_ITEM_FRAME) { + offsetDelta = frameType; + context.currentFrameType = Opcodes.F_SAME; + context.currentFrameStackCount = 0; + } else if (frameType < Frame.RESERVED) { + offsetDelta = frameType - Frame.SAME_LOCALS_1_STACK_ITEM_FRAME; + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); + context.currentFrameType = Opcodes.F_SAME1; + context.currentFrameStackCount = 1; + } else if (frameType >= Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { + offsetDelta = readUnsignedShort(currentOffset); + currentOffset += 2; + if (frameType == Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); + context.currentFrameType = Opcodes.F_SAME1; + context.currentFrameStackCount = 1; + } else if (frameType >= Frame.CHOP_FRAME && frameType < Frame.SAME_FRAME_EXTENDED) { + context.currentFrameType = Opcodes.F_CHOP; + context.currentFrameLocalCountDelta = Frame.SAME_FRAME_EXTENDED - frameType; + context.currentFrameLocalCount -= context.currentFrameLocalCountDelta; + context.currentFrameStackCount = 0; + } else if (frameType == Frame.SAME_FRAME_EXTENDED) { + context.currentFrameType = Opcodes.F_SAME; + context.currentFrameStackCount = 0; + } else if (frameType < Frame.FULL_FRAME) { + int local = expand ? context.currentFrameLocalCount : 0; + for (int k = frameType - Frame.SAME_FRAME_EXTENDED; k > 0; k--) { + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameLocalTypes, local++, charBuffer, labels); + } + context.currentFrameType = Opcodes.F_APPEND; + context.currentFrameLocalCountDelta = frameType - Frame.SAME_FRAME_EXTENDED; + context.currentFrameLocalCount += context.currentFrameLocalCountDelta; + context.currentFrameStackCount = 0; + } else { + final int numberOfLocals = readUnsignedShort(currentOffset); + currentOffset += 2; + context.currentFrameType = Opcodes.F_FULL; + context.currentFrameLocalCountDelta = numberOfLocals; + context.currentFrameLocalCount = numberOfLocals; + for (int local = 0; local < numberOfLocals; ++local) { + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameLocalTypes, local, charBuffer, labels); + } + final int numberOfStackItems = readUnsignedShort(currentOffset); + currentOffset += 2; + context.currentFrameStackCount = numberOfStackItems; + for (int stack = 0; stack < numberOfStackItems; ++stack) { + currentOffset = + readVerificationTypeInfo( + currentOffset, context.currentFrameStackTypes, stack, charBuffer, labels); + } + } + } else { + throw new IllegalArgumentException(); + } + context.currentFrameOffset += offsetDelta + 1; + createLabel(context.currentFrameOffset, labels); + return currentOffset; + } + + /** + * Reads a JVMS 'verification_type_info' structure and stores it at the given index in the given + * array. + * + * @param verificationTypeInfoOffset the start offset of the 'verification_type_info' structure to + * read. + * @param frame the array where the parsed type must be stored. + * @param index the index in 'frame' where the parsed type must be stored. + * @param charBuffer the buffer used to read strings in the constant pool. + * @param labels the labels of the method currently being parsed, indexed by their offset. If the + * parsed type is an ITEM_Uninitialized, a new label for the corresponding NEW instruction is + * stored in this array if it does not already exist. + * @return the end offset of the JVMS 'verification_type_info' structure. + */ + private int readVerificationTypeInfo( + final int verificationTypeInfoOffset, + final Object[] frame, + final int index, + final char[] charBuffer, + final Label[] labels) { + int currentOffset = verificationTypeInfoOffset; + int tag = classFileBuffer[currentOffset++] & 0xFF; + switch (tag) { + case Frame.ITEM_TOP: + frame[index] = Opcodes.TOP; + break; + case Frame.ITEM_INTEGER: + frame[index] = Opcodes.INTEGER; + break; + case Frame.ITEM_FLOAT: + frame[index] = Opcodes.FLOAT; + break; + case Frame.ITEM_DOUBLE: + frame[index] = Opcodes.DOUBLE; + break; + case Frame.ITEM_LONG: + frame[index] = Opcodes.LONG; + break; + case Frame.ITEM_NULL: + frame[index] = Opcodes.NULL; + break; + case Frame.ITEM_UNINITIALIZED_THIS: + frame[index] = Opcodes.UNINITIALIZED_THIS; + break; + case Frame.ITEM_OBJECT: + frame[index] = readClass(currentOffset, charBuffer); + currentOffset += 2; + break; + case Frame.ITEM_UNINITIALIZED: + frame[index] = createLabel(readUnsignedShort(currentOffset), labels); + currentOffset += 2; + break; + default: + throw new IllegalArgumentException(); + } + return currentOffset; + } + + // ---------------------------------------------------------------------------------------------- + // Methods to parse attributes + // ---------------------------------------------------------------------------------------------- + + /** + * Returns the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array + * field entry. + * + * @return the offset in {@link #classFileBuffer} of the first ClassFile's 'attributes' array + * field entry. + */ + final int getFirstAttributeOffset() { + // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes + // each), as well as the interfaces array field (2 bytes per interface). + int currentOffset = header + 8 + readUnsignedShort(header + 6) * 2; + + // Read the fields_count field. + int fieldsCount = readUnsignedShort(currentOffset); + currentOffset += 2; + // Skip the 'fields' array field. + while (fieldsCount-- > 0) { + // Invariant: currentOffset is the offset of a field_info structure. + // Skip the access_flags, name_index and descriptor_index fields (2 bytes each), and read the + // attributes_count field. + int attributesCount = readUnsignedShort(currentOffset + 6); + currentOffset += 8; + // Skip the 'attributes' array field. + while (attributesCount-- > 0) { + // Invariant: currentOffset is the offset of an attribute_info structure. + // Read the attribute_length field (2 bytes after the start of the attribute_info) and skip + // this many bytes, plus 6 for the attribute_name_index and attribute_length fields + // (yielding the total size of the attribute_info structure). + currentOffset += 6 + readInt(currentOffset + 2); + } + } + + // Skip the methods_count and 'methods' fields, using the same method as above. + int methodsCount = readUnsignedShort(currentOffset); + currentOffset += 2; + while (methodsCount-- > 0) { + int attributesCount = readUnsignedShort(currentOffset + 6); + currentOffset += 8; + while (attributesCount-- > 0) { + currentOffset += 6 + readInt(currentOffset + 2); + } + } + + // Skip the ClassFile's attributes_count field. + return currentOffset + 2; + } + + /** + * Reads the BootstrapMethods attribute to compute the offset of each bootstrap method. + * + * @param maxStringLength a conservative estimate of the maximum length of the strings contained + * in the constant pool of the class. + * @return the offsets of the bootstrap methods. + */ + private int[] readBootstrapMethodsAttribute(final int maxStringLength) { + char[] charBuffer = new char[maxStringLength]; + int currentAttributeOffset = getFirstAttributeOffset(); + for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { + // Read the attribute_info's attribute_name and attribute_length fields. + String attributeName = readUTF8(currentAttributeOffset, charBuffer); + int attributeLength = readInt(currentAttributeOffset + 2); + currentAttributeOffset += 6; + if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { + // Read the num_bootstrap_methods field and create an array of this size. + int[] result = new int[readUnsignedShort(currentAttributeOffset)]; + // Compute and store the offset of each 'bootstrap_methods' array field entry. + int currentBootstrapMethodOffset = currentAttributeOffset + 2; + for (int j = 0; j < result.length; ++j) { + result[j] = currentBootstrapMethodOffset; + // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each), + // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2). + currentBootstrapMethodOffset += + 4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2; + } + return result; + } + currentAttributeOffset += attributeLength; + } + throw new IllegalArgumentException(); + } + + /** + * Reads a non standard JVMS 'attribute' structure in {@link #classFileBuffer}. + * + * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of + * the class. Any attribute whose type is not equal to the type of one the prototypes will not + * be parsed: its byte array value will be passed unchanged to the ClassWriter. + * @param type the type of the attribute. + * @param offset the start offset of the JVMS 'attribute' structure in {@link #classFileBuffer}. + * The 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into + * account here. + * @param length the length of the attribute's content (excluding the 6 attribute header bytes). + * @param charBuffer the buffer to be used to read strings in the constant pool. + * @param codeAttributeOffset the start offset of the enclosing Code attribute in {@link + * #classFileBuffer}, or -1 if the attribute to be read is not a code attribute. The 6 + * attribute header bytes (attribute_name_index and attribute_length) are not taken into + * account here. + * @param labels the labels of the method's code, or {@literal null} if the attribute to be read + * is not a code attribute. + * @return the attribute that has been read. + */ + private Attribute readAttribute( + final Attribute[] attributePrototypes, + final String type, + final int offset, + final int length, + final char[] charBuffer, + final int codeAttributeOffset, + final Label[] labels) { + for (Attribute attributePrototype : attributePrototypes) { + if (attributePrototype.type.equals(type)) { + return attributePrototype.read( + this, offset, length, charBuffer, codeAttributeOffset, labels); + } + } + return new Attribute(type).read(this, offset, length, null, -1, null); + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods: low level parsing + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the number of entries in the class's constant pool table. + * + * @return the number of entries in the class's constant pool table. + */ + public int getItemCount() { + return cpInfoOffsets.length; + } + + /** + * Returns the start offset in this {@link ClassReader} of a JVMS 'cp_info' structure (i.e. a + * constant pool entry), plus one. This method is intended for {@link Attribute} sub classes, + * and is normally not needed by class generators or adapters. + * + * @param constantPoolEntryIndex the index a constant pool entry in the class's constant pool + * table. + * @return the start offset in this {@link ClassReader} of the corresponding JVMS 'cp_info' + * structure, plus one. + */ + public int getItem(final int constantPoolEntryIndex) { + return cpInfoOffsets[constantPoolEntryIndex]; + } + + /** + * Returns a conservative estimate of the maximum length of the strings contained in the class's + * constant pool table. + * + * @return a conservative estimate of the maximum length of the strings contained in the class's + * constant pool table. + */ + public int getMaxStringLength() { + return maxStringLength; + } + + /** + * Reads a byte value in this {@link ClassReader}. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start offset of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public int readByte(final int offset) { + return classFileBuffer[offset] & 0xFF; + } + + /** + * Reads an unsigned short value in this {@link ClassReader}. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start index of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public int readUnsignedShort(final int offset) { + byte[] classBuffer = classFileBuffer; + return ((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF); + } + + /** + * Reads a signed short value in this {@link ClassReader}. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start offset of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public short readShort(final int offset) { + byte[] classBuffer = classFileBuffer; + return (short) (((classBuffer[offset] & 0xFF) << 8) | (classBuffer[offset + 1] & 0xFF)); + } + + /** + * Reads a signed int value in this {@link ClassReader}. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start offset of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public int readInt(final int offset) { + byte[] classBuffer = classFileBuffer; + return ((classBuffer[offset] & 0xFF) << 24) + | ((classBuffer[offset + 1] & 0xFF) << 16) + | ((classBuffer[offset + 2] & 0xFF) << 8) + | (classBuffer[offset + 3] & 0xFF); + } + + /** + * Reads a signed long value in this {@link ClassReader}. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param offset the start offset of the value to be read in this {@link ClassReader}. + * @return the read value. + */ + public long readLong(final int offset) { + long l1 = readInt(offset); + long l0 = readInt(offset + 4) & 0xFFFFFFFFL; + return (l1 << 32) | l0; + } + + /** + * Reads a CONSTANT_Utf8 constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose + * value is the index of a CONSTANT_Utf8 entry in the class's constant pool table. + * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Utf8 entry. + */ + // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). + public String readUTF8(final int offset, final char[] charBuffer) { + int constantPoolEntryIndex = readUnsignedShort(offset); + if (offset == 0 || constantPoolEntryIndex == 0) { + return null; + } + return readUtf(constantPoolEntryIndex, charBuffer); + } + + /** + * Reads a CONSTANT_Utf8 constant pool entry in {@link #classFileBuffer}. + * + * @param constantPoolEntryIndex the index of a CONSTANT_Utf8 entry in the class's constant pool + * table. + * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Utf8 entry. + */ + final String readUtf(final int constantPoolEntryIndex, final char[] charBuffer) { + String value = constantUtf8Values[constantPoolEntryIndex]; + if (value != null) { + return value; + } + int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; + return constantUtf8Values[constantPoolEntryIndex] = + readUtf(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer); + } + + /** + * Reads an UTF8 string in {@link #classFileBuffer}. + * + * @param utfOffset the start offset of the UTF8 string to be read. + * @param utfLength the length of the UTF8 string to be read. + * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified UTF8 string. + */ + private String readUtf(final int utfOffset, final int utfLength, final char[] charBuffer) { + int currentOffset = utfOffset; + int endOffset = currentOffset + utfLength; + int strLength = 0; + byte[] classBuffer = classFileBuffer; + while (currentOffset < endOffset) { + int currentByte = classBuffer[currentOffset++]; + if ((currentByte & 0x80) == 0) { + charBuffer[strLength++] = (char) (currentByte & 0x7F); + } else if ((currentByte & 0xE0) == 0xC0) { + charBuffer[strLength++] = + (char) (((currentByte & 0x1F) << 6) + (classBuffer[currentOffset++] & 0x3F)); + } else { + charBuffer[strLength++] = + (char) + (((currentByte & 0xF) << 12) + + ((classBuffer[currentOffset++] & 0x3F) << 6) + + (classBuffer[currentOffset++] & 0x3F)); + } + } + return new String(charBuffer, 0, strLength); + } + + /** + * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or + * CONSTANT_Package constant pool entry in {@link #classFileBuffer}. This method is intended + * for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in {@link #classFileBuffer}, whose + * value is the index of a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, + * CONSTANT_Module or CONSTANT_Package entry in class's constant pool table. + * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified constant pool entry. + */ + private String readStringish(final int offset, final char[] charBuffer) { + // Get the start offset of the cp_info structure (plus one), and read the CONSTANT_Utf8 entry + // designated by the first two bytes of this cp_info. + return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer); + } + + /** + * Reads a CONSTANT_Class constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose + * value is the index of a CONSTANT_Class entry in class's constant pool table. + * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Class entry. + */ + public String readClass(final int offset, final char[] charBuffer) { + return readStringish(offset, charBuffer); + } + + /** + * Reads a CONSTANT_Module constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose + * value is the index of a CONSTANT_Module entry in class's constant pool table. + * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Module entry. + */ + public String readModule(final int offset, final char[] charBuffer) { + return readStringish(offset, charBuffer); + } + + /** + * Reads a CONSTANT_Package constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param offset the start offset of an unsigned short value in this {@link ClassReader}, whose + * value is the index of a CONSTANT_Package entry in class's constant pool table. + * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the String corresponding to the specified CONSTANT_Package entry. + */ + public String readPackage(final int offset, final char[] charBuffer) { + return readStringish(offset, charBuffer); + } + + /** + * Reads a CONSTANT_Dynamic constant pool entry in {@link #classFileBuffer}. + * + * @param constantPoolEntryIndex the index of a CONSTANT_Dynamic entry in the class's constant + * pool table. + * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the ConstantDynamic corresponding to the specified CONSTANT_Dynamic entry. + */ + private ConstantDynamic readConstantDynamic( + final int constantPoolEntryIndex, final char[] charBuffer) { + ConstantDynamic constantDynamic = constantDynamicValues[constantPoolEntryIndex]; + if (constantDynamic != null) { + return constantDynamic; + } + int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; + int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; + String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); + String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); + int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; + Handle handle = (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); + Object[] bootstrapMethodArguments = new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; + bootstrapMethodOffset += 4; + for (int i = 0; i < bootstrapMethodArguments.length; i++) { + bootstrapMethodArguments[i] = readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); + bootstrapMethodOffset += 2; + } + return constantDynamicValues[constantPoolEntryIndex] = + new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments); + } + + /** + * Reads a numeric or string constant pool entry in this {@link ClassReader}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param constantPoolEntryIndex the index of a CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, + * CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, + * CONSTANT_MethodHandle or CONSTANT_Dynamic entry in the class's constant pool. + * @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently + * large. It is not automatically resized. + * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, + * {@link Type}, {@link Handle} or {@link ConstantDynamic} corresponding to the specified + * constant pool entry. + */ + public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) { + int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; + switch (classFileBuffer[cpInfoOffset - 1]) { + case Symbol.CONSTANT_INTEGER_TAG: + return readInt(cpInfoOffset); + case Symbol.CONSTANT_FLOAT_TAG: + return Float.intBitsToFloat(readInt(cpInfoOffset)); + case Symbol.CONSTANT_LONG_TAG: + return readLong(cpInfoOffset); + case Symbol.CONSTANT_DOUBLE_TAG: + return Double.longBitsToDouble(readLong(cpInfoOffset)); + case Symbol.CONSTANT_CLASS_TAG: + return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer)); + case Symbol.CONSTANT_STRING_TAG: + return readUTF8(cpInfoOffset, charBuffer); + case Symbol.CONSTANT_METHOD_TYPE_TAG: + return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer)); + case Symbol.CONSTANT_METHOD_HANDLE_TAG: + int referenceKind = readByte(cpInfoOffset); + int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)]; + int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)]; + String owner = readClass(referenceCpInfoOffset, charBuffer); + String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); + String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); + boolean isInterface = + classFileBuffer[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; + return new Handle(referenceKind, owner, name, descriptor, isInterface); + case Symbol.CONSTANT_DYNAMIC_TAG: + return readConstantDynamic(constantPoolEntryIndex, charBuffer); + default: + throw new IllegalArgumentException(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ClassTooLargeException.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/ClassTooLargeException.class new file mode 100644 index 0000000000000000000000000000000000000000..f036989c40cb7b7af06102d05222bd5a3d27cccd GIT binary patch literal 978 zcmbVK%Wl&^6g`ti^T4I4NmHPKhE_lxw1x#jY7mPCkbLQ^&Amo!H_VJ!~(;@W7l`p6NY%X(oG}Hu-x!?7?zZjC65Pvu~X9ctbt1~2+v0& z;X4dl<<`aY^~#KE%2?MaE*n@vjv=k&L=Ho~JR3q-6IW8mYlSNeoBwE>sVuWIB?!suCGMkbI+1N-;%w7u+<0Avv@eP zqRKl`wshU+l4oq)l07~Y4CYLYbxNlwN~WDhAeM$b}+sxz`mz zNO}*NPs#m)VX-lVceytf$=J@HvtRY!9~laB>SX=EJ8mGCGaEq2>gRB@f$xD->x2fA1AsDT}Z9?23%cF=m-5b^KV6RURH&Z9b)aX0G z;whG^wPO^j#bXq|5Gsbdbec%e`HC3ZD567b2Pl)LG|7Yts$@~lh?zw%%^f4o8gf%+ ui*EfdS^bK_XL?MMFGS8aQ9@$^m?mVnhb{7G+2@0cpDqL+&JEsDO6F=Rn|JME-pZw%;zG)qzhbA|>-K!gDlMjt z=d4m`E?dgFPEn!dST>(^A5_>kG%@)x-W(gA>p&aYThSr7n-sdQSW8waXXO`CGa68# zX=r$^6`K|A+raWnA?;-BQWM&NCYt3(t9-P`N3(oH!JRD%J3^F+T+Uvwa^uB?@}ix0 zPuxh`1vl&DTXB!VJ>j`ox0uZ@JY3G^GIp^8eQ0mPHu61}FO>@gr|8<5L937*l%EC+ zd;<4U7OPOO^BIMap~=4 zq9tkvvbW&?`JJ)TPBBv&EZWz~*`i$<9G{&!+<{RfBux(+ID(@J%}bJh3e!Uq%(@_N zJQ>D5%Ff05Lz0mZ95e7~FrPPRh*_sxOxtv#fo_c~wBa+1!jzLK=j>HJ92DCR8?3iS zscE|I1$JH62@Mr_O7dG@av=I6{%ep!H zRKX5^Tjluy@$a00IecEBSNpg6w8FKG`^YoFSy~!Hq0w*KW!Hmvo0IjYrCi*njx>w}Lf`Q9m8}U#k^7$Zzjy4E&eZti5Oo($=SzBI%SjCF{ zA%aB%c{n_vS$U_9JBtM;&)%-!+$HXYS-1vi&bt`dbR)QCpoo$}ho*EgYv*_&+>rdb zn~qiUmUlnOJ+gjkXvkVdWdlpN9yB1^z3hr8qv+~{FjJlVzRNK&r>jSXA&AL|l z>XcRRPi`K7#4a$&A7V(q*$rqH@%7fZai1(2iiF=*u`mmxI<4^mn>RfCu$%h?U($^r#WNKmlr5d-tXqT0G;csDW(>uo^&x= z(6d;p2&nZ@7f94)n>u4(k^#YQSPC0@8}v5PwZb-(+(@Oc3z3xY^cs*t4_#i}Q)tprNqHCZ$*g2UPi=_qmmoy9v-~&)@-rr54OdYa zW%x9?YQ~p2o_vMh9^z;i;j=XvS1VAz<1&J;@>A*;?8z;-h-bL!^N!(JZA3;JG0WJ~ zSc`A0!f#DHJDprXYuxNy#<95BwTy#tvwIm2#Lb>%B;%&Jj9qcFcNzEIM(q4;^qpTp zzqz%7c)Ws7R?q9*d_r>fT^vWYXFtRnewRvkx z1&2Z>`($3nk4W>!*oL2AJ6^*++|cdlJANkEJ1xJ$ow{3+Z+01HU4XUz6h7HM;i% zw0iJu!iiu#_zqW|?wp7zy$pap+RJ1h>=J|-HhbRkWqK%-sZ$de7^z_V9VNl=^1zem zUH-9i3%yvOOn<;`yr;P&J(B^KgqB0NBm#*Nluab^MdSUgf58s?Ra5dxXJm;o*x8LOCT9+)5=Vldn zpn~aI={@9s68T?5{&!9IdjsTNjUtlw;s^L)7=FRy#~jGYeV?XY7ne?`1D%%{e(Y2_(Oz0 zO!%W80)Mj(o};l3f8Ec4n3wEbezHrzFNJtI>C_ZOo+jSunlQ%#kz+xf$M7>EO4wp} zU8lROq&<3JW(Xw89F~0&tNReUw%4w&gc^8#NQy95pN5Z9hbPF(q7L)?|A>s{w_YET zA{2fJ-JnxgRe{faw;|=_rQSp;i?gviHABB=zPw911dV`eS{68tZ$vbNmCCx values in {@link Opcodes}. + */ + protected final int api; + + /** The class visitor to which this visitor must delegate method calls. May be {@literal null}. */ + protected ClassVisitor cv; + + /** + * Constructs a new {@link ClassVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + */ + protected ClassVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link ClassVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + * @param classVisitor the class visitor to which this visitor must delegate method calls. May be + * null. + */ + protected ClassVisitor(final int api, final ClassVisitor classVisitor) { + if (api != Opcodes.ASM9 + && api != Opcodes.ASM8 + && api != Opcodes.ASM7 + && api != Opcodes.ASM6 + && api != Opcodes.ASM5 + && api != Opcodes.ASM4) { + throw new IllegalArgumentException("Unsupported api " + api); + } + this.api = api; + this.cv = classVisitor; + } + + /** + * The class visitor to which this visitor must delegate method calls. May be {@literal null}. + * + * @return the class visitor to which this visitor must delegate method calls, or {@literal null}. + */ + public ClassVisitor getDelegate() { + return cv; + } + + /** + * Visits the header of the class. + * + * @param version the class version. The minor version is stored in the 16 most significant bits, + * and the major version in the 16 least significant bits. + * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if + * the class is deprecated {@link Opcodes#ACC_DEPRECATED} or a record {@link + * Opcodes#ACC_RECORD}. + * @param name the internal name of the class (see {@link Type#getInternalName()}). + * @param signature the signature of this class. May be {@literal null} if the class is not a + * generic one, and does not extend or implement generic classes or interfaces. + * @param superName the internal of name of the super class (see {@link Type#getInternalName()}). + * For interfaces, the super class is {@link Object}. May be {@literal null}, but only for the + * {@link Object} class. + * @param interfaces the internal names of the class's interfaces (see {@link + * Type#getInternalName()}). May be {@literal null}. + */ + public void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) { + if (api < Opcodes.ASM8 && (access & Opcodes.ACC_RECORD) != 0) { + throw new UnsupportedOperationException("Records requires ASM8"); + } + if (cv != null) { + cv.visit(version, access, name, signature, superName, interfaces); + } + } + + /** + * Visits the source of the class. + * + * @param source the name of the source file from which the class was compiled. May be {@literal + * null}. + * @param debug additional debug information to compute the correspondence between source and + * compiled elements of the class. May be {@literal null}. + */ + public void visitSource(final String source, final String debug) { + if (cv != null) { + cv.visitSource(source, debug); + } + } + + /** + * Visit the module corresponding to the class. + * + * @param name the fully qualified name (using dots) of the module. + * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code + * ACC_MANDATED}. + * @param version the module version, or {@literal null}. + * @return a visitor to visit the module values, or {@literal null} if this visitor is not + * interested in visiting this module. + */ + public ModuleVisitor visitModule(final String name, final int access, final String version) { + if (api < Opcodes.ASM6) { + throw new UnsupportedOperationException("Module requires ASM6"); + } + if (cv != null) { + return cv.visitModule(name, access, version); + } + return null; + } + + /** + * Visits the nest host class of the class. A nest is a set of classes of the same package that + * share access to their private members. One of these classes, called the host, lists the other + * members of the nest, which in turn should link to the host of their nest. This method must be + * called only once and only if the visited class is a non-host member of a nest. A class is + * implicitly its own nest, so it's invalid to call this method with the visited class name as + * argument. + * + * @param nestHost the internal name of the host class of the nest (see {@link + * Type#getInternalName()}). + */ + public void visitNestHost(final String nestHost) { + if (api < Opcodes.ASM7) { + throw new UnsupportedOperationException("NestHost requires ASM7"); + } + if (cv != null) { + cv.visitNestHost(nestHost); + } + } + + /** + * Visits the enclosing class of the class. This method must be called only if this class is a + * local or anonymous class. See the JVMS 4.7.7 section for more details. + * + * @param owner internal name of the enclosing class of the class (see {@link + * Type#getInternalName()}). + * @param name the name of the method that contains the class, or {@literal null} if the class is + * not enclosed in a method or constructor of its enclosing class (e.g. if it is enclosed in + * an instance initializer, static initializer, instance variable initializer, or class + * variable initializer). + * @param descriptor the descriptor of the method that contains the class, or {@literal null} if + * the class is not enclosed in a method or constructor of its enclosing class (e.g. if it is + * enclosed in an instance initializer, static initializer, instance variable initializer, or + * class variable initializer). + */ + public void visitOuterClass(final String owner, final String name, final String descriptor) { + if (cv != null) { + cv.visitOuterClass(owner, name, descriptor); + } + } + + /** + * Visits an annotation of the class. + * + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + if (cv != null) { + return cv.visitAnnotation(descriptor, visible); + } + return null; + } + + /** + * Visits an annotation on a type in the class signature. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link + * TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See + * {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (api < Opcodes.ASM5) { + throw new UnsupportedOperationException("TypeAnnotation requires ASM5"); + } + if (cv != null) { + return cv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); + } + return null; + } + + /** + * Visits a non standard attribute of the class. + * + * @param attribute an attribute. + */ + public void visitAttribute(final Attribute attribute) { + if (cv != null) { + cv.visitAttribute(attribute); + } + } + + /** + * Visits a member of the nest. A nest is a set of classes of the same package that share access + * to their private members. One of these classes, called the host, lists the other members of the + * nest, which in turn should link to the host of their nest. This method must be called only if + * the visited class is the host of a nest. A nest host is implicitly a member of its own nest, so + * it's invalid to call this method with the visited class name as argument. + * + * @param nestMember the internal name of a nest member (see {@link Type#getInternalName()}). + */ + public void visitNestMember(final String nestMember) { + if (api < Opcodes.ASM7) { + throw new UnsupportedOperationException("NestMember requires ASM7"); + } + if (cv != null) { + cv.visitNestMember(nestMember); + } + } + + /** + * Visits a permitted subclasses. A permitted subclass is one of the allowed subclasses of the + * current class. + * + * @param permittedSubclass the internal name of a permitted subclass (see {@link + * Type#getInternalName()}). + */ + public void visitPermittedSubclass(final String permittedSubclass) { + if (api < Opcodes.ASM9) { + throw new UnsupportedOperationException("PermittedSubclasses requires ASM9"); + } + if (cv != null) { + cv.visitPermittedSubclass(permittedSubclass); + } + } + + /** + * Visits information about an inner class. This inner class is not necessarily a member of the + * class being visited. More precisely, every class or interface C which is referenced by this + * class and which is not a package member must be visited with this method. This class must + * reference its nested class or interface members, and its enclosing class, if any. See the JVMS + * 4.7.6 section for more details. + * + * @param name the internal name of C (see {@link Type#getInternalName()}). + * @param outerName the internal name of the class or interface C is a member of (see {@link + * Type#getInternalName()}). Must be {@literal null} if C is not the member of a class or + * interface (e.g. for local or anonymous classes). + * @param innerName the (simple) name of C. Must be {@literal null} for anonymous inner classes. + * @param access the access flags of C originally declared in the source code from which this + * class was compiled. + */ + public void visitInnerClass( + final String name, final String outerName, final String innerName, final int access) { + if (cv != null) { + cv.visitInnerClass(name, outerName, innerName, access); + } + } + + /** + * Visits a record component of the class. + * + * @param name the record component name. + * @param descriptor the record component descriptor (see {@link Type}). + * @param signature the record component signature. May be {@literal null} if the record component + * type does not use generic types. + * @return a visitor to visit this record component annotations and attributes, or {@literal null} + * if this class visitor is not interested in visiting these annotations and attributes. + */ + public RecordComponentVisitor visitRecordComponent( + final String name, final String descriptor, final String signature) { + if (api < Opcodes.ASM8) { + throw new UnsupportedOperationException("Record requires ASM8"); + } + if (cv != null) { + return cv.visitRecordComponent(name, descriptor, signature); + } + return null; + } + + /** + * Visits a field of the class. + * + * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if + * the field is synthetic and/or deprecated. + * @param name the field's name. + * @param descriptor the field's descriptor (see {@link Type}). + * @param signature the field's signature. May be {@literal null} if the field's type does not use + * generic types. + * @param value the field's initial value. This parameter, which may be {@literal null} if the + * field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link + * Long}, a {@link Double} or a {@link String} (for {@code int}, {@code float}, {@code long} + * or {@code String} fields respectively). This parameter is only used for static + * fields. Its value is ignored for non static fields, which must be initialized through + * bytecode instructions in constructors or methods. + * @return a visitor to visit field annotations and attributes, or {@literal null} if this class + * visitor is not interested in visiting these annotations and attributes. + */ + public FieldVisitor visitField( + final int access, + final String name, + final String descriptor, + final String signature, + final Object value) { + if (cv != null) { + return cv.visitField(access, name, descriptor, signature, value); + } + return null; + } + + /** + * Visits a method of the class. This method must return a new {@link MethodVisitor} + * instance (or {@literal null}) each time it is called, i.e., it should not return a previously + * returned visitor. + * + * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if + * the method is synthetic and/or deprecated. + * @param name the method's name. + * @param descriptor the method's descriptor (see {@link Type}). + * @param signature the method's signature. May be {@literal null} if the method parameters, + * return type and exceptions do not use generic types. + * @param exceptions the internal names of the method's exception classes (see {@link + * Type#getInternalName()}). May be {@literal null}. + * @return an object to visit the byte code of the method, or {@literal null} if this class + * visitor is not interested in visiting the code of this method. + */ + public MethodVisitor visitMethod( + final int access, + final String name, + final String descriptor, + final String signature, + final String[] exceptions) { + if (cv != null) { + return cv.visitMethod(access, name, descriptor, signature, exceptions); + } + return null; + } + + /** + * Visits the end of the class. This method, which is the last one to be called, is used to inform + * the visitor that all the fields and methods of the class have been visited. + */ + public void visitEnd() { + if (cv != null) { + cv.visitEnd(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ClassWriter.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/ClassWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..accc6b1672b36ca8847efd049cfd33f7118dc616 GIT binary patch literal 19225 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

    -=5v-1J51m zL(g66BhP*6W6wkC6HkXa=6Tv6&vOQQUN$_QUmH1|w+x>Sf;y>Cjikvsz|A#saEg$0 zlVxs14jF%=K>42gD5!h$B_MKwCBNr&)n6Z7EzcidDUyQf=Xq6!mj+dN4#RRJdoaoK zxDM0s$GpI70NQet&v+B|gp`)bGhTyL6_QWgXoO%}g_H{koec}S6t?%O(N7IRTOMS3 z2cA>EkB8kCsITMk^!qr`N+N3`P5ci|j5u~29(W8VT?BxGKB19ZJf^sKSTGPME-oH4 zVEFK3i2iZX^&n;+@(~4weM054z*BCVfN$iwcl6z{^-WKIAVT0+oEqj`B{vba6ROmCwk}bMo_&{JbJRTjXb({9GqL zJLRWI61W@XXSaObCbhezwpV^SlDjH3C*Xgc2*LraaZbdga?tBf*gGRi4#z;_uHwA~o5b;iz-?Qnzl9cnPw z>R@_@mXiW|wyPoVj&_c0Ety^Tb7q|cQ^VK`cL`Y`Z${nPbmFlK_@@svkcF0mrW&3( z+;n^J7G7Q=JHqJ;U6edd_z*`|9^}gx>I_LI$FK)Hvj{1#qRNU+-c)JF?u+(yy^D^Q zB(g86LdO+|T_j#dP%j-F(@jY&7Y9xBT^Tf;t;O8e^$r?7onpMs_!?8mXH264V>$(l z8ZdnZm_C!rjI(K+F&hk@1BTC~xyCt2HP_N2V?Naz=h9lEPBYd%m4+S0`ml+NfN|pb z2V0Ar+!T$YDcYb6T0n!-PNip1&M^vjISN}S`b0Q56osh#0Ae*tjdqSivjIcSwh{** zeZyBHIUy-}`*uU0j*L|r7yD+za)oT^QzQf07@F)ro9RHywV~0(Oi)c}pmJSMxyq7M z3qXx^L1iGO^Gcb};%U&jA?83UJrOkiY!75!eFA7@4z%(UL8DL)&~}~xT7?6x@t zme^UyfKKF!egyO>T#`TmeG0d8AGKn%1)^3;GTrun8J}XN83QCAlp4?U0frELgnvLw zor#j=LAIk*5wzx@tx%Lo6BR&UeNzuyI;zRBb6SNiIfX7cg)TXTE;)rZIRYOqH{S>E zu2mBdkJ(wLb@&!;O1xNtj1%sX_)9&k{HruZrrl!cRV3q3pjQz_7N|*x@`RBEh=Z!J zZCtCSoOHdf^swH${~PPEnu@s6rf)gcmyIjmp|6v_+QVvHdNte2r)P_kS^j)CMU(HO zXjn~0+}bk_as1=2AHRxOZ~~f=s}#7a*xb}S)H1`(BO>I4vz}a;NS~ZoAv0WJWcUqp zuwH4HJ<8P+zbh@jBP~TqoacR6WY~PdE2b!F10d zeq?0@5`28%smgBM9_h}J?#f_}bW0wvlMn79PsM(maKR6$SMHbEq1}`xy@#;f7x9z2 z?Xc`Q_LQ#oWY7-^#ubdm^84X$C670N_v6BP5>=x#^+oV`uwXJLlE<7({mrQ~z^taA zIfX`I#+o6Pg*8uNV3to2Ca z_9sJ~t!9G}LCRBe)Lg7R32pPx=E48##%>c+y~$mmQTrhtW zH9PR;(Rnr$wE(k4(d@PAP_tL4!wU9zX|u`Pw@YJ;s-8p zYk7Hn4e$qV=N(mnnd>mc2caJAJVMS 4 + * @author Eric Bruneton + */ +public class ClassWriter extends ClassVisitor { + + /** + * A flag to automatically compute the maximum stack size and the maximum number of local + * variables of methods. If this flag is set, then the arguments of the {@link + * MethodVisitor#visitMaxs} method of the {@link MethodVisitor} returned by the {@link + * #visitMethod} method will be ignored, and computed automatically from the signature and the + * bytecode of each method. + * + *

    Note: for classes whose version is {@link Opcodes#V1_7} of more, this option requires + * valid stack map frames. The maximum stack size is then computed from these frames, and from the + * bytecode instructions in between. If stack map frames are not present or must be recomputed, + * used {@link #COMPUTE_FRAMES} instead. + * + * @see #ClassWriter(int) + */ + public static final int COMPUTE_MAXS = 1; + + /** + * A flag to automatically compute the stack map frames of methods from scratch. If this flag is + * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack + * map frames are recomputed from the methods bytecode. The arguments of the {@link + * MethodVisitor#visitMaxs} method are also ignored and recomputed from the bytecode. In other + * words, {@link #COMPUTE_FRAMES} implies {@link #COMPUTE_MAXS}. + * + * @see #ClassWriter(int) + */ + public static final int COMPUTE_FRAMES = 2; + + /** + * The flags passed to the constructor. Must be zero or more of {@link #COMPUTE_MAXS} and {@link + * #COMPUTE_FRAMES}. + */ + private final int flags; + + // Note: fields are ordered as in the ClassFile structure, and those related to attributes are + // ordered as in Section 4.7 of the JVMS. + + /** + * The minor_version and major_version fields of the JVMS ClassFile structure. minor_version is + * stored in the 16 most significant bits, and major_version in the 16 least significant bits. + */ + private int version; + + /** The symbol table for this class (contains the constant_pool and the BootstrapMethods). */ + private final SymbolTable symbolTable; + + /** + * The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific + * access flags, such as {@link Opcodes#ACC_DEPRECATED} or {@link Opcodes#ACC_RECORD}, which are + * removed when generating the ClassFile structure. + */ + private int accessFlags; + + /** The this_class field of the JVMS ClassFile structure. */ + private int thisClass; + + /** The super_class field of the JVMS ClassFile structure. */ + private int superClass; + + /** The interface_count field of the JVMS ClassFile structure. */ + private int interfaceCount; + + /** The 'interfaces' array of the JVMS ClassFile structure. */ + private int[] interfaces; + + /** + * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their + * {@link FieldWriter#fv} field. This field stores the first element of this list. + */ + private FieldWriter firstField; + + /** + * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their + * {@link FieldWriter#fv} field. This field stores the last element of this list. + */ + private FieldWriter lastField; + + /** + * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their + * {@link MethodWriter#mv} field. This field stores the first element of this list. + */ + private MethodWriter firstMethod; + + /** + * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their + * {@link MethodWriter#mv} field. This field stores the last element of this list. + */ + private MethodWriter lastMethod; + + /** The number_of_classes field of the InnerClasses attribute, or 0. */ + private int numberOfInnerClasses; + + /** The 'classes' array of the InnerClasses attribute, or {@literal null}. */ + private ByteVector innerClasses; + + /** The class_index field of the EnclosingMethod attribute, or 0. */ + private int enclosingClassIndex; + + /** The method_index field of the EnclosingMethod attribute. */ + private int enclosingMethodIndex; + + /** The signature_index field of the Signature attribute, or 0. */ + private int signatureIndex; + + /** The source_file_index field of the SourceFile attribute, or 0. */ + private int sourceFileIndex; + + /** The debug_extension field of the SourceDebugExtension attribute, or {@literal null}. */ + private ByteVector debugExtension; + + /** + * The last runtime visible annotation of this class. The previous ones can be accessed with the + * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleAnnotation; + + /** + * The last runtime invisible annotation of this class. The previous ones can be accessed with the + * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleAnnotation; + + /** + * The last runtime visible type annotation of this class. The previous ones can be accessed with + * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleTypeAnnotation; + + /** + * The last runtime invisible type annotation of this class. The previous ones can be accessed + * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; + + /** The Module attribute of this class, or {@literal null}. */ + private ModuleWriter moduleWriter; + + /** The host_class_index field of the NestHost attribute, or 0. */ + private int nestHostClassIndex; + + /** The number_of_classes field of the NestMembers attribute, or 0. */ + private int numberOfNestMemberClasses; + + /** The 'classes' array of the NestMembers attribute, or {@literal null}. */ + private ByteVector nestMemberClasses; + + /** The number_of_classes field of the PermittedSubclasses attribute, or 0. */ + private int numberOfPermittedSubclasses; + + /** The 'classes' array of the PermittedSubclasses attribute, or {@literal null}. */ + private ByteVector permittedSubclasses; + + /** + * The record components of this class, stored in a linked list of {@link RecordComponentWriter} + * linked via their {@link RecordComponentWriter#delegate} field. This field stores the first + * element of this list. + */ + private RecordComponentWriter firstRecordComponent; + + /** + * The record components of this class, stored in a linked list of {@link RecordComponentWriter} + * linked via their {@link RecordComponentWriter#delegate} field. This field stores the last + * element of this list. + */ + private RecordComponentWriter lastRecordComponent; + + /** + * The first non standard attribute of this class. The next ones can be accessed with the {@link + * Attribute#nextAttribute} field. May be {@literal null}. + * + *

    WARNING: this list stores the attributes in the reverse order of their visit. + * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link + * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the + * reverse order specified by the user. + */ + private Attribute firstAttribute; + + /** + * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link + * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link + * MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link + * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}. + */ + private int compute; + + // ----------------------------------------------------------------------------------------------- + // Constructor + // ----------------------------------------------------------------------------------------------- + + /** + * Constructs a new {@link ClassWriter} object. + * + * @param flags option flags that can be used to modify the default behavior of this class. Must + * be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. + */ + public ClassWriter(final int flags) { + this(null, flags); + } + + /** + * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode + * transformations. These optimizations are the following: + * + *

      + *
    • The constant pool and bootstrap methods from the original class are copied as is in the + * new class, which saves time. New constant pool entries and new bootstrap methods will be + * added at the end if necessary, but unused constant pool entries or bootstrap methods + * won't be removed. + *
    • Methods that are not transformed are copied as is in the new class, directly from the + * original class bytecode (i.e. without emitting visit events for all the method + * instructions), which saves a lot of time. Untransformed methods are detected by + * the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come + * from a {@link ClassWriter} (and not from any other {@link ClassVisitor} instance). + *
    + * + * @param classReader the {@link ClassReader} used to read the original class. It will be used to + * copy the entire constant pool and bootstrap methods from the original class and also to + * copy other fragments of original bytecode where applicable. + * @param flags option flags that can be used to modify the default behavior of this class. Must + * be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. These option flags + * do not affect methods that are copied as is in the new class. This means that neither the + * maximum stack size nor the stack frames will be computed for these methods. + */ + @SuppressWarnings("this-escape") + public ClassWriter(final ClassReader classReader, final int flags) { + super(/* latest api = */ Opcodes.ASM9); + this.flags = flags; + symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader); + if ((flags & COMPUTE_FRAMES) != 0) { + compute = MethodWriter.COMPUTE_ALL_FRAMES; + } else if ((flags & COMPUTE_MAXS) != 0) { + compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL; + } else { + compute = MethodWriter.COMPUTE_NOTHING; + } + } + + // ----------------------------------------------------------------------------------------------- + // Accessors + // ----------------------------------------------------------------------------------------------- + + /** + * Returns true if all the given flags were passed to the constructor. + * + * @param flags some option flags. Must be zero or more of {@link #COMPUTE_MAXS} and {@link + * #COMPUTE_FRAMES}. + * @return true if all the given flags, or more, were passed to the constructor. + */ + public boolean hasFlags(final int flags) { + return (this.flags & flags) == flags; + } + + // ----------------------------------------------------------------------------------------------- + // Implementation of the ClassVisitor abstract class + // ----------------------------------------------------------------------------------------------- + + @Override + public final void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) { + this.version = version; + this.accessFlags = access; + this.thisClass = symbolTable.setMajorVersionAndClassName(version & 0xFFFF, name); + if (signature != null) { + this.signatureIndex = symbolTable.addConstantUtf8(signature); + } + this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index; + if (interfaces != null && interfaces.length > 0) { + interfaceCount = interfaces.length; + this.interfaces = new int[interfaceCount]; + for (int i = 0; i < interfaceCount; ++i) { + this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index; + } + } + if (compute == MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL && (version & 0xFFFF) >= Opcodes.V1_7) { + compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES; + } + } + + @Override + public final void visitSource(final String file, final String debug) { + if (file != null) { + sourceFileIndex = symbolTable.addConstantUtf8(file); + } + if (debug != null) { + debugExtension = new ByteVector().encodeUtf8(debug, 0, Integer.MAX_VALUE); + } + } + + @Override + public final ModuleVisitor visitModule( + final String name, final int access, final String version) { + return moduleWriter = + new ModuleWriter( + symbolTable, + symbolTable.addConstantModule(name).index, + access, + version == null ? 0 : symbolTable.addConstantUtf8(version)); + } + + @Override + public final void visitNestHost(final String nestHost) { + nestHostClassIndex = symbolTable.addConstantClass(nestHost).index; + } + + @Override + public final void visitOuterClass( + final String owner, final String name, final String descriptor) { + enclosingClassIndex = symbolTable.addConstantClass(owner).index; + if (name != null && descriptor != null) { + enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor); + } + } + + @Override + public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation); + } else { + return lastRuntimeInvisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation); + } + } + + @Override + public final AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation); + } else { + return lastRuntimeInvisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation); + } + } + + @Override + public final void visitAttribute(final Attribute attribute) { + // Store the attributes in the reverse order of their visit by this method. + attribute.nextAttribute = firstAttribute; + firstAttribute = attribute; + } + + @Override + public final void visitNestMember(final String nestMember) { + if (nestMemberClasses == null) { + nestMemberClasses = new ByteVector(); + } + ++numberOfNestMemberClasses; + nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index); + } + + @Override + public final void visitPermittedSubclass(final String permittedSubclass) { + if (permittedSubclasses == null) { + permittedSubclasses = new ByteVector(); + } + ++numberOfPermittedSubclasses; + permittedSubclasses.putShort(symbolTable.addConstantClass(permittedSubclass).index); + } + + @Override + public final void visitInnerClass( + final String name, final String outerName, final String innerName, final int access) { + if (innerClasses == null) { + innerClasses = new ByteVector(); + } + // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table + // which represents a class or interface C that is not a package member must have exactly one + // corresponding entry in the classes array". To avoid duplicates we keep track in the info + // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has + // already been added for C. If so, we store the index of this inner class entry (plus one) in + // the info field. This trick allows duplicate detection in O(1) time. + Symbol nameSymbol = symbolTable.addConstantClass(name); + if (nameSymbol.info == 0) { + ++numberOfInnerClasses; + innerClasses.putShort(nameSymbol.index); + innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index); + innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName)); + innerClasses.putShort(access); + nameSymbol.info = numberOfInnerClasses; + } + // Else, compare the inner classes entry nameSymbol.info - 1 with the arguments of this method + // and throw an exception if there is a difference? + } + + @Override + public final RecordComponentVisitor visitRecordComponent( + final String name, final String descriptor, final String signature) { + RecordComponentWriter recordComponentWriter = + new RecordComponentWriter(symbolTable, name, descriptor, signature); + if (firstRecordComponent == null) { + firstRecordComponent = recordComponentWriter; + } else { + lastRecordComponent.delegate = recordComponentWriter; + } + return lastRecordComponent = recordComponentWriter; + } + + @Override + public final FieldVisitor visitField( + final int access, + final String name, + final String descriptor, + final String signature, + final Object value) { + FieldWriter fieldWriter = + new FieldWriter(symbolTable, access, name, descriptor, signature, value); + if (firstField == null) { + firstField = fieldWriter; + } else { + lastField.fv = fieldWriter; + } + return lastField = fieldWriter; + } + + @Override + public final MethodVisitor visitMethod( + final int access, + final String name, + final String descriptor, + final String signature, + final String[] exceptions) { + MethodWriter methodWriter = + new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute); + if (firstMethod == null) { + firstMethod = methodWriter; + } else { + lastMethod.mv = methodWriter; + } + return lastMethod = methodWriter; + } + + @Override + public final void visitEnd() { + // Nothing to do. + } + + // ----------------------------------------------------------------------------------------------- + // Other public methods + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the content of the class file that was built by this ClassWriter. + * + * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter. + * @throws ClassTooLargeException if the constant pool of the class is too large. + * @throws MethodTooLargeException if the Code attribute of a method is too large. + */ + public byte[] toByteArray() { + // First step: compute the size in bytes of the ClassFile structure. + // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version, + // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count, + // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too. + int size = 24 + 2 * interfaceCount; + int fieldsCount = 0; + FieldWriter fieldWriter = firstField; + while (fieldWriter != null) { + ++fieldsCount; + size += fieldWriter.computeFieldInfoSize(); + fieldWriter = (FieldWriter) fieldWriter.fv; + } + int methodsCount = 0; + MethodWriter methodWriter = firstMethod; + while (methodWriter != null) { + ++methodsCount; + size += methodWriter.computeMethodInfoSize(); + methodWriter = (MethodWriter) methodWriter.mv; + } + + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + int attributesCount = 0; + if (innerClasses != null) { + ++attributesCount; + size += 8 + innerClasses.length; + symbolTable.addConstantUtf8(Constants.INNER_CLASSES); + } + if (enclosingClassIndex != 0) { + ++attributesCount; + size += 10; + symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD); + } + if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { + ++attributesCount; + size += 6; + symbolTable.addConstantUtf8(Constants.SYNTHETIC); + } + if (signatureIndex != 0) { + ++attributesCount; + size += 8; + symbolTable.addConstantUtf8(Constants.SIGNATURE); + } + if (sourceFileIndex != 0) { + ++attributesCount; + size += 8; + symbolTable.addConstantUtf8(Constants.SOURCE_FILE); + } + if (debugExtension != null) { + ++attributesCount; + size += 6 + debugExtension.length; + symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION); + } + if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { + ++attributesCount; + size += 6; + symbolTable.addConstantUtf8(Constants.DEPRECATED); + } + if (lastRuntimeVisibleAnnotation != null) { + ++attributesCount; + size += + lastRuntimeVisibleAnnotation.computeAnnotationsSize( + Constants.RUNTIME_VISIBLE_ANNOTATIONS); + } + if (lastRuntimeInvisibleAnnotation != null) { + ++attributesCount; + size += + lastRuntimeInvisibleAnnotation.computeAnnotationsSize( + Constants.RUNTIME_INVISIBLE_ANNOTATIONS); + } + if (lastRuntimeVisibleTypeAnnotation != null) { + ++attributesCount; + size += + lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + } + if (lastRuntimeInvisibleTypeAnnotation != null) { + ++attributesCount; + size += + lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + } + if (symbolTable.computeBootstrapMethodsSize() > 0) { + ++attributesCount; + size += symbolTable.computeBootstrapMethodsSize(); + } + if (moduleWriter != null) { + attributesCount += moduleWriter.getAttributeCount(); + size += moduleWriter.computeAttributesSize(); + } + if (nestHostClassIndex != 0) { + ++attributesCount; + size += 8; + symbolTable.addConstantUtf8(Constants.NEST_HOST); + } + if (nestMemberClasses != null) { + ++attributesCount; + size += 8 + nestMemberClasses.length; + symbolTable.addConstantUtf8(Constants.NEST_MEMBERS); + } + if (permittedSubclasses != null) { + ++attributesCount; + size += 8 + permittedSubclasses.length; + symbolTable.addConstantUtf8(Constants.PERMITTED_SUBCLASSES); + } + int recordComponentCount = 0; + int recordSize = 0; + if ((accessFlags & Opcodes.ACC_RECORD) != 0 || firstRecordComponent != null) { + RecordComponentWriter recordComponentWriter = firstRecordComponent; + while (recordComponentWriter != null) { + ++recordComponentCount; + recordSize += recordComponentWriter.computeRecordComponentInfoSize(); + recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate; + } + ++attributesCount; + size += 8 + recordSize; + symbolTable.addConstantUtf8(Constants.RECORD); + } + if (firstAttribute != null) { + attributesCount += firstAttribute.getAttributeCount(); + size += firstAttribute.computeAttributesSize(symbolTable); + } + // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous + // statements can add attribute names to the constant pool, thereby changing its size! + size += symbolTable.getConstantPoolLength(); + int constantPoolCount = symbolTable.getConstantPoolCount(); + if (constantPoolCount > 0xFFFF) { + throw new ClassTooLargeException(symbolTable.getClassName(), constantPoolCount); + } + + // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in + // dynamic resizes) and fill it with the ClassFile content. + ByteVector result = new ByteVector(size); + result.putInt(0xCAFEBABE).putInt(version); + symbolTable.putConstantPool(result); + int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0; + result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass); + result.putShort(interfaceCount); + for (int i = 0; i < interfaceCount; ++i) { + result.putShort(interfaces[i]); + } + result.putShort(fieldsCount); + fieldWriter = firstField; + while (fieldWriter != null) { + fieldWriter.putFieldInfo(result); + fieldWriter = (FieldWriter) fieldWriter.fv; + } + result.putShort(methodsCount); + boolean hasFrames = false; + boolean hasAsmInstructions = false; + methodWriter = firstMethod; + while (methodWriter != null) { + hasFrames |= methodWriter.hasFrames(); + hasAsmInstructions |= methodWriter.hasAsmInstructions(); + methodWriter.putMethodInfo(result); + methodWriter = (MethodWriter) methodWriter.mv; + } + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + result.putShort(attributesCount); + if (innerClasses != null) { + result + .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES)) + .putInt(innerClasses.length + 2) + .putShort(numberOfInnerClasses) + .putByteArray(innerClasses.data, 0, innerClasses.length); + } + if (enclosingClassIndex != 0) { + result + .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD)) + .putInt(4) + .putShort(enclosingClassIndex) + .putShort(enclosingMethodIndex); + } + if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { + result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); + } + if (signatureIndex != 0) { + result + .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) + .putInt(2) + .putShort(signatureIndex); + } + if (sourceFileIndex != 0) { + result + .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE)) + .putInt(2) + .putShort(sourceFileIndex); + } + if (debugExtension != null) { + int length = debugExtension.length; + result + .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION)) + .putInt(length) + .putByteArray(debugExtension.data, 0, length); + } + if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { + result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); + } + AnnotationWriter.putAnnotations( + symbolTable, + lastRuntimeVisibleAnnotation, + lastRuntimeInvisibleAnnotation, + lastRuntimeVisibleTypeAnnotation, + lastRuntimeInvisibleTypeAnnotation, + result); + symbolTable.putBootstrapMethods(result); + if (moduleWriter != null) { + moduleWriter.putAttributes(result); + } + if (nestHostClassIndex != 0) { + result + .putShort(symbolTable.addConstantUtf8(Constants.NEST_HOST)) + .putInt(2) + .putShort(nestHostClassIndex); + } + if (nestMemberClasses != null) { + result + .putShort(symbolTable.addConstantUtf8(Constants.NEST_MEMBERS)) + .putInt(nestMemberClasses.length + 2) + .putShort(numberOfNestMemberClasses) + .putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length); + } + if (permittedSubclasses != null) { + result + .putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBCLASSES)) + .putInt(permittedSubclasses.length + 2) + .putShort(numberOfPermittedSubclasses) + .putByteArray(permittedSubclasses.data, 0, permittedSubclasses.length); + } + if ((accessFlags & Opcodes.ACC_RECORD) != 0 || firstRecordComponent != null) { + result + .putShort(symbolTable.addConstantUtf8(Constants.RECORD)) + .putInt(recordSize + 2) + .putShort(recordComponentCount); + RecordComponentWriter recordComponentWriter = firstRecordComponent; + while (recordComponentWriter != null) { + recordComponentWriter.putRecordComponentInfo(result); + recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate; + } + } + if (firstAttribute != null) { + firstAttribute.putAttributes(symbolTable, result); + } + + // Third step: replace the ASM specific instructions, if any. + if (hasAsmInstructions) { + return replaceAsmInstructions(result.data, hasFrames); + } else { + return result.data; + } + } + + /** + * Returns the equivalent of the given class file, with the ASM specific instructions replaced + * with standard ones. This is done with a ClassReader -> ClassWriter round trip. + * + * @param classFile a class file containing ASM specific instructions, generated by this + * ClassWriter. + * @param hasFrames whether there is at least one stack map frames in 'classFile'. + * @return an equivalent of 'classFile', with the ASM specific instructions replaced with standard + * ones. + */ + private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasFrames) { + final Attribute[] attributes = getAttributePrototypes(); + firstField = null; + lastField = null; + firstMethod = null; + lastMethod = null; + lastRuntimeVisibleAnnotation = null; + lastRuntimeInvisibleAnnotation = null; + lastRuntimeVisibleTypeAnnotation = null; + lastRuntimeInvisibleTypeAnnotation = null; + moduleWriter = null; + nestHostClassIndex = 0; + numberOfNestMemberClasses = 0; + nestMemberClasses = null; + numberOfPermittedSubclasses = 0; + permittedSubclasses = null; + firstRecordComponent = null; + lastRecordComponent = null; + firstAttribute = null; + compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING; + new ClassReader(classFile, 0, /* checkClassVersion = */ false) + .accept( + this, + attributes, + (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS); + return toByteArray(); + } + + /** + * Returns the prototypes of the attributes used by this class, its fields and its methods. + * + * @return the prototypes of the attributes used by this class, its fields and its methods. + */ + private Attribute[] getAttributePrototypes() { + Attribute.Set attributePrototypes = new Attribute.Set(); + attributePrototypes.addAttributes(firstAttribute); + FieldWriter fieldWriter = firstField; + while (fieldWriter != null) { + fieldWriter.collectAttributePrototypes(attributePrototypes); + fieldWriter = (FieldWriter) fieldWriter.fv; + } + MethodWriter methodWriter = firstMethod; + while (methodWriter != null) { + methodWriter.collectAttributePrototypes(attributePrototypes); + methodWriter = (MethodWriter) methodWriter.mv; + } + RecordComponentWriter recordComponentWriter = firstRecordComponent; + while (recordComponentWriter != null) { + recordComponentWriter.collectAttributePrototypes(attributePrototypes); + recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate; + } + return attributePrototypes.toArray(); + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods: constant pool management for Attribute sub classes + // ----------------------------------------------------------------------------------------------- + + /** + * Adds a number or string constant to the constant pool of the class being build. Does nothing if + * the constant pool already contains a similar item. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param value the value of the constant to be added to the constant pool. This parameter must be + * an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. + * @return the index of a new or already existing constant item with the given value. + */ + public int newConst(final Object value) { + return symbolTable.addConstant(value).index; + } + + /** + * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant + * pool already contains a similar item. This method is intended for {@link Attribute} sub + * classes, and is normally not needed by class generators or adapters. + * + * @param value the String value. + * @return the index of a new or already existing UTF8 item. + */ + // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). + public int newUTF8(final String value) { + return symbolTable.addConstantUtf8(value); + } + + /** + * Adds a class reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param value the internal name of the class (see {@link Type#getInternalName()}). + * @return the index of a new or already existing class reference item. + */ + public int newClass(final String value) { + return symbolTable.addConstantClass(value).index; + } + + /** + * Adds a method type reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param methodDescriptor method descriptor of the method type. + * @return the index of a new or already existing method type reference item. + */ + public int newMethodType(final String methodDescriptor) { + return symbolTable.addConstantMethodType(methodDescriptor).index; + } + + /** + * Adds a module reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param moduleName name of the module. + * @return the index of a new or already existing module reference item. + */ + public int newModule(final String moduleName) { + return symbolTable.addConstantModule(moduleName).index; + } + + /** + * Adds a package reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param packageName name of the package in its internal form. + * @return the index of a new or already existing module reference item. + */ + public int newPackage(final String packageName) { + return symbolTable.addConstantPackage(packageName).index; + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. This method is intended for {@link Attribute} sub classes, + * and is normally not needed by class generators or adapters. + * + * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link + * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link + * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the field or method owner class (see {@link + * Type#getInternalName()}). + * @param name the name of the field or method. + * @param descriptor the descriptor of the field or method. + * @return the index of a new or already existing method type reference item. + * @deprecated this method is superseded by {@link #newHandle(int, String, String, String, + * boolean)}. + */ + @Deprecated + public int newHandle( + final int tag, final String owner, final String name, final String descriptor) { + return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. This method is intended for {@link Attribute} sub classes, + * and is normally not needed by class generators or adapters. + * + * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link + * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link + * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the field or method owner class (see {@link + * Type#getInternalName()}). + * @param name the name of the field or method. + * @param descriptor the descriptor of the field or method. + * @param isInterface true if the owner is an interface. + * @return the index of a new or already existing method type reference item. + */ + public int newHandle( + final int tag, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index; + } + + /** + * Adds a dynamic constant reference to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param name name of the invoked method. + * @param descriptor field descriptor of the constant type. + * @param bootstrapMethodHandle the bootstrap method. + * @param bootstrapMethodArguments the bootstrap method constant arguments. + * @return the index of a new or already existing dynamic constant reference item. + */ + public int newConstantDynamic( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + return symbolTable.addConstantDynamic( + name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) + .index; + } + + /** + * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if + * the constant pool already contains a similar item. This method is intended for {@link + * Attribute} sub classes, and is normally not needed by class generators or adapters. + * + * @param name name of the invoked method. + * @param descriptor descriptor of the invoke method. + * @param bootstrapMethodHandle the bootstrap method. + * @param bootstrapMethodArguments the bootstrap method constant arguments. + * @return the index of a new or already existing invokedynamic reference item. + */ + public int newInvokeDynamic( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + return symbolTable.addConstantInvokeDynamic( + name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) + .index; + } + + /** + * Adds a field reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param owner the internal name of the field's owner class (see {@link Type#getInternalName()}). + * @param name the field's name. + * @param descriptor the field's descriptor. + * @return the index of a new or already existing field reference item. + */ + public int newField(final String owner, final String name, final String descriptor) { + return symbolTable.addConstantFieldref(owner, name, descriptor).index; + } + + /** + * Adds a method reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param owner the internal name of the method's owner class (see {@link + * Type#getInternalName()}). + * @param name the method's name. + * @param descriptor the method's descriptor. + * @param isInterface {@literal true} if {@code owner} is an interface. + * @return the index of a new or already existing method reference item. + */ + public int newMethod( + final String owner, final String name, final String descriptor, final boolean isInterface) { + return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index; + } + + /** + * Adds a name and type to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param name a name. + * @param descriptor a type descriptor. + * @return the index of a new or already existing name and type item. + */ + public int newNameType(final String name, final String descriptor) { + return symbolTable.addConstantNameAndType(name, descriptor); + } + + // ----------------------------------------------------------------------------------------------- + // Default method to compute common super classes when computing stack map frames + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the common super type of the two given types. The default implementation of this method + * loads the two given classes and uses the java.lang.Class methods to find the common + * super class. It can be overridden to compute this common super type in other ways, in + * particular without actually loading any class, or to take into account the class that is + * currently being generated by this ClassWriter, which can of course not be loaded since it is + * under construction. + * + * @param type1 the internal name of a class (see {@link Type#getInternalName()}). + * @param type2 the internal name of another class (see {@link Type#getInternalName()}). + * @return the internal name of the common super class of the two given classes (see {@link + * Type#getInternalName()}). + */ + protected String getCommonSuperClass(final String type1, final String type2) { + ClassLoader classLoader = getClassLoader(); + Class class1; + try { + class1 = Class.forName(type1.replace('/', '.'), false, classLoader); + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(type1, e); + } + Class class2; + try { + class2 = Class.forName(type2.replace('/', '.'), false, classLoader); + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(type2, e); + } + if (class1.isAssignableFrom(class2)) { + return type1; + } + if (class2.isAssignableFrom(class1)) { + return type2; + } + if (class1.isInterface() || class2.isInterface()) { + return "java/lang/Object"; + } else { + do { + class1 = class1.getSuperclass(); + } while (!class1.isAssignableFrom(class2)); + return class1.getName().replace('.', '/'); + } + } + + /** + * Returns the {@link ClassLoader} to be used by the default implementation of {@link + * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by + * default. + * + * @return ClassLoader + */ + protected ClassLoader getClassLoader() { + return getClass().getClassLoader(); + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ConstantDynamic.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/ConstantDynamic.class new file mode 100644 index 0000000000000000000000000000000000000000..e0f789a847f91c03dbd51c350f1b67d05a636f33 GIT binary patch literal 2672 zcma)8TUQ%Z6#fpmOp*>Tr3vLyg^HA1fIzJZ4OSr7HkFH-7H#Wok_^c}n8C?J#V75% zKLB6!!KE+g(xrq-wM(lm*W$?^)a7!YnIQ=ww0(ec_RQYj{`PgU|KHwy07(=AXn{+B zTZ9K*25D9PP>vU6EgxUXtSVWP!8@gDs(FdQ6^<LwYaL8ilNEH zxNhX*x@Gl|l8MWu^>|X(N~WxtbDNsHu4WnBbSexT^EE$d(@?d1f+M$yXy>qjoKngf z>V~Ns{P9T<9XQ3%p3!x)WE%3uf?^i*9K+E3V+dT8wOmoLz(XQBahjp40cFO>m)8}| zEHRwAUB}CgKM_DTdIa=}ID@ASCCDaD3Cb2^V}>&24yPhXuHPr3A7|-}@dFVC^ zDz)3#<9s&EKgA;C6?4(r0j+eKtIj#?1d?YP2RyZiI<@C` z4L+l(`s_P(r}kF0oboXPOEH{19-wqXE6FRAuuwSCB*%8-Y4sDXv7#C!Gf7)xX{9~` zjGDAHZOYlT1$o2CwAWs!hgW8mTYI)~!3NTL*~luFRbIPbL;gqk*kPPjY71?DH*Hng z;&kiaYu7qy&sryKN;*&AGx{tnf?QncH>gW!+! zwgs&Cfoem#8a!)4t#A2+?f zjs=HJoKCLqiT(`X2fEmfz1G7G%ZUx>ahx#RXlmTrXuR3fco}at@hmkO-)U<67DgQ7 zF*-SIFVPO(-)`Xjd7ZVl%KIj6Io1h^lBY)C*1hK&oo`v@owiCfw*qeCZOiF9c-H}{ z&t9+*=Ic5Zwd}oDjUnT(=p`1dt_r%QdZlY$!rv>+eFeeuE!=J%n9J$}{sRN}j=JFc zI(EGdJ3rOzD?1$D^&LlC?T(y{0_@VK{Qf57(zJg)87@9-_~ z`VZ4z1y65boKqsH)shBCl1P#&cxDSBl7b`!?_zKZf}41{YCNL|kc*$FF9{13>eyXK z_yr;CA%=UH#ILx5--!2~6-U2KshZ_9b$gBohj5AdJx!E(L?YaR?;)lI_^hDld+P+H zl09#PIOktMloO{z^4-Pg9nQOg3zFmrMEQBCiwm`m>9j`Z0S(Td=)zwZ#NQajgSy(q z9de9+T^zS-M2x$gyoZUKySQk3PjtLoLBghxkoqf_u^G%A+=;*y(x~9oTC=oS8Q7;^ U3;)tLY`@O&WYzHsxoScFf4eqHJpcdz literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ConstantDynamic.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/ConstantDynamic.java new file mode 100644 index 00000000..cb992f83 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/ConstantDynamic.java @@ -0,0 +1,210 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +import java.util.Arrays; + +/** + * A constant whose value is computed at runtime, with a bootstrap method. + * + * @author Remi Forax + */ +public final class ConstantDynamic { + + /** The constant name (can be arbitrary). */ + private final String name; + + /** The constant type (must be a field descriptor). */ + private final String descriptor; + + /** The bootstrap method to use to compute the constant value at runtime. */ + private final Handle bootstrapMethod; + + /** + * The arguments to pass to the bootstrap method, in order to compute the constant value at + * runtime. + */ + private final Object[] bootstrapMethodArguments; + + /** + * Constructs a new {@link ConstantDynamic}. + * + * @param name the constant name (can be arbitrary). + * @param descriptor the constant type (must be a field descriptor). + * @param bootstrapMethod the bootstrap method to use to compute the constant value at runtime. + * @param bootstrapMethodArguments the arguments to pass to the bootstrap method, in order to + * compute the constant value at runtime. + */ + public ConstantDynamic( + final String name, + final String descriptor, + final Handle bootstrapMethod, + final Object... bootstrapMethodArguments) { + this.name = name; + this.descriptor = descriptor; + this.bootstrapMethod = bootstrapMethod; + this.bootstrapMethodArguments = bootstrapMethodArguments; + } + + /** + * Returns the name of this constant. + * + * @return the name of this constant. + */ + public String getName() { + return name; + } + + /** + * Returns the type of this constant. + * + * @return the type of this constant, as a field descriptor. + */ + public String getDescriptor() { + return descriptor; + } + + /** + * Returns the bootstrap method used to compute the value of this constant. + * + * @return the bootstrap method used to compute the value of this constant. + */ + public Handle getBootstrapMethod() { + return bootstrapMethod; + } + + /** + * Returns the number of arguments passed to the bootstrap method, in order to compute the value + * of this constant. + * + * @return the number of arguments passed to the bootstrap method, in order to compute the value + * of this constant. + */ + public int getBootstrapMethodArgumentCount() { + return bootstrapMethodArguments.length; + } + + /** + * Returns an argument passed to the bootstrap method, in order to compute the value of this + * constant. + * + * @param index an argument index, between 0 and {@link #getBootstrapMethodArgumentCount()} + * (exclusive). + * @return the argument passed to the bootstrap method, with the given index. + */ + public Object getBootstrapMethodArgument(final int index) { + return bootstrapMethodArguments[index]; + } + + /** + * Returns the arguments to pass to the bootstrap method, in order to compute the value of this + * constant. WARNING: this array must not be modified, and must not be returned to the user. + * + * @return the arguments to pass to the bootstrap method, in order to compute the value of this + * constant. + */ + Object[] getBootstrapMethodArgumentsUnsafe() { + return bootstrapMethodArguments; + } + + /** + * Returns the size of this constant. + * + * @return the size of this constant, i.e., 2 for {@code long} and {@code double}, 1 otherwise. + */ + public int getSize() { + char firstCharOfDescriptor = descriptor.charAt(0); + return (firstCharOfDescriptor == 'J' || firstCharOfDescriptor == 'D') ? 2 : 1; + } + + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + if (!(object instanceof ConstantDynamic)) { + return false; + } + ConstantDynamic constantDynamic = (ConstantDynamic) object; + return name.equals(constantDynamic.name) + && descriptor.equals(constantDynamic.descriptor) + && bootstrapMethod.equals(constantDynamic.bootstrapMethod) + && Arrays.equals(bootstrapMethodArguments, constantDynamic.bootstrapMethodArguments); + } + + @Override + public int hashCode() { + return name.hashCode() + ^ Integer.rotateLeft(descriptor.hashCode(), 8) + ^ Integer.rotateLeft(bootstrapMethod.hashCode(), 16) + ^ Integer.rotateLeft(Arrays.hashCode(bootstrapMethodArguments), 24); + } + + @Override + public String toString() { + return name + + " : " + + descriptor + + ' ' + + bootstrapMethod + + ' ' + + Arrays.toString(bootstrapMethodArguments); + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Constants.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Constants.class new file mode 100644 index 0000000000000000000000000000000000000000..eb33346d484ef732d47ae44948bcff103878ae9d GIT binary patch literal 6912 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 6 + * @author Eric Bruneton + */ +final class Constants { + + // The ClassFile attribute names, in the order they are defined in + // https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300. + + static final String CONSTANT_VALUE = "ConstantValue"; + static final String CODE = "Code"; + static final String STACK_MAP_TABLE = "StackMapTable"; + static final String EXCEPTIONS = "Exceptions"; + static final String INNER_CLASSES = "InnerClasses"; + static final String ENCLOSING_METHOD = "EnclosingMethod"; + static final String SYNTHETIC = "Synthetic"; + static final String SIGNATURE = "Signature"; + static final String SOURCE_FILE = "SourceFile"; + static final String SOURCE_DEBUG_EXTENSION = "SourceDebugExtension"; + static final String LINE_NUMBER_TABLE = "LineNumberTable"; + static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable"; + static final String LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; + static final String DEPRECATED = "Deprecated"; + static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; + static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; + static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; + static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = + "RuntimeInvisibleParameterAnnotations"; + static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations"; + static final String RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations"; + static final String ANNOTATION_DEFAULT = "AnnotationDefault"; + static final String BOOTSTRAP_METHODS = "BootstrapMethods"; + static final String METHOD_PARAMETERS = "MethodParameters"; + static final String MODULE = "Module"; + static final String MODULE_PACKAGES = "ModulePackages"; + static final String MODULE_MAIN_CLASS = "ModuleMainClass"; + static final String NEST_HOST = "NestHost"; + static final String NEST_MEMBERS = "NestMembers"; + static final String PERMITTED_SUBCLASSES = "PermittedSubclasses"; + static final String RECORD = "Record"; + + // ASM specific access flags. + // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard + // access flags, and also to make sure that these flags are automatically filtered out when + // written in class files (because access flags are stored using 16 bits only). + + static final int ACC_CONSTRUCTOR = 0x40000; // method access flag. + + // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}. + + /** + * A frame inserted between already existing frames. This internal stack map frame type (in + * addition to the ones declared in {@link Opcodes}) can only be used if the frame content can be + * computed from the previous existing frame and from the instructions between this existing frame + * and the inserted one, without any knowledge of the type hierarchy. This kind of frame is only + * used when an unconditional jump is inserted in a method while expanding an ASM specific + * instruction. Keep in sync with Opcodes.java. + */ + static final int F_INSERT = 256; + + // The JVM opcode values which are not part of the ASM public API. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html. + + static final int LDC_W = 19; + static final int LDC2_W = 20; + static final int ILOAD_0 = 26; + static final int ILOAD_1 = 27; + static final int ILOAD_2 = 28; + static final int ILOAD_3 = 29; + static final int LLOAD_0 = 30; + static final int LLOAD_1 = 31; + static final int LLOAD_2 = 32; + static final int LLOAD_3 = 33; + static final int FLOAD_0 = 34; + static final int FLOAD_1 = 35; + static final int FLOAD_2 = 36; + static final int FLOAD_3 = 37; + static final int DLOAD_0 = 38; + static final int DLOAD_1 = 39; + static final int DLOAD_2 = 40; + static final int DLOAD_3 = 41; + static final int ALOAD_0 = 42; + static final int ALOAD_1 = 43; + static final int ALOAD_2 = 44; + static final int ALOAD_3 = 45; + static final int ISTORE_0 = 59; + static final int ISTORE_1 = 60; + static final int ISTORE_2 = 61; + static final int ISTORE_3 = 62; + static final int LSTORE_0 = 63; + static final int LSTORE_1 = 64; + static final int LSTORE_2 = 65; + static final int LSTORE_3 = 66; + static final int FSTORE_0 = 67; + static final int FSTORE_1 = 68; + static final int FSTORE_2 = 69; + static final int FSTORE_3 = 70; + static final int DSTORE_0 = 71; + static final int DSTORE_1 = 72; + static final int DSTORE_2 = 73; + static final int DSTORE_3 = 74; + static final int ASTORE_0 = 75; + static final int ASTORE_1 = 76; + static final int ASTORE_2 = 77; + static final int ASTORE_3 = 78; + static final int WIDE = 196; + static final int GOTO_W = 200; + static final int JSR_W = 201; + + // Constants to convert between normal and wide jump instructions. + + // The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP. + static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - Opcodes.GOTO; + + // Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa. + + // The delta between the ASM_IFEQ, ..., ASM_IF_ACMPNE, ASM_GOTO and ASM_JSR opcodes + // and IFEQ, ..., IF_ACMPNE, GOTO and JSR. + static final int ASM_OPCODE_DELTA = 49; + + // The delta between the ASM_IFNULL and ASM_IFNONNULL opcodes and IFNULL and IFNONNULL. + static final int ASM_IFNULL_OPCODE_DELTA = 20; + + // ASM specific opcodes, used for long forward jump instructions. + + static final int ASM_IFEQ = Opcodes.IFEQ + ASM_OPCODE_DELTA; + static final int ASM_IFNE = Opcodes.IFNE + ASM_OPCODE_DELTA; + static final int ASM_IFLT = Opcodes.IFLT + ASM_OPCODE_DELTA; + static final int ASM_IFGE = Opcodes.IFGE + ASM_OPCODE_DELTA; + static final int ASM_IFGT = Opcodes.IFGT + ASM_OPCODE_DELTA; + static final int ASM_IFLE = Opcodes.IFLE + ASM_OPCODE_DELTA; + static final int ASM_IF_ICMPEQ = Opcodes.IF_ICMPEQ + ASM_OPCODE_DELTA; + static final int ASM_IF_ICMPNE = Opcodes.IF_ICMPNE + ASM_OPCODE_DELTA; + static final int ASM_IF_ICMPLT = Opcodes.IF_ICMPLT + ASM_OPCODE_DELTA; + static final int ASM_IF_ICMPGE = Opcodes.IF_ICMPGE + ASM_OPCODE_DELTA; + static final int ASM_IF_ICMPGT = Opcodes.IF_ICMPGT + ASM_OPCODE_DELTA; + static final int ASM_IF_ICMPLE = Opcodes.IF_ICMPLE + ASM_OPCODE_DELTA; + static final int ASM_IF_ACMPEQ = Opcodes.IF_ACMPEQ + ASM_OPCODE_DELTA; + static final int ASM_IF_ACMPNE = Opcodes.IF_ACMPNE + ASM_OPCODE_DELTA; + static final int ASM_GOTO = Opcodes.GOTO + ASM_OPCODE_DELTA; + static final int ASM_JSR = Opcodes.JSR + ASM_OPCODE_DELTA; + static final int ASM_IFNULL = Opcodes.IFNULL + ASM_IFNULL_OPCODE_DELTA; + static final int ASM_IFNONNULL = Opcodes.IFNONNULL + ASM_IFNULL_OPCODE_DELTA; + static final int ASM_GOTO_W = 220; + + private Constants() {} + + static void checkAsmExperimental(final Object caller) { + Class callerClass = caller.getClass(); + String internalName = callerClass.getName().replace('.', '/'); + if (!isWhitelisted(internalName)) { + checkIsPreview(callerClass.getClassLoader().getResourceAsStream(internalName + ".class")); + } + } + + static boolean isWhitelisted(final String internalName) { + if (!internalName.startsWith("jdk/internal/org/objectweb/asm/")) { + return false; + } + String member = "(Annotation|Class|Field|Method|Module|RecordComponent|Signature)"; + return internalName.contains("Test$") + || Pattern.matches( + "jdk/internal/org/objectweb/asm/util/Trace" + member + "Visitor(\\$.*)?", internalName) + || Pattern.matches( + "jdk/internal/org/objectweb/asm/util/Check" + member + "Adapter(\\$.*)?", internalName); + } + + static void checkIsPreview(final InputStream classInputStream) { + if (classInputStream == null) { + throw new IllegalStateException("Bytecode not available, can't check class version"); + } + int minorVersion; + try (DataInputStream callerClassStream = new DataInputStream(classInputStream); ) { + callerClassStream.readInt(); + minorVersion = callerClassStream.readUnsignedShort(); + } catch (IOException ioe) { + throw new IllegalStateException("I/O error, can't check class version", ioe); + } + if (minorVersion != 0xFFFF) { + throw new IllegalStateException( + "ASM9_EXPERIMENTAL can only be used by classes compiled with --enable-preview"); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Context.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Context.class new file mode 100644 index 0000000000000000000000000000000000000000..c2754c3b09cd0644ab7949f92e8be808f7ab90b2 GIT binary patch literal 1161 zcma)6&2G~`5S~p#10l3&3~ix63oUJuN|-wcDY!(cWSWXZz4WxUH_oQcZnR$W^H`ja zIPd^G6k>MSstF*{gLgbL-+c48_K%<6z5_r2hgB%SQU%I2xB<%q>SOwW`WY3e-;2g9 z)&!Pcal!R#0!z)-Sp{wq*dHesJ{OuPK{H>f)Rz|fkwreuCw?H&_X$HisKU4;K)0F2i0DSea6lbCLF@noEJ<nDs=WaHFJ8HOyuEL4;hQr*nTAwwVq6w_enrzX5ECgaNhh_<` z97inE^j~3y4wHMhl|L>qPGv3&wjW=(EPp#3PdShYmbV&m!A^=v#MHn{(%hZd$vR_M zk2of8E?SiPHn5^q#4lkgBpCy2Y&n>9p32+-~R^EXXD_5Ofhc&A= zob=$X)$cj~I&4^d)7kGk`2e=8{h`A>a`Lg0+fMGl6N`K5^j)hHwBZi}2<+jTkJ4J& gUx9o0~#dH?_b literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Context.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/Context.java new file mode 100644 index 00000000..bec67f53 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/Context.java @@ -0,0 +1,168 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * Information about a class being parsed in a {@link ClassReader}. + * + * @author Eric Bruneton + */ +final class Context { + + /** The prototypes of the attributes that must be parsed in this class. */ + Attribute[] attributePrototypes; + + /** + * The options used to parse this class. One or more of {@link ClassReader#SKIP_CODE}, {@link + * ClassReader#SKIP_DEBUG}, {@link ClassReader#SKIP_FRAMES}, {@link ClassReader#EXPAND_FRAMES} or + * {@link ClassReader#EXPAND_ASM_INSNS}. + */ + int parsingOptions; + + /** The buffer used to read strings in the constant pool. */ + char[] charBuffer; + + // Information about the current method, i.e. the one read in the current (or latest) call + // to {@link ClassReader#readMethod()}. + + /** The access flags of the current method. */ + int currentMethodAccessFlags; + + /** The name of the current method. */ + String currentMethodName; + + /** The descriptor of the current method. */ + String currentMethodDescriptor; + + /** + * The labels of the current method, indexed by bytecode offset (only bytecode offsets for which a + * label is needed have a non null associated Label). + */ + Label[] currentMethodLabels; + + // Information about the current type annotation target, i.e. the one read in the current + // (or latest) call to {@link ClassReader#readAnnotationTarget()}. + + /** + * The target_type and target_info of the current type annotation target, encoded as described in + * {@link TypeReference}. + */ + int currentTypeAnnotationTarget; + + /** The target_path of the current type annotation target. */ + TypePath currentTypeAnnotationTargetPath; + + /** The start of each local variable range in the current local variable annotation. */ + Label[] currentLocalVariableAnnotationRangeStarts; + + /** The end of each local variable range in the current local variable annotation. */ + Label[] currentLocalVariableAnnotationRangeEnds; + + /** + * The local variable index of each local variable range in the current local variable annotation. + */ + int[] currentLocalVariableAnnotationRangeIndices; + + // Information about the current stack map frame, i.e. the one read in the current (or latest) + // call to {@link ClassReader#readFrame()}. + + /** The bytecode offset of the current stack map frame. */ + int currentFrameOffset; + + /** + * The type of the current stack map frame. One of {@link Opcodes#F_FULL}, {@link + * Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or {@link Opcodes#F_SAME1}. + */ + int currentFrameType; + + /** + * The number of local variable types in the current stack map frame. Each type is represented + * with a single array element (even long and double). + */ + int currentFrameLocalCount; + + /** + * The delta number of local variable types in the current stack map frame (each type is + * represented with a single array element - even long and double). This is the number of local + * variable types in this frame, minus the number of local variable types in the previous frame. + */ + int currentFrameLocalCountDelta; + + /** + * The types of the local variables in the current stack map frame. Each type is represented with + * a single array element (even long and double), using the format described in {@link + * MethodVisitor#visitFrame}. Depending on {@link #currentFrameType}, this contains the types of + * all the local variables, or only those of the additional ones (compared to the previous frame). + */ + Object[] currentFrameLocalTypes; + + /** + * The number stack element types in the current stack map frame. Each type is represented with a + * single array element (even long and double). + */ + int currentFrameStackCount; + + /** + * The types of the stack elements in the current stack map frame. Each type is represented with a + * single array element (even long and double), using the format described in {@link + * MethodVisitor#visitFrame}. + */ + Object[] currentFrameStackTypes; +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/CurrentFrame.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/CurrentFrame.class new file mode 100644 index 0000000000000000000000000000000000000000..4a875802623a708333d2586a56962b4c4f2b00a8 GIT binary patch literal 1073 zcma)5%Wl&^6g`vJNt+r<3IsySqhQ)5rIr*lnSPdJ~2P6AcD?as1f{;#8=ZhmKTp zM|un4r>DYmcoI2d#UsJccoD=wI%MeWO)D~{+!NuT=W3!A3#(``G{slpXDI=F*qcnM z5N2nQC&R&VVTarcMNVhoN)uNttm7KPeuc_Wrj&@&@_S|^)ST40mA@;r6{J-HbMV2W zchrJ~4GY(CgJH#&Cud_Nqh)GYAoN@YV8BuJIH*#1xe5aYQ=Y~`G3-?36+Nc0kSBhwi%l5nT+JC)le~K`wY^(~Q+AqRt;j0n zKUprX=z^xqd|xDqTt<3PQij${X37`iAf&RkFBjtJf`8$7Mm?+1${;^!SHN(SZbQ0j zf1|&D0rowA@6f5o9e71s^%}Rx>J(A9jV|3N9(S-w7|Gj%8ncuP1l8mU9v#XCHLo3joJynn1Vw&-26+PFuS c)@b8C9-y9E+jt0rP}+oG6E4GJ^4GBQ7dw6!djJ3c literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/CurrentFrame.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/CurrentFrame.java new file mode 100644 index 00000000..580b9a95 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/CurrentFrame.java @@ -0,0 +1,87 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * Information about the input stack map frame at the "current" instruction of a method. This is + * implemented as a Frame subclass for a "basic block" containing only one instruction. + * + * @author Eric Bruneton + */ +final class CurrentFrame extends Frame { + + CurrentFrame(final Label owner) { + super(owner); + } + + /** + * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the + * instruction just after the given one. It is assumed that the value of this object when this + * method is called is the stack map frame status just before the given instruction is executed. + */ + @Override + void execute( + final int opcode, final int arg, final Symbol symbolArg, final SymbolTable symbolTable) { + super.execute(opcode, arg, symbolArg, symbolTable); + Frame successor = new Frame(null); + merge(symbolTable, successor, 0); + copyFrom(successor); + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Edge.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Edge.class new file mode 100644 index 0000000000000000000000000000000000000000..449ab00e94888f08502ea981127fe5217c0afa63 GIT binary patch literal 648 zcmah`%TB^T6g|^|P^^NAPkhE`uu{E^!}mmRy|bcGu;Oq_Vqi%%K! z@?Oh87Dfg+6O%9*w!7^I+mo>fCHL(h?ASrVdJ>M!qn=%DcLYPqlXn3Ft10%hi98An zM$~s*5k*1Buv;IaQ|FHGj}?8^#2ktYSt*|5k^Ig$wi-L8HO_A?nhaBwKt?f_af|zX zp;HW?ZK}7GYV*3*xYXZV!qcR`%2KJF!FUzipze_5#cp=eCo{B z1DE?P9(oG@HB<4u7cu0nf_~_VGfxc~O6ySF5RNDcjW$nX3G*=N4;Bb%SR}mk4=DYRP0ot@}rZ{lg0|w621AvO;IgcA7EB#fQ+?2z?5|`z|1@KHLTLPKn&oKCZAy7 l8Pj+nwO6cB*BbG$o~V;j;;USWiL=_an0V{txj{(7<}dg{jSm0- literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Edge.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/Edge.java new file mode 100644 index 00000000..59a7ee83 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/Edge.java @@ -0,0 +1,123 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * An edge in the control flow graph of a method. Each node of this graph is a basic block, + * represented with the Label corresponding to its first instruction. Each edge goes from one node + * to another, i.e. from one basic block to another (called the predecessor and successor blocks, + * respectively). An edge corresponds either to a jump or ret instruction or to an exception + * handler. + * + * @see Label + * @author Eric Bruneton + */ +final class Edge { + + /** + * A control flow graph edge corresponding to a jump or ret instruction. Only used with {@link + * ClassWriter#COMPUTE_FRAMES}. + */ + static final int JUMP = 0; + + /** + * A control flow graph edge corresponding to an exception handler. Only used with {@link + * ClassWriter#COMPUTE_MAXS}. + */ + static final int EXCEPTION = 0x7FFFFFFF; + + /** + * Information about this control flow graph edge. + * + *
      + *
    • If {@link ClassWriter#COMPUTE_MAXS} is used, this field contains either a stack size + * delta (for an edge corresponding to a jump instruction), or the value EXCEPTION (for an + * edge corresponding to an exception handler). The stack size delta is the stack size just + * after the jump instruction, minus the stack size at the beginning of the predecessor + * basic block, i.e. the one containing the jump instruction. + *
    • If {@link ClassWriter#COMPUTE_FRAMES} is used, this field contains either the value JUMP + * (for an edge corresponding to a jump instruction), or the index, in the {@link + * ClassWriter} type table, of the exception type that is handled (for an edge corresponding + * to an exception handler). + *
    + */ + final int info; + + /** The successor block of this control flow graph edge. */ + final Label successor; + + /** + * The next edge in the list of outgoing edges of a basic block. See {@link Label#outgoingEdges}. + */ + Edge nextEdge; + + /** + * Constructs a new Edge. + * + * @param info see {@link #info}. + * @param successor see {@link #successor}. + * @param nextEdge see {@link #nextEdge}. + */ + Edge(final int info, final Label successor, final Edge nextEdge) { + this.info = info; + this.successor = successor; + this.nextEdge = nextEdge; + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/FieldVisitor.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/FieldVisitor.class new file mode 100644 index 0000000000000000000000000000000000000000..b06e5c175e9cf360635f3a96553dde0c25fdc6d6 GIT binary patch literal 2227 zcmbVN-%}e^6#i}!2!w@%4NzsVrnQzNK+|feKT=yMg-Yc|Es&PJZIVm65H{&%gZilB zzo3qeGnsKl$2ZYw!;H+>w?6nssps5Xl2|%0^&$7(JvsL~-~G0Yde{FOO}f{t7f?sN1*$vWn1nw zflJAS#h2KbP30o!L2nolj@u^?+cI~}Oxd(cnH3dKAec<$!sr(`e**GKwNNR_S`fWJ zkYH&D^U%#h7Y`wjWmw>BJIX@2EK6p2#wpczr0vdqR*+TKs@P$i5;)cNTXh}FF5ReG z<)U;V7(s6jMv3pbU8`5C6~~pugjux`{MVR<*KnF-F{@Q+7X_x0i_arvQ%6ibc$Og& z3~@$aEV*#J;~N^z;Z1=ax8hM07)l=9LZCw!XOWWv!!M$f>!k`vYnZ?!X--EG5DRR( zpdo{c0)fq4I>}3=my7Bx4R7PJKy;U@WyZEEuE_!m+S>Vyhh0a^ukwjl2Sn1{7*yZ zUvm49j0;?$p)-_5YE3i_@l~T$ zh_4sT)O_iB&Oultu#U z_Q9I;6(rx~^ghCdKG48bLytCa#n597Tr~8-2GWMEH*n6-;|-iXz|h74MmF~GivDU7 zhS9|9O`P4w`KM{)2~z3FCzxVRLB(m5do1!4rGO+XdQY~ATNz8(Q5+Lq^cKfupCd8C zZQ>ok$Fx5N@eggKS12IpM;3ua!teyi&@9N-m41w=Jz98j@DYK!3Zr=rei*@hhb*jS zo(Ql2ao+q4{X9*KHF0TAFqC(S0p;=qDflG@@l^-&c#CaooWtKJy^NAQ`D& z`0>6b@#)1Op&lcp>p!CZ0Mi@#JNtO=sYfBklQB6p9BShIP8K6-<2Uq(eTz80!zjMT zIDSxUE_x

    Z3oL;gCH4h%OW-jb8~}Q%NKI6K&~Bo(SzD7~!}k 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModules$2.class b/tests/test_data/std/jdk/internal/module/SystemModules$2.class new file mode 100644 index 0000000000000000000000000000000000000000..e7e2847862597a581bc1571b116e50df0ccc0fda GIT binary patch literal 69454 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModules$3.class b/tests/test_data/std/jdk/internal/module/SystemModules$3.class new file mode 100644 index 0000000000000000000000000000000000000000..376b52a6f25c117e65bf0c080c64f0f2fd5db99d GIT binary patch literal 69454 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModules$4.class b/tests/test_data/std/jdk/internal/module/SystemModules$4.class new file mode 100644 index 0000000000000000000000000000000000000000..f36351778662d7e27e570add0ddc57863e425729 GIT binary patch literal 69454 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 bW0Vn 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModules$5.class b/tests/test_data/std/jdk/internal/module/SystemModules$5.class new file mode 100644 index 0000000000000000000000000000000000000000..6f75408db0a853f096ba8db2f82e8967c9c3add5 GIT binary patch literal 69454 zcmd44cbpu>(KkL}XQnUDP3w|Q0f7iYXoV!AL=p<1h|mdy$g8`Rw9+MR@1zqs7#y$x z1I8HJ7;wheCRxZNV+=Te4LIkFZJe_)kL~C8t?KUCnY~@<e+rhG*NB#Diu1-6I=w!vjNl2-|8_BQMSuyN3#cc!K%|9Wvvbm8D@cZmLPC z;sV>6w%1C5)o5Ftl}J5#q|n=w9}29{wrZ%K?8aO%FRaM6S`JB!-ZeZ_=-<3x#+gLq zgj%cFYO$?D_d4+OwfT!i3Pbr~V71wn7}CFNYvm#1pe=5_V8+TlAitpA>aZpfPMx+j zWA8XE866xL8U{*}ZL5K+j|>-jXLsc>iBoOM8Q6pgIRrz}6q`pFWSX^qowc8J045RG zWV?rUVx~0MRuI;K5T_*1lwc6&vRIy%I*+PVk&vc-{p)7jwA!1e;>Ls*B}R&9TN zhsM>m&eJ`|_>7&LvT^jdETdI~XS(hl#2seMA`WJ4DyWnfUu6Rt<`(SbYD?BicmY+NGMSxtYd9!0uM_+v$_8Mf#KY6 zVW3}FSQ4`Iq`Nm)EN&|FLa2|ot;rQ0WOKui?u{eEsB)rhO{r7`v=0vS=lh3?!dhrs z`&F*fUmVW$4-XCufMbhnYigxh1ymXu=~k#NG3;g{x(8GT!a4;KSZcg!U?^YM49b>i z#gpagh5qdW+ko?mRH>S3VXe}_t?CZtHwo*sRIe!Nh2j#{>FMH;{^3F&y6rOj?#m5t z5!M-4zl>6U9&Og!R=xR^Ee=BZH^k3L4$d)s_7|{3wqSbly%mVPQqM&cUG_Z@~2G!5Y0&_F*J zx-(S@iNLG~>k>04*M-r7X3IhNF0-vhMwQDihU5zC3Ns9;5MfgX5IwB-Aqcpz zt|41NI-u+cxH-^Q07=){*2IbxdI!3>}Jp6EBeRM2RN}xZc*{A#%W#R+t z<7R31FcZ|5>xXyK$8z(K(YvL>>`)(6!>4Skj;FIf*T>Bt zF}i{uf10`{gSsV0iyi{>7&Sl%L}Zwi=@VpQs9+Oh<})-6^rN@X55|2~KjS(19QBN6 z#qMDs{;X|HPdOTUFv*{SR4tfZVg1@H4Q1%n()g`yo$_C@uo79n zC$j!fj(+bzj$Ow;jeW3rGtKm0%;aOKWVZ~{3i+E+)v;FDx|!ttA6gvY8s)m7zy4Xy z!|i?9ZY=Hp(LzQ>xGy&d4uF6E)`cVe#gReswe#T1|CY0>uTbn3wymXa>!8{w3EQ=; z8~;mQ{ht!I3Ou(x@Z9#xS*yJ*Tae$F6o!GJ&DjCo8Scn$%;t)H!mh=hZqIdKhWq;9 z1PZ%eZB0vxXiR@uSi8Kiv9Y5)?4Bx;X%#j$c`CMuCTSV$%?*>Q zBkU=Gh+kG8FC|3C7k5+{x&PR!R@B(}xdAqU5mBMUv0*!$TC(6pwA z!Eg;eqafUZv^nE{G35=ADe5%BAqK z21bTxXKi1PC7M?;JKI{3^5>QLoxO@fwWXkF9M{5nsu17RLC*#C_S@_m5L&Wtw5@|l zM%6~BTBoNC=KG6*{dU{(1}JM=%f^Kax7%9?)4s*Nl~8#{Dn_Lu(bHFA-<2O)TIeVL z&VHwfQIQ+BXaK?M{^3)xbA~s+6zgSRXs58>Wm|{vs-rsCD`%G>v#_U!oY%ErZSVH{ z(3*HY-fde4rfQ$Db|toh*iGwxOI6=%TXR&^vItIgVR2`_idKvi7paI(soDF;_aQBy z<2W1-V#K=g6onc{U~@NiZOOW{Ddei?mGY%t-=C~$VmjHS*w-k=m1<)9ynozhs^+?# zgZahzVYO?sv6F7)dhtpu^?`l#0sPE_Zn7tXMcbBPe@9EERPkeGg5rvc272MjBaGVX5rdNY>)e zB|*ny1}|0wB)p5DSNeN$Lm)m^qW6ia^;YNl@}+v88C#D-UEMp=^*(E`i^pBb8ZBMx zbG9{;r68_F>xop=$s@D|X+aJR^p=LFAjF;;lxlu{45I76C*n{Vg)gS!Z^WQ=FbSo8 zp4Ssr9uA_KP$h+ar7wm3Wg0N)`e98k@7V?t$hRqV_#%m6vL5N|{7`mrep7CwcQ~z{ zUbd~nNcG23wH)i72qDoWxCWa_oVS&_{~B0Y%~$|ovMMz5tMbFSW&NArxK?gxXSHs=16>_=la$laNZ+%q%t(=r|FYUi zB(b5hro9@3AJ{)6gYctqowMl?VV-_Mnm;*LTZe`>6|>8ShAZjCpXorcI_FwhC=Lhq zE3gJB!&V{EL^bJ1%>HGa{RML!JM&ukj4-WB0FOrkk>U{!0zK(CK5Iwe9IE$CW_cqnh25HS zSh)a?4Z{_&)^fumLwVug@cgh8OUBlwpdGf-x!#?{0!04s@_3>?0dwY-uWI%-%+n+2 zFeu4;^_0)aoTK#SN{2acCOEuPILGJ!LT?Voaa*8M9K=_6gKtW(c{f`w2Vs^t5V8qz zVh3>*-m%ek0tI>=5mAY&6?*!GgJ?=zQ0zfFL{#FqMX`^1N`_QmGlheY3U3vuYl>Sy zwb71-{RiP7yb=#gPdRMutgII6AlF_vtIN8C!BC+Pre%%Zrkerdr_^_rFEu!8btIu; z9ZcN1Y9r98rgLUB^tNJeDV(#aHpVftb2b(hc@<-Z?#mT=hX;gnt_fKo-shZ;l~1)z zm?jRz;8>csg3g7yzcDoiX*UIIH{zy3#V&^Og9F8a>ZM0BWK1u`Zfu5yvq_UY<~fI{ zoh{YS++N@jgtJvg=i-eQ4$qz5^4LedJBz~vrynbvP)=0N4h~@P3TLo9ghbJtIZ&oU z6(7tM&M=Hcsx$3h48>s^KHPP-Yf+2`r6XTwv^?g-;hF5V{7yc)bS^HBvG7_|>gCe% zfKmL6)au|sFBb0QaCitirP{943}NRwv0$%;MliKX3pvXH8s`mq5gLzNIM?Y;X*}V) zNr!rPbn>=ouO*zf=o#T+6~htETlGL(7$cwuxg7ea4r|rJMVGc zOYQHpt$DOV+jIEGTxFXMFO}W0z_|<5ty;Kx@xpaWpy-ZF96w>5(@nxL4(*sufW=YiT<@uJq|KUm+0!94>=zudOt#@8}yDQg1Qu)qoZy*pLgzs zq^k;i(FnxkAtv`hZIzd15xwCfPUjP3bh*<~o9r-xE5fgXg* zIM2ZA!2uuN_ao0BhlQ~v&!=p$+tD-JC!FW70oz+eVjt|#7vR=as!GA;*fkT*m#~T4 zYc)E3)J%KPMMEj0VBcl26?u#6>rXoFB%QZ%U*bt}~V3|bQf*^L7O!xRUE zU-wtcK=P4c&)>0`PL`9@zE)Njel4y@3+MH+?$I;Z2i$0L{)PEUcC)>Zr#<6;G=|K2 zaKN=d2i4OBS=tb|ScfuMXb!a9jE=Y|s*TuCkTplD%Y@TiUx(9GJuNL+qnq@3LR?#< zdNsAX7M`_+J+8Q3tqwSh&wXA<|q*SYs_IL5jmijtvWH?zZ zqz!6Ztt24p_+SpQSvo^-qZAn>VaawuZT0111SiCI+lc8bI$4l9yd|#Ds^`^A3TRxL z=gTT?yKOz2wEQ~OlrVMwkCtfDOADRDc?gEN6YH$~+|GnbCRSh2J%arb_B8a0L3T)A zuXQJ5S}SPGjota)xVCVoR#x1pT5!J16=!!E1a)t{X7wIHxCc~L!|C2xmAMCEZ(E_` z(HyLOj4!P=9E?Gs6oq?m<<84m^cFS>cgDD?k~wf^R=CQVQ z)IK)KBH#lpBise!k`jd>ln?av@%zw1N#co6VU_U9(`j)@6qx}FZEM!}>Kb$IE~+8| zW!>}L7Zhr(Dv*oXgPf!XhDd>?b-(>_Z2q__l$jDa>=X-cl|!lqC6yb1GbLi z<+HMk>NdN3&OR`Kn0DU241{IS0~Z3X?+Et-Y^}$QVKElC+&&1yXfZo5I9w2JcNN`M zNrKQwyLWW8(9Q4LcuEy)9^YEsnj0MyZlQ|0E<=tgt1TmKAlz-^lO=AIl%>A$&9B*b zxC7%OMbUjxWh-B<4YX0iIa$TcTp8h`h5qi|5!~N(N5-dNNBc45JH|I}sGHq9lF=XQUD)L;hI@tfV zaUdUeKSV^&6Yh;wmT2Wc*aBfD-aZaWcqwo|!A113qW_SNJ>*8oc|?SA9Cej`d1n<* zCfzTB<+v@RJmhy(;c2=Be$n0m*t{EYJEO{JD;3L`j#IerMI?U@6_lBOUt;l9=!M;m z{(*j@%n%QB@5WAWPyOn>zWaW=w5O@mwbEW6Oo(WuT08LGDcgh(Q!oa{T**qp{U}8* z%Sy8-=+?0y_hb4DGubRr0dE!2ZB+8cKJI?@efJ|slX%%oU9NT!vQ+oQ2xWESI=co- zIX{%|hnpGiY#(&R`Cp%gtF!CYE?nKUY~8Xmm(;tT;()G;IHh{+iSH7?JKk-=frv^9 z_fdWIf@74pr;AIM?&CWAq~ezP{VVrLgw+{oj%M})@uw(61Rf;bu)y0X>UAymX&u^9 zo%Hu)2lJ#55q?zf1X3?NW5PwGQN4{wWt(vDCR{`mOGTUWw2eUYP!ob$1r#7Ws8~kL z3W#Xp9M44vu++bLlg34yk6&tIRJaUlkZv*NHsYMlMQpFsWDswdV|)bo)HU~wdE6Bi zE+TvCMjrppQpzWU6xS(5_tf2s!o~t#xrft(=pGX>3heM60(p^$?CD6LE;2koaE}Lw z>t_3K(THL}!bNOPzm#Vh4fc-U0#z})5m$3vh>i}ol|SA(n8&(7n6Jw7;ld`E1w{IE zFw?YWP9nyqqjYhx3Piey@9A*4<`x2aI_k~^i5Fg7MD+Mo=23_*I9qyzuqJMc;(Y<( zBEY8+P<6CeAk3$upg0kR0QD7mFu{oMX|zhEYU&Z=)4WwrinzFpo4~?FppW0k#Z5Hs zNIy`m5be{%6mhEn>_UuB2XVOo(ZwOU@aiJSrw<-fIWLy(Edv8|e3?PSPt%~DDjG6~ z`I(`qcYZ}UZiBd=A&?&;Sg=WC5arX7pn9TG`W^z_dCefEH})9`O0UQuj#uFsF2)r^ z2GP3|8r)}pp>N|zQDhLb8`}`qXmRx*gGgP9tYKa<83g50nDen<1|c{t1`2aN>Dw}l zQ-=&Up=&|{hD2=4RID-A3%2SGvN9vNSlwyksae*UGxgruX*l{)D5Js;z# z+t~G)LozdP7M3{_Zepxkl`6wsX#_KH+i=T3Pw7s%$Q-7>E`eh+ek)XKo9x2muQldU zbtbEOF6k94?(8zsM?63mujwwR&dlL(GYE+aRaN{pQFktEY?Znyrpi4YK{l{*j~wdl z#*y9-*F36vf9u&0bFE{_l*t-WDf%#M<-owUkwKA}9}}#Ui9$MA)0oZ7ad4g$dTCXX zT?I|EI8R4xB}SeAf1zq+y40v+$(fV(R#6coGAGB}DI30vwA992|2EU*;xa@N3M{*D z1aDj=$6q?0$_9s1;p--;O7^^zZ(!pZu09qyu${tRCT4kk)brgG73Ns z43-|Rh8t+sV)EL}D$-kh`JMvKRM94WwE*gB4cJCa)bu7NR*68V^R*DFM9r>*D3lHu zGV2oCSRPSZ2@-;3{pDhCX2Q)cuZ>kwUj3|uo13hTneC-p$X)mr4f%2jj-3sxjhmZn z(lxND^wL4*+=SPjs->+eVV{(W^T%1=2*!npeMGYVSlq@4>Bht^CD~%}%C0eWd#co3 zzHsfBx|^!h?OHl_Ox-PsEkY89g>ZC|+}K)$#|uZ2wR#h~{bX-66U5(`7iOLIR~ddi z4iJ+a4<>f)$&R@mUZCbn(x%g)DlOu%@Aek zT|6G5Oyx^)!J?9oFYL|jSOlv8U+3~FOGj~?xs*^)&?_QyW#Z5)$=5ZDRt*mz(LG;X zW$-gfgTJB5;EVAYsqSG$p?s-d2c=kvq&0Z;yi6&+31L*D_4v4#&pr87hH7^`meE_V znYX}GQFp@GReURUE;OVn%CmQK1N^9TnciY#Zo+mX@dVqE%+0AH?( z!}1C!$7}Niv7@f_HV92lr582kjd(4<~qM zXep8-xCF8lc1{W0HM_o2sfI#U*LVpkJUNJ(71}l`mS=J4E(gi| zYJBZYA(NZV#Pv(b-Ml7Zx^JDDtOqGNv{8amz)K^@b#TTXUr4*q4^F&AL`!<v=E(mRncr47Gbo2JvclO-f@J@*1YKgvSSBr5^(xOy)BD|APpEy=3!{rHF)S~)}L1yJ= zh^ymEHr`T-S|ae3XiT3e^G?<4Em2N3-dm1cMHS4m%U7L+U3Y)_g?Miz&Y;KBg5oiW z{j9edK4Tf`z#zLue^qDI$(SZ1>%v=;u&D{*GqT06)nkFgZx4HG6TTre=uvM2Ls_jW zlR`HC-Ff=3t?9fd z_7T$!OJw3cMC=Er>Ig5FaNJUlvONXdPla;C1&1n_@oPg~-d$9<1)>={z+3x!3Vf4& zTVXicJq%5{1@cGYg1g9AM*M+1Z)>#{BSToWy$OctR>q$aUcWvY!bb?z$MrlY5gk<4 zm3w&SM4yH5hDcU^4#vZvFH_4)Cg*celQ@OshZ-lwG@O*&@2nx{|+U*F_o=$I5(cK(%0Rg@+Sle))n5 z4BE)RQ|2$mcsMv_FOQ$=3%4H5jrpB1DvWW+4tGP&KjwB^@b>p44$l+%&nz{yQa@3- z668$1V2I9zcYh_zsBJk{crbB0FELcIm+Ye60)nq4z4h=o+LRlBUGBhbr$1EMq!?|< zUk=@tAHv5zuw(Z=jj5&U@r68g6a2v-?=d}L@k&y~Pe2$`0!PK!Z9^N66y9g_YlNvL z{4C+Xe73w_)%J6GLgThnoM`rJdEcq$*==wWh4*<|1)VE9YQ@3+{N@4SeG%KJu_Sbj zBrM_cT2f+cm`YY~U&b;X+uHQ~qV@sP4R_%E2)GKuds%yu@#8cV-QDy)knp~?mumdo zap8SKN8_vYran*JvrTy4+H;3Pdfe~qnaRqB{GNNk`e|@&^dThOvC!Y1@~~ah=ZK|J zer?3Vu2COPCZFKVY2ne%QCXz2N2(=uj{M1P^@@c4I#wf$3(PruN`&IIRc*ZpKa@iagR++ z^!Fcy_gC9Ge&1S-!T0a`!m<1)`HXy5%ELCh;!W;~tcGlW$=G~XylG#x37mdD@eaKzlZ(&{Qs^K{?wX}E&s9m)*geC6{L@Q2_Lb6W&d^aF_PvZ zrm&CPEW+KV@9Fx8JS^EaOmx$+Scq|5E7X5opzn_QwNrN%_HoKy_=5MT5?DHDKJ`8UeTloe?J(l zs*l;O`TM)?J9`5xleyxP_=KyEP*M6@mx&L&X30@m)U`FuGWWjptU1DB^ck$ItXPd~x$%MP~fNwHH(NKp$rLbKy^t3uGQs6oih_ zN*x@b;|`{V?m4?kjgap-b)aZ2j|l%L$n2i_qj0MJdIy54=}zeEm7HFBCEG_tY03CH z;*S}md*aWG#a$uz#5)d6f$)#RA^!OKrpT}GPtZG2!-8@qm55?ognyFu(W*AsKIekN zg^x%T2P3Ojn@iOYwBj$3j;Us}8Q zl23$>H;CeQ?UGNZO?DxFN<7}s_;_=OH?OIR=}H`c^-p(4&VCziZSzM;`1_GX+KXrT z2)-xZqdyA?lGf?1XQ`6#&vbA3^`Gw{hZV9PyM1_HMfe*ihL|kfisB;sEW$^SN&g4I z_FT_Ex9|~MN`C>WR6Fih_y{khzr>WN#U8Yua~Hh!-D?m}r=juh6!_S#-$OT-@RJbd zqU_m)K^AWQE2a6epdB@D2>Q~!W#Qu$i?ZSM z)Y9ARD|w3XK1J-mBx%5;WtY=ruY*_>r=$KNoVz1PLBH3PULY4f7HjORCwsuz4}Z@+ z4nda$8=)w^hgs#DB)ELfpC>^8*++OPe($zo@5>jjFfs1Z0Pjj%!%DWIY1d>WKceX) zxD|g{BU!)11^O6?k7$?P3ad)%xb%Hh#K3%OOZayuLe_n_s)HP?0@bA@Qm`!a~RT2Ju`rM=J zLDobw{7<;oJ=qFVpI-I2_3b}Ut^?I|5`H_JUV<0?Lt44ggTWk{e5za(>n0R*@gH$- zoOTu>QnOO}rBox!A7EJ4zl3kCl&1Vqio-!A=~1%ud`+&WRN--oOC%~J*5H%wC#UW9 zz`xX(?A1XL=4qdY|GNHJH50cnTk}u^E-0Wn;|9&O;<|;mt>YEd9;Y(&*{x zn>N9Ke8>IX1usAx)880`2fq#9v4o2Kz81TZvw^JwW({sIRT4h@^0Cuas=&_8=1qNB zKKurA5I#$L9)w<^em@&bMAF8JS)!IPQ3$Dxo!>;gA$~!J#0!zNv0SWBQ=Pl}*v_P@ z8`QocXIJcTu8WBh`Q~O0K<3TBg{5)PeYiR=$sa{@F|=&t_CG0 zA)GdMpPE1d@$QoU*K%%^O=^srvg-((r9Z)3R$a|5F8krNB_F}EvGSZ?t*MN?2gDI^ zvaxz+Y;Al4tk6eq<_Z5_dtsB|4$j2QqWI5V$c>vYckq|1dlq?B%WM&DkFABdn1<|^H9$#et_`rtpV z5BZ1d6*R%;CvSs~x9Wpt{&-ywxij8(<5YczfP88AW8}L-#fzXti@GU~g@P*JN9?o( zZF)+^)Fdp}zd@6ADat#lb#7c7-9iMN6xoMKDDPYZli`e3dcq!l0J2ykl(*CL6>%wx z{>QMW6i6_QUWuqMOvUOfTX^jxI6&)>aSf7ik%9veUmgE&@dWctvZ4qOfSLc_G~bH% z4q%Lf8UN+*z4^^B)4@#oBZhG^YdE(V0tKvR?bE2bS+>|;z!4S%a&|SDQ4))9IzYs5 z*Fgkx5CPmHe!6CIM&=;`xNmLHx;Kx1ECyvq?oHUtfUHmh_{Qv$R1_O5EfE|`HxH_D zm=<3w5+YbY$5@r>(x4(ZUVBPo2BXKxeol0M^-}LrXane9zN%fiJtP7If8r2)sXVrf z@vbU$v4@?d00E)+)$s~VMX=Pp=KIe-GiKjh`m|KA3|@=DiqI~yIv8Z-Hhno1*Wfyo z#?E!HVr+f-KS5o8F|z6Ut13nou)t4)60bCHg8iqDL3}I58Y*_<9$L^fb|+^ZCRu+5 z1fp!1xSHx{{a6f91ERNKEQa(T+50)Rb@%^s-#M%B4YT09I%~h+e7EhR_gtcHDsAoA zF_=~V<`(4Ki%$PMf*|VOIPq3+fY4Q)VcS+JK!_@i5TSrh#^^$u2(~09De-^W4pMgTElqNKDaV5aWNZ2 zaCJiA#Kp-4@dkIrPhP)8$7OM0lH{a_PrYJXgvfZ`PNlKOQ_@-@c(ajARNxzIScBIm zx-yMK@HV5DlU38CsgcZMdS#s4-Qewdua~OTLx(B>2;fa<>XEus7reuGP06vh zZt51nJL$>-S&OnK>g!7)K&(nxljL(8Ar$cCVKjetr9rh(BJ9$`9cUOGG<_m$Su~gCrGSTA)D>YLl_QQ!O(H;aEd^CZfDNRiN$13rLBuIPF zA9q)L;Z-bc4$NrDf-AfYFT7BM(*!z$`?aT{s~~=>Ee~?*Qike5oGH_6Bs((_q}$K{ z=|Kk8t+F6?17sfNWr_i4~;+vYw zSE>t|rRHDJA&@=dyH+{s%W!AQVEmHa!tAjf{yz3-nE#b7 zITGq`+CbQ!a0Ej$Q?&{Z|BIfzv2~WOQGaW&E@eypW;S~IPY+7NuF7>U92|@X|Hqyx zF7DeLSN!LmDz4d9s`x)uE1pcBu+bfYrhglYU5=v&{#PFmj3u`;Blyp5^`)1%5}%w3 z*Ek8LTRvIi(3kMs&h|+c8Gndh0p!p-`~05ViVbX{#!u=@+72M?rNV zdGbpT!RKz^ny3DFPc)WCe-mA0mv`YK;JvBI6QPNXlp)B+9rRC|^sjidpT^(IrT!t0 z_t+vb;j8lI%XMf8N&uRNw*UL~=r#s0=^Eaxtr z;|MW5EnEpi4oWv9Dw6#k;@&fJHa36!LV>w2V{R;|OZ!61)PERgo>#xlLvI(P?m4aP zE0{f|K=5q_g^kD6jSvX7@%t5oGNLW&-j z^Rd@sYUsEpo;8Ilos)>;pjIkW;Abc3#+3-=3MaujRltb;7ANL}5GU&)%DUkm7FQm^ zutSKY?v?-g)KYDmmQg7Y~MAmq}Tcx!SE8MSMe&0Mu zxY>>Kn@98_P!HbP7pt)(Q%_Ku#YXKLkc`C0b#9H@12b>KLFuwM}os%4! zS8IeoY;5ey z#m^s=)31|5obe4SAx8DiH&tA6wU()RM#(7ae6jX{E4LBiQupXbe)~F(`jl|2%MESD zfeA=DWX3ra|3!Qi3z4d~KzYHljj@}pI+>lU6Nsy*cY2|ImigyRaZRnb+G@dzd8)yw zIas&752~u|c~Dg+5N}dv!BtRGwWjNTFbTw45ZdiJb>XbJM;;}_TcH<|F>Bf>_itXX zY{r@OmMdFS?X?(Fv(P~>KRcLa~$p|%9_$PMNCXK{`dhvE~Gj)CoxrK;- zWQ*Mhpil%$2n5vvRfhG8I2ykQtlsCtAKt;6%#P-SKmd)eN$R(OaK}R+XvU(n1^-wx zIDpS#;$JXeUJx(i?FGHej~iBWy-GmF>v>~PRDW0`#NGP761}5De=Hyn5u1L<-f5!$ z7!w~PT0Vr~)f}&-H#FGA!$i;6vvif}VzTMdLzQVP)eFSEz}1YD>%kb!gecfJo9x@{ zRk=a*#cYcUrZ0i(yfYA=AhsoI2I7AFtr{3Lw9~d0Bqz4&zp|8#rMkwPJ}4fl6AuW) z&1wcV(Rc+C^n=YG4IA8a{jy%rewTQJ+V93;P9;91;y;0S6#u(S-<+}zw;T&^(ul__ z%MzAtxfVVcDjvtLX8f`Ny+a?d!~@7!_*rAs>c@@xvE$ySpVjT*S-sVu+MRqRa{F7> z$;-pTp0Ju$K4vv*`tV6IS~!Yts5z;f^P)DI46~*7W&)bkJ^V#{8hek7jlR zyRF$>8#2)xD$1Z}UPp$DJminuZ5`9K!AEXB=cvhXoD;~Mz`2kfpQN(%{A87-3X4^? z2HB-5TZ`D8?3pSXA$yj}N@UMg z*$K#=tFkS~p0Bd4$X=+jZOCp^*>+@mRJH@zO)5JP*)1yDiR@ODorG+!%1%bMUuCBt zJE*c#ksVUm{g542*=fjbSK0lM9aY%_kiA%Crz3l*${vX9~$)8D6(%-*_p_`MP&~|_N^*A3)ve~HjC^{Dmxq5n^pF3WN%g3Imq6ovU8EW zU1jGXdxy#%f$V!!_DE#!RN14Dy-Q_}M)n?+JqFnisO+)Gen@5KBl{7RU4ZPpDtjEV z_o?jhVZ#&FCpNgz{UoFhc5U#Yhar*CuC5J1w7YAAh#u|Q5c<*MNQ3Agq#}9}X-)JL z(%R^0q;=6VNb95Lx^`P%WEp>6%XoM~^c2ZG3G0_T1j~JRV)P=Fk<`B2QKQOEioOF)3(TmZO(T}62qNl0O&$!Mjrq0RH)6^RY{x3UfRd0*%<5lxx zF*-mM)%9;ovnA2*q6eehyRAQRcYikJOQQ$PLj9{LJ0)zc$Rn^Pi2h#U(QDvB5WS96 zFu!V|A0l7NT&s&-WFGwsX#?}FG5QAbP0@dlhSIhS^Q7&VflmdJyMX?aM7y-{wXlG& zm3ED(v5bDz8O|=JUk&Eh3i{P#eyyZm&F0rC`X$Y;)%2^y{5maqSlVsU?$FGUcBdI` zP4twsCu?R(d#Wiv9n%&#*UXBuEKA#N{FV;pbVt_LSyMBhLk z80e=bnx|(`Uki;aZis$JA^`md!4&e>Db@?f#{9K}7#(ZdA zX)o)jSDl=v*t8;gZnwQ!VYtRLI6wM(^km%6T2p*M^qQ7OX|FSd7e)_92Sv{$x;fK4 z%3+Ad<8IC}#TyBavke~I^y^$hT2FL84FSs_?ejYt6smb?Ux=*^6gwqv>%I zo&q&ZcaJIFOucN$#$;K9)+~us!Dg+H?4<5V&A;WzHNPY0Fx)}+o9N{eFq4X_Ip5~wC@Co z(!PsnyhqXa0isdb9|8d39|5S5_Pqe0@;-n%X@3HsUfQq|VS}_`DZ)l+!&Zb%(uTDl z9R@Cj&C&)R!${g>GNiQ0T1=2OnTr-_lf7t_HW>`4nCAf6rTqnf4rzZ0V4}2N0O*wV zR{$nS`y~LZ>8}Dzk@nXCrb_#p0Q*V%+W^y~{at|lrTu+18?!p_#l;`5pOtyS{^77Aq}FFkc#MJ zq&3lEq_xpfq;=7$Nb95JNE@P+NE@ToNSmTHNW*9?(&lI#(kMC;sf^A-Iw3k6X-jl2 z($?sFq;1iKNZX^0NIRk)q!Xh}NIRn~NGC;Gkxq_!kxq$7^rl9GNcW3|kWPz+k?tRD zM|wasigbE(G13F0OOYNFU5@nN=t`uAL{}r75xoKFq0x0nXGU*AdRX)pq_d*8BF#oO zAe|lEg!J&}W~6hXTanI9NrVkj{@j zgmgjl5v0dO_aZ$$x)13I(*7I3iP7^&Pm=aO02WI7p8zLI`+ooyN&DXbi=!_iT@t;F zbg8ue7vL1>*Z`+W#|2m>9S>l+bOL}C(y0MhDV;iiRnlnySS_6{ zv;eG?P8&d%bUFamNv9Lw4Czb;I8!=P0oF@r8o*i7IRIdTbPfbKTRH~=oFknX0Ov;E zMS5QJ3exkVUn0FAdKKw~(QlCEqyxDMH%5O(+8zBBX^(Vf0YJMt0GnXR0XD;g18jlq z1}I1e8-{QzY&XC*=|CBUy|CQ?eK6Vp{jk;m1F*~hgD}JZ7fA;K91cmF&@D-Fw@c>?f;UTNJ;7U~vw`5P z(m99VJEU_S!P}&B0l{}l8>_I{x?S2>ht1ZzU=j)50b@w;-O|Yse2;Xx3BDKhkl>xt z$rF5^bT$*bOF9LDcS~m*!F!~QmD_B+U)or^&DIB`(?{@w(itH5A?aL1@WZf-1U~|s zNbsZ5#>#HC?uE@G_%Z1e3En525rQ9=Hr9Ew^$BTXr8irjl+F%P&J|LZ)1Yset z`kSqXVBQEmES*aTeoER{{ms@c>0Cze5$Rk(a5oGT!B0yY8ll;GR617?d`vpm5PV!Z z*Ajd}I&UQSq;%d)@H5i6o*)Gq6YmpOwyy1fP@6 z+e^CHxpn<4>D;!QAjvDH^eS`a;^FeY5nmU>yx!d_@m)c|d zyvK&|bUw!07jlN3k8>8=Y3Y2Dv)C|8=K;=Q!z`VLIEy`qbUsDdl%13g*z#$1WQ^s2 z3H>SA2#kW>(JOjGFVvcxSE`mIA_F2GHAKK|N>Gu)-iwikgNBvI$UmtZt}>K()5HUj zB`e{BnZaaWHv>nZ91Ra>d@e@AdA1rF;eLz<{2F2~w)@igd`HM07i08A{ev0$y#B!~ z{j&bSOnp)RV79)je^9JKI$txtxFWV}q-MC@w^SZmKk0l&<*{*-&i7QFTyEzFDo>uX z^COif*VOrm%9D%e{7mH$wvf&%D$j)cQstYe{8g1laeBjdbgz+aTR0={8GOO1DM2ZPM-7?M_mYpA?O- zpu8D(3VD0(e&p@B`;)ilPA6~AJ&3$L_Ye$K06={uK)ZBT z19V6isvq8-3(XI2&xK-#x937X!`pMu0+=FQXlHnPE|fF8Jr}wd-ky6Q!2Z&O#tjdU zE);G!UAoY#;epbHS`819F0^WRuymnR!$YLo4=_WzP^ICa(uF1sXG#|eG(1eY(3{~b z>5c+qrF${JZ0TMKaJY1#JHt8Bg{lnaN*9_koQI_XaD;TB|H31sdmX@0(uMX5kCrZ! zUwDjkq5HyPrF#RweCgfD~^oNIEYAESBya086C%9)P7-U;w8`_fCLQrF$2^GU?s}uw1$y09Ya24*{%{?neMt zN#`2?@P@tx0B`6!0Pu#s2XH#p8vwka9|6D{`UwEMp`QW38+ru*-q0@rpbcLIfH(9T z0C+>c1AsU52LO0Oe*!pHy7vN{C*Au1&X?{d04~640=N(h2>>q9KL9pj`2cidjhvFmI}aTtP+4NSRj>chmU#tWUTM(!&%=!$HI6RwYwoh;n?PmX6ZZ|8xhzS z#A#{ev56>Kd9W4ORE@C&R9BZLRet~+9yT~c_cIDX843@&k5JpF16!gC35yLL5W=30 zvOY=^xP?c>$iXBXqilrx7-vZzyH9YIw50|fHDo^^@MSu>2hoq0)msOthvHLZZCw=T{y-xbr)q0)uv8(ku z>0?*xb<)SK*6XB?U9Hy{Q?1uYAG=zwlRkE}UMGF*YQ0YS7$=B~8|hvht{uGZ_M zk6o?TNgumfuaiD@|DxKmKGu4j^|99LtdF%`M_gIDTCXFpEM2YF5m}b5*6Ro@%Z%3R z(vZnPsL^<>yd-vdSaUEHhJ8exA%gp+aa>6ekl$?GSjDnFEao zA@(dY2diJaT(GsiSsis?W50q|M#ltDhA>2CCTtm^50SD*nOS6yGPB7ZW#*7Q%FH8s zlsS^@QRZk6gQ8;rP__U7g~tQb$jpfVwKB61piX8M0o2P3_7Sj0nNt87Wo8*blgz9D z2xVp!K(ox8*2Ph1vxLKX9S68W#{n{@n>YYrw!oBj#ihXXcvE^tTnaQ##L`BnTxQlY zQ5%@3bC{^};(DNCp=o_VTne%lnbKTbO0+LAopy7l*l1w<&D?3BR1v+N62klC;kR+k zKCU^yHL<-w4Qw7T&Pb^hel0WI@8Cu|xzQ!u=(18puzQ86h%Ey6f(-%ixP~iUTdIf& zSp^--XuOdtzPa?UPC8E+BCj{aZbr&WabfoR+;%UK%2}w2GA}uPXKht%x3^5%FJg0I%Vc_0Fz|qS%Aqh^Lc_vJm)gNQc^&}X$(I4(oxBJD@8o3wcqd;2 zI80`!3M|Yw0N|Z`3jp59cL3m>d=CKL$qxYFo%{%3o^*c#0Po~y0Ps#;0f2Y%O8|H$ zuL8h3`3(TPlivZrJNW|uypulx90&CX0Po~)04GTI9{})9{t0jrR3X4ZXhDFJWrna` z1U(3_7%C883A7);QYb!vQ=szzPK8ncSSB+>-*PBCfE6-BWUiDMB6F3@5Phqm00B;e z?gLl@wFhuIG#=4)0M3>fV%9lO zWdP^O4DswdnIWE?FEhlm3uK0PcA?A=&vG(DJliNU#ItUhA)fWf4Dl>4GsLq^GDAGu zEHlKjEiywqE65D-Y^%%=&$h`7@vK*7h-ZB=Lpf;3>k$U2G}V*;>*R-BfeZBJ>tuy(j&fHCOzWI<e-tj6=ev)^h%9EeuEmV1g$XDo7 zC>_rC7HK3XZVu}_V?OyY-jWVj?b(8+C9Y0^7A z4g@3v-d`~j5t}sD!BXj9?+ntx-g?r(-Uiaa-b~WL-Yn9=9wCIHIRGe|2Y|vO0cxao zG(fHNjs>Wb-U5Jnumhk0oB(J969Af|w+J8vi2%)@4Iq-BTw=JIPK3$H9L7}cZpbJ?(FJc*E@hozd zrE^3{9@p5R@?2%7%5$AdD4$}A^q?xPkls}lg(zmxHAxofgK+6x%R=-<7NR$^5M9qg zRA3=`8zvmH(gy$`x)A_E^mYIU(EtF1=pq0JQ4s(_Gy(u2+5rF|+6e$5x bW0Vn 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModules$all.class b/tests/test_data/std/jdk/internal/module/SystemModules$all.class new file mode 100644 index 0000000000000000000000000000000000000000..71e765d62958a8b1567de7520f2eb78fd4fc4c03 GIT binary patch literal 80512 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 SEw{^}rgI)iZ<`$QEB*&Y9Ey_w literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModules.class b/tests/test_data/std/jdk/internal/module/SystemModules.class new file mode 100644 index 0000000000000000000000000000000000000000..921b3b576d159242098014c5a60db1b4d682dcb2 GIT binary patch literal 595 zcmaix%}xR_5XYzZvGS!XsCN$<_ToMOhKt5vBGIs(^fWBZQYc;0c1?UW4?choWgOZ~ zKtuF2?acr8pK0gw>-_@&uHiI*3WKxRWF8A;xmGCSMLsDckCQiJ`C{lUCV*WAtr@;z zEKz0g!+6G1OQ|WEWGRJx#B`1sHw<>V(KCY%74B48jM3)0G+_{W?;CDXEtXUv{Y5u= zxnDb%-954v_82sM=?QhlErI6_+%mamy^gqs=LTq|tNH%Hyo|7N))6> moduleReads(); +} diff --git a/tests/test_data/std/jdk/internal/module/SystemModulesMap.class b/tests/test_data/std/jdk/internal/module/SystemModulesMap.class new file mode 100644 index 0000000000000000000000000000000000000000..0a528fd13e176e1c6ec439ec994c2df8d92c48db GIT binary patch literal 944 zcma))U2oGc6oy~ZkC?2CE_7pz&utkr1Ddjpt08W<-QXe;QpA;M+^(IQR*5%>e+5^Q zK=1?hqoy6F=|0e=#*!7E*Ux*-vE$RT-~RyYpv~Y8qC>wQYnjAC`NL6kq@*AGNVOd9 zXF<9z#ugYu^+P}I>yHejruUVhJ`l&kS0e8DU%n4yM_Z`WP(s;86&CFarLN^+*l2ot zGt2D~HxqIxxrI3!HB+h)$*wq3`oD7C>@>O2!hIWclWJ~q1E0lErVNWs@7vzxIRl;a z;~q75a`BE9;Y%nmI=oaO2iX%XuDz+*u8# Y?zP+9u5rIK?xt~X8uuIHZsl&A19GeL761SM literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/module/SystemModulesMap.java b/tests/test_data/std/jdk/internal/module/SystemModulesMap.java new file mode 100644 index 00000000..3753737c --- /dev/null +++ b/tests/test_data/std/jdk/internal/module/SystemModulesMap.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +/** + * This class is generated/overridden at link time to return the names of the + * SystemModules classes generated at link time. + * + * @see SystemModuleFinders + * @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin + */ + +class SystemModulesMap { + + /** + * Returns the SystemModules object to reconstitute all modules or null + * if this is an exploded build. + */ + static SystemModules allSystemModules() { + return null; + } + + /** + * Returns the SystemModules object to reconstitute default modules or null + * if this is an exploded build. + */ + static SystemModules defaultSystemModules() { + return null; + } + + /** + * Returns the array of initial module names identified at link time. + */ + static String[] moduleNames() { + return new String[0]; + } + + /** + * Returns the array of SystemModules class names. The elements + * correspond to the elements in the array returned by moduleNames(). + */ + static String[] classNames() { + return new String[0]; + } +} \ No newline at end of file diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/AnnotationVisitor.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/AnnotationVisitor.class new file mode 100644 index 0000000000000000000000000000000000000000..63496d452436872169c12c1dfd227c64787d1c7a GIT binary patch literal 2177 zcmbVNU31$+6g?~3@kf;p%V`Q#DQPLK<0f?|B~Tn%(l!B?)B#cq9e6;tg;8QlMwSB% z{{V((7+(Aa!&{l54m2|bh8Z6CQNUSA*e1>t!b5gf*SqJOd-m?l?|Uta=}smAuhz=2vXn@eI#$?6TFiJjWFnTefV= zyCSfZEv_H-cww%bLITM+Qc}SYfvGKH$H+GfyPn_hsRbh0xpExi0%!jPexp@&YGylv zBoHAihqxTZ6sBYgfTH)3sb?!ZyC9YEh%brtj=w=FTo2(H`wV*L!%phts<_`%_N8hq>JR zJuFB~5nt1B+2QaWS?b85$s%y5r-fViz}Gk%u=h2VLXA{}B6Tac$@5bXfAT2*8z_Q* zj0n7f^)QD#XTex3_dOQwauL`eQv^QoY1CjtNF(HfXGFUBE(J&f((>?cP~~)fzK5p< zIZXH)KBa%3QOV~+y3>8#X=YUNNz&NBtD)`)1f|Os5wdO52sV0X0o!=Mw$Q^f`{}+Q z-Iqw?E1xbGoa)nQeL4-Vkyu)yk+?*u(l8RINy$zU5?2_KX=eUG+{5L&LOK>)R*>k| zWd4TC-wq|3=`&~g%$bmRh>tBKx values in {@link Opcodes}. + */ + protected final int api; + + /** + * The annotation visitor to which this visitor must delegate method calls. May be {@literal + * null}. + */ + protected AnnotationVisitor av; + + /** + * Constructs a new {@link AnnotationVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + */ + protected AnnotationVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link AnnotationVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + * @param annotationVisitor the annotation visitor to which this visitor must delegate method + * calls. May be {@literal null}. + */ + protected AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) { + if (api != Opcodes.ASM9 + && api != Opcodes.ASM8 + && api != Opcodes.ASM7 + && api != Opcodes.ASM6 + && api != Opcodes.ASM5 + && api != Opcodes.ASM4) { + throw new IllegalArgumentException("Unsupported api " + api); + } + this.api = api; + this.av = annotationVisitor; + } + + /** + * The annotation visitor to which this visitor must delegate method calls. May be {@literal + * null}. + * + * @return the annotation visitor to which this visitor must delegate method calls, or {@literal + * null}. + */ + public AnnotationVisitor getDelegate() { + return av; + } + + /** + * Visits a primitive value of the annotation. + * + * @param name the value name. + * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link + * Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, + * {@link String} or {@link Type} of {@link Type#OBJECT} or {@link Type#ARRAY} sort. This + * value can also be an array of byte, boolean, short, char, int, long, float or double values + * (this is equivalent to using {@link #visitArray} and visiting each array element in turn, + * but is more convenient). + */ + public void visit(final String name, final Object value) { + if (av != null) { + av.visit(name, value); + } + } + + /** + * Visits an enumeration value of the annotation. + * + * @param name the value name. + * @param descriptor the class descriptor of the enumeration class. + * @param value the actual enumeration value. + */ + public void visitEnum(final String name, final String descriptor, final String value) { + if (av != null) { + av.visitEnum(name, descriptor, value); + } + } + + /** + * Visits a nested annotation value of the annotation. + * + * @param name the value name. + * @param descriptor the class descriptor of the nested annotation class. + * @return a visitor to visit the actual nested annotation value, or {@literal null} if this + * visitor is not interested in visiting this nested annotation. The nested annotation + * value must be fully visited before calling other methods on this annotation visitor. + */ + public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { + if (av != null) { + return av.visitAnnotation(name, descriptor); + } + return null; + } + + /** + * Visits an array value of the annotation. Note that arrays of primitive values (such as byte, + * boolean, short, char, int, long, float or double) can be passed as value to {@link #visit + * visit}. This is what {@link ClassReader} does for non empty arrays of primitive values. + * + * @param name the value name. + * @return a visitor to visit the actual array value elements, or {@literal null} if this visitor + * is not interested in visiting these values. The 'name' parameters passed to the methods of + * this visitor are ignored. All the array values must be visited before calling other + * methods on this annotation visitor. + */ + public AnnotationVisitor visitArray(final String name) { + if (av != null) { + return av.visitArray(name); + } + return null; + } + + /** Visits the end of the annotation. */ + public void visitEnd() { + if (av != null) { + av.visitEnd(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/AnnotationWriter.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/AnnotationWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..738b81e907db3ddb65c953cd12964e02d7f1f65d GIT binary patch literal 9750 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 + * 4.7.16 + * @see JVMS + * 4.7.20 + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +final class AnnotationWriter extends AnnotationVisitor { + + /** Where the constants used in this AnnotationWriter must be stored. */ + private final SymbolTable symbolTable; + + /** + * Whether values are named or not. AnnotationWriter instances used for annotation default and + * annotation arrays use unnamed values (i.e. they generate an 'element_value' structure for each + * value, instead of an element_name_index followed by an element_value). + */ + private final boolean useNamedValues; + + /** + * The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values + * visited so far. All the fields of these structures, except the last one - the + * element_value_pairs array, must be set before this ByteVector is passed to the constructor + * (num_element_value_pairs can be set to 0, it is reset to the correct value in {@link + * #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit() + * methods. + * + *

    values in {@link Opcodes}. + */ + protected final int api; + + /** The field visitor to which this visitor must delegate method calls. May be {@literal null}. */ + protected FieldVisitor fv; + + /** + * Constructs a new {@link FieldVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + */ + protected FieldVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link FieldVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + * @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be + * null. + */ + protected FieldVisitor(final int api, final FieldVisitor fieldVisitor) { + if (api != Opcodes.ASM9 + && api != Opcodes.ASM8 + && api != Opcodes.ASM7 + && api != Opcodes.ASM6 + && api != Opcodes.ASM5 + && api != Opcodes.ASM4) { + throw new IllegalArgumentException("Unsupported api " + api); + } + this.api = api; + this.fv = fieldVisitor; + } + + /** + * The field visitor to which this visitor must delegate method calls. May be {@literal null}. + * + * @return the field visitor to which this visitor must delegate method calls, or {@literal null}. + */ + public FieldVisitor getDelegate() { + return fv; + } + + /** + * Visits an annotation of the field. + * + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + if (fv != null) { + return fv.visitAnnotation(descriptor, visible); + } + return null; + } + + /** + * Visits an annotation on the type of the field. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#FIELD}. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (api < Opcodes.ASM5) { + throw new UnsupportedOperationException("This feature requires ASM5"); + } + if (fv != null) { + return fv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); + } + return null; + } + + /** + * Visits a non standard attribute of the field. + * + * @param attribute an attribute. + */ + public void visitAttribute(final Attribute attribute) { + if (fv != null) { + fv.visitAttribute(attribute); + } + } + + /** + * Visits the end of the field. This method, which is the last one to be called, is used to inform + * the visitor that all the annotations and attributes of the field have been visited. + */ + public void visitEnd() { + if (fv != null) { + fv.visitEnd(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/FieldWriter.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/FieldWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..3076050db3300143585dee62442165dd6216d2a6 GIT binary patch literal 5574 zcmc&&|8o>)8UMVwBbz%mo#7K^(R+M88O`$5pz zNwi|AhGjaIqb=H`8nFsZ#>hyYW4oSVd-r(9-lfo*-h0A0Wn@c+J(?Zz%9cHv>&lD% zl{(r*f5JA#%)C8fo)&6{j<*T5iC`DY);KW>zpd7>M!qd_tx?hIvx;Ti7ToT*x4h`FNyc67jY=q%+`5B?b zvT1k>sf&c~&9kCr^K&=va}@Vn)zN!%6NiM%P8~TxvZDscynSjema_DA9e2pm&YGna z&<{YcM2fvB zydwb)bySl7zt14f4&nm>;eD(wkv`Ry2;ptThjiSJqb%{Grnk>H;gkzz+4YNEEG;XB zQPeP^!^AO#u82t4GwGQHp3`!)HgGeCjyq*fVKWccC@iY1xftr?SRaI?J)Sz2zp&!EO)_%BG!GIP#W4HAl@Ed|1OrbbJ(N*_}m%aTq%5hD?TU zBiope#Axb?G&EeD>nbRmj$B`xmJGhRE!sROGrbj6$NShPGr9L#w)x(Pv0<}ZX;54C zIz^*YFv^xRtQBJ1J8sdx$mZ4Wp(_!{{0mxEDwE!kE!NHEDkQ5NB%92zWhA(>8nW5k z6-T&e$TNy3_Zj29p&CA?keZ8F(;zCkdRG^hM)I~ zLlw1>Hb;3eTM$!c$eAb?%>hd;mZ_TD+bmJ6pyzGdEcdZ}bj8vb)nf}g#Ra@jFXXL~ zcUjI_uORJFe3J5I_9@Qd{_NA731Izr44T~=&Gh_>_)^7x5hEhg?dQ>&$y`RVn}4!b@b)89$UYZRb_A3i&v9+wVux??&&dA* zjlIl{>;){vG&=DjHgXiVIs@6ETWQ~LaVw24;|aPY=Ek6w(wwj0s}-Xz&=2vcr!{^a z%X}MFZt9_3y;pE2?dlEe3TS%*+McFqE11H@H=|0`bYe~nEX#jX zR7f@S(xgr28K&IWmII92!{=1PN_pcW)Xpn7c(hk2Sw1`X2n#VS9F!818?>68s6v@Mm=4FW8B{;!gYx1Nb{z{MT!oE>tXzVTcJLm`e=s z*R$(brg}NOzTA2Wt5*Pg7g+Afv_xRc1TaZ>1&@8J$~Ux6*__{`b^(#xcY1{q{Y_cTsbi_D`~ zO}MVJKE8nt+`tZ1hh7y!pNeBZ)$?wu;a-)%{ff5^rK6-8;ix8@QYlQT7CfXD;}O-0 z$C!SPtL1n?wc$y%5>KgiJfk}ByjqPbY7MTcwYa9%;T5$Wud0oBO{MVlhw3H$_KR*4Jua?Xo(qP_+#r2S!Wej{fGkU@GO4J OF-gi9-o1W;<^Kk^Hz?Zx literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/FieldWriter.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/FieldWriter.java new file mode 100644 index 00000000..c3e78d04 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/FieldWriter.java @@ -0,0 +1,316 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A {@link FieldVisitor} that generates a corresponding 'field_info' structure, as defined in the + * Java Virtual Machine Specification (JVMS). + * + * @see JVMS + * 4.5 + * @author Eric Bruneton + */ +final class FieldWriter extends FieldVisitor { + + /** Where the constants used in this FieldWriter must be stored. */ + private final SymbolTable symbolTable; + + // Note: fields are ordered as in the field_info structure, and those related to attributes are + // ordered as in Section 4.7 of the JVMS. + + /** + * The access_flags field of the field_info JVMS structure. This field can contain ASM specific + * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the + * ClassFile structure. + */ + private final int accessFlags; + + /** The name_index field of the field_info JVMS structure. */ + private final int nameIndex; + + /** The descriptor_index field of the field_info JVMS structure. */ + private final int descriptorIndex; + + /** + * The signature_index field of the Signature attribute of this field_info, or 0 if there is no + * Signature attribute. + */ + private int signatureIndex; + + /** + * The constantvalue_index field of the ConstantValue attribute of this field_info, or 0 if there + * is no ConstantValue attribute. + */ + private int constantValueIndex; + + /** + * The last runtime visible annotation of this field. The previous ones can be accessed with the + * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleAnnotation; + + /** + * The last runtime invisible annotation of this field. The previous ones can be accessed with the + * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleAnnotation; + + /** + * The last runtime visible type annotation of this field. The previous ones can be accessed with + * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleTypeAnnotation; + + /** + * The last runtime invisible type annotation of this field. The previous ones can be accessed + * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; + + /** + * The first non standard attribute of this field. The next ones can be accessed with the {@link + * Attribute#nextAttribute} field. May be {@literal null}. + * + *

    WARNING: this list stores the attributes in the reverse order of their visit. + * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link + * #putFieldInfo} method writes the attributes in the order defined by this list, i.e. in the + * reverse order specified by the user. + */ + private Attribute firstAttribute; + + // ----------------------------------------------------------------------------------------------- + // Constructor + // ----------------------------------------------------------------------------------------------- + + /** + * Constructs a new {@link FieldWriter}. + * + * @param symbolTable where the constants used in this FieldWriter must be stored. + * @param access the field's access flags (see {@link Opcodes}). + * @param name the field's name. + * @param descriptor the field's descriptor (see {@link Type}). + * @param signature the field's signature. May be {@literal null}. + * @param constantValue the field's constant value. May be {@literal null}. + */ + FieldWriter( + final SymbolTable symbolTable, + final int access, + final String name, + final String descriptor, + final String signature, + final Object constantValue) { + super(/* latest api = */ Opcodes.ASM9); + this.symbolTable = symbolTable; + this.accessFlags = access; + this.nameIndex = symbolTable.addConstantUtf8(name); + this.descriptorIndex = symbolTable.addConstantUtf8(descriptor); + if (signature != null) { + this.signatureIndex = symbolTable.addConstantUtf8(signature); + } + if (constantValue != null) { + this.constantValueIndex = symbolTable.addConstant(constantValue).index; + } + } + + // ----------------------------------------------------------------------------------------------- + // Implementation of the FieldVisitor abstract class + // ----------------------------------------------------------------------------------------------- + + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation); + } else { + return lastRuntimeInvisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation); + } + } + + @Override + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation); + } else { + return lastRuntimeInvisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation); + } + } + + @Override + public void visitAttribute(final Attribute attribute) { + // Store the attributes in the reverse order of their visit by this method. + attribute.nextAttribute = firstAttribute; + firstAttribute = attribute; + } + + @Override + public void visitEnd() { + // Nothing to do. + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the size of the field_info JVMS structure generated by this FieldWriter. Also adds the + * names of the attributes of this field in the constant pool. + * + * @return the size in bytes of the field_info JVMS structure. + */ + int computeFieldInfoSize() { + // The access_flags, name_index, descriptor_index and attributes_count fields use 8 bytes. + int size = 8; + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + if (constantValueIndex != 0) { + // ConstantValue attributes always use 8 bytes. + symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE); + size += 8; + } + size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex); + size += + AnnotationWriter.computeAnnotationsSize( + lastRuntimeVisibleAnnotation, + lastRuntimeInvisibleAnnotation, + lastRuntimeVisibleTypeAnnotation, + lastRuntimeInvisibleTypeAnnotation); + if (firstAttribute != null) { + size += firstAttribute.computeAttributesSize(symbolTable); + } + return size; + } + + /** + * Puts the content of the field_info JVMS structure generated by this FieldWriter into the given + * ByteVector. + * + * @param output where the field_info structure must be put. + */ + void putFieldInfo(final ByteVector output) { + boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5; + // Put the access_flags, name_index and descriptor_index fields. + int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0; + output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex); + // Compute and put the attributes_count field. + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + int attributesCount = 0; + if (constantValueIndex != 0) { + ++attributesCount; + } + if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { + ++attributesCount; + } + if (signatureIndex != 0) { + ++attributesCount; + } + if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { + ++attributesCount; + } + if (lastRuntimeVisibleAnnotation != null) { + ++attributesCount; + } + if (lastRuntimeInvisibleAnnotation != null) { + ++attributesCount; + } + if (lastRuntimeVisibleTypeAnnotation != null) { + ++attributesCount; + } + if (lastRuntimeInvisibleTypeAnnotation != null) { + ++attributesCount; + } + if (firstAttribute != null) { + attributesCount += firstAttribute.getAttributeCount(); + } + output.putShort(attributesCount); + // Put the field_info attributes. + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + if (constantValueIndex != 0) { + output + .putShort(symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE)) + .putInt(2) + .putShort(constantValueIndex); + } + Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output); + AnnotationWriter.putAnnotations( + symbolTable, + lastRuntimeVisibleAnnotation, + lastRuntimeInvisibleAnnotation, + lastRuntimeVisibleTypeAnnotation, + lastRuntimeInvisibleTypeAnnotation, + output); + if (firstAttribute != null) { + firstAttribute.putAttributes(symbolTable, output); + } + } + + /** + * Collects the attributes of this field into the given set of attribute prototypes. + * + * @param attributePrototypes a set of attribute prototypes. + */ + final void collectAttributePrototypes(final Attribute.Set attributePrototypes) { + attributePrototypes.addAttributes(firstAttribute); + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Frame.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Frame.class new file mode 100644 index 0000000000000000000000000000000000000000..2ad1f5ac12858f53f417bfdbb179ce3fb087008f GIT binary patch literal 19293 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 map frames are computed in two steps: + * + *

      + *
    • During the visit of each instruction in MethodWriter, the state of the frame at the end of + * the current basic block is updated by simulating the action of the instruction on the + * previous state of this so called "output frame". + *
    • After all instructions have been visited, a fix point algorithm is used in MethodWriter to + * compute the "input frame" of each basic block (i.e. the stack map frame at the beginning of + * the basic block). See {@link MethodWriter#computeAllFrames}. + *
    + * + *

    Output stack map frames are computed relatively to the input frame of the basic block, which + * is not yet known when output frames are computed. It is therefore necessary to be able to + * represent abstract types such as "the type at position x in the input frame locals" or "the type + * at position x from the top of the input frame stack" or even "the type at position x in the input + * frame, with y more (or less) array dimensions". This explains the rather complicated type format + * used in this class, explained below. + * + *

    The local variables and the operand stack of input and output frames contain values called + * "abstract types" hereafter. An abstract type is represented with 4 fields named DIM, KIND, FLAGS + * and VALUE, packed in a single int value for better performance and memory efficiency: + * + *

    + *   =====================================
    + *   |...DIM|KIND|.F|...............VALUE|
    + *   =====================================
    + * 
    + * + *
      + *
    • the DIM field, stored in the 6 most significant bits, is a signed number of array + * dimensions (from -32 to 31, included). It can be retrieved with {@link #DIM_MASK} and a + * right shift of {@link #DIM_SHIFT}. + *
    • the KIND field, stored in 4 bits, indicates the kind of VALUE used. These 4 bits can be + * retrieved with {@link #KIND_MASK} and, without any shift, must be equal to {@link + * #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link + * #FORWARD_UNINITIALIZED_KIND},{@link #LOCAL_KIND} or {@link #STACK_KIND}. + *
    • the FLAGS field, stored in 2 bits, contains up to 2 boolean flags. Currently only one flag + * is defined, namely {@link #TOP_IF_LONG_OR_DOUBLE_FLAG}. + *
    • the VALUE field, stored in the remaining 20 bits, contains either + *
        + *
      • one of the constants {@link #ITEM_TOP}, {@link #ITEM_ASM_BOOLEAN}, {@link + * #ITEM_ASM_BYTE}, {@link #ITEM_ASM_CHAR} or {@link #ITEM_ASM_SHORT}, {@link + * #ITEM_INTEGER}, {@link #ITEM_FLOAT}, {@link #ITEM_LONG}, {@link #ITEM_DOUBLE}, {@link + * #ITEM_NULL} or {@link #ITEM_UNINITIALIZED_THIS}, if KIND is equal to {@link + * #CONSTANT_KIND}. + *
      • the index of a {@link Symbol#TYPE_TAG} {@link Symbol} in the type table of a {@link + * SymbolTable}, if KIND is equal to {@link #REFERENCE_KIND}. + *
      • the index of an {@link Symbol#UNINITIALIZED_TYPE_TAG} {@link Symbol} in the type + * table of a {@link SymbolTable}, if KIND is equal to {@link #UNINITIALIZED_KIND}. + *
      • the index of a {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG} {@link Symbol} in the + * type table of a {@link SymbolTable}, if KIND is equal to {@link + * #FORWARD_UNINITIALIZED_KIND}. + *
      • the index of a local variable in the input stack frame, if KIND is equal to {@link + * #LOCAL_KIND}. + *
      • a position relatively to the top of the stack of the input stack frame, if KIND is + * equal to {@link #STACK_KIND}, + *
      + *
    + * + *

    Output frames can contain abstract types of any kind and with a positive or negative array + * dimension (and even unassigned types, represented by 0 - which does not correspond to any valid + * abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND, + * UNINITIALIZED_KIND or FORWARD_UNINITIALIZED_KIND abstract types of positive or {@literal null} + * array dimension. In all cases the type table contains only internal type names (array type + * descriptors are forbidden - array dimensions must be represented through the DIM field). + * + *

    The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE + + * TOP), for local variables as well as in the operand stack. This is necessary to be able to + * simulate DUPx_y instructions, whose effect would be dependent on the concrete types represented + * by the abstract types in the stack (which are not always known). + * + * @author Eric Bruneton + */ +class Frame { + + // Constants used in the StackMapTable attribute. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.4. + + static final int SAME_FRAME = 0; + static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; + static final int RESERVED = 128; + static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; + static final int CHOP_FRAME = 248; + static final int SAME_FRAME_EXTENDED = 251; + static final int APPEND_FRAME = 252; + static final int FULL_FRAME = 255; + + static final int ITEM_TOP = 0; + static final int ITEM_INTEGER = 1; + static final int ITEM_FLOAT = 2; + static final int ITEM_DOUBLE = 3; + static final int ITEM_LONG = 4; + static final int ITEM_NULL = 5; + static final int ITEM_UNINITIALIZED_THIS = 6; + static final int ITEM_OBJECT = 7; + static final int ITEM_UNINITIALIZED = 8; + // Additional, ASM specific constants used in abstract types below. + private static final int ITEM_ASM_BOOLEAN = 9; + private static final int ITEM_ASM_BYTE = 10; + private static final int ITEM_ASM_CHAR = 11; + private static final int ITEM_ASM_SHORT = 12; + + // The size and offset in bits of each field of an abstract type. + + private static final int DIM_SIZE = 6; + private static final int KIND_SIZE = 4; + private static final int FLAGS_SIZE = 2; + private static final int VALUE_SIZE = 32 - DIM_SIZE - KIND_SIZE - FLAGS_SIZE; + + private static final int DIM_SHIFT = KIND_SIZE + FLAGS_SIZE + VALUE_SIZE; + private static final int KIND_SHIFT = FLAGS_SIZE + VALUE_SIZE; + private static final int FLAGS_SHIFT = VALUE_SIZE; + + // Bitmasks to get each field of an abstract type. + + private static final int DIM_MASK = ((1 << DIM_SIZE) - 1) << DIM_SHIFT; + private static final int KIND_MASK = ((1 << KIND_SIZE) - 1) << KIND_SHIFT; + private static final int VALUE_MASK = (1 << VALUE_SIZE) - 1; + + // Constants to manipulate the DIM field of an abstract type. + + /** The constant to be added to an abstract type to get one with one more array dimension. */ + private static final int ARRAY_OF = +1 << DIM_SHIFT; + + /** The constant to be added to an abstract type to get one with one less array dimension. */ + private static final int ELEMENT_OF = -1 << DIM_SHIFT; + + // Possible values for the KIND field of an abstract type. + + private static final int CONSTANT_KIND = 1 << KIND_SHIFT; + private static final int REFERENCE_KIND = 2 << KIND_SHIFT; + private static final int UNINITIALIZED_KIND = 3 << KIND_SHIFT; + private static final int FORWARD_UNINITIALIZED_KIND = 4 << KIND_SHIFT; + private static final int LOCAL_KIND = 5 << KIND_SHIFT; + private static final int STACK_KIND = 6 << KIND_SHIFT; + + // Possible flags for the FLAGS field of an abstract type. + + /** + * A flag used for LOCAL_KIND and STACK_KIND abstract types, indicating that if the resolved, + * concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been + * partially overridden with an xSTORE instruction). + */ + private static final int TOP_IF_LONG_OR_DOUBLE_FLAG = 1 << FLAGS_SHIFT; + + // Useful predefined abstract types (all the possible CONSTANT_KIND types). + + private static final int TOP = CONSTANT_KIND | ITEM_TOP; + private static final int BOOLEAN = CONSTANT_KIND | ITEM_ASM_BOOLEAN; + private static final int BYTE = CONSTANT_KIND | ITEM_ASM_BYTE; + private static final int CHAR = CONSTANT_KIND | ITEM_ASM_CHAR; + private static final int SHORT = CONSTANT_KIND | ITEM_ASM_SHORT; + private static final int INTEGER = CONSTANT_KIND | ITEM_INTEGER; + private static final int FLOAT = CONSTANT_KIND | ITEM_FLOAT; + private static final int LONG = CONSTANT_KIND | ITEM_LONG; + private static final int DOUBLE = CONSTANT_KIND | ITEM_DOUBLE; + private static final int NULL = CONSTANT_KIND | ITEM_NULL; + private static final int UNINITIALIZED_THIS = CONSTANT_KIND | ITEM_UNINITIALIZED_THIS; + + // ----------------------------------------------------------------------------------------------- + // Instance fields + // ----------------------------------------------------------------------------------------------- + + /** The basic block to which these input and output stack map frames correspond. */ + Label owner; + + /** The input stack map frame locals. This is an array of abstract types. */ + private int[] inputLocals; + + /** The input stack map frame stack. This is an array of abstract types. */ + private int[] inputStack; + + /** The output stack map frame locals. This is an array of abstract types. */ + private int[] outputLocals; + + /** The output stack map frame stack. This is an array of abstract types. */ + private int[] outputStack; + + /** + * The start of the output stack, relatively to the input stack. This offset is always negative or + * null. A null offset means that the output stack must be appended to the input stack. A -n + * offset means that the first n output stack elements must replace the top n input stack + * elements, and that the other elements must be appended to the input stack. + */ + private short outputStackStart; + + /** The index of the top stack element in {@link #outputStack}. */ + private short outputStackTop; + + /** The number of types that are initialized in the basic block. See {@link #initializations}. */ + private int initializationCount; + + /** + * The abstract types that are initialized in the basic block. A constructor invocation on an + * UNINITIALIZED, FORWARD_UNINITIALIZED or UNINITIALIZED_THIS abstract type must replace every + * occurrence of this type in the local variables and in the operand stack. This cannot be + * done during the first step of the algorithm since, during this step, the local variables and + * the operand stack types are still abstract. It is therefore necessary to store the abstract + * types of the constructors which are invoked in the basic block, in order to do this replacement + * during the second step of the algorithm, where the frames are fully computed. Note that this + * array can contain abstract types that are relative to the input locals or to the input stack. + */ + private int[] initializations; + + // ----------------------------------------------------------------------------------------------- + // Constructor + // ----------------------------------------------------------------------------------------------- + + /** + * Constructs a new Frame. + * + * @param owner the basic block to which these input and output stack map frames correspond. + */ + Frame(final Label owner) { + this.owner = owner; + } + + /** + * Sets this frame to the value of the given frame. + * + *

    WARNING: after this method is called the two frames share the same data structures. It is + * recommended to discard the given frame to avoid unexpected side effects. + * + * @param frame The new frame value. + */ + final void copyFrom(final Frame frame) { + inputLocals = frame.inputLocals; + inputStack = frame.inputStack; + outputStackStart = 0; + outputLocals = frame.outputLocals; + outputStack = frame.outputStack; + outputStackTop = frame.outputStackTop; + initializationCount = frame.initializationCount; + initializations = frame.initializations; + } + + // ----------------------------------------------------------------------------------------------- + // Static methods to get abstract types from other type formats + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the abstract type corresponding to the given public API frame element type. + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param type a frame element type described using the same format as in {@link + * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link + * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or + * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating + * a NEW instruction (for uninitialized types). + * @return the abstract type corresponding to the given frame element type. + */ + static int getAbstractTypeFromApiFormat(final SymbolTable symbolTable, final Object type) { + if (type instanceof Integer) { + return CONSTANT_KIND | ((Integer) type).intValue(); + } else if (type instanceof String) { + String descriptor = Type.getObjectType((String) type).getDescriptor(); + return getAbstractTypeFromDescriptor(symbolTable, descriptor, 0); + } else { + Label label = (Label) type; + if ((label.flags & Label.FLAG_RESOLVED) != 0) { + return UNINITIALIZED_KIND | symbolTable.addUninitializedType("", label.bytecodeOffset); + } else { + return FORWARD_UNINITIALIZED_KIND | symbolTable.addForwardUninitializedType("", label); + } + } + } + + /** + * Returns the abstract type corresponding to the internal name of a class. + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param internalName the internal name of a class. This must not be an array type + * descriptor. + * @return the abstract type value corresponding to the given internal name. + */ + static int getAbstractTypeFromInternalName( + final SymbolTable symbolTable, final String internalName) { + return REFERENCE_KIND | symbolTable.addType(internalName); + } + + /** + * Returns the abstract type corresponding to the given type descriptor. + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param buffer a string ending with a type descriptor. + * @param offset the start offset of the type descriptor in buffer. + * @return the abstract type corresponding to the given type descriptor. + */ + private static int getAbstractTypeFromDescriptor( + final SymbolTable symbolTable, final String buffer, final int offset) { + String internalName; + switch (buffer.charAt(offset)) { + case 'V': + return 0; + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + return INTEGER; + case 'F': + return FLOAT; + case 'J': + return LONG; + case 'D': + return DOUBLE; + case 'L': + internalName = buffer.substring(offset + 1, buffer.length() - 1); + return REFERENCE_KIND | symbolTable.addType(internalName); + case '[': + int elementDescriptorOffset = offset + 1; + while (buffer.charAt(elementDescriptorOffset) == '[') { + ++elementDescriptorOffset; + } + int typeValue; + switch (buffer.charAt(elementDescriptorOffset)) { + case 'Z': + typeValue = BOOLEAN; + break; + case 'C': + typeValue = CHAR; + break; + case 'B': + typeValue = BYTE; + break; + case 'S': + typeValue = SHORT; + break; + case 'I': + typeValue = INTEGER; + break; + case 'F': + typeValue = FLOAT; + break; + case 'J': + typeValue = LONG; + break; + case 'D': + typeValue = DOUBLE; + break; + case 'L': + internalName = buffer.substring(elementDescriptorOffset + 1, buffer.length() - 1); + typeValue = REFERENCE_KIND | symbolTable.addType(internalName); + break; + default: + throw new IllegalArgumentException( + "Invalid descriptor fragment: " + buffer.substring(elementDescriptorOffset)); + } + return ((elementDescriptorOffset - offset) << DIM_SHIFT) | typeValue; + default: + throw new IllegalArgumentException("Invalid descriptor: " + buffer.substring(offset)); + } + } + + // ----------------------------------------------------------------------------------------------- + // Methods related to the input frame + // ----------------------------------------------------------------------------------------------- + + /** + * Sets the input frame from the given method description. This method is used to initialize the + * first frame of a method, which is implicit (i.e. not stored explicitly in the StackMapTable + * attribute). + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param access the method's access flags. + * @param descriptor the method descriptor. + * @param maxLocals the maximum number of local variables of the method. + */ + final void setInputFrameFromDescriptor( + final SymbolTable symbolTable, + final int access, + final String descriptor, + final int maxLocals) { + inputLocals = new int[maxLocals]; + inputStack = new int[0]; + int inputLocalIndex = 0; + if ((access & Opcodes.ACC_STATIC) == 0) { + if ((access & Constants.ACC_CONSTRUCTOR) == 0) { + inputLocals[inputLocalIndex++] = + REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName()); + } else { + inputLocals[inputLocalIndex++] = UNINITIALIZED_THIS; + } + } + for (Type argumentType : Type.getArgumentTypes(descriptor)) { + int abstractType = + getAbstractTypeFromDescriptor(symbolTable, argumentType.getDescriptor(), 0); + inputLocals[inputLocalIndex++] = abstractType; + if (abstractType == LONG || abstractType == DOUBLE) { + inputLocals[inputLocalIndex++] = TOP; + } + } + while (inputLocalIndex < maxLocals) { + inputLocals[inputLocalIndex++] = TOP; + } + } + + /** + * Sets the input frame from the given public API frame description. + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param numLocal the number of local variables. + * @param local the local variable types, described using the same format as in {@link + * MethodVisitor#visitFrame}. + * @param numStack the number of operand stack elements. + * @param stack the operand stack types, described using the same format as in {@link + * MethodVisitor#visitFrame}. + */ + final void setInputFrameFromApiFormat( + final SymbolTable symbolTable, + final int numLocal, + final Object[] local, + final int numStack, + final Object[] stack) { + int inputLocalIndex = 0; + for (int i = 0; i < numLocal; ++i) { + inputLocals[inputLocalIndex++] = getAbstractTypeFromApiFormat(symbolTable, local[i]); + if (local[i] == Opcodes.LONG || local[i] == Opcodes.DOUBLE) { + inputLocals[inputLocalIndex++] = TOP; + } + } + while (inputLocalIndex < inputLocals.length) { + inputLocals[inputLocalIndex++] = TOP; + } + int numStackTop = 0; + for (int i = 0; i < numStack; ++i) { + if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { + ++numStackTop; + } + } + inputStack = new int[numStack + numStackTop]; + int inputStackIndex = 0; + for (int i = 0; i < numStack; ++i) { + inputStack[inputStackIndex++] = getAbstractTypeFromApiFormat(symbolTable, stack[i]); + if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { + inputStack[inputStackIndex++] = TOP; + } + } + outputStackTop = 0; + initializationCount = 0; + } + + final int getInputStackSize() { + return inputStack.length; + } + + // ----------------------------------------------------------------------------------------------- + // Methods related to the output frame + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the abstract type stored at the given local variable index in the output frame. + * + * @param localIndex the index of the local variable whose value must be returned. + * @return the abstract type stored at the given local variable index in the output frame. + */ + private int getLocal(final int localIndex) { + if (outputLocals == null || localIndex >= outputLocals.length) { + // If this local has never been assigned in this basic block, it is still equal to its value + // in the input frame. + return LOCAL_KIND | localIndex; + } else { + int abstractType = outputLocals[localIndex]; + if (abstractType == 0) { + // If this local has never been assigned in this basic block, so it is still equal to its + // value in the input frame. + abstractType = outputLocals[localIndex] = LOCAL_KIND | localIndex; + } + return abstractType; + } + } + + /** + * Replaces the abstract type stored at the given local variable index in the output frame. + * + * @param localIndex the index of the output frame local variable that must be set. + * @param abstractType the value that must be set. + */ + private void setLocal(final int localIndex, final int abstractType) { + // Create and/or resize the output local variables array if necessary. + if (outputLocals == null) { + outputLocals = new int[10]; + } + int outputLocalsLength = outputLocals.length; + if (localIndex >= outputLocalsLength) { + int[] newOutputLocals = new int[Math.max(localIndex + 1, 2 * outputLocalsLength)]; + System.arraycopy(outputLocals, 0, newOutputLocals, 0, outputLocalsLength); + outputLocals = newOutputLocals; + } + // Set the local variable. + outputLocals[localIndex] = abstractType; + } + + /** + * Pushes the given abstract type on the output frame stack. + * + * @param abstractType an abstract type. + */ + private void push(final int abstractType) { + // Create and/or resize the output stack array if necessary. + if (outputStack == null) { + outputStack = new int[10]; + } + int outputStackLength = outputStack.length; + if (outputStackTop >= outputStackLength) { + int[] newOutputStack = new int[Math.max(outputStackTop + 1, 2 * outputStackLength)]; + System.arraycopy(outputStack, 0, newOutputStack, 0, outputStackLength); + outputStack = newOutputStack; + } + // Pushes the abstract type on the output stack. + outputStack[outputStackTop++] = abstractType; + // Updates the maximum size reached by the output stack, if needed (note that this size is + // relative to the input stack size, which is not known yet). + short outputStackSize = (short) (outputStackStart + outputStackTop); + if (outputStackSize > owner.outputStackMax) { + owner.outputStackMax = outputStackSize; + } + } + + /** + * Pushes the abstract type corresponding to the given descriptor on the output frame stack. + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param descriptor a type or method descriptor (in which case its return type is pushed). + */ + private void push(final SymbolTable symbolTable, final String descriptor) { + int typeDescriptorOffset = + descriptor.charAt(0) == '(' ? Type.getReturnTypeOffset(descriptor) : 0; + int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset); + if (abstractType != 0) { + push(abstractType); + if (abstractType == LONG || abstractType == DOUBLE) { + push(TOP); + } + } + } + + /** + * Pops an abstract type from the output frame stack and returns its value. + * + * @return the abstract type that has been popped from the output frame stack. + */ + private int pop() { + if (outputStackTop > 0) { + return outputStack[--outputStackTop]; + } else { + // If the output frame stack is empty, pop from the input stack. + return STACK_KIND | -(--outputStackStart); + } + } + + /** + * Pops the given number of abstract types from the output frame stack. + * + * @param elements the number of abstract types that must be popped. + */ + private void pop(final int elements) { + if (outputStackTop >= elements) { + outputStackTop -= (short)elements; + } else { + // If the number of elements to be popped is greater than the number of elements in the output + // stack, clear it, and pop the remaining elements from the input stack. + outputStackStart -= (short) (elements - outputStackTop); + outputStackTop = 0; + } + } + + /** + * Pops as many abstract types from the output frame stack as described by the given descriptor. + * + * @param descriptor a type or method descriptor (in which case its argument types are popped). + */ + private void pop(final String descriptor) { + char firstDescriptorChar = descriptor.charAt(0); + if (firstDescriptorChar == '(') { + pop((Type.getArgumentsAndReturnSizes(descriptor) >> 2) - 1); + } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') { + pop(2); + } else { + pop(1); + } + } + + // ----------------------------------------------------------------------------------------------- + // Methods to handle uninitialized types + // ----------------------------------------------------------------------------------------------- + + /** + * Adds an abstract type to the list of types on which a constructor is invoked in the basic + * block. + * + * @param abstractType an abstract type on a which a constructor is invoked. + */ + private void addInitializedType(final int abstractType) { + // Create and/or resize the initializations array if necessary. + if (initializations == null) { + initializations = new int[2]; + } + int initializationsLength = initializations.length; + if (initializationCount >= initializationsLength) { + int[] newInitializations = + new int[Math.max(initializationCount + 1, 2 * initializationsLength)]; + System.arraycopy(initializations, 0, newInitializations, 0, initializationsLength); + initializations = newInitializations; + } + // Store the abstract type. + initializations[initializationCount++] = abstractType; + } + + /** + * Returns the "initialized" abstract type corresponding to the given abstract type. + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param abstractType an abstract type. + * @return the REFERENCE_KIND abstract type corresponding to abstractType if it is + * UNINITIALIZED_THIS or an UNINITIALIZED_KIND or FORWARD_UNINITIALIZED_KIND abstract type for + * one of the types on which a constructor is invoked in the basic block. Otherwise returns + * abstractType. + */ + private int getInitializedType(final SymbolTable symbolTable, final int abstractType) { + if (abstractType == UNINITIALIZED_THIS + || (abstractType & (DIM_MASK | KIND_MASK)) == UNINITIALIZED_KIND + || (abstractType & (DIM_MASK | KIND_MASK)) == FORWARD_UNINITIALIZED_KIND) { + for (int i = 0; i < initializationCount; ++i) { + int initializedType = initializations[i]; + int dim = initializedType & DIM_MASK; + int kind = initializedType & KIND_MASK; + int value = initializedType & VALUE_MASK; + if (kind == LOCAL_KIND) { + initializedType = dim + inputLocals[value]; + } else if (kind == STACK_KIND) { + initializedType = dim + inputStack[inputStack.length - value]; + } + if (abstractType == initializedType) { + if (abstractType == UNINITIALIZED_THIS) { + return REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName()); + } else { + return REFERENCE_KIND + | symbolTable.addType(symbolTable.getType(abstractType & VALUE_MASK).value); + } + } + } + } + return abstractType; + } + + // ----------------------------------------------------------------------------------------------- + // Main method, to simulate the execution of each instruction on the output frame + // ----------------------------------------------------------------------------------------------- + + /** + * Simulates the action of the given instruction on the output stack frame. + * + * @param opcode the opcode of the instruction. + * @param arg the numeric operand of the instruction, if any. + * @param argSymbol the Symbol operand of the instruction, if any. + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + */ + void execute( + final int opcode, final int arg, final Symbol argSymbol, final SymbolTable symbolTable) { + // Abstract types popped from the stack or read from local variables. + int abstractType1; + int abstractType2; + int abstractType3; + int abstractType4; + switch (opcode) { + case Opcodes.NOP: + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + case Opcodes.GOTO: + case Opcodes.RETURN: + break; + case Opcodes.ACONST_NULL: + push(NULL); + break; + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.BIPUSH: + case Opcodes.SIPUSH: + case Opcodes.ILOAD: + push(INTEGER); + break; + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.LLOAD: + push(LONG); + push(TOP); + break; + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.FLOAD: + push(FLOAT); + break; + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.DLOAD: + push(DOUBLE); + push(TOP); + break; + case Opcodes.LDC: + switch (argSymbol.tag) { + case Symbol.CONSTANT_INTEGER_TAG: + push(INTEGER); + break; + case Symbol.CONSTANT_LONG_TAG: + push(LONG); + push(TOP); + break; + case Symbol.CONSTANT_FLOAT_TAG: + push(FLOAT); + break; + case Symbol.CONSTANT_DOUBLE_TAG: + push(DOUBLE); + push(TOP); + break; + case Symbol.CONSTANT_CLASS_TAG: + push(REFERENCE_KIND | symbolTable.addType("java/lang/Class")); + break; + case Symbol.CONSTANT_STRING_TAG: + push(REFERENCE_KIND | symbolTable.addType("java/lang/String")); + break; + case Symbol.CONSTANT_METHOD_TYPE_TAG: + push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodType")); + break; + case Symbol.CONSTANT_METHOD_HANDLE_TAG: + push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodHandle")); + break; + case Symbol.CONSTANT_DYNAMIC_TAG: + push(symbolTable, argSymbol.value); + break; + default: + throw new AssertionError(); + } + break; + case Opcodes.ALOAD: + push(getLocal(arg)); + break; + case Opcodes.LALOAD: + case Opcodes.D2L: + pop(2); + push(LONG); + push(TOP); + break; + case Opcodes.DALOAD: + case Opcodes.L2D: + pop(2); + push(DOUBLE); + push(TOP); + break; + case Opcodes.AALOAD: + pop(1); + abstractType1 = pop(); + push(abstractType1 == NULL ? abstractType1 : ELEMENT_OF + abstractType1); + break; + case Opcodes.ISTORE: + case Opcodes.FSTORE: + case Opcodes.ASTORE: + abstractType1 = pop(); + setLocal(arg, abstractType1); + if (arg > 0) { + int previousLocalType = getLocal(arg - 1); + if (previousLocalType == LONG || previousLocalType == DOUBLE) { + setLocal(arg - 1, TOP); + } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND + || (previousLocalType & KIND_MASK) == STACK_KIND) { + // The type of the previous local variable is not known yet, but if it later appears + // to be LONG or DOUBLE, we should then use TOP instead. + setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG); + } + } + break; + case Opcodes.LSTORE: + case Opcodes.DSTORE: + pop(1); + abstractType1 = pop(); + setLocal(arg, abstractType1); + setLocal(arg + 1, TOP); + if (arg > 0) { + int previousLocalType = getLocal(arg - 1); + if (previousLocalType == LONG || previousLocalType == DOUBLE) { + setLocal(arg - 1, TOP); + } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND + || (previousLocalType & KIND_MASK) == STACK_KIND) { + // The type of the previous local variable is not known yet, but if it later appears + // to be LONG or DOUBLE, we should then use TOP instead. + setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG); + } + } + break; + case Opcodes.IASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.FASTORE: + case Opcodes.AASTORE: + pop(3); + break; + case Opcodes.LASTORE: + case Opcodes.DASTORE: + pop(4); + break; + case Opcodes.POP: + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + case Opcodes.IRETURN: + case Opcodes.FRETURN: + case Opcodes.ARETURN: + case Opcodes.TABLESWITCH: + case Opcodes.LOOKUPSWITCH: + case Opcodes.ATHROW: + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + pop(1); + break; + case Opcodes.POP2: + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + case Opcodes.LRETURN: + case Opcodes.DRETURN: + pop(2); + break; + case Opcodes.DUP: + abstractType1 = pop(); + push(abstractType1); + push(abstractType1); + break; + case Opcodes.DUP_X1: + abstractType1 = pop(); + abstractType2 = pop(); + push(abstractType1); + push(abstractType2); + push(abstractType1); + break; + case Opcodes.DUP_X2: + abstractType1 = pop(); + abstractType2 = pop(); + abstractType3 = pop(); + push(abstractType1); + push(abstractType3); + push(abstractType2); + push(abstractType1); + break; + case Opcodes.DUP2: + abstractType1 = pop(); + abstractType2 = pop(); + push(abstractType2); + push(abstractType1); + push(abstractType2); + push(abstractType1); + break; + case Opcodes.DUP2_X1: + abstractType1 = pop(); + abstractType2 = pop(); + abstractType3 = pop(); + push(abstractType2); + push(abstractType1); + push(abstractType3); + push(abstractType2); + push(abstractType1); + break; + case Opcodes.DUP2_X2: + abstractType1 = pop(); + abstractType2 = pop(); + abstractType3 = pop(); + abstractType4 = pop(); + push(abstractType2); + push(abstractType1); + push(abstractType4); + push(abstractType3); + push(abstractType2); + push(abstractType1); + break; + case Opcodes.SWAP: + abstractType1 = pop(); + abstractType2 = pop(); + push(abstractType1); + push(abstractType2); + break; + case Opcodes.IALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + case Opcodes.IADD: + case Opcodes.ISUB: + case Opcodes.IMUL: + case Opcodes.IDIV: + case Opcodes.IREM: + case Opcodes.IAND: + case Opcodes.IOR: + case Opcodes.IXOR: + case Opcodes.ISHL: + case Opcodes.ISHR: + case Opcodes.IUSHR: + case Opcodes.L2I: + case Opcodes.D2I: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + pop(2); + push(INTEGER); + break; + case Opcodes.LADD: + case Opcodes.LSUB: + case Opcodes.LMUL: + case Opcodes.LDIV: + case Opcodes.LREM: + case Opcodes.LAND: + case Opcodes.LOR: + case Opcodes.LXOR: + pop(4); + push(LONG); + push(TOP); + break; + case Opcodes.FALOAD: + case Opcodes.FADD: + case Opcodes.FSUB: + case Opcodes.FMUL: + case Opcodes.FDIV: + case Opcodes.FREM: + case Opcodes.L2F: + case Opcodes.D2F: + pop(2); + push(FLOAT); + break; + case Opcodes.DADD: + case Opcodes.DSUB: + case Opcodes.DMUL: + case Opcodes.DDIV: + case Opcodes.DREM: + pop(4); + push(DOUBLE); + push(TOP); + break; + case Opcodes.LSHL: + case Opcodes.LSHR: + case Opcodes.LUSHR: + pop(3); + push(LONG); + push(TOP); + break; + case Opcodes.IINC: + setLocal(arg, INTEGER); + break; + case Opcodes.I2L: + case Opcodes.F2L: + pop(1); + push(LONG); + push(TOP); + break; + case Opcodes.I2F: + pop(1); + push(FLOAT); + break; + case Opcodes.I2D: + case Opcodes.F2D: + pop(1); + push(DOUBLE); + push(TOP); + break; + case Opcodes.F2I: + case Opcodes.ARRAYLENGTH: + case Opcodes.INSTANCEOF: + pop(1); + push(INTEGER); + break; + case Opcodes.LCMP: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + pop(4); + push(INTEGER); + break; + case Opcodes.JSR: + case Opcodes.RET: + throw new IllegalArgumentException("JSR/RET are not supported with computeFrames option"); + case Opcodes.GETSTATIC: + push(symbolTable, argSymbol.value); + break; + case Opcodes.PUTSTATIC: + pop(argSymbol.value); + break; + case Opcodes.GETFIELD: + pop(1); + push(symbolTable, argSymbol.value); + break; + case Opcodes.PUTFIELD: + pop(argSymbol.value); + pop(); + break; + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.INVOKEINTERFACE: + pop(argSymbol.value); + if (opcode != Opcodes.INVOKESTATIC) { + abstractType1 = pop(); + if (opcode == Opcodes.INVOKESPECIAL && argSymbol.name.charAt(0) == '<') { + addInitializedType(abstractType1); + } + } + push(symbolTable, argSymbol.value); + break; + case Opcodes.INVOKEDYNAMIC: + pop(argSymbol.value); + push(symbolTable, argSymbol.value); + break; + case Opcodes.NEW: + push(UNINITIALIZED_KIND | symbolTable.addUninitializedType(argSymbol.value, arg)); + break; + case Opcodes.NEWARRAY: + pop(); + switch (arg) { + case Opcodes.T_BOOLEAN: + push(ARRAY_OF | BOOLEAN); + break; + case Opcodes.T_CHAR: + push(ARRAY_OF | CHAR); + break; + case Opcodes.T_BYTE: + push(ARRAY_OF | BYTE); + break; + case Opcodes.T_SHORT: + push(ARRAY_OF | SHORT); + break; + case Opcodes.T_INT: + push(ARRAY_OF | INTEGER); + break; + case Opcodes.T_FLOAT: + push(ARRAY_OF | FLOAT); + break; + case Opcodes.T_DOUBLE: + push(ARRAY_OF | DOUBLE); + break; + case Opcodes.T_LONG: + push(ARRAY_OF | LONG); + break; + default: + throw new IllegalArgumentException(); + } + break; + case Opcodes.ANEWARRAY: + String arrayElementType = argSymbol.value; + pop(); + if (arrayElementType.charAt(0) == '[') { + push(symbolTable, '[' + arrayElementType); + } else { + push(ARRAY_OF | REFERENCE_KIND | symbolTable.addType(arrayElementType)); + } + break; + case Opcodes.CHECKCAST: + String castType = argSymbol.value; + pop(); + if (castType.charAt(0) == '[') { + push(symbolTable, castType); + } else { + push(REFERENCE_KIND | symbolTable.addType(castType)); + } + break; + case Opcodes.MULTIANEWARRAY: + pop(arg); + push(symbolTable, argSymbol.value); + break; + default: + throw new IllegalArgumentException(); + } + } + + // ----------------------------------------------------------------------------------------------- + // Frame merging methods, used in the second step of the stack map frame computation algorithm + // ----------------------------------------------------------------------------------------------- + + /** + * Computes the concrete output type corresponding to a given abstract output type. + * + * @param abstractOutputType an abstract output type. + * @param numStack the size of the input stack, used to resolve abstract output types of + * STACK_KIND kind. + * @return the concrete output type corresponding to 'abstractOutputType'. + */ + private int getConcreteOutputType(final int abstractOutputType, final int numStack) { + int dim = abstractOutputType & DIM_MASK; + int kind = abstractOutputType & KIND_MASK; + if (kind == LOCAL_KIND) { + // By definition, a LOCAL_KIND type designates the concrete type of a local variable at + // the beginning of the basic block corresponding to this frame (which is known when + // this method is called, but was not when the abstract type was computed). + int concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK]; + if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 + && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { + concreteOutputType = TOP; + } + return concreteOutputType; + } else if (kind == STACK_KIND) { + // By definition, a STACK_KIND type designates the concrete type of a local variable at + // the beginning of the basic block corresponding to this frame (which is known when + // this method is called, but was not when the abstract type was computed). + int concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)]; + if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 + && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { + concreteOutputType = TOP; + } + return concreteOutputType; + } else { + return abstractOutputType; + } + } + + /** + * Merges the input frame of the given {@link Frame} with the input and output frames of this + * {@link Frame}. Returns {@literal true} if the given frame has been changed by this operation + * (the input and output frames of this {@link Frame} are never changed). + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param dstFrame the {@link Frame} whose input frame must be updated. This should be the frame + * of a successor, in the control flow graph, of the basic block corresponding to this frame. + * @param catchTypeIndex if 'frame' corresponds to an exception handler basic block, the type + * table index of the caught exception type, otherwise 0. + * @return {@literal true} if the input frame of 'frame' has been changed by this operation. + */ + final boolean merge( + final SymbolTable symbolTable, final Frame dstFrame, final int catchTypeIndex) { + boolean frameChanged = false; + + // Compute the concrete types of the local variables at the end of the basic block corresponding + // to this frame, by resolving its abstract output types, and merge these concrete types with + // those of the local variables in the input frame of dstFrame. + int numLocal = inputLocals.length; + int numStack = inputStack.length; + if (dstFrame.inputLocals == null) { + dstFrame.inputLocals = new int[numLocal]; + frameChanged = true; + } + for (int i = 0; i < numLocal; ++i) { + int concreteOutputType; + if (outputLocals != null && i < outputLocals.length) { + int abstractOutputType = outputLocals[i]; + if (abstractOutputType == 0) { + // If the local variable has never been assigned in this basic block, it is equal to its + // value at the beginning of the block. + concreteOutputType = inputLocals[i]; + } else { + concreteOutputType = getConcreteOutputType(abstractOutputType, numStack); + } + } else { + // If the local variable has never been assigned in this basic block, it is equal to its + // value at the beginning of the block. + concreteOutputType = inputLocals[i]; + } + // concreteOutputType might be an uninitialized type from the input locals or from the input + // stack. However, if a constructor has been called for this class type in the basic block, + // then this type is no longer uninitialized at the end of basic block. + if (initializations != null) { + concreteOutputType = getInitializedType(symbolTable, concreteOutputType); + } + frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputLocals, i); + } + + // If dstFrame is an exception handler block, it can be reached from any instruction of the + // basic block corresponding to this frame, in particular from the first one. Therefore, the + // input locals of dstFrame should be compatible (i.e. merged) with the input locals of this + // frame (and the input stack of dstFrame should be compatible, i.e. merged, with a one + // element stack containing the caught exception type). + if (catchTypeIndex > 0) { + for (int i = 0; i < numLocal; ++i) { + frameChanged |= merge(symbolTable, inputLocals[i], dstFrame.inputLocals, i); + } + if (dstFrame.inputStack == null) { + dstFrame.inputStack = new int[1]; + frameChanged = true; + } + frameChanged |= merge(symbolTable, catchTypeIndex, dstFrame.inputStack, 0); + return frameChanged; + } + + // Compute the concrete types of the stack operands at the end of the basic block corresponding + // to this frame, by resolving its abstract output types, and merge these concrete types with + // those of the stack operands in the input frame of dstFrame. + int numInputStack = inputStack.length + outputStackStart; + if (dstFrame.inputStack == null) { + dstFrame.inputStack = new int[numInputStack + outputStackTop]; + frameChanged = true; + } + // First, do this for the stack operands that have not been popped in the basic block + // corresponding to this frame, and which are therefore equal to their value in the input + // frame (except for uninitialized types, which may have been initialized). + for (int i = 0; i < numInputStack; ++i) { + int concreteOutputType = inputStack[i]; + if (initializations != null) { + concreteOutputType = getInitializedType(symbolTable, concreteOutputType); + } + frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, i); + } + // Then, do this for the stack operands that have pushed in the basic block (this code is the + // same as the one above for local variables). + for (int i = 0; i < outputStackTop; ++i) { + int abstractOutputType = outputStack[i]; + int concreteOutputType = getConcreteOutputType(abstractOutputType, numStack); + if (initializations != null) { + concreteOutputType = getInitializedType(symbolTable, concreteOutputType); + } + frameChanged |= + merge(symbolTable, concreteOutputType, dstFrame.inputStack, numInputStack + i); + } + return frameChanged; + } + + /** + * Merges the type at the given index in the given abstract type array with the given type. + * Returns {@literal true} if the type array has been modified by this operation. + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param sourceType the abstract type with which the abstract type array element must be merged. + * This type should be of {@link #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link + * #UNINITIALIZED_KIND} or {@link #FORWARD_UNINITIALIZED_KIND} kind, with positive or + * {@literal null} array dimensions. + * @param dstTypes an array of abstract types. These types should be of {@link #CONSTANT_KIND}, + * {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND} or {@link #FORWARD_UNINITIALIZED_KIND} + * kind, with positive or {@literal null} array dimensions. + * @param dstIndex the index of the type that must be merged in dstTypes. + * @return {@literal true} if the type array has been modified by this operation. + */ + private static boolean merge( + final SymbolTable symbolTable, + final int sourceType, + final int[] dstTypes, + final int dstIndex) { + int dstType = dstTypes[dstIndex]; + if (dstType == sourceType) { + // If the types are equal, merge(sourceType, dstType) = dstType, so there is no change. + return false; + } + int srcType = sourceType; + if ((sourceType & ~DIM_MASK) == NULL) { + if (dstType == NULL) { + return false; + } + srcType = NULL; + } + if (dstType == 0) { + // If dstTypes[dstIndex] has never been assigned, merge(srcType, dstType) = srcType. + dstTypes[dstIndex] = srcType; + return true; + } + int mergedType; + if ((dstType & DIM_MASK) != 0 || (dstType & KIND_MASK) == REFERENCE_KIND) { + // If dstType is a reference type of any array dimension. + if (srcType == NULL) { + // If srcType is the NULL type, merge(srcType, dstType) = dstType, so there is no change. + return false; + } else if ((srcType & (DIM_MASK | KIND_MASK)) == (dstType & (DIM_MASK | KIND_MASK))) { + // If srcType has the same array dimension and the same kind as dstType. + if ((dstType & KIND_MASK) == REFERENCE_KIND) { + // If srcType and dstType are reference types with the same array dimension, + // merge(srcType, dstType) = dim(srcType) | common super class of srcType and dstType. + mergedType = + (srcType & DIM_MASK) + | REFERENCE_KIND + | symbolTable.addMergedType(srcType & VALUE_MASK, dstType & VALUE_MASK); + } else { + // If srcType and dstType are array types of equal dimension but different element types, + // merge(srcType, dstType) = dim(srcType) - 1 | java/lang/Object. + int mergedDim = ELEMENT_OF + (srcType & DIM_MASK); + mergedType = mergedDim | REFERENCE_KIND | symbolTable.addType("java/lang/Object"); + } + } else if ((srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND) { + // If srcType is any other reference or array type, + // merge(srcType, dstType) = min(srcDdim, dstDim) | java/lang/Object + // where srcDim is the array dimension of srcType, minus 1 if srcType is an array type + // with a non reference element type (and similarly for dstDim). + int srcDim = srcType & DIM_MASK; + if (srcDim != 0 && (srcType & KIND_MASK) != REFERENCE_KIND) { + srcDim = ELEMENT_OF + srcDim; + } + int dstDim = dstType & DIM_MASK; + if (dstDim != 0 && (dstType & KIND_MASK) != REFERENCE_KIND) { + dstDim = ELEMENT_OF + dstDim; + } + mergedType = + Math.min(srcDim, dstDim) | REFERENCE_KIND | symbolTable.addType("java/lang/Object"); + } else { + // If srcType is any other type, merge(srcType, dstType) = TOP. + mergedType = TOP; + } + } else if (dstType == NULL) { + // If dstType is the NULL type, merge(srcType, dstType) = srcType, or TOP if srcType is not a + // an array type or a reference type. + mergedType = + (srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND ? srcType : TOP; + } else { + // If dstType is any other type, merge(srcType, dstType) = TOP whatever srcType. + mergedType = TOP; + } + if (mergedType != dstType) { + dstTypes[dstIndex] = mergedType; + return true; + } + return false; + } + + // ----------------------------------------------------------------------------------------------- + // Frame output methods, to generate StackMapFrame attributes + // ----------------------------------------------------------------------------------------------- + + /** + * Makes the given {@link MethodWriter} visit the input frame of this {@link Frame}. The visit is + * done with the {@link MethodWriter#visitFrameStart}, {@link MethodWriter#visitAbstractType} and + * {@link MethodWriter#visitFrameEnd} methods. + * + * @param methodWriter the {@link MethodWriter} that should visit the input frame of this {@link + * Frame}. + */ + final void accept(final MethodWriter methodWriter) { + // Compute the number of locals, ignoring TOP types that are just after a LONG or a DOUBLE, and + // all trailing TOP types. + int[] localTypes = inputLocals; + int numLocal = 0; + int numTrailingTop = 0; + int i = 0; + while (i < localTypes.length) { + int localType = localTypes[i]; + i += (localType == LONG || localType == DOUBLE) ? 2 : 1; + if (localType == TOP) { + numTrailingTop++; + } else { + numLocal += numTrailingTop + 1; + numTrailingTop = 0; + } + } + // Compute the stack size, ignoring TOP types that are just after a LONG or a DOUBLE. + int[] stackTypes = inputStack; + int numStack = 0; + i = 0; + while (i < stackTypes.length) { + int stackType = stackTypes[i]; + i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1; + numStack++; + } + // Visit the frame and its content. + int frameIndex = methodWriter.visitFrameStart(owner.bytecodeOffset, numLocal, numStack); + i = 0; + while (numLocal-- > 0) { + int localType = localTypes[i]; + i += (localType == LONG || localType == DOUBLE) ? 2 : 1; + methodWriter.visitAbstractType(frameIndex++, localType); + } + i = 0; + while (numStack-- > 0) { + int stackType = stackTypes[i]; + i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1; + methodWriter.visitAbstractType(frameIndex++, stackType); + } + methodWriter.visitFrameEnd(); + } + + /** + * Put the given abstract type in the given ByteVector, using the JVMS verification_type_info + * format used in StackMapTable attributes. + * + * @param symbolTable the type table to use to lookup and store type {@link Symbol}. + * @param abstractType an abstract type, restricted to {@link Frame#CONSTANT_KIND}, {@link + * Frame#REFERENCE_KIND}, {@link Frame#UNINITIALIZED_KIND} or {@link + * Frame#FORWARD_UNINITIALIZED_KIND} types. + * @param output where the abstract type must be put. + * @see JVMS + * 4.7.4 + */ + static void putAbstractType( + final SymbolTable symbolTable, final int abstractType, final ByteVector output) { + int arrayDimensions = (abstractType & Frame.DIM_MASK) >> DIM_SHIFT; + if (arrayDimensions == 0) { + int typeValue = abstractType & VALUE_MASK; + switch (abstractType & KIND_MASK) { + case CONSTANT_KIND: + output.putByte(typeValue); + break; + case REFERENCE_KIND: + output + .putByte(ITEM_OBJECT) + .putShort(symbolTable.addConstantClass(symbolTable.getType(typeValue).value).index); + break; + case UNINITIALIZED_KIND: + output.putByte(ITEM_UNINITIALIZED).putShort((int) symbolTable.getType(typeValue).data); + break; + case FORWARD_UNINITIALIZED_KIND: + output.putByte(ITEM_UNINITIALIZED); + symbolTable.getForwardUninitializedLabel(typeValue).put(output); + break; + default: + throw new AssertionError(); + } + } else { + // Case of an array type, we need to build its descriptor first. + StringBuilder typeDescriptor = new StringBuilder(); + while (arrayDimensions-- > 0) { + typeDescriptor.append('['); + } + if ((abstractType & KIND_MASK) == REFERENCE_KIND) { + typeDescriptor + .append('L') + .append(symbolTable.getType(abstractType & VALUE_MASK).value) + .append(';'); + } else { + switch (abstractType & VALUE_MASK) { + case Frame.ITEM_ASM_BOOLEAN: + typeDescriptor.append('Z'); + break; + case Frame.ITEM_ASM_BYTE: + typeDescriptor.append('B'); + break; + case Frame.ITEM_ASM_CHAR: + typeDescriptor.append('C'); + break; + case Frame.ITEM_ASM_SHORT: + typeDescriptor.append('S'); + break; + case Frame.ITEM_INTEGER: + typeDescriptor.append('I'); + break; + case Frame.ITEM_FLOAT: + typeDescriptor.append('F'); + break; + case Frame.ITEM_LONG: + typeDescriptor.append('J'); + break; + case Frame.ITEM_DOUBLE: + typeDescriptor.append('D'); + break; + default: + throw new AssertionError(); + } + } + output + .putByte(ITEM_OBJECT) + .putShort(symbolTable.addConstantClass(typeDescriptor.toString()).index); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Handle.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Handle.class new file mode 100644 index 0000000000000000000000000000000000000000..049552129f3df7df080470b91140c82f580085cd GIT binary patch literal 2280 zcmbVOT~ixX7=BLJd=R!YrcG)DF}0Q^3nA9luR@U)EJXRJ1(}iFbO~En2pbHGjF*02 zdEH%v!o1ZMoKI_iv5^#}M@9PxQ~V+b^A#~F6d`<^}Td7tM!&wIkpe}4Wo zfI++%MnIu+ac(JZJFZo6%u>Ewna`JJ7p9}8(X^y#U$;1OX z+GHY1_Qi_5;+88i{h*ExJfzTKuNI_g*Uch%s+lN`6I-WlP%6Dv}XqYd0_;PD+JOR33yTho|1sVzXhCQUDLLE zJ%T<3o~D6*9nWBZOx^O|^*Nfkdy8I$bN^R4*=c6=i+Fg{cC7KWqisILW zY8OT)%WIXQb;%ayEq-tIh@5bmijML&2qG?>Ln|)b;*D$vZ)6vEBW2Gq3c|nzG~pt> zTeO256GmHiE~T}_nl}*EZbEC?LDQ%F(8P;If&zRmaqAL>Xr1+g@GLITW4M=`(x4^j zWpzUOk?~>)1P#Nq&m*wQ#lesYu{ zhd8E<9W)zlTWB@9w-7gSTSyuyZ3`(Q5!^z%5DR$3Iv5SSMsTmA8E>E!Z{i5vLJDuQ zTJLyd`~5v@WYaaW=^EK|jcmF~mMG++VWAYBN4APE&r!-0G(JP?W(|gr0p9b{>HdOh zI)zaTa7O6W2gg4-5d2}o;IW3m$%DZkH4Gka7@Rs7e5+w_2PPW8Za>I*r(rO!;A-%1 zJSfr7)h^>>1hvhsZ=rpFVAE#TZD?as#cnBw~@Yq6ZDewlAf2K zm!g;QJYVSo$(Om|_0pF-v#+R&Z>WabJnQc$-tTb+Kd@_lB&(k=Ltok;?L(_6<0>xW z1p-g7Ew1nhc#_wlg(H7pBn)jpPM^OJe9M8ZGhPn9i>O-pwBJA^HXz-1jUMrLav<=| z1&)N=xo~X{Y@DJ6?(qE!lK7Q(@}0U`c2z-1&&3e9tfaBna~l6=5D>h)t03MbOaU?c z1&o(=(Cuf=#d@~AN-}-U&z_5)_3hSeJi#eJ8-MyHg7IF?$Ff|%jq{=oznZ?Nf3E{I aTn8$Nz^h>xyUgvwqQm=u?j&~zVCpZh0;CE6 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Handle.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/Handle.java new file mode 100644 index 00000000..7e5a9e1a --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/Handle.java @@ -0,0 +1,221 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A reference to a field or a method. + * + * @author Remi Forax + * @author Eric Bruneton + */ +public final class Handle { + + /** + * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link + * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + */ + private final int tag; + + /** The internal name of the class that owns the field or method designated by this handle. */ + private final String owner; + + /** The name of the field or method designated by this handle. */ + private final String name; + + /** The descriptor of the field or method designated by this handle. */ + private final String descriptor; + + /** Whether the owner is an interface or not. */ + private final boolean isInterface; + + /** + * Constructs a new field or method handle. + * + * @param tag the kind of field or method designated by this Handle. Must be {@link + * Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link + * Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link + * Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the class that owns the field or method designated by this + * handle (see {@link Type#getInternalName()}). + * @param name the name of the field or method designated by this handle. + * @param descriptor the descriptor of the field or method designated by this handle. + * @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String, + * boolean)}. + */ + @Deprecated + public Handle(final int tag, final String owner, final String name, final String descriptor) { + this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Constructs a new field or method handle. + * + * @param tag the kind of field or method designated by this Handle. Must be {@link + * Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link + * Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link + * Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the class that owns the field or method designated by this + * handle (see {@link Type#getInternalName()}). + * @param name the name of the field or method designated by this handle. + * @param descriptor the descriptor of the field or method designated by this handle. + * @param isInterface whether the owner is an interface or not. + */ + public Handle( + final int tag, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + this.tag = tag; + this.owner = owner; + this.name = name; + this.descriptor = descriptor; + this.isInterface = isInterface; + } + + /** + * Returns the kind of field or method designated by this handle. + * + * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link + * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link + * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + */ + public int getTag() { + return tag; + } + + /** + * Returns the internal name of the class that owns the field or method designated by this handle. + * + * @return the internal name of the class that owns the field or method designated by this handle + * (see {@link Type#getInternalName()}). + */ + public String getOwner() { + return owner; + } + + /** + * Returns the name of the field or method designated by this handle. + * + * @return the name of the field or method designated by this handle. + */ + public String getName() { + return name; + } + + /** + * Returns the descriptor of the field or method designated by this handle. + * + * @return the descriptor of the field or method designated by this handle. + */ + public String getDesc() { + return descriptor; + } + + /** + * Returns true if the owner of the field or method designated by this handle is an interface. + * + * @return true if the owner of the field or method designated by this handle is an interface. + */ + public boolean isInterface() { + return isInterface; + } + + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + if (!(object instanceof Handle)) { + return false; + } + Handle handle = (Handle) object; + return tag == handle.tag + && isInterface == handle.isInterface + && owner.equals(handle.owner) + && name.equals(handle.name) + && descriptor.equals(handle.descriptor); + } + + @Override + public int hashCode() { + return tag + + (isInterface ? 64 : 0) + + owner.hashCode() * name.hashCode() * descriptor.hashCode(); + } + + /** + * Returns the textual representation of this handle. The textual representation is: + * + *

      + *
    • for a reference to a class: owner "." name descriptor " (" tag ")", + *
    • for a reference to an interface: owner "." name descriptor " (" tag " itf)". + *
    + */ + @Override + public String toString() { + return owner + '.' + name + descriptor + " (" + tag + (isInterface ? " itf" : "") + ')'; + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Handler.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Handler.class new file mode 100644 index 0000000000000000000000000000000000000000..cd586df91d8b9adc773f6f5f23b1580fb7d073df GIT binary patch literal 2598 zcmc&$+fN*26#spD-(}b?&@HwIMa2rU+it~LFCb`df&wK{G3txMGG({j?vi2X%}X`$ z!Km@c2aQ;@jn+hs7>hKTc#Ssksqfx3{s%tR;_rMjE+u_fOq%#G^PM^8`_B2D%lFHC zf9ccD0qn$R0s#c02pI??qL4aZ9ky~Mt2~w4J8{6yy9$xsV!7z{DFi#a#^Z<~9!0`H z9Sns{2PO~Zie=Y!%2p{?ai($=ed>rkk+WtFG>Rr(@Em*EwFc5yM{VA6^M!rKrfmf^DEqH5upS!}nyQvv z_DtR>PP-L?Y8+b5cFc8(<*A+o4_zy@XjOQwb9GR!=B~jjA$djLXrLX}Db$tiqi(gV zH4*wdbzV0Z=)jG1;n;^NhwTU0WESe=s(oC|JiBT+`xkf|H=#3%E(4~txMMZLqmZ09 z=Gytnq`i0l{u$eiBCF7_-0VS4?3C>UPb@7hNyl^2@vRC+{-0Wm3x;k3w_uw>^OWuG zKAN|u-D0J@&zdONLw0$}EhuDGjjn4jf$g|0irWp`fjbqtYLsmU%Qep1F1I2!J?oAY zDh{vymd?SNjaok1qY&E3nk%dsDwge$*+Ubyqcf1JR>@nXamy)6M!quS7K$_E2LCcE z82gLP%<^=HHEED|c>ihiw~YytC?x#P-C|2PGR(dura!d4o~r!8VQbot7%BO+OkYvu zvEp$eZ(#B(tFJJ=>bln&>dR`?HBM%&%({%n&i;pkOm?g?>*Vb{#S#G<{zcg$(~Yeh zqyULMf|L+6rIb*pUP+vKB~|K`#K;vwD||=zkoBO@L+NFD5ly?f2xVp#5H+(4s5dt+ zAZ4aQ3urRehZoTN5%&bp%Xb^1d>=;$k0XvJki?T{!c(N*6WEBSaTl$9o=>h4Q6dXQ zr6oZr$lHbB5!8|(4QWZRhAHuua=#!vNMB-WF|(U9XOZI5#HV?Y8m?^%Xj=xC)DEAg z>lf(gMGeOEj#t67pr5b=OpAskU|MwXf-EYD(+jK~Wnf8l&ODE>nm0`b%Vf{tdPbxi zJ&R3!T|rx2P8P9c-m^4lr3A=`(p<5Jp;wxTFR0tH2Mv^8VXm(d_iJp)>&)sT^Lc}W`X<@o z6!zdW2JkjU@D3ityLbfep@0ui!G~<($9M^6b;Sm}ym7bRzB%0Ew{H$Rbo*NH4F4(C zF?I)zVwY~82?x6=g&8Z)SnG)6USeuOEOLpwtkh0*5lN*Q>esT+O6N#8vPkL{|Rn=NN3ZXVJ_;a06G!xC zG~*Yh@+&g<4c+*iJVMS + * 4.7.3 + * @author Eric Bruneton + */ +final class Handler { + + /** + * The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the + * exception handler's scope (inclusive). + */ + final Label startPc; + + /** + * The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception + * handler's scope (exclusive). + */ + final Label endPc; + + /** + * The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the + * exception handler's code. + */ + final Label handlerPc; + + /** + * The catch_type field of this JVMS exception_table entry. This is the constant pool index of the + * internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions. + */ + final int catchType; + + /** + * The internal name of the type of exceptions handled by this handler, or {@literal null} to + * catch any exceptions. + */ + final String catchTypeDescriptor; + + /** The next exception handler. */ + Handler nextHandler; + + /** + * Constructs a new Handler. + * + * @param startPc the start_pc field of this JVMS exception_table entry. + * @param endPc the end_pc field of this JVMS exception_table entry. + * @param handlerPc the handler_pc field of this JVMS exception_table entry. + * @param catchType The catch_type field of this JVMS exception_table entry. + * @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler, + * or {@literal null} to catch any exceptions. + */ + Handler( + final Label startPc, + final Label endPc, + final Label handlerPc, + final int catchType, + final String catchTypeDescriptor) { + this.startPc = startPc; + this.endPc = endPc; + this.handlerPc = handlerPc; + this.catchType = catchType; + this.catchTypeDescriptor = catchTypeDescriptor; + } + + /** + * Constructs a new Handler from the given one, with a different scope. + * + * @param handler an existing Handler. + * @param startPc the start_pc field of this JVMS exception_table entry. + * @param endPc the end_pc field of this JVMS exception_table entry. + */ + Handler(final Handler handler, final Label startPc, final Label endPc) { + this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor); + this.nextHandler = handler.nextHandler; + } + + /** + * Removes the range between start and end from the Handler list that begins with the given + * element. + * + * @param firstHandler the beginning of a Handler list. May be {@literal null}. + * @param start the start of the range to be removed. + * @param end the end of the range to be removed. Maybe {@literal null}. + * @return the exception handler list with the start-end range removed. + */ + static Handler removeRange(final Handler firstHandler, final Label start, final Label end) { + if (firstHandler == null) { + return null; + } else { + firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end); + } + int handlerStart = firstHandler.startPc.bytecodeOffset; + int handlerEnd = firstHandler.endPc.bytecodeOffset; + int rangeStart = start.bytecodeOffset; + int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset; + // Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect. + if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) { + return firstHandler; + } + if (rangeStart <= handlerStart) { + if (rangeEnd >= handlerEnd) { + // If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler. + return firstHandler.nextHandler; + } else { + // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[ + return new Handler(firstHandler, end, firstHandler.endPc); + } + } else if (rangeEnd >= handlerEnd) { + // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[ + return new Handler(firstHandler, firstHandler.startPc, start); + } else { + // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = + // [handlerStart,rangeStart[ + [rangeEnd,handerEnd[ + firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc); + return new Handler(firstHandler, firstHandler.startPc, start); + } + } + + /** + * Returns the number of elements of the Handler list that begins with the given element. + * + * @param firstHandler the beginning of a Handler list. May be {@literal null}. + * @return the number of elements of the Handler list that begins with 'handler'. + */ + static int getExceptionTableLength(final Handler firstHandler) { + int length = 0; + Handler handler = firstHandler; + while (handler != null) { + length++; + handler = handler.nextHandler; + } + return length; + } + + /** + * Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that + * begins with the given element. This includes the exception_table_length field. + * + * @param firstHandler the beginning of a Handler list. May be {@literal null}. + * @return the size in bytes of the exception_table_length and exception_table structures. + */ + static int getExceptionTableSize(final Handler firstHandler) { + return 2 + 8 * getExceptionTableLength(firstHandler); + } + + /** + * Puts the JVMS exception_table corresponding to the Handler list that begins with the given + * element. This includes the exception_table_length field. + * + * @param firstHandler the beginning of a Handler list. May be {@literal null}. + * @param output where the exception_table_length and exception_table structures must be put. + */ + static void putExceptionTable(final Handler firstHandler, final ByteVector output) { + output.putShort(getExceptionTableLength(firstHandler)); + Handler handler = firstHandler; + while (handler != null) { + output + .putShort(handler.startPc.bytecodeOffset) + .putShort(handler.endPc.bytecodeOffset) + .putShort(handler.handlerPc.bytecodeOffset) + .putShort(handler.catchType); + handler = handler.nextHandler; + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Label.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Label.class new file mode 100644 index 0000000000000000000000000000000000000000..04f693a3078c672b56ddd98aad6d3ea2c946d908 GIT binary patch literal 6620 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 Ac>n+a literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Label.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/Label.java new file mode 100644 index 00000000..c321fc8a --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/Label.java @@ -0,0 +1,686 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A position in the bytecode of a method. Labels are used for jump, goto, and switch instructions, + * and for try catch blocks. A label designates the instruction that is just after. Note + * however that there can be other elements between a label and the instruction it designates (such + * as other labels, stack map frames, line numbers, etc.). + * + * @author Eric Bruneton + */ +public class Label { + + /** + * A flag indicating that a label is only used for debug attributes. Such a label is not the start + * of a basic block, the target of a jump instruction, or an exception handler. It can be safely + * ignored in control flow graph analysis algorithms (for optimization purposes). + */ + static final int FLAG_DEBUG_ONLY = 1; + + /** + * A flag indicating that a label is the target of a jump instruction, or the start of an + * exception handler. + */ + static final int FLAG_JUMP_TARGET = 2; + + /** A flag indicating that the bytecode offset of a label is known. */ + static final int FLAG_RESOLVED = 4; + + /** A flag indicating that a label corresponds to a reachable basic block. */ + static final int FLAG_REACHABLE = 8; + + /** + * A flag indicating that the basic block corresponding to a label ends with a subroutine call. By + * construction in {@link MethodWriter#visitJumpInsn}, labels with this flag set have at least two + * outgoing edges: + * + *
      + *
    • the first one corresponds to the instruction that follows the jsr instruction in the + * bytecode, i.e. where execution continues when it returns from the jsr call. This is a + * virtual control flow edge, since execution never goes directly from the jsr to the next + * instruction. Instead, it goes to the subroutine and eventually returns to the instruction + * following the jsr. This virtual edge is used to compute the real outgoing edges of the + * basic blocks ending with a ret instruction, in {@link #addSubroutineRetSuccessors}. + *
    • the second one corresponds to the target of the jsr instruction, + *
    + */ + static final int FLAG_SUBROUTINE_CALLER = 16; + + /** + * A flag indicating that the basic block corresponding to a label is the start of a subroutine. + */ + static final int FLAG_SUBROUTINE_START = 32; + + /** A flag indicating that the basic block corresponding to a label is the end of a subroutine. */ + static final int FLAG_SUBROUTINE_END = 64; + + /** A flag indicating that this label has at least one associated line number. */ + static final int FLAG_LINE_NUMBER = 128; + + /** + * The number of elements to add to the {@link #otherLineNumbers} array when it needs to be + * resized to store a new source line number. + */ + static final int LINE_NUMBERS_CAPACITY_INCREMENT = 4; + + /** + * The number of elements to add to the {@link #forwardReferences} array when it needs to be + * resized to store a new forward reference. + */ + static final int FORWARD_REFERENCES_CAPACITY_INCREMENT = 6; + + /** + * The bit mask to extract the type of a forward reference to this label. The extracted type is + * either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link #FORWARD_REFERENCE_TYPE_WIDE}. + * + * @see #forwardReferences + */ + static final int FORWARD_REFERENCE_TYPE_MASK = 0xF0000000; + + /** + * The type of forward references stored with two bytes in the bytecode. This is the case, for + * instance, of a forward reference from an ifnull instruction. + */ + static final int FORWARD_REFERENCE_TYPE_SHORT = 0x10000000; + + /** + * The type of forward references stored in four bytes in the bytecode. This is the case, for + * instance, of a forward reference from a lookupswitch instruction. + */ + static final int FORWARD_REFERENCE_TYPE_WIDE = 0x20000000; + + /** + * The type of forward references stored in two bytes in the stack map table. This is the + * case of the labels of {@link Frame#ITEM_UNINITIALIZED} stack map frame elements, when the NEW + * instruction is after the <init> constructor call (in bytecode offset order). + */ + static final int FORWARD_REFERENCE_TYPE_STACK_MAP = 0x30000000; + + /** + * The bit mask to extract the 'handle' of a forward reference to this label. The extracted handle + * is the bytecode offset where the forward reference value is stored (using either 2 or 4 bytes, + * as indicated by the {@link #FORWARD_REFERENCE_TYPE_MASK}). + * + * @see #forwardReferences + */ + static final int FORWARD_REFERENCE_HANDLE_MASK = 0x0FFFFFFF; + + /** + * A sentinel element used to indicate the end of a list of labels. + * + * @see #nextListElement + */ + static final Label EMPTY_LIST = new Label(); + + /** + * A user managed state associated with this label. Warning: this field is used by the ASM tree + * package. In order to use it with the ASM tree package you must override the getLabelNode method + * in MethodNode. + */ + public Object info; + + /** + * The type and status of this label or its corresponding basic block. Must be zero or more of + * {@link #FLAG_DEBUG_ONLY}, {@link #FLAG_JUMP_TARGET}, {@link #FLAG_RESOLVED}, {@link + * #FLAG_REACHABLE}, {@link #FLAG_SUBROUTINE_CALLER}, {@link #FLAG_SUBROUTINE_START}, {@link + * #FLAG_SUBROUTINE_END}. + */ + short flags; + + /** + * The source line number corresponding to this label, if {@link #FLAG_LINE_NUMBER} is set. If + * there are several source line numbers corresponding to this label, the first one is stored in + * this field, and the remaining ones are stored in {@link #otherLineNumbers}. + */ + private short lineNumber; + + /** + * The source line numbers corresponding to this label, in addition to {@link #lineNumber}, or + * null. The first element of this array is the number n of source line numbers it contains, which + * are stored between indices 1 and n (inclusive). + */ + private int[] otherLineNumbers; + + /** + * The offset of this label in the bytecode of its method, in bytes. This value is set if and only + * if the {@link #FLAG_RESOLVED} flag is set. + */ + int bytecodeOffset; + + /** + * The forward references to this label. The first element is the number of forward references, + * times 2 (this corresponds to the index of the last element actually used in this array). Then, + * each forward reference is described with two consecutive integers noted + * 'sourceInsnBytecodeOffset' and 'reference': + * + *
      + *
    • 'sourceInsnBytecodeOffset' is the bytecode offset of the instruction that contains the + * forward reference, + *
    • 'reference' contains the type and the offset in the bytecode where the forward reference + * value must be stored, which can be extracted with {@link #FORWARD_REFERENCE_TYPE_MASK} + * and {@link #FORWARD_REFERENCE_HANDLE_MASK}. + *
    + * + *

    For instance, for an ifnull instruction at bytecode offset x, 'sourceInsnBytecodeOffset' is + * equal to x, and 'reference' is of type {@link #FORWARD_REFERENCE_TYPE_SHORT} with value x + 1 + * (because the ifnull instruction uses a 2 bytes bytecode offset operand stored one byte after + * the start of the instruction itself). For the default case of a lookupswitch instruction at + * bytecode offset x, 'sourceInsnBytecodeOffset' is equal to x, and 'reference' is of type {@link + * #FORWARD_REFERENCE_TYPE_WIDE} with value between x + 1 and x + 4 (because the lookupswitch + * instruction uses a 4 bytes bytecode offset operand stored one to four bytes after the start of + * the instruction itself). + */ + private int[] forwardReferences; + + // ----------------------------------------------------------------------------------------------- + + // Fields for the control flow and data flow graph analysis algorithms (used to compute the + // maximum stack size or the stack map frames). A control flow graph contains one node per "basic + // block", and one edge per "jump" from one basic block to another. Each node (i.e., each basic + // block) is represented with the Label object that corresponds to the first instruction of this + // basic block. Each node also stores the list of its successors in the graph, as a linked list of + // Edge objects. + // + // The control flow analysis algorithms used to compute the maximum stack size or the stack map + // frames are similar and use two steps. The first step, during the visit of each instruction, + // builds information about the state of the local variables and the operand stack at the end of + // each basic block, called the "output frame", relatively to the frame state at the + // beginning of the basic block, which is called the "input frame", and which is unknown + // during this step. The second step, in {@link MethodWriter#computeAllFrames} and {@link + // MethodWriter#computeMaxStackAndLocal}, is a fix point algorithm + // that computes information about the input frame of each basic block, from the input state of + // the first basic block (known from the method signature), and by the using the previously + // computed relative output frames. + // + // The algorithm used to compute the maximum stack size only computes the relative output and + // absolute input stack heights, while the algorithm used to compute stack map frames computes + // relative output frames and absolute input frames. + + /** + * The number of elements in the input stack of the basic block corresponding to this label. This + * field is computed in {@link MethodWriter#computeMaxStackAndLocal}. + */ + short inputStackSize; + + /** + * The number of elements in the output stack, at the end of the basic block corresponding to this + * label. This field is only computed for basic blocks that end with a RET instruction. + */ + short outputStackSize; + + /** + * The maximum height reached by the output stack, relatively to the top of the input stack, in + * the basic block corresponding to this label. This maximum is always positive or {@literal + * null}. + */ + short outputStackMax; + + /** + * The id of the subroutine to which this basic block belongs, or 0. If the basic block belongs to + * several subroutines, this is the id of the "oldest" subroutine that contains it (with the + * convention that a subroutine calling another one is "older" than the callee). This field is + * computed in {@link MethodWriter#computeMaxStackAndLocal}, if the method contains JSR + * instructions. + */ + short subroutineId; + + /** + * The input and output stack map frames of the basic block corresponding to this label. This + * field is only used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} or {@link + * MethodWriter#COMPUTE_INSERTED_FRAMES} option is used. + */ + Frame frame; + + /** + * The successor of this label, in the order they are visited in {@link MethodVisitor#visitLabel}. + * This linked list does not include labels used for debug info only. If the {@link + * MethodWriter#COMPUTE_ALL_FRAMES} or {@link MethodWriter#COMPUTE_INSERTED_FRAMES} option is used + * then it does not contain either successive labels that denote the same bytecode offset (in this + * case only the first label appears in this list). + */ + Label nextBasicBlock; + + /** + * The outgoing edges of the basic block corresponding to this label, in the control flow graph of + * its method. These edges are stored in a linked list of {@link Edge} objects, linked to each + * other by their {@link Edge#nextEdge} field. + */ + Edge outgoingEdges; + + /** + * The next element in the list of labels to which this label belongs, or {@literal null} if it + * does not belong to any list. All lists of labels must end with the {@link #EMPTY_LIST} + * sentinel, in order to ensure that this field is null if and only if this label does not belong + * to a list of labels. Note that there can be several lists of labels at the same time, but that + * a label can belong to at most one list at a time (unless some lists share a common tail, but + * this is not used in practice). + * + *

    List of labels are used in {@link MethodWriter#computeAllFrames} and {@link + * MethodWriter#computeMaxStackAndLocal} to compute stack map frames and the maximum stack size, + * respectively, as well as in {@link #markSubroutine} and {@link #addSubroutineRetSuccessors} to + * compute the basic blocks belonging to subroutines and their outgoing edges. Outside of these + * methods, this field should be null (this property is a precondition and a postcondition of + * these methods). + */ + Label nextListElement; + + // ----------------------------------------------------------------------------------------------- + // Constructor and accessors + // ----------------------------------------------------------------------------------------------- + + /** Constructs a new label. */ + public Label() { + // Nothing to do. + } + + /** + * Returns the bytecode offset corresponding to this label. This offset is computed from the start + * of the method's bytecode. This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @return the bytecode offset corresponding to this label. + * @throws IllegalStateException if this label is not resolved yet. + */ + public int getOffset() { + if ((flags & FLAG_RESOLVED) == 0) { + throw new IllegalStateException("Label offset position has not been resolved yet"); + } + return bytecodeOffset; + } + + /** + * Returns the "canonical" {@link Label} instance corresponding to this label's bytecode offset, + * if known, otherwise the label itself. The canonical instance is the first label (in the order + * of their visit by {@link MethodVisitor#visitLabel}) corresponding to this bytecode offset. It + * cannot be known for labels which have not been visited yet. + * + *

    This method should only be used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} option + * is used. + * + * @return the label itself if {@link #frame} is null, otherwise the Label's frame owner. This + * corresponds to the "canonical" label instance described above thanks to the way the label + * frame is set in {@link MethodWriter#visitLabel}. + */ + final Label getCanonicalInstance() { + return frame == null ? this : frame.owner; + } + + // ----------------------------------------------------------------------------------------------- + // Methods to manage line numbers + // ----------------------------------------------------------------------------------------------- + + /** + * Adds a source line number corresponding to this label. + * + * @param lineNumber a source line number (which should be strictly positive). + */ + final void addLineNumber(final int lineNumber) { + if ((flags & FLAG_LINE_NUMBER) == 0) { + flags |= FLAG_LINE_NUMBER; + this.lineNumber = (short) lineNumber; + } else { + if (otherLineNumbers == null) { + otherLineNumbers = new int[LINE_NUMBERS_CAPACITY_INCREMENT]; + } + int otherLineNumberIndex = ++otherLineNumbers[0]; + if (otherLineNumberIndex >= otherLineNumbers.length) { + int[] newLineNumbers = new int[otherLineNumbers.length + LINE_NUMBERS_CAPACITY_INCREMENT]; + System.arraycopy(otherLineNumbers, 0, newLineNumbers, 0, otherLineNumbers.length); + otherLineNumbers = newLineNumbers; + } + otherLineNumbers[otherLineNumberIndex] = lineNumber; + } + } + + /** + * Makes the given visitor visit this label and its source line numbers, if applicable. + * + * @param methodVisitor a method visitor. + * @param visitLineNumbers whether to visit of the label's source line numbers, if any. + */ + final void accept(final MethodVisitor methodVisitor, final boolean visitLineNumbers) { + methodVisitor.visitLabel(this); + if (visitLineNumbers && (flags & FLAG_LINE_NUMBER) != 0) { + methodVisitor.visitLineNumber(lineNumber & 0xFFFF, this); + if (otherLineNumbers != null) { + for (int i = 1; i <= otherLineNumbers[0]; ++i) { + methodVisitor.visitLineNumber(otherLineNumbers[i], this); + } + } + } + } + + // ----------------------------------------------------------------------------------------------- + // Methods to compute offsets and to manage forward references + // ----------------------------------------------------------------------------------------------- + + /** + * Puts a reference to this label in the bytecode of a method. If the bytecode offset of the label + * is known, the relative bytecode offset between the label and the instruction referencing it is + * computed and written directly. Otherwise, a null relative offset is written and a new forward + * reference is declared for this label. + * + * @param code the bytecode of the method. This is where the reference is appended. + * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the + * reference to be appended. + * @param wideReference whether the reference must be stored in 4 bytes (instead of 2 bytes). + */ + final void put( + final ByteVector code, final int sourceInsnBytecodeOffset, final boolean wideReference) { + if ((flags & FLAG_RESOLVED) == 0) { + if (wideReference) { + addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_WIDE, code.length); + code.putInt(-1); + } else { + addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_SHORT, code.length); + code.putShort(-1); + } + } else { + if (wideReference) { + code.putInt(bytecodeOffset - sourceInsnBytecodeOffset); + } else { + code.putShort(bytecodeOffset - sourceInsnBytecodeOffset); + } + } + } + + /** + * Puts a reference to this label in the stack map table of a method. If the bytecode + * offset of the label is known, it is written directly. Otherwise, a null relative offset is + * written and a new forward reference is declared for this label. + * + * @param stackMapTableEntries the stack map table where the label offset must be added. + */ + final void put(final ByteVector stackMapTableEntries) { + if ((flags & FLAG_RESOLVED) == 0) { + addForwardReference(0, FORWARD_REFERENCE_TYPE_STACK_MAP, stackMapTableEntries.length); + } + stackMapTableEntries.putShort(bytecodeOffset); + } + + /** + * Adds a forward reference to this label. This method must be called only for a true forward + * reference, i.e. only if this label is not resolved yet. For backward references, the relative + * bytecode offset of the reference can be, and must be, computed and stored directly. + * + * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the + * reference stored at referenceHandle. + * @param referenceType either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link + * #FORWARD_REFERENCE_TYPE_WIDE}. + * @param referenceHandle the offset in the bytecode where the forward reference value must be + * stored. + */ + private void addForwardReference( + final int sourceInsnBytecodeOffset, final int referenceType, final int referenceHandle) { + if (forwardReferences == null) { + forwardReferences = new int[FORWARD_REFERENCES_CAPACITY_INCREMENT]; + } + int lastElementIndex = forwardReferences[0]; + if (lastElementIndex + 2 >= forwardReferences.length) { + int[] newValues = new int[forwardReferences.length + FORWARD_REFERENCES_CAPACITY_INCREMENT]; + System.arraycopy(forwardReferences, 0, newValues, 0, forwardReferences.length); + forwardReferences = newValues; + } + forwardReferences[++lastElementIndex] = sourceInsnBytecodeOffset; + forwardReferences[++lastElementIndex] = referenceType | referenceHandle; + forwardReferences[0] = lastElementIndex; + } + + /** + * Sets the bytecode offset of this label to the given value and resolves the forward references + * to this label, if any. This method must be called when this label is added to the bytecode of + * the method, i.e. when its bytecode offset becomes known. This method fills in the blanks that + * where left in the bytecode (and optionally in the stack map table) by each forward reference + * previously added to this label. + * + * @param code the bytecode of the method. + * @param stackMapTableEntries the 'entries' array of the StackMapTable code attribute of the + * method. Maybe {@literal null}. + * @param bytecodeOffset the bytecode offset of this label. + * @return {@literal true} if a blank that was left for this label was too small to store the + * offset. In such a case the corresponding jump instruction is replaced with an equivalent + * ASM specific instruction using an unsigned two bytes offset. These ASM specific + * instructions are later replaced with standard bytecode instructions with wider offsets (4 + * bytes instead of 2), in ClassReader. + */ + final boolean resolve( + final byte[] code, final ByteVector stackMapTableEntries, final int bytecodeOffset) { + this.flags |= FLAG_RESOLVED; + this.bytecodeOffset = bytecodeOffset; + if (forwardReferences == null) { + return false; + } + boolean hasAsmInstructions = false; + for (int i = forwardReferences[0]; i > 0; i -= 2) { + final int sourceInsnBytecodeOffset = forwardReferences[i - 1]; + final int reference = forwardReferences[i]; + final int relativeOffset = bytecodeOffset - sourceInsnBytecodeOffset; + int handle = reference & FORWARD_REFERENCE_HANDLE_MASK; + if ((reference & FORWARD_REFERENCE_TYPE_MASK) == FORWARD_REFERENCE_TYPE_SHORT) { + if (relativeOffset < Short.MIN_VALUE || relativeOffset > Short.MAX_VALUE) { + // Change the opcode of the jump instruction, in order to be able to find it later in + // ClassReader. These ASM specific opcodes are similar to jump instruction opcodes, except + // that the 2 bytes offset is unsigned (and can therefore represent values from 0 to + // 65535, which is sufficient since the size of a method is limited to 65535 bytes). + int opcode = code[sourceInsnBytecodeOffset] & 0xFF; + if (opcode < Opcodes.IFNULL) { + // Change IFEQ ... JSR to ASM_IFEQ ... ASM_JSR. + code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_OPCODE_DELTA); + } else { + // Change IFNULL and IFNONNULL to ASM_IFNULL and ASM_IFNONNULL. + code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_IFNULL_OPCODE_DELTA); + } + hasAsmInstructions = true; + } + code[handle++] = (byte) (relativeOffset >>> 8); + code[handle] = (byte) relativeOffset; + } else if ((reference & FORWARD_REFERENCE_TYPE_MASK) == FORWARD_REFERENCE_TYPE_WIDE) { + code[handle++] = (byte) (relativeOffset >>> 24); + code[handle++] = (byte) (relativeOffset >>> 16); + code[handle++] = (byte) (relativeOffset >>> 8); + code[handle] = (byte) relativeOffset; + } else { + stackMapTableEntries.data[handle++] = (byte) (bytecodeOffset >>> 8); + stackMapTableEntries.data[handle] = (byte) bytecodeOffset; + } + } + return hasAsmInstructions; + } + + // ----------------------------------------------------------------------------------------------- + // Methods related to subroutines + // ----------------------------------------------------------------------------------------------- + + /** + * Finds the basic blocks that belong to the subroutine starting with the basic block + * corresponding to this label, and marks these blocks as belonging to this subroutine. This + * method follows the control flow graph to find all the blocks that are reachable from the + * current basic block WITHOUT following any jsr target. + * + *

    Note: a precondition and postcondition of this method is that all labels must have a null + * {@link #nextListElement}. + * + * @param subroutineId the id of the subroutine starting with the basic block corresponding to + * this label. + */ + final void markSubroutine(final short subroutineId) { + // Data flow algorithm: put this basic block in a list of blocks to process (which are blocks + // belonging to subroutine subroutineId) and, while there are blocks to process, remove one from + // the list, mark it as belonging to the subroutine, and add its successor basic blocks in the + // control flow graph to the list of blocks to process (if not already done). + Label listOfBlocksToProcess = this; + listOfBlocksToProcess.nextListElement = EMPTY_LIST; + while (listOfBlocksToProcess != EMPTY_LIST) { + // Remove a basic block from the list of blocks to process. + Label basicBlock = listOfBlocksToProcess; + listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; + basicBlock.nextListElement = null; + + // If it is not already marked as belonging to a subroutine, mark it as belonging to + // subroutineId and add its successors to the list of blocks to process (unless already done). + if (basicBlock.subroutineId == 0) { + basicBlock.subroutineId = subroutineId; + listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess); + } + } + } + + /** + * Finds the basic blocks that end a subroutine starting with the basic block corresponding to + * this label and, for each one of them, adds an outgoing edge to the basic block following the + * given subroutine call. In other words, completes the control flow graph by adding the edges + * corresponding to the return from this subroutine, when called from the given caller basic + * block. + * + *

      + *
    • In expanded form, all frames must have the F_NEW type. + *
    • In compressed form, frames are basically "deltas" from the state of the previous frame: + *
        + *
      • {@link Opcodes#F_SAME} representing frame with exactly the same locals as the + * previous frame and with the empty stack. + *
      • {@link Opcodes#F_SAME1} representing frame with exactly the same locals as the + * previous frame and with single value on the stack ( numStack is 1 and + * stack[0] contains value for the type of the stack item). + *
      • {@link Opcodes#F_APPEND} representing frame with current locals are the same as the + * locals in the previous frame, except that additional locals are defined ( + * numLocal is 1, 2 or 3 and local elements contains values + * representing added types). + *
      • {@link Opcodes#F_CHOP} representing frame with current locals are the same as the + * locals in the previous frame, except that the last 1-3 locals are absent and with + * the empty stack (numLocal is 1, 2 or 3). + *
      • {@link Opcodes#F_FULL} representing complete frame data. + *
      + *
    + * + *
    + * In both cases the first frame, corresponding to the method's parameters and access flags, is + * implicit and must not be visited. Also, it is illegal to visit two or more frames for the same + * code location (i.e., at least one instruction must be visited between two calls to visitFrame). + * + * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded + * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link + * Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. + * @param numLocal the number of local variables in the visited frame. Long and double values + * count for one variable. + * @param local the local variable types in this frame. This array must not be modified. Primitive + * types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link + * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a single element). + * Reference types are represented by String objects (representing internal names, see {@link + * Type#getInternalName()}), and uninitialized types by Label objects (this label designates + * the NEW instruction that created this uninitialized value). + * @param numStack the number of operand stack elements in the visited frame. Long and double + * values count for one stack element. + * @param stack the operand stack types in this frame. This array must not be modified. Its + * content has the same format as the "local" array. + * @throws IllegalStateException if a frame is visited just after another one, without any + * instruction between the two (unless this frame is a Opcodes#F_SAME frame, in which case it + * is silently ignored). + */ + public void visitFrame( + final int type, + final int numLocal, + final Object[] local, + final int numStack, + final Object[] stack) { + if (mv != null) { + mv.visitFrame(type, numLocal, local, numStack, stack); + } + } + + // ----------------------------------------------------------------------------------------------- + // Normal instructions + // ----------------------------------------------------------------------------------------------- + + /** + * Visits a zero operand instruction. + * + * @param opcode the opcode of the instruction to be visited. This opcode is either NOP, + * ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, + * LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, + * FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE, + * AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, + * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, + * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, + * LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, + * D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, + * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT. + */ + public void visitInsn(final int opcode) { + if (mv != null) { + mv.visitInsn(opcode); + } + } + + /** + * Visits an instruction with a single int operand. + * + * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH + * or NEWARRAY. + * @param operand the operand of the instruction to be visited.
    + * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE. + *
    + * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE. + *
    + * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link + * Opcodes#T_CHAR}, {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE}, + * {@link Opcodes#T_SHORT}, {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. + */ + public void visitIntInsn(final int opcode, final int operand) { + if (mv != null) { + mv.visitIntInsn(opcode, operand); + } + } + + /** + * Visits a local variable instruction. A local variable instruction is an instruction that loads + * or stores the value of a local variable. + * + * @param opcode the opcode of the local variable instruction to be visited. This opcode is either + * ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param varIndex the operand of the instruction to be visited. This operand is the index of a + * local variable. + */ + public void visitVarInsn(final int opcode, final int varIndex) { + if (mv != null) { + mv.visitVarInsn(opcode, varIndex); + } + } + + /** + * Visits a type instruction. A type instruction is an instruction that takes the internal name of + * a class as parameter (see {@link Type#getInternalName()}). + * + * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, + * ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param type the operand of the instruction to be visited. This operand must be the internal + * name of an object or array class (see {@link Type#getInternalName()}). + */ + public void visitTypeInsn(final int opcode, final String type) { + if (mv != null) { + mv.visitTypeInsn(opcode, type); + } + } + + /** + * Visits a field instruction. A field instruction is an instruction that loads or stores the + * value of a field of an object. + * + * @param opcode the opcode of the type instruction to be visited. This opcode is either + * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. + * @param owner the internal name of the field's owner class (see {@link Type#getInternalName()}). + * @param name the field's name. + * @param descriptor the field's descriptor (see {@link Type}). + */ + public void visitFieldInsn( + final int opcode, final String owner, final String name, final String descriptor) { + if (mv != null) { + mv.visitFieldInsn(opcode, owner, name, descriptor); + } + } + + /** + * Visits a method instruction. A method instruction is an instruction that invokes a method. + * + * @param opcode the opcode of the type instruction to be visited. This opcode is either + * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. + * @param owner the internal name of the method's owner class (see {@link + * Type#getInternalName()}). + * @param name the method's name. + * @param descriptor the method's descriptor (see {@link Type}). + * @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead. + */ + @Deprecated + public void visitMethodInsn( + final int opcode, final String owner, final String name, final String descriptor) { + int opcodeAndSource = opcode | (api < Opcodes.ASM5 ? Opcodes.SOURCE_DEPRECATED : 0); + visitMethodInsn(opcodeAndSource, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE); + } + + /** + * Visits a method instruction. A method instruction is an instruction that invokes a method. + * + * @param opcode the opcode of the type instruction to be visited. This opcode is either + * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. + * @param owner the internal name of the method's owner class (see {@link + * Type#getInternalName()}). + * @param name the method's name. + * @param descriptor the method's descriptor (see {@link Type}). + * @param isInterface if the method's owner class is an interface. + */ + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + if (api < Opcodes.ASM5 && (opcode & Opcodes.SOURCE_DEPRECATED) == 0) { + if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) { + throw new UnsupportedOperationException("INVOKESPECIAL/STATIC on interfaces requires ASM5"); + } + visitMethodInsn(opcode, owner, name, descriptor); + return; + } + if (mv != null) { + mv.visitMethodInsn(opcode & ~Opcodes.SOURCE_MASK, owner, name, descriptor, isInterface); + } + } + + /** + * Visits an invokedynamic instruction. + * + * @param name the method's name. + * @param descriptor the method's descriptor (see {@link Type}). + * @param bootstrapMethodHandle the bootstrap method. + * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be + * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link + * Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify + * the content of the array so a caller should expect that this array may change. + */ + public void visitInvokeDynamicInsn( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + if (api < Opcodes.ASM5) { + throw new UnsupportedOperationException(REQUIRES_ASM5); + } + if (mv != null) { + mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); + } + } + + /** + * Visits a jump instruction. A jump instruction is an instruction that may jump to another + * instruction. + * + * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ, + * IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, + * IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. + * @param label the operand of the instruction to be visited. This operand is a label that + * designates the instruction to which the jump instruction may jump. + */ + public void visitJumpInsn(final int opcode, final Label label) { + if (mv != null) { + mv.visitJumpInsn(opcode, label); + } + } + + /** + * Visits a label. A label designates the instruction that will be visited just after it. + * + * @param label a {@link Label} object. + */ + public void visitLabel(final Label label) { + if (mv != null) { + mv.visitLabel(label); + } + } + + // ----------------------------------------------------------------------------------------------- + // Special instructions + // ----------------------------------------------------------------------------------------------- + + /** + * Visits a LDC instruction. Note that new constant types may be added in future versions of the + * Java Virtual Machine. To easily detect new constant types, implementations of this method + * should check for unexpected constant types, like this: + * + *
    +      * if (cst instanceof Integer) {
    +      *     // ...
    +      * } else if (cst instanceof Float) {
    +      *     // ...
    +      * } else if (cst instanceof Long) {
    +      *     // ...
    +      * } else if (cst instanceof Double) {
    +      *     // ...
    +      * } else if (cst instanceof String) {
    +      *     // ...
    +      * } else if (cst instanceof Type) {
    +      *     int sort = ((Type) cst).getSort();
    +      *     if (sort == Type.OBJECT) {
    +      *         // ...
    +      *     } else if (sort == Type.ARRAY) {
    +      *         // ...
    +      *     } else if (sort == Type.METHOD) {
    +      *         // ...
    +      *     } else {
    +      *         // throw an exception
    +      *     }
    +      * } else if (cst instanceof Handle) {
    +      *     // ...
    +      * } else if (cst instanceof ConstantDynamic) {
    +      *     // ...
    +      * } else {
    +      *     // throw an exception
    +      * }
    +      * 
    + * + * @param value the constant to be loaded on the stack. This parameter must be a non null {@link + * Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link + * Type} of OBJECT or ARRAY sort for {@code .class} constants, for classes whose version is + * 49, a {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle + * constants, for classes whose version is 51 or a {@link ConstantDynamic} for a constant + * dynamic for classes whose version is 55. + */ + public void visitLdcInsn(final Object value) { + if (api < Opcodes.ASM5 + && (value instanceof Handle + || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) { + throw new UnsupportedOperationException(REQUIRES_ASM5); + } + if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) { + throw new UnsupportedOperationException("This feature requires ASM7"); + } + if (mv != null) { + mv.visitLdcInsn(value); + } + } + + /** + * Visits an IINC instruction. + * + * @param varIndex index of the local variable to be incremented. + * @param increment amount to increment the local variable by. + */ + public void visitIincInsn(final int varIndex, final int increment) { + if (mv != null) { + mv.visitIincInsn(varIndex, increment); + } + } + + /** + * Visits a TABLESWITCH instruction. + * + * @param min the minimum key value. + * @param max the maximum key value. + * @param dflt beginning of the default handler block. + * @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the + * handler block for the {@code min + i} key. + */ + public void visitTableSwitchInsn( + final int min, final int max, final Label dflt, final Label... labels) { + if (mv != null) { + mv.visitTableSwitchInsn(min, max, dflt, labels); + } + } + + /** + * Visits a LOOKUPSWITCH instruction. + * + * @param dflt beginning of the default handler block. + * @param keys the values of the keys. + * @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the + * handler block for the {@code keys[i]} key. + */ + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { + if (mv != null) { + mv.visitLookupSwitchInsn(dflt, keys, labels); + } + } + + /** + * Visits a MULTIANEWARRAY instruction. + * + * @param descriptor an array type descriptor (see {@link Type}). + * @param numDimensions the number of dimensions of the array to allocate. + */ + public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { + if (mv != null) { + mv.visitMultiANewArrayInsn(descriptor, numDimensions); + } + } + + /** + * Visits an annotation on an instruction. This method must be called just after the + * annotated instruction. It can be called several times for the same instruction. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#INSTANCEOF}, {@link TypeReference#NEW}, {@link + * TypeReference#CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE}, {@link + * TypeReference#CAST}, {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link + * TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT}, {@link + * TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link + * TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitInsnAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (api < Opcodes.ASM5) { + throw new UnsupportedOperationException(REQUIRES_ASM5); + } + if (mv != null) { + return mv.visitInsnAnnotation(typeRef, typePath, descriptor, visible); + } + return null; + } + + // ----------------------------------------------------------------------------------------------- + // Exceptions table entries, debug information, max stack and max locals + // ----------------------------------------------------------------------------------------------- + + /** + * Visits a try catch block. + * + * @param start the beginning of the exception handler's scope (inclusive). + * @param end the end of the exception handler's scope (exclusive). + * @param handler the beginning of the exception handler's code. + * @param type the internal name of the type of exceptions handled by the handler (see {@link + * Type#getInternalName()}), or {@literal null} to catch any exceptions (for "finally" + * blocks). + * @throws IllegalArgumentException if one of the labels has already been visited by this visitor + * (by the {@link #visitLabel} method). + */ + public void visitTryCatchBlock( + final Label start, final Label end, final Label handler, final String type) { + if (mv != null) { + mv.visitTryCatchBlock(start, end, handler, type); + } + } + + /** + * Visits an annotation on an exception handler type. This method must be called after the + * {@link #visitTryCatchBlock} for the annotated exception handler. It can be called several times + * for the same exception handler. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#EXCEPTION_PARAMETER}. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitTryCatchAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (api < Opcodes.ASM5) { + throw new UnsupportedOperationException(REQUIRES_ASM5); + } + if (mv != null) { + return mv.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible); + } + return null; + } + + /** + * Visits a local variable declaration. + * + * @param name the name of a local variable. + * @param descriptor the type descriptor of this local variable. + * @param signature the type signature of this local variable. May be {@literal null} if the local + * variable type does not use generic types. + * @param start the first instruction corresponding to the scope of this local variable + * (inclusive). + * @param end the last instruction corresponding to the scope of this local variable (exclusive). + * @param index the local variable's index. + * @throws IllegalArgumentException if one of the labels has not already been visited by this + * visitor (by the {@link #visitLabel} method). + */ + public void visitLocalVariable( + final String name, + final String descriptor, + final String signature, + final Label start, + final Label end, + final int index) { + if (mv != null) { + mv.visitLocalVariable(name, descriptor, signature, start, end, index); + } + } + + /** + * Visits an annotation on a local variable type. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE}. See {@link + * TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param start the fist instructions corresponding to the continuous ranges that make the scope + * of this local variable (inclusive). + * @param end the last instructions corresponding to the continuous ranges that make the scope of + * this local variable (exclusive). This array must have the same size as the 'start' array. + * @param index the local variable's index in each range. This array must have the same size as + * the 'start' array. + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitLocalVariableAnnotation( + final int typeRef, + final TypePath typePath, + final Label[] start, + final Label[] end, + final int[] index, + final String descriptor, + final boolean visible) { + if (api < Opcodes.ASM5) { + throw new UnsupportedOperationException(REQUIRES_ASM5); + } + if (mv != null) { + return mv.visitLocalVariableAnnotation( + typeRef, typePath, start, end, index, descriptor, visible); + } + return null; + } + + /** + * Visits a line number declaration. + * + * @param line a line number. This number refers to the source file from which the class was + * compiled. + * @param start the first instruction corresponding to this line number. + * @throws IllegalArgumentException if {@code start} has not already been visited by this visitor + * (by the {@link #visitLabel} method). + */ + public void visitLineNumber(final int line, final Label start) { + if (mv != null) { + mv.visitLineNumber(line, start); + } + } + + /** + * Visits the maximum stack size and the maximum number of local variables of the method. + * + * @param maxStack maximum stack size of the method. + * @param maxLocals maximum number of local variables for the method. + */ + public void visitMaxs(final int maxStack, final int maxLocals) { + if (mv != null) { + mv.visitMaxs(maxStack, maxLocals); + } + } + + /** + * Visits the end of the method. This method, which is the last one to be called, is used to + * inform the visitor that all the annotations and attributes of the method have been visited. + */ + public void visitEnd() { + if (mv != null) { + mv.visitEnd(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodWriter.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..7df8abdeb2eb5df718c282f664111c9021335bb4 GIT binary patch literal 35956 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 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodWriter.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodWriter.java new file mode 100644 index 00000000..efeffc7b --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodWriter.java @@ -0,0 +1,2426 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A {@link MethodVisitor} that generates a corresponding 'method_info' structure, as defined in the + * Java Virtual Machine Specification (JVMS). + * + * @see JVMS + * 4.6 + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +final class MethodWriter extends MethodVisitor { + + /** Indicates that nothing must be computed. */ + static final int COMPUTE_NOTHING = 0; + + /** + * Indicates that the maximum stack size and the maximum number of local variables must be + * computed, from scratch. + */ + static final int COMPUTE_MAX_STACK_AND_LOCAL = 1; + + /** + * Indicates that the maximum stack size and the maximum number of local variables must be + * computed, from the existing stack map frames. This can be done more efficiently than with the + * control flow graph algorithm used for {@link #COMPUTE_MAX_STACK_AND_LOCAL}, by using a linear + * scan of the bytecode instructions. + */ + static final int COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES = 2; + + /** + * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not + * computed. They should all be of type F_NEW and should be sufficient to compute the content of + * the F_INSERT frames, together with the bytecode instructions between a F_NEW and a F_INSERT + * frame - and without any knowledge of the type hierarchy (by definition of F_INSERT). + */ + static final int COMPUTE_INSERTED_FRAMES = 3; + + /** + * Indicates that all the stack map frames must be computed. In this case the maximum stack size + * and the maximum number of local variables is also computed. + */ + static final int COMPUTE_ALL_FRAMES = 4; + + /** Indicates that {@link #STACK_SIZE_DELTA} is not applicable (not constant or never used). */ + private static final int NA = 0; + + /** + * The stack size variation corresponding to each JVM opcode. The stack size variation for opcode + * 'o' is given by the array element at index 'o'. + * + * @see JVMS 6 + */ + private static final int[] STACK_SIZE_DELTA = { + 0, // nop = 0 (0x0) + 1, // aconst_null = 1 (0x1) + 1, // iconst_m1 = 2 (0x2) + 1, // iconst_0 = 3 (0x3) + 1, // iconst_1 = 4 (0x4) + 1, // iconst_2 = 5 (0x5) + 1, // iconst_3 = 6 (0x6) + 1, // iconst_4 = 7 (0x7) + 1, // iconst_5 = 8 (0x8) + 2, // lconst_0 = 9 (0x9) + 2, // lconst_1 = 10 (0xa) + 1, // fconst_0 = 11 (0xb) + 1, // fconst_1 = 12 (0xc) + 1, // fconst_2 = 13 (0xd) + 2, // dconst_0 = 14 (0xe) + 2, // dconst_1 = 15 (0xf) + 1, // bipush = 16 (0x10) + 1, // sipush = 17 (0x11) + 1, // ldc = 18 (0x12) + NA, // ldc_w = 19 (0x13) + NA, // ldc2_w = 20 (0x14) + 1, // iload = 21 (0x15) + 2, // lload = 22 (0x16) + 1, // fload = 23 (0x17) + 2, // dload = 24 (0x18) + 1, // aload = 25 (0x19) + NA, // iload_0 = 26 (0x1a) + NA, // iload_1 = 27 (0x1b) + NA, // iload_2 = 28 (0x1c) + NA, // iload_3 = 29 (0x1d) + NA, // lload_0 = 30 (0x1e) + NA, // lload_1 = 31 (0x1f) + NA, // lload_2 = 32 (0x20) + NA, // lload_3 = 33 (0x21) + NA, // fload_0 = 34 (0x22) + NA, // fload_1 = 35 (0x23) + NA, // fload_2 = 36 (0x24) + NA, // fload_3 = 37 (0x25) + NA, // dload_0 = 38 (0x26) + NA, // dload_1 = 39 (0x27) + NA, // dload_2 = 40 (0x28) + NA, // dload_3 = 41 (0x29) + NA, // aload_0 = 42 (0x2a) + NA, // aload_1 = 43 (0x2b) + NA, // aload_2 = 44 (0x2c) + NA, // aload_3 = 45 (0x2d) + -1, // iaload = 46 (0x2e) + 0, // laload = 47 (0x2f) + -1, // faload = 48 (0x30) + 0, // daload = 49 (0x31) + -1, // aaload = 50 (0x32) + -1, // baload = 51 (0x33) + -1, // caload = 52 (0x34) + -1, // saload = 53 (0x35) + -1, // istore = 54 (0x36) + -2, // lstore = 55 (0x37) + -1, // fstore = 56 (0x38) + -2, // dstore = 57 (0x39) + -1, // astore = 58 (0x3a) + NA, // istore_0 = 59 (0x3b) + NA, // istore_1 = 60 (0x3c) + NA, // istore_2 = 61 (0x3d) + NA, // istore_3 = 62 (0x3e) + NA, // lstore_0 = 63 (0x3f) + NA, // lstore_1 = 64 (0x40) + NA, // lstore_2 = 65 (0x41) + NA, // lstore_3 = 66 (0x42) + NA, // fstore_0 = 67 (0x43) + NA, // fstore_1 = 68 (0x44) + NA, // fstore_2 = 69 (0x45) + NA, // fstore_3 = 70 (0x46) + NA, // dstore_0 = 71 (0x47) + NA, // dstore_1 = 72 (0x48) + NA, // dstore_2 = 73 (0x49) + NA, // dstore_3 = 74 (0x4a) + NA, // astore_0 = 75 (0x4b) + NA, // astore_1 = 76 (0x4c) + NA, // astore_2 = 77 (0x4d) + NA, // astore_3 = 78 (0x4e) + -3, // iastore = 79 (0x4f) + -4, // lastore = 80 (0x50) + -3, // fastore = 81 (0x51) + -4, // dastore = 82 (0x52) + -3, // aastore = 83 (0x53) + -3, // bastore = 84 (0x54) + -3, // castore = 85 (0x55) + -3, // sastore = 86 (0x56) + -1, // pop = 87 (0x57) + -2, // pop2 = 88 (0x58) + 1, // dup = 89 (0x59) + 1, // dup_x1 = 90 (0x5a) + 1, // dup_x2 = 91 (0x5b) + 2, // dup2 = 92 (0x5c) + 2, // dup2_x1 = 93 (0x5d) + 2, // dup2_x2 = 94 (0x5e) + 0, // swap = 95 (0x5f) + -1, // iadd = 96 (0x60) + -2, // ladd = 97 (0x61) + -1, // fadd = 98 (0x62) + -2, // dadd = 99 (0x63) + -1, // isub = 100 (0x64) + -2, // lsub = 101 (0x65) + -1, // fsub = 102 (0x66) + -2, // dsub = 103 (0x67) + -1, // imul = 104 (0x68) + -2, // lmul = 105 (0x69) + -1, // fmul = 106 (0x6a) + -2, // dmul = 107 (0x6b) + -1, // idiv = 108 (0x6c) + -2, // ldiv = 109 (0x6d) + -1, // fdiv = 110 (0x6e) + -2, // ddiv = 111 (0x6f) + -1, // irem = 112 (0x70) + -2, // lrem = 113 (0x71) + -1, // frem = 114 (0x72) + -2, // drem = 115 (0x73) + 0, // ineg = 116 (0x74) + 0, // lneg = 117 (0x75) + 0, // fneg = 118 (0x76) + 0, // dneg = 119 (0x77) + -1, // ishl = 120 (0x78) + -1, // lshl = 121 (0x79) + -1, // ishr = 122 (0x7a) + -1, // lshr = 123 (0x7b) + -1, // iushr = 124 (0x7c) + -1, // lushr = 125 (0x7d) + -1, // iand = 126 (0x7e) + -2, // land = 127 (0x7f) + -1, // ior = 128 (0x80) + -2, // lor = 129 (0x81) + -1, // ixor = 130 (0x82) + -2, // lxor = 131 (0x83) + 0, // iinc = 132 (0x84) + 1, // i2l = 133 (0x85) + 0, // i2f = 134 (0x86) + 1, // i2d = 135 (0x87) + -1, // l2i = 136 (0x88) + -1, // l2f = 137 (0x89) + 0, // l2d = 138 (0x8a) + 0, // f2i = 139 (0x8b) + 1, // f2l = 140 (0x8c) + 1, // f2d = 141 (0x8d) + -1, // d2i = 142 (0x8e) + 0, // d2l = 143 (0x8f) + -1, // d2f = 144 (0x90) + 0, // i2b = 145 (0x91) + 0, // i2c = 146 (0x92) + 0, // i2s = 147 (0x93) + -3, // lcmp = 148 (0x94) + -1, // fcmpl = 149 (0x95) + -1, // fcmpg = 150 (0x96) + -3, // dcmpl = 151 (0x97) + -3, // dcmpg = 152 (0x98) + -1, // ifeq = 153 (0x99) + -1, // ifne = 154 (0x9a) + -1, // iflt = 155 (0x9b) + -1, // ifge = 156 (0x9c) + -1, // ifgt = 157 (0x9d) + -1, // ifle = 158 (0x9e) + -2, // if_icmpeq = 159 (0x9f) + -2, // if_icmpne = 160 (0xa0) + -2, // if_icmplt = 161 (0xa1) + -2, // if_icmpge = 162 (0xa2) + -2, // if_icmpgt = 163 (0xa3) + -2, // if_icmple = 164 (0xa4) + -2, // if_acmpeq = 165 (0xa5) + -2, // if_acmpne = 166 (0xa6) + 0, // goto = 167 (0xa7) + 1, // jsr = 168 (0xa8) + 0, // ret = 169 (0xa9) + -1, // tableswitch = 170 (0xaa) + -1, // lookupswitch = 171 (0xab) + -1, // ireturn = 172 (0xac) + -2, // lreturn = 173 (0xad) + -1, // freturn = 174 (0xae) + -2, // dreturn = 175 (0xaf) + -1, // areturn = 176 (0xb0) + 0, // return = 177 (0xb1) + NA, // getstatic = 178 (0xb2) + NA, // putstatic = 179 (0xb3) + NA, // getfield = 180 (0xb4) + NA, // putfield = 181 (0xb5) + NA, // invokevirtual = 182 (0xb6) + NA, // invokespecial = 183 (0xb7) + NA, // invokestatic = 184 (0xb8) + NA, // invokeinterface = 185 (0xb9) + NA, // invokedynamic = 186 (0xba) + 1, // new = 187 (0xbb) + 0, // newarray = 188 (0xbc) + 0, // anewarray = 189 (0xbd) + 0, // arraylength = 190 (0xbe) + NA, // athrow = 191 (0xbf) + 0, // checkcast = 192 (0xc0) + 0, // instanceof = 193 (0xc1) + -1, // monitorenter = 194 (0xc2) + -1, // monitorexit = 195 (0xc3) + NA, // wide = 196 (0xc4) + NA, // multianewarray = 197 (0xc5) + -1, // ifnull = 198 (0xc6) + -1, // ifnonnull = 199 (0xc7) + NA, // goto_w = 200 (0xc8) + NA // jsr_w = 201 (0xc9) + }; + + /** Where the constants used in this MethodWriter must be stored. */ + private final SymbolTable symbolTable; + + // Note: fields are ordered as in the method_info structure, and those related to attributes are + // ordered as in Section 4.7 of the JVMS. + + /** + * The access_flags field of the method_info JVMS structure. This field can contain ASM specific + * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the + * ClassFile structure. + */ + private final int accessFlags; + + /** The name_index field of the method_info JVMS structure. */ + private final int nameIndex; + + /** The name of this method. */ + private final String name; + + /** The descriptor_index field of the method_info JVMS structure. */ + private final int descriptorIndex; + + /** The descriptor of this method. */ + private final String descriptor; + + // Code attribute fields and sub attributes: + + /** The max_stack field of the Code attribute. */ + private int maxStack; + + /** The max_locals field of the Code attribute. */ + private int maxLocals; + + /** The 'code' field of the Code attribute. */ + private final ByteVector code = new ByteVector(); + + /** + * The first element in the exception handler list (used to generate the exception_table of the + * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May + * be {@literal null}. + */ + private Handler firstHandler; + + /** + * The last element in the exception handler list (used to generate the exception_table of the + * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May + * be {@literal null}. + */ + private Handler lastHandler; + + /** The line_number_table_length field of the LineNumberTable code attribute. */ + private int lineNumberTableLength; + + /** The line_number_table array of the LineNumberTable code attribute, or {@literal null}. */ + private ByteVector lineNumberTable; + + /** The local_variable_table_length field of the LocalVariableTable code attribute. */ + private int localVariableTableLength; + + /** + * The local_variable_table array of the LocalVariableTable code attribute, or {@literal null}. + */ + private ByteVector localVariableTable; + + /** The local_variable_type_table_length field of the LocalVariableTypeTable code attribute. */ + private int localVariableTypeTableLength; + + /** + * The local_variable_type_table array of the LocalVariableTypeTable code attribute, or {@literal + * null}. + */ + private ByteVector localVariableTypeTable; + + /** The number_of_entries field of the StackMapTable code attribute. */ + private int stackMapTableNumberOfEntries; + + /** The 'entries' array of the StackMapTable code attribute. */ + private ByteVector stackMapTableEntries; + + /** + * The last runtime visible type annotation of the Code attribute. The previous ones can be + * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastCodeRuntimeVisibleTypeAnnotation; + + /** + * The last runtime invisible type annotation of the Code attribute. The previous ones can be + * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastCodeRuntimeInvisibleTypeAnnotation; + + /** + * The first non standard attribute of the Code attribute. The next ones can be accessed with the + * {@link Attribute#nextAttribute} field. May be {@literal null}. + * + *

    WARNING: this list stores the attributes in the reverse order of their visit. + * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link + * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the + * reverse order specified by the user. + */ + private Attribute firstCodeAttribute; + + // Other method_info attributes: + + /** The number_of_exceptions field of the Exceptions attribute. */ + private final int numberOfExceptions; + + /** The exception_index_table array of the Exceptions attribute, or {@literal null}. */ + private final int[] exceptionIndexTable; + + /** The signature_index field of the Signature attribute. */ + private final int signatureIndex; + + /** + * The last runtime visible annotation of this method. The previous ones can be accessed with the + * {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleAnnotation; + + /** + * The last runtime invisible annotation of this method. The previous ones can be accessed with + * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleAnnotation; + + /** The number of method parameters that can have runtime visible annotations, or 0. */ + private int visibleAnnotableParameterCount; + + /** + * The runtime visible parameter annotations of this method. Each array element contains the last + * annotation of a parameter (which can be {@literal null} - the previous ones can be accessed + * with the {@link AnnotationWriter#previousAnnotation} field). May be {@literal null}. + */ + private AnnotationWriter[] lastRuntimeVisibleParameterAnnotations; + + /** The number of method parameters that can have runtime visible annotations, or 0. */ + private int invisibleAnnotableParameterCount; + + /** + * The runtime invisible parameter annotations of this method. Each array element contains the + * last annotation of a parameter (which can be {@literal null} - the previous ones can be + * accessed with the {@link AnnotationWriter#previousAnnotation} field). May be {@literal null}. + */ + private AnnotationWriter[] lastRuntimeInvisibleParameterAnnotations; + + /** + * The last runtime visible type annotation of this method. The previous ones can be accessed with + * the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleTypeAnnotation; + + /** + * The last runtime invisible type annotation of this method. The previous ones can be accessed + * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; + + /** The default_value field of the AnnotationDefault attribute, or {@literal null}. */ + private ByteVector defaultValue; + + /** The parameters_count field of the MethodParameters attribute. */ + private int parametersCount; + + /** The 'parameters' array of the MethodParameters attribute, or {@literal null}. */ + private ByteVector parameters; + + /** + * The first non standard attribute of this method. The next ones can be accessed with the {@link + * Attribute#nextAttribute} field. May be {@literal null}. + * + *

    WARNING: this list stores the attributes in the reverse order of their visit. + * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link + * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the + * reverse order specified by the user. + */ + private Attribute firstAttribute; + + // ----------------------------------------------------------------------------------------------- + // Fields used to compute the maximum stack size and number of locals, and the stack map frames + // ----------------------------------------------------------------------------------------------- + + /** + * Indicates what must be computed. Must be one of {@link #COMPUTE_ALL_FRAMES}, {@link + * #COMPUTE_INSERTED_FRAMES}, {@link COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link + * #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}. + */ + private final int compute; + + /** + * The first basic block of the method. The next ones (in bytecode offset order) can be accessed + * with the {@link Label#nextBasicBlock} field. + */ + private Label firstBasicBlock; + + /** + * The last basic block of the method (in bytecode offset order). This field is updated each time + * a basic block is encountered, and is used to append it at the end of the basic block list. + */ + private Label lastBasicBlock; + + /** + * The current basic block, i.e. the basic block of the last visited instruction. When {@link + * #compute} is equal to {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_ALL_FRAMES}, this + * field is {@literal null} for unreachable code. When {@link #compute} is equal to {@link + * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES} or {@link #COMPUTE_INSERTED_FRAMES}, this field stays + * unchanged throughout the whole method (i.e. the whole code is seen as a single basic block; + * indeed, the existing frames are sufficient by hypothesis to compute any intermediate frame - + * and the maximum stack size as well - without using any control flow graph). + */ + private Label currentBasicBlock; + + /** + * The relative stack size after the last visited instruction. This size is relative to the + * beginning of {@link #currentBasicBlock}, i.e. the true stack size after the last visited + * instruction is equal to the {@link Label#inputStackSize} of the current basic block plus {@link + * #relativeStackSize}. When {@link #compute} is equal to {@link + * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of + * the method, so this relative size is also equal to the absolute stack size after the last + * visited instruction. + */ + private int relativeStackSize; + + /** + * The maximum relative stack size after the last visited instruction. This size is relative to + * the beginning of {@link #currentBasicBlock}, i.e. the true maximum stack size after the last + * visited instruction is equal to the {@link Label#inputStackSize} of the current basic block + * plus {@link #maxRelativeStackSize}.When {@link #compute} is equal to {@link + * #COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES}, {@link #currentBasicBlock} is always the start of + * the method, so this relative size is also equal to the absolute maximum stack size after the + * last visited instruction. + */ + private int maxRelativeStackSize; + + /** The number of local variables in the last visited stack map frame. */ + private int currentLocals; + + /** The bytecode offset of the last frame that was written in {@link #stackMapTableEntries}. */ + private int previousFrameOffset; + + /** + * The last frame that was written in {@link #stackMapTableEntries}. This field has the same + * format as {@link #currentFrame}. + */ + private int[] previousFrame; + + /** + * The current stack map frame. The first element contains the bytecode offset of the instruction + * to which the frame corresponds, the second element is the number of locals and the third one is + * the number of stack elements. The local variables start at index 3 and are followed by the + * operand stack elements. In summary frame[0] = offset, frame[1] = numLocal, frame[2] = numStack. + * Local variables and operand stack entries contain abstract types, as defined in {@link Frame}, + * but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND}, {@link + * Frame#UNINITIALIZED_KIND} or {@link Frame#FORWARD_UNINITIALIZED_KIND} abstract types. Long and + * double types use only one array entry. + */ + private int[] currentFrame; + + /** Whether this method contains subroutines. */ + private boolean hasSubroutines; + + // ----------------------------------------------------------------------------------------------- + // Other miscellaneous status fields + // ----------------------------------------------------------------------------------------------- + + /** Whether the bytecode of this method contains ASM specific instructions. */ + private boolean hasAsmInstructions; + + /** + * The start offset of the last visited instruction. Used to set the offset field of type + * annotations of type 'offset_target' (see JVMS + * 4.7.20.1). + */ + private int lastBytecodeOffset; + + /** + * The offset in bytes in {@link SymbolTable#getSource} from which the method_info for this method + * (excluding its first 6 bytes) must be copied, or 0. + */ + private int sourceOffset; + + /** + * The length in bytes in {@link SymbolTable#getSource} which must be copied to get the + * method_info for this method (excluding its first 6 bytes for access_flags, name_index and + * descriptor_index). + */ + private int sourceLength; + + // ----------------------------------------------------------------------------------------------- + // Constructor and accessors + // ----------------------------------------------------------------------------------------------- + + /** + * Constructs a new {@link MethodWriter}. + * + * @param symbolTable where the constants used in this AnnotationWriter must be stored. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param descriptor the method's descriptor (see {@link Type}). + * @param signature the method's signature. May be {@literal null}. + * @param exceptions the internal names of the method's exceptions. May be {@literal null}. + * @param compute indicates what must be computed (see #compute). + */ + MethodWriter( + final SymbolTable symbolTable, + final int access, + final String name, + final String descriptor, + final String signature, + final String[] exceptions, + final int compute) { + super(/* latest api = */ Opcodes.ASM9); + this.symbolTable = symbolTable; + this.accessFlags = "".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access; + this.nameIndex = symbolTable.addConstantUtf8(name); + this.name = name; + this.descriptorIndex = symbolTable.addConstantUtf8(descriptor); + this.descriptor = descriptor; + this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature); + if (exceptions != null && exceptions.length > 0) { + numberOfExceptions = exceptions.length; + this.exceptionIndexTable = new int[numberOfExceptions]; + for (int i = 0; i < numberOfExceptions; ++i) { + this.exceptionIndexTable[i] = symbolTable.addConstantClass(exceptions[i]).index; + } + } else { + numberOfExceptions = 0; + this.exceptionIndexTable = null; + } + this.compute = compute; + if (compute != COMPUTE_NOTHING) { + // Update maxLocals and currentLocals. + int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2; + if ((access & Opcodes.ACC_STATIC) != 0) { + --argumentsSize; + } + maxLocals = argumentsSize; + currentLocals = argumentsSize; + // Create and visit the label for the first basic block. + firstBasicBlock = new Label(); + visitLabel(firstBasicBlock); + } + } + + boolean hasFrames() { + return stackMapTableNumberOfEntries > 0; + } + + boolean hasAsmInstructions() { + return hasAsmInstructions; + } + + // ----------------------------------------------------------------------------------------------- + // Implementation of the MethodVisitor abstract class + // ----------------------------------------------------------------------------------------------- + + @Override + public void visitParameter(final String name, final int access) { + if (parameters == null) { + parameters = new ByteVector(); + } + ++parametersCount; + parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access); + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + defaultValue = new ByteVector(); + return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null); + } + + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation); + } else { + return lastRuntimeInvisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation); + } + } + + @Override + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation); + } else { + return lastRuntimeInvisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation); + } + } + + @Override + public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) { + if (visible) { + visibleAnnotableParameterCount = parameterCount; + } else { + invisibleAnnotableParameterCount = parameterCount; + } + } + + @Override + public AnnotationVisitor visitParameterAnnotation( + final int parameter, final String annotationDescriptor, final boolean visible) { + if (visible) { + if (lastRuntimeVisibleParameterAnnotations == null) { + lastRuntimeVisibleParameterAnnotations = + new AnnotationWriter[Type.getArgumentCount(descriptor)]; + } + return lastRuntimeVisibleParameterAnnotations[parameter] = + AnnotationWriter.create( + symbolTable, annotationDescriptor, lastRuntimeVisibleParameterAnnotations[parameter]); + } else { + if (lastRuntimeInvisibleParameterAnnotations == null) { + lastRuntimeInvisibleParameterAnnotations = + new AnnotationWriter[Type.getArgumentCount(descriptor)]; + } + return lastRuntimeInvisibleParameterAnnotations[parameter] = + AnnotationWriter.create( + symbolTable, + annotationDescriptor, + lastRuntimeInvisibleParameterAnnotations[parameter]); + } + } + + @Override + public void visitAttribute(final Attribute attribute) { + // Store the attributes in the reverse order of their visit by this method. + if (attribute.isCodeAttribute()) { + attribute.nextAttribute = firstCodeAttribute; + firstCodeAttribute = attribute; + } else { + attribute.nextAttribute = firstAttribute; + firstAttribute = attribute; + } + } + + @Override + public void visitCode() { + // Nothing to do. + } + + @Override + public void visitFrame( + final int type, + final int numLocal, + final Object[] local, + final int numStack, + final Object[] stack) { + if (compute == COMPUTE_ALL_FRAMES) { + return; + } + + if (compute == COMPUTE_INSERTED_FRAMES) { + if (currentBasicBlock.frame == null) { + // This should happen only once, for the implicit first frame (which is explicitly visited + // in ClassReader if the EXPAND_ASM_INSNS option is used - and COMPUTE_INSERTED_FRAMES + // can't be set if EXPAND_ASM_INSNS is not used). + currentBasicBlock.frame = new CurrentFrame(currentBasicBlock); + currentBasicBlock.frame.setInputFrameFromDescriptor( + symbolTable, accessFlags, descriptor, numLocal); + currentBasicBlock.frame.accept(this); + } else { + if (type == Opcodes.F_NEW) { + currentBasicBlock.frame.setInputFrameFromApiFormat( + symbolTable, numLocal, local, numStack, stack); + } + // If type is not F_NEW then it is F_INSERT by hypothesis, and currentBlock.frame contains + // the stack map frame at the current instruction, computed from the last F_NEW frame and + // the bytecode instructions in between (via calls to CurrentFrame#execute). + currentBasicBlock.frame.accept(this); + } + } else if (type == Opcodes.F_NEW) { + if (previousFrame == null) { + int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2; + Frame implicitFirstFrame = new Frame(new Label()); + implicitFirstFrame.setInputFrameFromDescriptor( + symbolTable, accessFlags, descriptor, argumentsSize); + implicitFirstFrame.accept(this); + } + currentLocals = numLocal; + int frameIndex = visitFrameStart(code.length, numLocal, numStack); + for (int i = 0; i < numLocal; ++i) { + currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]); + } + for (int i = 0; i < numStack; ++i) { + currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]); + } + visitFrameEnd(); + } else { + if (symbolTable.getMajorVersion() < Opcodes.V1_6) { + throw new IllegalArgumentException("Class versions V1_5 or less must use F_NEW frames."); + } + int offsetDelta; + if (stackMapTableEntries == null) { + stackMapTableEntries = new ByteVector(); + offsetDelta = code.length; + } else { + offsetDelta = code.length - previousFrameOffset - 1; + if (offsetDelta < 0) { + if (type == Opcodes.F_SAME) { + return; + } else { + throw new IllegalStateException(); + } + } + } + + switch (type) { + case Opcodes.F_FULL: + currentLocals = numLocal; + stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal); + for (int i = 0; i < numLocal; ++i) { + putFrameType(local[i]); + } + stackMapTableEntries.putShort(numStack); + for (int i = 0; i < numStack; ++i) { + putFrameType(stack[i]); + } + break; + case Opcodes.F_APPEND: + currentLocals += numLocal; + stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + numLocal).putShort(offsetDelta); + for (int i = 0; i < numLocal; ++i) { + putFrameType(local[i]); + } + break; + case Opcodes.F_CHOP: + currentLocals -= numLocal; + stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - numLocal).putShort(offsetDelta); + break; + case Opcodes.F_SAME: + if (offsetDelta < 64) { + stackMapTableEntries.putByte(offsetDelta); + } else { + stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta); + } + break; + case Opcodes.F_SAME1: + if (offsetDelta < 64) { + stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta); + } else { + stackMapTableEntries + .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) + .putShort(offsetDelta); + } + putFrameType(stack[0]); + break; + default: + throw new IllegalArgumentException(); + } + + previousFrameOffset = code.length; + ++stackMapTableNumberOfEntries; + } + + if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) { + relativeStackSize = numStack; + for (int i = 0; i < numStack; ++i) { + if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { + relativeStackSize++; + } + } + if (relativeStackSize > maxRelativeStackSize) { + maxRelativeStackSize = relativeStackSize; + } + } + + maxStack = Math.max(maxStack, numStack); + maxLocals = Math.max(maxLocals, currentLocals); + } + + @Override + public void visitInsn(final int opcode) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + code.putByte(opcode); + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute(opcode, 0, null, null); + } else { + int size = relativeStackSize + STACK_SIZE_DELTA[opcode]; + if (size > maxRelativeStackSize) { + maxRelativeStackSize = size; + } + relativeStackSize = size; + } + if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { + endCurrentBasicBlockWithNoSuccessor(); + } + } + } + + @Override + public void visitIntInsn(final int opcode, final int operand) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + if (opcode == Opcodes.SIPUSH) { + code.put12(opcode, operand); + } else { // BIPUSH or NEWARRAY + code.put11(opcode, operand); + } + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute(opcode, operand, null, null); + } else if (opcode != Opcodes.NEWARRAY) { + // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY. + int size = relativeStackSize + 1; + if (size > maxRelativeStackSize) { + maxRelativeStackSize = size; + } + relativeStackSize = size; + } + } + } + + @Override + public void visitVarInsn(final int opcode, final int varIndex) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + if (varIndex < 4 && opcode != Opcodes.RET) { + int optimizedOpcode; + if (opcode < Opcodes.ISTORE) { + optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + varIndex; + } else { + optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + varIndex; + } + code.putByte(optimizedOpcode); + } else if (varIndex >= 256) { + code.putByte(Constants.WIDE).put12(opcode, varIndex); + } else { + code.put11(opcode, varIndex); + } + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute(opcode, varIndex, null, null); + } else { + if (opcode == Opcodes.RET) { + // No stack size delta. + currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_END; + currentBasicBlock.outputStackSize = (short) relativeStackSize; + endCurrentBasicBlockWithNoSuccessor(); + } else { // xLOAD or xSTORE + int size = relativeStackSize + STACK_SIZE_DELTA[opcode]; + if (size > maxRelativeStackSize) { + maxRelativeStackSize = size; + } + relativeStackSize = size; + } + } + } + if (compute != COMPUTE_NOTHING) { + int currentMaxLocals; + if (opcode == Opcodes.LLOAD + || opcode == Opcodes.DLOAD + || opcode == Opcodes.LSTORE + || opcode == Opcodes.DSTORE) { + currentMaxLocals = varIndex + 2; + } else { + currentMaxLocals = varIndex + 1; + } + if (currentMaxLocals > maxLocals) { + maxLocals = currentMaxLocals; + } + } + if (opcode >= Opcodes.ISTORE && compute == COMPUTE_ALL_FRAMES && firstHandler != null) { + // If there are exception handler blocks, each instruction within a handler range is, in + // theory, a basic block (since execution can jump from this instruction to the exception + // handler). As a consequence, the local variable types at the beginning of the handler + // block should be the merge of the local variable types at all the instructions within the + // handler range. However, instead of creating a basic block for each instruction, we can + // get the same result in a more efficient way. Namely, by starting a new basic block after + // each xSTORE instruction, which is what we do here. + visitLabel(new Label()); + } + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + Symbol typeSymbol = symbolTable.addConstantClass(type); + code.put12(opcode, typeSymbol.index); + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable); + } else if (opcode == Opcodes.NEW) { + // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF. + int size = relativeStackSize + 1; + if (size > maxRelativeStackSize) { + maxRelativeStackSize = size; + } + relativeStackSize = size; + } + } + } + + @Override + public void visitFieldInsn( + final int opcode, final String owner, final String name, final String descriptor) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + Symbol fieldrefSymbol = symbolTable.addConstantFieldref(owner, name, descriptor); + code.put12(opcode, fieldrefSymbol.index); + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute(opcode, 0, fieldrefSymbol, symbolTable); + } else { + int size; + char firstDescChar = descriptor.charAt(0); + switch (opcode) { + case Opcodes.GETSTATIC: + size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 2 : 1); + break; + case Opcodes.PUTSTATIC: + size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1); + break; + case Opcodes.GETFIELD: + size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 1 : 0); + break; + case Opcodes.PUTFIELD: + default: + size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -3 : -2); + break; + } + if (size > maxRelativeStackSize) { + maxRelativeStackSize = size; + } + relativeStackSize = size; + } + } + } + + @Override + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + Symbol methodrefSymbol = symbolTable.addConstantMethodref(owner, name, descriptor, isInterface); + if (opcode == Opcodes.INVOKEINTERFACE) { + code.put12(Opcodes.INVOKEINTERFACE, methodrefSymbol.index) + .put11(methodrefSymbol.getArgumentsAndReturnSizes() >> 2, 0); + } else { + code.put12(opcode, methodrefSymbol.index); + } + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute(opcode, 0, methodrefSymbol, symbolTable); + } else { + int argumentsAndReturnSize = methodrefSymbol.getArgumentsAndReturnSizes(); + int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2); + int size; + if (opcode == Opcodes.INVOKESTATIC) { + size = relativeStackSize + stackSizeDelta + 1; + } else { + size = relativeStackSize + stackSizeDelta; + } + if (size > maxRelativeStackSize) { + maxRelativeStackSize = size; + } + relativeStackSize = size; + } + } + } + + @Override + public void visitInvokeDynamicInsn( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + Symbol invokeDynamicSymbol = + symbolTable.addConstantInvokeDynamic( + name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); + code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index); + code.putShort(0); + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable); + } else { + int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes(); + int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1; + int size = relativeStackSize + stackSizeDelta; + if (size > maxRelativeStackSize) { + maxRelativeStackSize = size; + } + relativeStackSize = size; + } + } + } + + @Override + public void visitJumpInsn(final int opcode, final Label label) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + // Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode. + int baseOpcode = + opcode >= Constants.GOTO_W ? opcode - Constants.WIDE_JUMP_OPCODE_DELTA : opcode; + boolean nextInsnIsJumpTarget = false; + if ((label.flags & Label.FLAG_RESOLVED) != 0 + && label.bytecodeOffset - code.length < Short.MIN_VALUE) { + // Case of a backward jump with an offset < -32768. In this case we automatically replace GOTO + // with GOTO_W, JSR with JSR_W and IFxxx with IFNOTxxx GOTO_W L:..., where + // IFNOTxxx is the "opposite" opcode of IFxxx (e.g. IFNE for IFEQ) and where designates + // the instruction just after the GOTO_W. + if (baseOpcode == Opcodes.GOTO) { + code.putByte(Constants.GOTO_W); + } else if (baseOpcode == Opcodes.JSR) { + code.putByte(Constants.JSR_W); + } else { + // Put the "opposite" opcode of baseOpcode. This can be done by flipping the least + // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ (with a + // pre and post offset by 1). The jump offset is 8 bytes (3 for IFNOTxxx, 5 for GOTO_W). + code.putByte(baseOpcode >= Opcodes.IFNULL ? baseOpcode ^ 1 : ((baseOpcode + 1) ^ 1) - 1); + code.putShort(8); + // Here we could put a GOTO_W in theory, but if ASM specific instructions are used in this + // method or another one, and if the class has frames, we will need to insert a frame after + // this GOTO_W during the additional ClassReader -> ClassWriter round trip to remove the ASM + // specific instructions. To not miss this additional frame, we need to use an ASM_GOTO_W + // here, which has the unfortunate effect of forcing this additional round trip (which in + // some case would not have been really necessary, but we can't know this at this point). + code.putByte(Constants.ASM_GOTO_W); + hasAsmInstructions = true; + // The instruction after the GOTO_W becomes the target of the IFNOT instruction. + nextInsnIsJumpTarget = true; + } + label.put(code, code.length - 1, true); + } else if (baseOpcode != opcode) { + // Case of a GOTO_W or JSR_W specified by the user (normally ClassReader when used to remove + // ASM specific instructions). In this case we keep the original instruction. + code.putByte(opcode); + label.put(code, code.length - 1, true); + } else { + // Case of a jump with an offset >= -32768, or of a jump with an unknown offset. In these + // cases we store the offset in 2 bytes (which will be increased via a ClassReader -> + // ClassWriter round trip if it turns out that 2 bytes are not sufficient). + code.putByte(baseOpcode); + label.put(code, code.length - 1, false); + } + + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + Label nextBasicBlock = null; + if (compute == COMPUTE_ALL_FRAMES) { + currentBasicBlock.frame.execute(baseOpcode, 0, null, null); + // Record the fact that 'label' is the target of a jump instruction. + label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; + // Add 'label' as a successor of the current basic block. + addSuccessorToCurrentBasicBlock(Edge.JUMP, label); + if (baseOpcode != Opcodes.GOTO) { + // The next instruction starts a new basic block (except for GOTO: by default the code + // following a goto is unreachable - unless there is an explicit label for it - and we + // should not compute stack frame types for its instructions). + nextBasicBlock = new Label(); + } + } else if (compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute(baseOpcode, 0, null, null); + } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) { + // No need to update maxRelativeStackSize (the stack size delta is always negative). + relativeStackSize += STACK_SIZE_DELTA[baseOpcode]; + } else { + if (baseOpcode == Opcodes.JSR) { + // Record the fact that 'label' designates a subroutine, if not already done. + if ((label.flags & Label.FLAG_SUBROUTINE_START) == 0) { + label.flags |= Label.FLAG_SUBROUTINE_START; + hasSubroutines = true; + } + currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_CALLER; + // Note that, by construction in this method, a block which calls a subroutine has at + // least two successors in the control flow graph: the first one (added below) leads to + // the instruction after the JSR, while the second one (added here) leads to the JSR + // target. Note that the first successor is virtual (it does not correspond to a possible + // execution path): it is only used to compute the successors of the basic blocks ending + // with a ret, in {@link Label#addSubroutineRetSuccessors}. + addSuccessorToCurrentBasicBlock(relativeStackSize + 1, label); + // The instruction after the JSR starts a new basic block. + nextBasicBlock = new Label(); + } else { + // No need to update maxRelativeStackSize (the stack size delta is always negative). + relativeStackSize += STACK_SIZE_DELTA[baseOpcode]; + addSuccessorToCurrentBasicBlock(relativeStackSize, label); + } + } + // If the next instruction starts a new basic block, call visitLabel to add the label of this + // instruction as a successor of the current block, and to start a new basic block. + if (nextBasicBlock != null) { + if (nextInsnIsJumpTarget) { + nextBasicBlock.flags |= Label.FLAG_JUMP_TARGET; + } + visitLabel(nextBasicBlock); + } + if (baseOpcode == Opcodes.GOTO) { + endCurrentBasicBlockWithNoSuccessor(); + } + } + } + + @Override + public void visitLabel(final Label label) { + // Resolve the forward references to this label, if any. + hasAsmInstructions |= label.resolve(code.data, stackMapTableEntries, code.length); + // visitLabel starts a new basic block (except for debug only labels), so we need to update the + // previous and current block references and list of successors. + if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) { + return; + } + if (compute == COMPUTE_ALL_FRAMES) { + if (currentBasicBlock != null) { + if (label.bytecodeOffset == currentBasicBlock.bytecodeOffset) { + // We use {@link Label#getCanonicalInstance} to store the state of a basic block in only + // one place, but this does not work for labels which have not been visited yet. + // Therefore, when we detect here two labels having the same bytecode offset, we need to + // - consolidate the state scattered in these two instances into the canonical instance: + currentBasicBlock.flags |= (short)(label.flags & Label.FLAG_JUMP_TARGET); + // - make sure the two instances share the same Frame instance (the implementation of + // {@link Label#getCanonicalInstance} relies on this property; here label.frame should be + // null): + label.frame = currentBasicBlock.frame; + // - and make sure to NOT assign 'label' into 'currentBasicBlock' or 'lastBasicBlock', so + // that they still refer to the canonical instance for this bytecode offset. + return; + } + // End the current basic block (with one new successor). + addSuccessorToCurrentBasicBlock(Edge.JUMP, label); + } + // Append 'label' at the end of the basic block list. + if (lastBasicBlock != null) { + if (label.bytecodeOffset == lastBasicBlock.bytecodeOffset) { + // Same comment as above. + lastBasicBlock.flags |= (short)(label.flags & Label.FLAG_JUMP_TARGET); + // Here label.frame should be null. + label.frame = lastBasicBlock.frame; + currentBasicBlock = lastBasicBlock; + return; + } + lastBasicBlock.nextBasicBlock = label; + } + lastBasicBlock = label; + // Make it the new current basic block. + currentBasicBlock = label; + // Here label.frame should be null. + label.frame = new Frame(label); + } else if (compute == COMPUTE_INSERTED_FRAMES) { + if (currentBasicBlock == null) { + // This case should happen only once, for the visitLabel call in the constructor. Indeed, if + // compute is equal to COMPUTE_INSERTED_FRAMES, currentBasicBlock stays unchanged. + currentBasicBlock = label; + } else { + // Update the frame owner so that a correct frame offset is computed in Frame.accept(). + currentBasicBlock.frame.owner = label; + } + } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { + if (currentBasicBlock != null) { + // End the current basic block (with one new successor). + currentBasicBlock.outputStackMax = (short) maxRelativeStackSize; + addSuccessorToCurrentBasicBlock(relativeStackSize, label); + } + // Start a new current basic block, and reset the current and maximum relative stack sizes. + currentBasicBlock = label; + relativeStackSize = 0; + maxRelativeStackSize = 0; + // Append the new basic block at the end of the basic block list. + if (lastBasicBlock != null) { + lastBasicBlock.nextBasicBlock = label; + } + lastBasicBlock = label; + } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES && currentBasicBlock == null) { + // This case should happen only once, for the visitLabel call in the constructor. Indeed, if + // compute is equal to COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES, currentBasicBlock stays + // unchanged. + currentBasicBlock = label; + } + } + + @Override + public void visitLdcInsn(final Object value) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + Symbol constantSymbol = symbolTable.addConstant(value); + int constantIndex = constantSymbol.index; + char firstDescriptorChar; + boolean isLongOrDouble = + constantSymbol.tag == Symbol.CONSTANT_LONG_TAG + || constantSymbol.tag == Symbol.CONSTANT_DOUBLE_TAG + || (constantSymbol.tag == Symbol.CONSTANT_DYNAMIC_TAG + && ((firstDescriptorChar = constantSymbol.value.charAt(0)) == 'J' + || firstDescriptorChar == 'D')); + if (isLongOrDouble) { + code.put12(Constants.LDC2_W, constantIndex); + } else if (constantIndex >= 256) { + code.put12(Constants.LDC_W, constantIndex); + } else { + code.put11(Opcodes.LDC, constantIndex); + } + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute(Opcodes.LDC, 0, constantSymbol, symbolTable); + } else { + int size = relativeStackSize + (isLongOrDouble ? 2 : 1); + if (size > maxRelativeStackSize) { + maxRelativeStackSize = size; + } + relativeStackSize = size; + } + } + } + + @Override + public void visitIincInsn(final int varIndex, final int increment) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + if ((varIndex > 255) || (increment > 127) || (increment < -128)) { + code.putByte(Constants.WIDE).put12(Opcodes.IINC, varIndex).putShort(increment); + } else { + code.putByte(Opcodes.IINC).put11(varIndex, increment); + } + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null + && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) { + currentBasicBlock.frame.execute(Opcodes.IINC, varIndex, null, null); + } + if (compute != COMPUTE_NOTHING) { + int currentMaxLocals = varIndex + 1; + if (currentMaxLocals > maxLocals) { + maxLocals = currentMaxLocals; + } + } + } + + @Override + public void visitTableSwitchInsn( + final int min, final int max, final Label dflt, final Label... labels) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + code.putByte(Opcodes.TABLESWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4); + dflt.put(code, lastBytecodeOffset, true); + code.putInt(min).putInt(max); + for (Label label : labels) { + label.put(code, lastBytecodeOffset, true); + } + // If needed, update the maximum stack size and number of locals, and stack map frames. + visitSwitchInsn(dflt, labels); + } + + @Override + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + code.putByte(Opcodes.LOOKUPSWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4); + dflt.put(code, lastBytecodeOffset, true); + code.putInt(labels.length); + for (int i = 0; i < labels.length; ++i) { + code.putInt(keys[i]); + labels[i].put(code, lastBytecodeOffset, true); + } + // If needed, update the maximum stack size and number of locals, and stack map frames. + visitSwitchInsn(dflt, labels); + } + + private void visitSwitchInsn(final Label dflt, final Label[] labels) { + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES) { + currentBasicBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); + // Add all the labels as successors of the current basic block. + addSuccessorToCurrentBasicBlock(Edge.JUMP, dflt); + dflt.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; + for (Label label : labels) { + addSuccessorToCurrentBasicBlock(Edge.JUMP, label); + label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; + } + } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { + // No need to update maxRelativeStackSize (the stack size delta is always negative). + --relativeStackSize; + // Add all the labels as successors of the current basic block. + addSuccessorToCurrentBasicBlock(relativeStackSize, dflt); + for (Label label : labels) { + addSuccessorToCurrentBasicBlock(relativeStackSize, label); + } + } + // End the current basic block. + endCurrentBasicBlockWithNoSuccessor(); + } + } + + @Override + public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { + lastBytecodeOffset = code.length; + // Add the instruction to the bytecode of the method. + Symbol descSymbol = symbolTable.addConstantClass(descriptor); + code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions); + // If needed, update the maximum stack size and number of locals, and stack map frames. + if (currentBasicBlock != null) { + if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { + currentBasicBlock.frame.execute( + Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable); + } else { + // No need to update maxRelativeStackSize (the stack size delta is always negative). + relativeStackSize += 1 - numDimensions; + } + } + } + + @Override + public AnnotationVisitor visitInsnAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (visible) { + return lastCodeRuntimeVisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, + (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), + typePath, + descriptor, + lastCodeRuntimeVisibleTypeAnnotation); + } else { + return lastCodeRuntimeInvisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, + (typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), + typePath, + descriptor, + lastCodeRuntimeInvisibleTypeAnnotation); + } + } + + @Override + public void visitTryCatchBlock( + final Label start, final Label end, final Label handler, final String type) { + Handler newHandler = + new Handler( + start, end, handler, type != null ? symbolTable.addConstantClass(type).index : 0, type); + if (firstHandler == null) { + firstHandler = newHandler; + } else { + lastHandler.nextHandler = newHandler; + } + lastHandler = newHandler; + } + + @Override + public AnnotationVisitor visitTryCatchAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (visible) { + return lastCodeRuntimeVisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeVisibleTypeAnnotation); + } else { + return lastCodeRuntimeInvisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeInvisibleTypeAnnotation); + } + } + + @Override + public void visitLocalVariable( + final String name, + final String descriptor, + final String signature, + final Label start, + final Label end, + final int index) { + if (signature != null) { + if (localVariableTypeTable == null) { + localVariableTypeTable = new ByteVector(); + } + ++localVariableTypeTableLength; + localVariableTypeTable + .putShort(start.bytecodeOffset) + .putShort(end.bytecodeOffset - start.bytecodeOffset) + .putShort(symbolTable.addConstantUtf8(name)) + .putShort(symbolTable.addConstantUtf8(signature)) + .putShort(index); + } + if (localVariableTable == null) { + localVariableTable = new ByteVector(); + } + ++localVariableTableLength; + localVariableTable + .putShort(start.bytecodeOffset) + .putShort(end.bytecodeOffset - start.bytecodeOffset) + .putShort(symbolTable.addConstantUtf8(name)) + .putShort(symbolTable.addConstantUtf8(descriptor)) + .putShort(index); + if (compute != COMPUTE_NOTHING) { + char firstDescChar = descriptor.charAt(0); + int currentMaxLocals = index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1); + if (currentMaxLocals > maxLocals) { + maxLocals = currentMaxLocals; + } + } + } + + @Override + public AnnotationVisitor visitLocalVariableAnnotation( + final int typeRef, + final TypePath typePath, + final Label[] start, + final Label[] end, + final int[] index, + final String descriptor, + final boolean visible) { + // Create a ByteVector to hold a 'type_annotation' JVMS structure. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. + ByteVector typeAnnotation = new ByteVector(); + // Write target_type, target_info, and target_path. + typeAnnotation.putByte(typeRef >>> 24).putShort(start.length); + for (int i = 0; i < start.length; ++i) { + typeAnnotation + .putShort(start[i].bytecodeOffset) + .putShort(end[i].bytecodeOffset - start[i].bytecodeOffset) + .putShort(index[i]); + } + TypePath.put(typePath, typeAnnotation); + // Write type_index and reserve space for num_element_value_pairs. + typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); + if (visible) { + return lastCodeRuntimeVisibleTypeAnnotation = + new AnnotationWriter( + symbolTable, + /* useNamedValues = */ true, + typeAnnotation, + lastCodeRuntimeVisibleTypeAnnotation); + } else { + return lastCodeRuntimeInvisibleTypeAnnotation = + new AnnotationWriter( + symbolTable, + /* useNamedValues = */ true, + typeAnnotation, + lastCodeRuntimeInvisibleTypeAnnotation); + } + } + + @Override + public void visitLineNumber(final int line, final Label start) { + if (lineNumberTable == null) { + lineNumberTable = new ByteVector(); + } + ++lineNumberTableLength; + lineNumberTable.putShort(start.bytecodeOffset); + lineNumberTable.putShort(line); + } + + @Override + public void visitMaxs(final int maxStack, final int maxLocals) { + if (compute == COMPUTE_ALL_FRAMES) { + computeAllFrames(); + } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { + computeMaxStackAndLocal(); + } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL_FROM_FRAMES) { + this.maxStack = maxRelativeStackSize; + } else { + this.maxStack = maxStack; + this.maxLocals = maxLocals; + } + } + + /** Computes all the stack map frames of the method, from scratch. */ + private void computeAllFrames() { + // Complete the control flow graph with exception handler blocks. + Handler handler = firstHandler; + while (handler != null) { + String catchTypeDescriptor = + handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor; + int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor); + // Mark handlerBlock as an exception handler. + Label handlerBlock = handler.handlerPc.getCanonicalInstance(); + handlerBlock.flags |= Label.FLAG_JUMP_TARGET; + // Add handlerBlock as a successor of all the basic blocks in the exception handler range. + Label handlerRangeBlock = handler.startPc.getCanonicalInstance(); + Label handlerRangeEnd = handler.endPc.getCanonicalInstance(); + while (handlerRangeBlock != handlerRangeEnd) { + handlerRangeBlock.outgoingEdges = + new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges); + handlerRangeBlock = handlerRangeBlock.nextBasicBlock; + } + handler = handler.nextHandler; + } + + // Create and visit the first (implicit) frame. + Frame firstFrame = firstBasicBlock.frame; + firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals); + firstFrame.accept(this); + + // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks + // whose stack map frame has changed) and, while there are blocks to process, remove one from + // the list and update the stack map frames of its successor blocks in the control flow graph + // (which might change them, in which case these blocks must be processed too, and are thus + // added to the list of blocks to process). Also compute the maximum stack size of the method, + // as a by-product. + Label listOfBlocksToProcess = firstBasicBlock; + listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST; + int maxStackSize = 0; + while (listOfBlocksToProcess != Label.EMPTY_LIST) { + // Remove a basic block from the list of blocks to process. + Label basicBlock = listOfBlocksToProcess; + listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; + basicBlock.nextListElement = null; + // By definition, basicBlock is reachable. + basicBlock.flags |= Label.FLAG_REACHABLE; + // Update the (absolute) maximum stack size. + int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax; + if (maxBlockStackSize > maxStackSize) { + maxStackSize = maxBlockStackSize; + } + // Update the successor blocks of basicBlock in the control flow graph. + Edge outgoingEdge = basicBlock.outgoingEdges; + while (outgoingEdge != null) { + Label successorBlock = outgoingEdge.successor.getCanonicalInstance(); + boolean successorBlockChanged = + basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info); + if (successorBlockChanged && successorBlock.nextListElement == null) { + // If successorBlock has changed it must be processed. Thus, if it is not already in the + // list of blocks to process, add it to this list. + successorBlock.nextListElement = listOfBlocksToProcess; + listOfBlocksToProcess = successorBlock; + } + outgoingEdge = outgoingEdge.nextEdge; + } + } + + // Loop over all the basic blocks and visit the stack map frames that must be stored in the + // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from + // exception handler ranges. + Label basicBlock = firstBasicBlock; + while (basicBlock != null) { + if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) + == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) { + basicBlock.frame.accept(this); + } + if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) { + // Find the start and end bytecode offsets of this unreachable block. + Label nextBasicBlock = basicBlock.nextBasicBlock; + int startOffset = basicBlock.bytecodeOffset; + int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1; + if (endOffset >= startOffset) { + // Replace its instructions with NOP ... NOP ATHROW. + for (int i = startOffset; i < endOffset; ++i) { + code.data[i] = Opcodes.NOP; + } + code.data[endOffset] = (byte) Opcodes.ATHROW; + // Emit a frame for this unreachable block, with no local and a Throwable on the stack + // (so that the ATHROW could consume this Throwable if it were reachable). + int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1); + currentFrame[frameIndex] = + Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable"); + visitFrameEnd(); + // Remove this unreachable basic block from the exception handler ranges. + firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock); + // The maximum stack size is now at least one, because of the Throwable declared above. + maxStackSize = Math.max(maxStackSize, 1); + } + } + basicBlock = basicBlock.nextBasicBlock; + } + + this.maxStack = maxStackSize; + } + + /** Computes the maximum stack size of the method. */ + private void computeMaxStackAndLocal() { + // Complete the control flow graph with exception handler blocks. + Handler handler = firstHandler; + while (handler != null) { + Label handlerBlock = handler.handlerPc; + Label handlerRangeBlock = handler.startPc; + Label handlerRangeEnd = handler.endPc; + // Add handlerBlock as a successor of all the basic blocks in the exception handler range. + while (handlerRangeBlock != handlerRangeEnd) { + if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) { + handlerRangeBlock.outgoingEdges = + new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges); + } else { + // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing + // edges to preserve the hypothesis about JSR block successors order (see + // {@link #visitJumpInsn}). + handlerRangeBlock.outgoingEdges.nextEdge.nextEdge = + new Edge( + Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge); + } + handlerRangeBlock = handlerRangeBlock.nextBasicBlock; + } + handler = handler.nextHandler; + } + + // Complete the control flow graph with the successor blocks of subroutines, if needed. + if (hasSubroutines) { + // First step: find the subroutines. This step determines, for each basic block, to which + // subroutine(s) it belongs. Start with the main "subroutine": + short numSubroutines = 1; + firstBasicBlock.markSubroutine(numSubroutines); + // Then, mark the subroutines called by the main subroutine, then the subroutines called by + // those called by the main subroutine, etc. + for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) { + Label basicBlock = firstBasicBlock; + while (basicBlock != null) { + if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0 + && basicBlock.subroutineId == currentSubroutine) { + Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor; + if (jsrTarget.subroutineId == 0) { + // If this subroutine has not been marked yet, find its basic blocks. + jsrTarget.markSubroutine(++numSubroutines); + } + } + basicBlock = basicBlock.nextBasicBlock; + } + } + // Second step: find the successors in the control flow graph of each subroutine basic block + // 'r' ending with a RET instruction. These successors are the virtual successors of the basic + // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'. + Label basicBlock = firstBasicBlock; + while (basicBlock != null) { + if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { + // By construction, jsr targets are stored in the second outgoing edge of basic blocks + // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}). + Label subroutine = basicBlock.outgoingEdges.nextEdge.successor; + subroutine.addSubroutineRetSuccessors(basicBlock); + } + basicBlock = basicBlock.nextBasicBlock; + } + } + + // Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks + // whose input stack size has changed) and, while there are blocks to process, remove one + // from the list, update the input stack size of its successor blocks in the control flow + // graph, and add these blocks to the list of blocks to process (if not already done). + Label listOfBlocksToProcess = firstBasicBlock; + listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST; + int maxStackSize = maxStack; + while (listOfBlocksToProcess != Label.EMPTY_LIST) { + // Remove a basic block from the list of blocks to process. Note that we don't reset + // basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already + // processed basic blocks. + Label basicBlock = listOfBlocksToProcess; + listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; + // Compute the (absolute) input stack size and maximum stack size of this block. + int inputStackTop = basicBlock.inputStackSize; + int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax; + // Update the absolute maximum stack size of the method. + if (maxBlockStackSize > maxStackSize) { + maxStackSize = maxBlockStackSize; + } + // Update the input stack size of the successor blocks of basicBlock in the control flow + // graph, and add these blocks to the list of blocks to process, if not already done. + Edge outgoingEdge = basicBlock.outgoingEdges; + if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { + // Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual + // edges which lead to the instruction just after the jsr, and do not correspond to a + // possible execution path (see {@link #visitJumpInsn} and + // {@link Label#FLAG_SUBROUTINE_CALLER}). + outgoingEdge = outgoingEdge.nextEdge; + } + while (outgoingEdge != null) { + Label successorBlock = outgoingEdge.successor; + if (successorBlock.nextListElement == null) { + successorBlock.inputStackSize = + (short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info); + successorBlock.nextListElement = listOfBlocksToProcess; + listOfBlocksToProcess = successorBlock; + } + outgoingEdge = outgoingEdge.nextEdge; + } + } + this.maxStack = maxStackSize; + } + + @Override + public void visitEnd() { + // Nothing to do. + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods: control flow analysis algorithm + // ----------------------------------------------------------------------------------------------- + + /** + * Adds a successor to {@link #currentBasicBlock} in the control flow graph. + * + * @param info information about the control flow edge to be added. + * @param successor the successor block to be added to the current basic block. + */ + private void addSuccessorToCurrentBasicBlock(final int info, final Label successor) { + currentBasicBlock.outgoingEdges = new Edge(info, successor, currentBasicBlock.outgoingEdges); + } + + /** + * Ends the current basic block. This method must be used in the case where the current basic + * block does not have any successor. + * + *

    WARNING: this method must be called after the currently visited instruction has been put in + * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic + * block after the current instruction). + */ + private void endCurrentBasicBlockWithNoSuccessor() { + if (compute == COMPUTE_ALL_FRAMES) { + Label nextBasicBlock = new Label(); + nextBasicBlock.frame = new Frame(nextBasicBlock); + nextBasicBlock.resolve(code.data, stackMapTableEntries, code.length); + lastBasicBlock.nextBasicBlock = nextBasicBlock; + lastBasicBlock = nextBasicBlock; + currentBasicBlock = null; + } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { + currentBasicBlock.outputStackMax = (short) maxRelativeStackSize; + currentBasicBlock = null; + } + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods: stack map frames + // ----------------------------------------------------------------------------------------------- + + /** + * Starts the visit of a new stack map frame, stored in {@link #currentFrame}. + * + * @param offset the bytecode offset of the instruction to which the frame corresponds. + * @param numLocal the number of local variables in the frame. + * @param numStack the number of stack elements in the frame. + * @return the index of the next element to be written in this frame. + */ + int visitFrameStart(final int offset, final int numLocal, final int numStack) { + int frameLength = 3 + numLocal + numStack; + if (currentFrame == null || currentFrame.length < frameLength) { + currentFrame = new int[frameLength]; + } + currentFrame[0] = offset; + currentFrame[1] = numLocal; + currentFrame[2] = numStack; + return 3; + } + + /** + * Sets an abstract type in {@link #currentFrame}. + * + * @param frameIndex the index of the element to be set in {@link #currentFrame}. + * @param abstractType an abstract type. + */ + void visitAbstractType(final int frameIndex, final int abstractType) { + currentFrame[frameIndex] = abstractType; + } + + /** + * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by + * updating the StackMapTable number_of_entries (except if the current frame is the first one, + * which is implicit in StackMapTable). Then resets {@link #currentFrame} to {@literal null}. + */ + void visitFrameEnd() { + if (previousFrame != null) { + if (stackMapTableEntries == null) { + stackMapTableEntries = new ByteVector(); + } + putFrame(); + ++stackMapTableNumberOfEntries; + } + previousFrame = currentFrame; + currentFrame = null; + } + + /** Compresses and writes {@link #currentFrame} in a new StackMapTable entry. */ + private void putFrame() { + final int numLocal = currentFrame[1]; + final int numStack = currentFrame[2]; + if (symbolTable.getMajorVersion() < Opcodes.V1_6) { + // Generate a StackMap attribute entry, which are always uncompressed. + stackMapTableEntries.putShort(currentFrame[0]).putShort(numLocal); + putAbstractTypes(3, 3 + numLocal); + stackMapTableEntries.putShort(numStack); + putAbstractTypes(3 + numLocal, 3 + numLocal + numStack); + return; + } + final int offsetDelta = + stackMapTableNumberOfEntries == 0 + ? currentFrame[0] + : currentFrame[0] - previousFrame[0] - 1; + final int previousNumlocal = previousFrame[1]; + final int numLocalDelta = numLocal - previousNumlocal; + int type = Frame.FULL_FRAME; + if (numStack == 0) { + switch (numLocalDelta) { + case -3: + case -2: + case -1: + type = Frame.CHOP_FRAME; + break; + case 0: + type = offsetDelta < 64 ? Frame.SAME_FRAME : Frame.SAME_FRAME_EXTENDED; + break; + case 1: + case 2: + case 3: + type = Frame.APPEND_FRAME; + break; + default: + // Keep the FULL_FRAME type. + break; + } + } else if (numLocalDelta == 0 && numStack == 1) { + type = + offsetDelta < 63 + ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + : Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; + } + if (type != Frame.FULL_FRAME) { + // Verify if locals are the same as in the previous frame. + int frameIndex = 3; + for (int i = 0; i < previousNumlocal && i < numLocal; i++) { + if (currentFrame[frameIndex] != previousFrame[frameIndex]) { + type = Frame.FULL_FRAME; + break; + } + frameIndex++; + } + } + switch (type) { + case Frame.SAME_FRAME: + stackMapTableEntries.putByte(offsetDelta); + break; + case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME: + stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta); + putAbstractTypes(3 + numLocal, 4 + numLocal); + break; + case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: + stackMapTableEntries + .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) + .putShort(offsetDelta); + putAbstractTypes(3 + numLocal, 4 + numLocal); + break; + case Frame.SAME_FRAME_EXTENDED: + stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta); + break; + case Frame.CHOP_FRAME: + stackMapTableEntries + .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta) + .putShort(offsetDelta); + break; + case Frame.APPEND_FRAME: + stackMapTableEntries + .putByte(Frame.SAME_FRAME_EXTENDED + numLocalDelta) + .putShort(offsetDelta); + putAbstractTypes(3 + previousNumlocal, 3 + numLocal); + break; + case Frame.FULL_FRAME: + default: + stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(numLocal); + putAbstractTypes(3, 3 + numLocal); + stackMapTableEntries.putShort(numStack); + putAbstractTypes(3 + numLocal, 3 + numLocal + numStack); + break; + } + } + + /** + * Puts some abstract types of {@link #currentFrame} in {@link #stackMapTableEntries} , using the + * JVMS verification_type_info format used in StackMapTable attributes. + * + * @param start index of the first type in {@link #currentFrame} to write. + * @param end index of last type in {@link #currentFrame} to write (exclusive). + */ + private void putAbstractTypes(final int start, final int end) { + for (int i = start; i < end; ++i) { + Frame.putAbstractType(symbolTable, currentFrame[i], stackMapTableEntries); + } + } + + /** + * Puts the given public API frame element type in {@link #stackMapTableEntries} , using the JVMS + * verification_type_info format used in StackMapTable attributes. + * + * @param type a frame element type described using the same format as in {@link + * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link + * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or + * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating + * a NEW instruction (for uninitialized types). + */ + private void putFrameType(final Object type) { + if (type instanceof Integer) { + stackMapTableEntries.putByte(((Integer) type).intValue()); + } else if (type instanceof String) { + stackMapTableEntries + .putByte(Frame.ITEM_OBJECT) + .putShort(symbolTable.addConstantClass((String) type).index); + } else { + stackMapTableEntries.putByte(Frame.ITEM_UNINITIALIZED); + ((Label) type).put(stackMapTableEntries); + } + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods + // ----------------------------------------------------------------------------------------------- + + /** + * Returns whether the attributes of this method can be copied from the attributes of the given + * method (assuming there is no method visitor between the given ClassReader and this + * MethodWriter). This method should only be called just after this MethodWriter has been created, + * and before any content is visited. It returns true if the attributes corresponding to the + * constructor arguments (at most a Signature, an Exception, a Deprecated and a Synthetic + * attribute) are the same as the corresponding attributes in the given method. + * + * @param source the source ClassReader from which the attributes of this method might be copied. + * @param hasSyntheticAttribute whether the method_info JVMS structure from which the attributes + * of this method might be copied contains a Synthetic attribute. + * @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes + * of this method might be copied contains a Deprecated attribute. + * @param descriptorIndex the descriptor_index field of the method_info JVMS structure from which + * the attributes of this method might be copied. + * @param signatureIndex the constant pool index contained in the Signature attribute of the + * method_info JVMS structure from which the attributes of this method might be copied, or 0. + * @param exceptionsOffset the offset in 'source.b' of the Exceptions attribute of the method_info + * JVMS structure from which the attributes of this method might be copied, or 0. + * @return whether the attributes of this method can be copied from the attributes of the + * method_info JVMS structure in 'source.b', between 'methodInfoOffset' and 'methodInfoOffset' + * + 'methodInfoLength'. + */ + boolean canCopyMethodAttributes( + final ClassReader source, + final boolean hasSyntheticAttribute, + final boolean hasDeprecatedAttribute, + final int descriptorIndex, + final int signatureIndex, + final int exceptionsOffset) { + // If the method descriptor has changed, with more locals than the max_locals field of the + // original Code attribute, if any, then the original method attributes can't be copied. A + // conservative check on the descriptor changes alone ensures this (being more precise is not + // worth the additional complexity, because these cases should be rare -- if a transform changes + // a method descriptor, most of the time it needs to change the method's code too). + if (source != symbolTable.getSource() + || descriptorIndex != this.descriptorIndex + || signatureIndex != this.signatureIndex + || hasDeprecatedAttribute != ((accessFlags & Opcodes.ACC_DEPRECATED) != 0)) { + return false; + } + boolean needSyntheticAttribute = + symbolTable.getMajorVersion() < Opcodes.V1_5 && (accessFlags & Opcodes.ACC_SYNTHETIC) != 0; + if (hasSyntheticAttribute != needSyntheticAttribute) { + return false; + } + if (exceptionsOffset == 0) { + if (numberOfExceptions != 0) { + return false; + } + } else if (source.readUnsignedShort(exceptionsOffset) == numberOfExceptions) { + int currentExceptionOffset = exceptionsOffset + 2; + for (int i = 0; i < numberOfExceptions; ++i) { + if (source.readUnsignedShort(currentExceptionOffset) != exceptionIndexTable[i]) { + return false; + } + currentExceptionOffset += 2; + } + } + return true; + } + + /** + * Sets the source from which the attributes of this method will be copied. + * + * @param methodInfoOffset the offset in 'symbolTable.getSource()' of the method_info JVMS + * structure from which the attributes of this method will be copied. + * @param methodInfoLength the length in 'symbolTable.getSource()' of the method_info JVMS + * structure from which the attributes of this method will be copied. + */ + void setMethodAttributesSource(final int methodInfoOffset, final int methodInfoLength) { + // Don't copy the attributes yet, instead store their location in the source class reader so + // they can be copied later, in {@link #putMethodInfo}. Note that we skip the 6 header bytes + // of the method_info JVMS structure. + this.sourceOffset = methodInfoOffset + 6; + this.sourceLength = methodInfoLength - 6; + } + + /** + * Returns the size of the method_info JVMS structure generated by this MethodWriter. Also add the + * names of the attributes of this method in the constant pool. + * + * @return the size in bytes of the method_info JVMS structure. + */ + int computeMethodInfoSize() { + // If this method_info must be copied from an existing one, the size computation is trivial. + if (sourceOffset != 0) { + // sourceLength excludes the first 6 bytes for access_flags, name_index and descriptor_index. + return 6 + sourceLength; + } + // 2 bytes each for access_flags, name_index, descriptor_index and attributes_count. + int size = 8; + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + if (code.length > 0) { + if (code.length > 65535) { + throw new MethodTooLargeException( + symbolTable.getClassName(), name, descriptor, code.length); + } + symbolTable.addConstantUtf8(Constants.CODE); + // The Code attribute has 6 header bytes, plus 2, 2, 4 and 2 bytes respectively for max_stack, + // max_locals, code_length and attributes_count, plus the bytecode and the exception table. + size += 16 + code.length + Handler.getExceptionTableSize(firstHandler); + if (stackMapTableEntries != null) { + boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6; + symbolTable.addConstantUtf8(useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap"); + // 6 header bytes and 2 bytes for number_of_entries. + size += 8 + stackMapTableEntries.length; + } + if (lineNumberTable != null) { + symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE); + // 6 header bytes and 2 bytes for line_number_table_length. + size += 8 + lineNumberTable.length; + } + if (localVariableTable != null) { + symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE); + // 6 header bytes and 2 bytes for local_variable_table_length. + size += 8 + localVariableTable.length; + } + if (localVariableTypeTable != null) { + symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE); + // 6 header bytes and 2 bytes for local_variable_type_table_length. + size += 8 + localVariableTypeTable.length; + } + if (lastCodeRuntimeVisibleTypeAnnotation != null) { + size += + lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + } + if (lastCodeRuntimeInvisibleTypeAnnotation != null) { + size += + lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + } + if (firstCodeAttribute != null) { + size += + firstCodeAttribute.computeAttributesSize( + symbolTable, code.data, code.length, maxStack, maxLocals); + } + } + if (numberOfExceptions > 0) { + symbolTable.addConstantUtf8(Constants.EXCEPTIONS); + size += 8 + 2 * numberOfExceptions; + } + size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex); + size += + AnnotationWriter.computeAnnotationsSize( + lastRuntimeVisibleAnnotation, + lastRuntimeInvisibleAnnotation, + lastRuntimeVisibleTypeAnnotation, + lastRuntimeInvisibleTypeAnnotation); + if (lastRuntimeVisibleParameterAnnotations != null) { + size += + AnnotationWriter.computeParameterAnnotationsSize( + Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, + lastRuntimeVisibleParameterAnnotations, + visibleAnnotableParameterCount == 0 + ? lastRuntimeVisibleParameterAnnotations.length + : visibleAnnotableParameterCount); + } + if (lastRuntimeInvisibleParameterAnnotations != null) { + size += + AnnotationWriter.computeParameterAnnotationsSize( + Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, + lastRuntimeInvisibleParameterAnnotations, + invisibleAnnotableParameterCount == 0 + ? lastRuntimeInvisibleParameterAnnotations.length + : invisibleAnnotableParameterCount); + } + if (defaultValue != null) { + symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT); + size += 6 + defaultValue.length; + } + if (parameters != null) { + symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS); + // 6 header bytes and 1 byte for parameters_count. + size += 7 + parameters.length; + } + if (firstAttribute != null) { + size += firstAttribute.computeAttributesSize(symbolTable); + } + return size; + } + + /** + * Puts the content of the method_info JVMS structure generated by this MethodWriter into the + * given ByteVector. + * + * @param output where the method_info structure must be put. + */ + void putMethodInfo(final ByteVector output) { + boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5; + int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0; + output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex); + // If this method_info must be copied from an existing one, copy it now and return early. + if (sourceOffset != 0) { + output.putByteArray(symbolTable.getSource().classFileBuffer, sourceOffset, sourceLength); + return; + } + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + int attributeCount = 0; + if (code.length > 0) { + ++attributeCount; + } + if (numberOfExceptions > 0) { + ++attributeCount; + } + if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { + ++attributeCount; + } + if (signatureIndex != 0) { + ++attributeCount; + } + if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + } + if (lastRuntimeVisibleAnnotation != null) { + ++attributeCount; + } + if (lastRuntimeInvisibleAnnotation != null) { + ++attributeCount; + } + if (lastRuntimeVisibleParameterAnnotations != null) { + ++attributeCount; + } + if (lastRuntimeInvisibleParameterAnnotations != null) { + ++attributeCount; + } + if (lastRuntimeVisibleTypeAnnotation != null) { + ++attributeCount; + } + if (lastRuntimeInvisibleTypeAnnotation != null) { + ++attributeCount; + } + if (defaultValue != null) { + ++attributeCount; + } + if (parameters != null) { + ++attributeCount; + } + if (firstAttribute != null) { + attributeCount += firstAttribute.getAttributeCount(); + } + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + output.putShort(attributeCount); + if (code.length > 0) { + // 2, 2, 4 and 2 bytes respectively for max_stack, max_locals, code_length and + // attributes_count, plus the bytecode and the exception table. + int size = 10 + code.length + Handler.getExceptionTableSize(firstHandler); + int codeAttributeCount = 0; + if (stackMapTableEntries != null) { + // 6 header bytes and 2 bytes for number_of_entries. + size += 8 + stackMapTableEntries.length; + ++codeAttributeCount; + } + if (lineNumberTable != null) { + // 6 header bytes and 2 bytes for line_number_table_length. + size += 8 + lineNumberTable.length; + ++codeAttributeCount; + } + if (localVariableTable != null) { + // 6 header bytes and 2 bytes for local_variable_table_length. + size += 8 + localVariableTable.length; + ++codeAttributeCount; + } + if (localVariableTypeTable != null) { + // 6 header bytes and 2 bytes for local_variable_type_table_length. + size += 8 + localVariableTypeTable.length; + ++codeAttributeCount; + } + if (lastCodeRuntimeVisibleTypeAnnotation != null) { + size += + lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + ++codeAttributeCount; + } + if (lastCodeRuntimeInvisibleTypeAnnotation != null) { + size += + lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( + Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + ++codeAttributeCount; + } + if (firstCodeAttribute != null) { + size += + firstCodeAttribute.computeAttributesSize( + symbolTable, code.data, code.length, maxStack, maxLocals); + codeAttributeCount += firstCodeAttribute.getAttributeCount(); + } + output + .putShort(symbolTable.addConstantUtf8(Constants.CODE)) + .putInt(size) + .putShort(maxStack) + .putShort(maxLocals) + .putInt(code.length) + .putByteArray(code.data, 0, code.length); + Handler.putExceptionTable(firstHandler, output); + output.putShort(codeAttributeCount); + if (stackMapTableEntries != null) { + boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6; + output + .putShort( + symbolTable.addConstantUtf8( + useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap")) + .putInt(2 + stackMapTableEntries.length) + .putShort(stackMapTableNumberOfEntries) + .putByteArray(stackMapTableEntries.data, 0, stackMapTableEntries.length); + } + if (lineNumberTable != null) { + output + .putShort(symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE)) + .putInt(2 + lineNumberTable.length) + .putShort(lineNumberTableLength) + .putByteArray(lineNumberTable.data, 0, lineNumberTable.length); + } + if (localVariableTable != null) { + output + .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE)) + .putInt(2 + localVariableTable.length) + .putShort(localVariableTableLength) + .putByteArray(localVariableTable.data, 0, localVariableTable.length); + } + if (localVariableTypeTable != null) { + output + .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE)) + .putInt(2 + localVariableTypeTable.length) + .putShort(localVariableTypeTableLength) + .putByteArray(localVariableTypeTable.data, 0, localVariableTypeTable.length); + } + if (lastCodeRuntimeVisibleTypeAnnotation != null) { + lastCodeRuntimeVisibleTypeAnnotation.putAnnotations( + symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output); + } + if (lastCodeRuntimeInvisibleTypeAnnotation != null) { + lastCodeRuntimeInvisibleTypeAnnotation.putAnnotations( + symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output); + } + if (firstCodeAttribute != null) { + firstCodeAttribute.putAttributes( + symbolTable, code.data, code.length, maxStack, maxLocals, output); + } + } + if (numberOfExceptions > 0) { + output + .putShort(symbolTable.addConstantUtf8(Constants.EXCEPTIONS)) + .putInt(2 + 2 * numberOfExceptions) + .putShort(numberOfExceptions); + for (int exceptionIndex : exceptionIndexTable) { + output.putShort(exceptionIndex); + } + } + Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output); + AnnotationWriter.putAnnotations( + symbolTable, + lastRuntimeVisibleAnnotation, + lastRuntimeInvisibleAnnotation, + lastRuntimeVisibleTypeAnnotation, + lastRuntimeInvisibleTypeAnnotation, + output); + if (lastRuntimeVisibleParameterAnnotations != null) { + AnnotationWriter.putParameterAnnotations( + symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS), + lastRuntimeVisibleParameterAnnotations, + visibleAnnotableParameterCount == 0 + ? lastRuntimeVisibleParameterAnnotations.length + : visibleAnnotableParameterCount, + output); + } + if (lastRuntimeInvisibleParameterAnnotations != null) { + AnnotationWriter.putParameterAnnotations( + symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS), + lastRuntimeInvisibleParameterAnnotations, + invisibleAnnotableParameterCount == 0 + ? lastRuntimeInvisibleParameterAnnotations.length + : invisibleAnnotableParameterCount, + output); + } + if (defaultValue != null) { + output + .putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT)) + .putInt(defaultValue.length) + .putByteArray(defaultValue.data, 0, defaultValue.length); + } + if (parameters != null) { + output + .putShort(symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS)) + .putInt(1 + parameters.length) + .putByte(parametersCount) + .putByteArray(parameters.data, 0, parameters.length); + } + if (firstAttribute != null) { + firstAttribute.putAttributes(symbolTable, output); + } + } + + /** + * Collects the attributes of this method into the given set of attribute prototypes. + * + * @param attributePrototypes a set of attribute prototypes. + */ + final void collectAttributePrototypes(final Attribute.Set attributePrototypes) { + attributePrototypes.addAttributes(firstAttribute); + attributePrototypes.addAttributes(firstCodeAttribute); + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleVisitor.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleVisitor.class new file mode 100644 index 0000000000000000000000000000000000000000..2870e12890f9c4138d24f80de54ba2282249ff48 GIT binary patch literal 2476 zcmbVN+fy4=9R5xc2nh?hlu~W5(pqasfne2o0j({imdediqF66olAXAao10B!e5;O+ zI(^qM?>f%tj16P!=#w4CM;+gE{7=;Hx4VF(1O^{+&e?PMzVCO3N4z!Jiz;1ks~#Y9HwNO17Lcs(yq3 zKVdlpW$2WlLxupjb6DZTHp_IOVC40}c`IKl8YO#bJ!@2Kvs?<|h{BQWdyBSZmhu;B zW+7)-Ve})^g`?EFRI1i0m9k|Uxk0^R4$9GhhKF#Be$guxqm)w^NzSw)jStX=O4-*=m2a~ef0iRlzASn#(264R|#)}%x3r5Jn zm}fLa-K2(#BD>4kU8*{gFKKuQmp3IZSmnBzYa_WW-4zWlOBJ}lQ<6FXCP0SMBvV@< zGGmsExmt0>u&(JV1@6RW%2~aT(JfQHz0H9Aj#*XcDekP(o<*B3p4BVfweGxOUo<5D zZ6b|H+8m(n$LW^hW;8{}eQ{6-RwSnH6TQ>bB1MtS8da(b)(xx5O5@5s2huNLoy7t1v(Yg{rNH|%Ihqar16oS|YD;MgZw%~e1$nR7Q+9hiZ_EWggN zGx#_MQwg;J^$nLk%yE=h1Iuh6uVbF8e)k#{91!Ux0?XhKtkVN)^2^V=bEypk6Y<^# zCKB;T17{QQXai%3c&vd`A|7wxWFmg3fn#^kw|p1<%Nuwg{$LY{L=z7;abg3feoQ59 zV<1x7)WA`&AW)pDAACzqjAt>-_kheX`~{&Lft-G<@+eqKYYrT z?^FD7M`01yJR8!S756$)-(uuzE?jqriNLx;qq!G68YLCZ9r5N8Zwp{l9^XT^OsAW8 zeA|RxN8$%`--n3cqyM-zx+ObGoD2~~tRE`EB|F956i>ENd`yZ@NO7wT#jC9p>^UCA z8Xe4k3&dS3dK@bTMw)oKmE=>Be1;f4cSut1t1Ua?c+DXp5)*0I@l2fQl%Z9gZ86-G zMztUDcq{Q2B>s}bU$r52t=ma_9dGO;W_R0<_*^UTcO70cI;8ypwUv4F*ll;6V2f!rdm0ECC6{9j^7;)x0YgC!HmJ>AQ0Z7 zC*4|Nda|6PaeHi6I7_8OT(+=GO-#3P{Xwoj(Tl$vF1Mf}9+#IIy~KH&NIu;77gMX> Aod5s; literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleVisitor.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleVisitor.java new file mode 100644 index 00000000..0e8f4843 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleVisitor.java @@ -0,0 +1,224 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A visitor to visit a Java module. The methods of this class must be called in the following + * order: ( {@code visitMainClass} | ( {@code visitPackage} | {@code visitRequire} | {@code + * visitExport} | {@code visitOpen} | {@code visitUse} | {@code visitProvide} )* ) {@code visitEnd}. + * + * @author Remi Forax + * @author Eric Bruneton + */ +public abstract class ModuleVisitor { + /** + * The ASM API version implemented by this visitor. The value of this field must be one of {@link + * Opcodes#ASM6} or {@link Opcodes#ASM7}. + */ + protected final int api; + + /** + * The module visitor to which this visitor must delegate method calls. May be {@literal null}. + */ + protected ModuleVisitor mv; + + /** + * Constructs a new {@link ModuleVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6} + * or {@link Opcodes#ASM7}. + */ + protected ModuleVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link ModuleVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6} + * or {@link Opcodes#ASM7}. + * @param moduleVisitor the module visitor to which this visitor must delegate method calls. May + * be null. + */ + protected ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) { + if (api != Opcodes.ASM9 + && api != Opcodes.ASM8 + && api != Opcodes.ASM7 + && api != Opcodes.ASM6 + && api != Opcodes.ASM5 + && api != Opcodes.ASM4) { + throw new IllegalArgumentException("Unsupported api " + api); + } + this.api = api; + this.mv = moduleVisitor; + } + + /** + * The module visitor to which this visitor must delegate method calls. May be {@literal null}. + * + * @return the module visitor to which this visitor must delegate method calls, or {@literal + * null}. + */ + public ModuleVisitor getDelegate() { + return mv; + } + + /** + * Visit the main class of the current module. + * + * @param mainClass the internal name of the main class of the current module (see {@link + * Type#getInternalName()}). + */ + public void visitMainClass(final String mainClass) { + if (mv != null) { + mv.visitMainClass(mainClass); + } + } + + /** + * Visit a package of the current module. + * + * @param packaze the internal name of a package (see {@link Type#getInternalName()}). + */ + public void visitPackage(final String packaze) { + if (mv != null) { + mv.visitPackage(packaze); + } + } + + /** + * Visits a dependence of the current module. + * + * @param module the fully qualified name (using dots) of the dependence. + * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code + * ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}. + * @param version the module version at compile time, or {@literal null}. + */ + public void visitRequire(final String module, final int access, final String version) { + if (mv != null) { + mv.visitRequire(module, access, version); + } + } + + /** + * Visit an exported package of the current module. + * + * @param packaze the internal name of the exported package (see {@link Type#getInternalName()}). + * @param access the access flag of the exported package, valid values are among {@code + * ACC_SYNTHETIC} and {@code ACC_MANDATED}. + * @param modules the fully qualified names (using dots) of the modules that can access the public + * classes of the exported package, or {@literal null}. + */ + public void visitExport(final String packaze, final int access, final String... modules) { + if (mv != null) { + mv.visitExport(packaze, access, modules); + } + } + + /** + * Visit an open package of the current module. + * + * @param packaze the internal name of the opened package (see {@link Type#getInternalName()}). + * @param access the access flag of the opened package, valid values are among {@code + * ACC_SYNTHETIC} and {@code ACC_MANDATED}. + * @param modules the fully qualified names (using dots) of the modules that can use deep + * reflection to the classes of the open package, or {@literal null}. + */ + public void visitOpen(final String packaze, final int access, final String... modules) { + if (mv != null) { + mv.visitOpen(packaze, access, modules); + } + } + + /** + * Visit a service used by the current module. The name must be the internal name of an interface + * or a class. + * + * @param service the internal name of the service (see {@link Type#getInternalName()}). + */ + public void visitUse(final String service) { + if (mv != null) { + mv.visitUse(service); + } + } + + /** + * Visit an implementation of a service. + * + * @param service the internal name of the service (see {@link Type#getInternalName()}). + * @param providers the internal names (see {@link Type#getInternalName()}) of the implementations + * of the service (there is at least one provider). + */ + public void visitProvide(final String service, final String... providers) { + if (mv != null) { + mv.visitProvide(service, providers); + } + } + + /** + * Visits the end of the module. This method, which is the last one to be called, is used to + * inform the visitor that everything have been visited. + */ + public void visitEnd() { + if (mv != null) { + mv.visitEnd(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleWriter.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..8257f4c8d877ba9bbe50cfe665a9e88a8c13491c GIT binary patch literal 4666 zcmb_gYj9Op75;YaAmNs zP_-7N*0x&fqph{IMMlLs>Wr8KwGN~Hu(dej_{Sew|EZ(nV;mi4{Gs5t_CEI^z4hXZ z!-TW zs&n`Bm_P1jBB%nY5kuU9Wup>R3hiaC?)1mAlkSk0@d7`s5Z~yfyx?wyXiIjLU6-!mv`3%{HJMXWqyFT6XLQmfj)5|l2Mcfah~33DYOzFN(UeBG%b9Zf zQ{(PQ1=TO|IvdMGUSs6jC!L9moZn!hUe0UH`H-8=cz#M>wXi~=wG57}rvi6~-1_Ni zG+?FB*rX6?F>Ksu<0jm!P?>fg%z9}zLsrUpR?w&&yT!&DQDM0!r~P!GL9eyZB4;sw z+D++`q>VN?smf;Dj7Bfcb=X*^%}=NO8IK{C!&`0KCWrR4Gj_t6Ff>);cHCiMy^U_X zOCedt>mv3Q63+N|ub;{UPAce~bTV|Zr)A){GvjnlI;n}y!65CWCVE=SIc}8F>ASGO zLXVA&5|}mD1%+IA5^izuZX55Gn+vBLFQox#Ld3-_Hnxg?wMCHk7#bve_t@Bm?F`p+ zHW)lcwiVVfvC9F!CSv#6=okArf_wdJDiG`U*%%P(i;JwAf)eR28@sWG8C)bi5Ik_F zLR~2~byn}QF({@Mg~#3h#znM#bYQ5Zj~NV03=0nr(sbW;<-u}U0csEjxa1+N?@59VxVE{GDK zNgGoVpg056p9(~sZ(|w{vIC7f0bx}f-YPF0u1VPmTu@W-6VAt&ugqYDqC!7(qR&{58i zVZ?OI9vVrp%aIIcY|NFavt~^9BA+wTq4U(eLkbaRRlY`86mPFt5~wwWfuRZAG#;i^ zBiLv98q=Xfj`qJ@p>PwQ(k+@hrrJU z)ImdrqP(&JU6bq%gMKzW=5F_77%wi)yLA#F+{zXc<0r>rPF)Uru4-le>L=%{esZqz zSs@)t?>Pzeo_$I0Io9-^?MUxA()6BvNbfn&^qw6^?>Wl!p3PP7ImPsz&7M!2Kb4q) z!b4oWg^0#?G+7(Dh-k8H4%NxVIV6%R=dd(c7oEfMTDi{d(G1724Th>@?C=$Lp{n=TRe)j(P0Nncpks z_lo%lg#HE+54^|^+Ls97^Ze9%8A-fCde3SoNn<1rWj#Y8P-qxJt`N8$kMJzQK!IVa zIBKEcDl9}T)L3{z@dp(=Q)KHYM$h2?J15kXM>tg3{OMSF1-nGHXX{xv8u_L7XOkAD6`b!~xzj(gC;CZur#N&%t zjxQ1Qm$4RKVY0o79r!Af=~ay5>qy}n`DELHrP_B(KD5hRGNZepZ;^so!kZ@r7fHdl zNx?-@@ER%j-v5~b#cC>5Ev+F1Qii#79TCJM*H+8-nRq{7wfyiMs^wEUMNi|?_)M5> zml+NT+(FuCzt#?q+I42N@9MbJ9gTFy>SA@#bIiB8Sl5Pl?n-^!v0QI z7NFt^n!_Awrc2MGDRiuj*QFX&fup!S_?fn38)07mXYoRK@i=wM#l|T8>w6hi^gN=G z`?=Ya-+Ya7(H* zaAFzPt7b7S)>ntm=J44XKHKHFkuMNygT6ZA$@T1qFEXS`hl77A_$LOH%+8nC zGIc*wzhR@~q*2L)*uO4sHnnM_!U1!NUGD_<2`>3qY97nYW3PEoYbp|IpGTUj{YF62 zv_Qx+f?*>di&`LT8o`JWkX9`adX3{3x2P%%uXI8w~7 zM^z;rS5s!<2}MiaGMg{UM4;LVJwV0lFkILUAcIn}J9;4HTl_`<&dJ!V4w literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleWriter.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleWriter.java new file mode 100644 index 00000000..18b1a22f --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/ModuleWriter.java @@ -0,0 +1,285 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A {@link ModuleVisitor} that generates the corresponding Module, ModulePackages and + * ModuleMainClass attributes, as defined in the Java Virtual Machine Specification (JVMS). + * + * @see JVMS + * 4.7.25 + * @see JVMS + * 4.7.26 + * @see JVMS + * 4.7.27 + * @author Remi Forax + * @author Eric Bruneton + */ +final class ModuleWriter extends ModuleVisitor { + + /** Where the constants used in this AnnotationWriter must be stored. */ + private final SymbolTable symbolTable; + + /** The module_name_index field of the JVMS Module attribute. */ + private final int moduleNameIndex; + + /** The module_flags field of the JVMS Module attribute. */ + private final int moduleFlags; + + /** The module_version_index field of the JVMS Module attribute. */ + private final int moduleVersionIndex; + + /** The requires_count field of the JVMS Module attribute. */ + private int requiresCount; + + /** The binary content of the 'requires' array of the JVMS Module attribute. */ + private final ByteVector requires; + + /** The exports_count field of the JVMS Module attribute. */ + private int exportsCount; + + /** The binary content of the 'exports' array of the JVMS Module attribute. */ + private final ByteVector exports; + + /** The opens_count field of the JVMS Module attribute. */ + private int opensCount; + + /** The binary content of the 'opens' array of the JVMS Module attribute. */ + private final ByteVector opens; + + /** The uses_count field of the JVMS Module attribute. */ + private int usesCount; + + /** The binary content of the 'uses_index' array of the JVMS Module attribute. */ + private final ByteVector usesIndex; + + /** The provides_count field of the JVMS Module attribute. */ + private int providesCount; + + /** The binary content of the 'provides' array of the JVMS Module attribute. */ + private final ByteVector provides; + + /** The provides_count field of the JVMS ModulePackages attribute. */ + private int packageCount; + + /** The binary content of the 'package_index' array of the JVMS ModulePackages attribute. */ + private final ByteVector packageIndex; + + /** The main_class_index field of the JVMS ModuleMainClass attribute, or 0. */ + private int mainClassIndex; + + ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) { + super(/* latest api = */ Opcodes.ASM9); + this.symbolTable = symbolTable; + this.moduleNameIndex = name; + this.moduleFlags = access; + this.moduleVersionIndex = version; + this.requires = new ByteVector(); + this.exports = new ByteVector(); + this.opens = new ByteVector(); + this.usesIndex = new ByteVector(); + this.provides = new ByteVector(); + this.packageIndex = new ByteVector(); + } + + @Override + public void visitMainClass(final String mainClass) { + this.mainClassIndex = symbolTable.addConstantClass(mainClass).index; + } + + @Override + public void visitPackage(final String packaze) { + packageIndex.putShort(symbolTable.addConstantPackage(packaze).index); + packageCount++; + } + + @Override + public void visitRequire(final String module, final int access, final String version) { + requires + .putShort(symbolTable.addConstantModule(module).index) + .putShort(access) + .putShort(version == null ? 0 : symbolTable.addConstantUtf8(version)); + requiresCount++; + } + + @Override + public void visitExport(final String packaze, final int access, final String... modules) { + exports.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); + if (modules == null) { + exports.putShort(0); + } else { + exports.putShort(modules.length); + for (String module : modules) { + exports.putShort(symbolTable.addConstantModule(module).index); + } + } + exportsCount++; + } + + @Override + public void visitOpen(final String packaze, final int access, final String... modules) { + opens.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); + if (modules == null) { + opens.putShort(0); + } else { + opens.putShort(modules.length); + for (String module : modules) { + opens.putShort(symbolTable.addConstantModule(module).index); + } + } + opensCount++; + } + + @Override + public void visitUse(final String service) { + usesIndex.putShort(symbolTable.addConstantClass(service).index); + usesCount++; + } + + @Override + public void visitProvide(final String service, final String... providers) { + provides.putShort(symbolTable.addConstantClass(service).index); + provides.putShort(providers.length); + for (String provider : providers) { + provides.putShort(symbolTable.addConstantClass(provider).index); + } + providesCount++; + } + + @Override + public void visitEnd() { + // Nothing to do. + } + + /** + * Returns the number of Module, ModulePackages and ModuleMainClass attributes generated by this + * ModuleWriter. + * + * @return the number of Module, ModulePackages and ModuleMainClass attributes (between 1 and 3). + */ + int getAttributeCount() { + return 1 + (packageCount > 0 ? 1 : 0) + (mainClassIndex > 0 ? 1 : 0); + } + + /** + * Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this + * ModuleWriter. Also add the names of these attributes in the constant pool. + * + * @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes. + */ + int computeAttributesSize() { + symbolTable.addConstantUtf8(Constants.MODULE); + // 6 attribute header bytes, 6 bytes for name, flags and version, and 5 * 2 bytes for counts. + int size = + 22 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; + if (packageCount > 0) { + symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES); + // 6 attribute header bytes, and 2 bytes for package_count. + size += 8 + packageIndex.length; + } + if (mainClassIndex > 0) { + symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS); + // 6 attribute header bytes, and 2 bytes for main_class_index. + size += 8; + } + return size; + } + + /** + * Puts the Module, ModulePackages and ModuleMainClass attributes generated by this ModuleWriter + * in the given ByteVector. + * + * @param output where the attributes must be put. + */ + void putAttributes(final ByteVector output) { + // 6 bytes for name, flags and version, and 5 * 2 bytes for counts. + int moduleAttributeLength = + 16 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; + output + .putShort(symbolTable.addConstantUtf8(Constants.MODULE)) + .putInt(moduleAttributeLength) + .putShort(moduleNameIndex) + .putShort(moduleFlags) + .putShort(moduleVersionIndex) + .putShort(requiresCount) + .putByteArray(requires.data, 0, requires.length) + .putShort(exportsCount) + .putByteArray(exports.data, 0, exports.length) + .putShort(opensCount) + .putByteArray(opens.data, 0, opens.length) + .putShort(usesCount) + .putByteArray(usesIndex.data, 0, usesIndex.length) + .putShort(providesCount) + .putByteArray(provides.data, 0, provides.length); + if (packageCount > 0) { + output + .putShort(symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES)) + .putInt(2 + packageIndex.length) + .putShort(packageCount) + .putByteArray(packageIndex.data, 0, packageIndex.length); + } + if (mainClassIndex > 0) { + output + .putShort(symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS)) + .putInt(2) + .putShort(mainClassIndex); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Opcodes.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Opcodes.class new file mode 100644 index 0000000000000000000000000000000000000000..b652c805815df05264e5d62205b17534e8a8b288 GIT binary patch literal 7638 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 LeT-H^>?i*LT>$9> literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Opcodes.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/Opcodes.java new file mode 100644 index 00000000..8353b787 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/Opcodes.java @@ -0,0 +1,590 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * The JVM opcodes, access flags and array type codes. This interface does not define all the JVM + * opcodes because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes + * are automatically replaced by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and + * xSTORE_n opcodes are therefore not defined in this interface. Likewise for LDC, automatically + * replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W. + * + * @see JVMS 6 + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +// DontCheck(InterfaceIsType): can't be fixed (for backward binary compatibility). +public interface Opcodes { + + // ASM API versions. + + int ASM4 = 4 << 16 | 0 << 8; + int ASM5 = 5 << 16 | 0 << 8; + int ASM6 = 6 << 16 | 0 << 8; + int ASM7 = 7 << 16 | 0 << 8; + int ASM8 = 8 << 16 | 0 << 8; + int ASM9 = 9 << 16 | 0 << 8; + + /* + * Internal flags used to redirect calls to deprecated methods. For instance, if a visitOldStuff + * method in API_OLD is deprecated and replaced with visitNewStuff in API_NEW, then the + * redirection should be done as follows: + * + *

    +      * public class StuffVisitor {
    +      *   ...
    +      *
    +      *   @Deprecated public void visitOldStuff(int arg, ...) {
    +      *     // SOURCE_DEPRECATED means "a call from a deprecated method using the old 'api' value".
    +      *     visitNewStuf(arg | (api < API_NEW ? SOURCE_DEPRECATED : 0), ...);
    +      *   }
    +      *
    +      *   public void visitNewStuff(int argAndSource, ...) {
    +      *     if (api < API_NEW && (argAndSource & SOURCE_DEPRECATED) == 0) {
    +      *       visitOldStuff(argAndSource, ...);
    +      *     } else {
    +      *       int arg = argAndSource & ~SOURCE_MASK;
    +      *       [ do stuff ]
    +      *     }
    +      *   }
    +      * }
    +      * 
    + * + *

    If 'api' is equal to API_NEW, there are two cases: + * + *

      + *
    • call visitNewStuff: the redirection test is skipped and 'do stuff' is executed directly. + *
    • call visitOldSuff: the source is not set to SOURCE_DEPRECATED before calling + * visitNewStuff, but the redirection test is skipped anyway in visitNewStuff, which + * directly executes 'do stuff'. + *
    + * + *

    If 'api' is equal to API_OLD, there are two cases: + * + *

      + *
    • call visitOldSuff: the source is set to SOURCE_DEPRECATED before calling visitNewStuff. + * Because of this visitNewStuff does not redirect back to visitOldStuff, and instead + * executes 'do stuff'. + *
    • call visitNewStuff: the call is redirected to visitOldStuff because the source is 0. + * visitOldStuff now sets the source to SOURCE_DEPRECATED and calls visitNewStuff back. This + * time visitNewStuff does not redirect the call, and instead executes 'do stuff'. + *
    + * + *

    User subclasses

    + * + *

    If a user subclass overrides one of these methods, there are only two cases: either 'api' is + * API_OLD and visitOldStuff is overridden (and visitNewStuff is not), or 'api' is API_NEW or + * more, and visitNewStuff is overridden (and visitOldStuff is not). Any other case is a user + * programming error. + * + *

    If 'api' is equal to API_NEW, the class hierarchy is equivalent to + * + *

    +      * public class StuffVisitor {
    +      *   @Deprecated public void visitOldStuff(int arg, ...) { visitNewStuf(arg, ...); }
    +      *   public void visitNewStuff(int arg, ...) { [ do stuff ] }
    +      * }
    +      * class UserStuffVisitor extends StuffVisitor {
    +      *   @Override public void visitNewStuff(int arg, ...) {
    +      *     super.visitNewStuff(int arg, ...); // optional
    +      *     [ do user stuff ]
    +      *   }
    +      * }
    +      * 
    + * + *

    It is then obvious that whether visitNewStuff or visitOldStuff is called, 'do stuff' and 'do + * user stuff' will be executed, in this order. + * + *

    If 'api' is equal to API_OLD, the class hierarchy is equivalent to + * + *

    +      * public class StuffVisitor {
    +      *   @Deprecated public void visitOldStuff(int arg, ...) {
    +      *     visitNewStuff(arg | SOURCE_DEPRECATED, ...);
    +      *   }
    +      *   public void visitNewStuff(int argAndSource...) {
    +      *     if ((argAndSource & SOURCE_DEPRECATED) == 0) {
    +      *       visitOldStuff(argAndSource, ...);
    +      *     } else {
    +      *       int arg = argAndSource & ~SOURCE_MASK;
    +      *       [ do stuff ]
    +      *     }
    +      *   }
    +      * }
    +      * class UserStuffVisitor extends StuffVisitor {
    +      *   @Override public void visitOldStuff(int arg, ...) {
    +      *     super.visitOldStuff(int arg, ...); // optional
    +      *     [ do user stuff ]
    +      *   }
    +      * }
    +      * 
    + * + *

    and there are two cases: + * + *

      + *
    • call visitOldStuff: in the call to super.visitOldStuff, the source is set to + * SOURCE_DEPRECATED and visitNewStuff is called. Here 'do stuff' is run because the source + * was previously set to SOURCE_DEPRECATED, and execution eventually returns to + * UserStuffVisitor.visitOldStuff, where 'do user stuff' is run. + *
    • call visitNewStuff: the call is redirected to UserStuffVisitor.visitOldStuff because the + * source is 0. Execution continues as in the previous case, resulting in 'do stuff' and 'do + * user stuff' being executed, in this order. + *
    + * + *

    ASM subclasses

    + * + *

    In ASM packages, subclasses of StuffVisitor can typically be sub classed again by the user, + * and can be used with API_OLD or API_NEW. Because of this, if such a subclass must override + * visitNewStuff, it must do so in the following way (and must not override visitOldStuff): + * + *

    +      * public class AsmStuffVisitor extends StuffVisitor {
    +      *   @Override public void visitNewStuff(int argAndSource, ...) {
    +      *     if (api < API_NEW && (argAndSource & SOURCE_DEPRECATED) == 0) {
    +      *       super.visitNewStuff(argAndSource, ...);
    +      *       return;
    +      *     }
    +      *     super.visitNewStuff(argAndSource, ...); // optional
    +      *     int arg = argAndSource & ~SOURCE_MASK;
    +      *     [ do other stuff ]
    +      *   }
    +      * }
    +      * 
    + * + *

    If a user class extends this with 'api' equal to API_NEW, the class hierarchy is equivalent + * to + * + *

    +      * public class StuffVisitor {
    +      *   @Deprecated public void visitOldStuff(int arg, ...) { visitNewStuf(arg, ...); }
    +      *   public void visitNewStuff(int arg, ...) { [ do stuff ] }
    +      * }
    +      * public class AsmStuffVisitor extends StuffVisitor {
    +      *   @Override public void visitNewStuff(int arg, ...) {
    +      *     super.visitNewStuff(arg, ...);
    +      *     [ do other stuff ]
    +      *   }
    +      * }
    +      * class UserStuffVisitor extends StuffVisitor {
    +      *   @Override public void visitNewStuff(int arg, ...) {
    +      *     super.visitNewStuff(int arg, ...);
    +      *     [ do user stuff ]
    +      *   }
    +      * }
    +      * 
    + * + *

    It is then obvious that whether visitNewStuff or visitOldStuff is called, 'do stuff', 'do + * other stuff' and 'do user stuff' will be executed, in this order. If, on the other hand, a user + * class extends AsmStuffVisitor with 'api' equal to API_OLD, the class hierarchy is equivalent to + * + *

    +      * public class StuffVisitor {
    +      *   @Deprecated public void visitOldStuff(int arg, ...) {
    +      *     visitNewStuf(arg | SOURCE_DEPRECATED, ...);
    +      *   }
    +      *   public void visitNewStuff(int argAndSource, ...) {
    +      *     if ((argAndSource & SOURCE_DEPRECATED) == 0) {
    +      *       visitOldStuff(argAndSource, ...);
    +      *     } else {
    +      *       int arg = argAndSource & ~SOURCE_MASK;
    +      *       [ do stuff ]
    +      *     }
    +      *   }
    +      * }
    +      * public class AsmStuffVisitor extends StuffVisitor {
    +      *   @Override public void visitNewStuff(int argAndSource, ...) {
    +      *     if ((argAndSource & SOURCE_DEPRECATED) == 0) {
    +      *       super.visitNewStuff(argAndSource, ...);
    +      *       return;
    +      *     }
    +      *     super.visitNewStuff(argAndSource, ...); // optional
    +      *     int arg = argAndSource & ~SOURCE_MASK;
    +      *     [ do other stuff ]
    +      *   }
    +      * }
    +      * class UserStuffVisitor extends StuffVisitor {
    +      *   @Override public void visitOldStuff(int arg, ...) {
    +      *     super.visitOldStuff(arg, ...);
    +      *     [ do user stuff ]
    +      *   }
    +      * }
    +      * 
    + * + *

    and, here again, whether visitNewStuff or visitOldStuff is called, 'do stuff', 'do other + * stuff' and 'do user stuff' will be executed, in this order (exercise left to the reader). + * + *

    Notes

    + * + *
      + *
    • the SOURCE_DEPRECATED flag is set only if 'api' is API_OLD, just before calling + * visitNewStuff. By hypothesis, this method is not overridden by the user. Therefore, user + * classes can never see this flag. Only ASM subclasses must take care of extracting the + * actual argument value by clearing the source flags. + *
    • because the SOURCE_DEPRECATED flag is immediately cleared in the caller, the caller can + * call visitOldStuff or visitNewStuff (in 'do stuff' and 'do user stuff') on a delegate + * visitor without any risks (breaking the redirection logic, "leaking" the flag, etc). + *
    • all the scenarios discussed above are unit tested in MethodVisitorTest. + *
    + */ + + int SOURCE_DEPRECATED = 0x100; + int SOURCE_MASK = SOURCE_DEPRECATED; + + // Java ClassFile versions (the minor version is stored in the 16 most significant bits, and the + // major version in the 16 least significant bits). + + int V1_1 = 3 << 16 | 45; + int V1_2 = 0 << 16 | 46; + int V1_3 = 0 << 16 | 47; + int V1_4 = 0 << 16 | 48; + int V1_5 = 0 << 16 | 49; + int V1_6 = 0 << 16 | 50; + int V1_7 = 0 << 16 | 51; + int V1_8 = 0 << 16 | 52; + int V9 = 0 << 16 | 53; + int V10 = 0 << 16 | 54; + int V11 = 0 << 16 | 55; + int V12 = 0 << 16 | 56; + int V13 = 0 << 16 | 57; + int V14 = 0 << 16 | 58; + int V15 = 0 << 16 | 59; + int V16 = 0 << 16 | 60; + int V17 = 0 << 16 | 61; + int V18 = 0 << 16 | 62; + int V19 = 0 << 16 | 63; + int V20 = 0 << 16 | 64; + int V21 = 0 << 16 | 65; + int V22 = 0 << 16 | 66; + int V23 = 0 << 16 | 67; + + /** + * Version flag indicating that the class is using 'preview' features. + * + *

    {@code version & V_PREVIEW == V_PREVIEW} tests if a version is flagged with {@code + * V_PREVIEW}. + */ + int V_PREVIEW = 0xFFFF0000; + + // Access flags values, defined in + // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1 + // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5-200-A.1 + // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6-200-A.1 + // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25 + + int ACC_PUBLIC = 0x0001; // class, field, method + int ACC_PRIVATE = 0x0002; // class, field, method + int ACC_PROTECTED = 0x0004; // class, field, method + int ACC_STATIC = 0x0008; // field, method + int ACC_FINAL = 0x0010; // class, field, method, parameter + int ACC_SUPER = 0x0020; // class + int ACC_SYNCHRONIZED = 0x0020; // method + int ACC_OPEN = 0x0020; // module + int ACC_TRANSITIVE = 0x0020; // module requires + int ACC_VOLATILE = 0x0040; // field + int ACC_BRIDGE = 0x0040; // method + int ACC_STATIC_PHASE = 0x0040; // module requires + int ACC_VARARGS = 0x0080; // method + int ACC_TRANSIENT = 0x0080; // field + int ACC_NATIVE = 0x0100; // method + int ACC_INTERFACE = 0x0200; // class + int ACC_ABSTRACT = 0x0400; // class, method + int ACC_STRICT = 0x0800; // method + int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module * + int ACC_ANNOTATION = 0x2000; // class + int ACC_ENUM = 0x4000; // class(?) field inner + int ACC_MANDATED = 0x8000; // field, method, parameter, module, module * + int ACC_MODULE = 0x8000; // class + + // ASM specific access flags. + // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard + // access flags, and also to make sure that these flags are automatically filtered out when + // written in class files (because access flags are stored using 16 bits only). + + int ACC_RECORD = 0x10000; // class + int ACC_DEPRECATED = 0x20000; // class, field, method + + // Possible values for the type operand of the NEWARRAY instruction. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html#jvms-6.5.newarray. + + int T_BOOLEAN = 4; + int T_CHAR = 5; + int T_FLOAT = 6; + int T_DOUBLE = 7; + int T_BYTE = 8; + int T_SHORT = 9; + int T_INT = 10; + int T_LONG = 11; + + // Possible values for the reference_kind field of CONSTANT_MethodHandle_info structures. + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4.8. + + int H_GETFIELD = 1; + int H_GETSTATIC = 2; + int H_PUTFIELD = 3; + int H_PUTSTATIC = 4; + int H_INVOKEVIRTUAL = 5; + int H_INVOKESTATIC = 6; + int H_INVOKESPECIAL = 7; + int H_NEWINVOKESPECIAL = 8; + int H_INVOKEINTERFACE = 9; + + // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}. + + /** An expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */ + int F_NEW = -1; + + /** A compressed frame with complete frame data. */ + int F_FULL = 0; + + /** + * A compressed frame where locals are the same as the locals in the previous frame, except that + * additional 1-3 locals are defined, and with an empty stack. + */ + int F_APPEND = 1; + + /** + * A compressed frame where locals are the same as the locals in the previous frame, except that + * the last 1-3 locals are absent and with an empty stack. + */ + int F_CHOP = 2; + + /** + * A compressed frame with exactly the same locals as the previous frame and with an empty stack. + */ + int F_SAME = 3; + + /** + * A compressed frame with exactly the same locals as the previous frame and with a single value + * on the stack. + */ + int F_SAME1 = 4; + + // Standard stack map frame element types, used in {@link ClassVisitor#visitFrame}. + + Integer TOP = Frame.ITEM_TOP; + Integer INTEGER = Frame.ITEM_INTEGER; + Integer FLOAT = Frame.ITEM_FLOAT; + Integer DOUBLE = Frame.ITEM_DOUBLE; + Integer LONG = Frame.ITEM_LONG; + Integer NULL = Frame.ITEM_NULL; + Integer UNINITIALIZED_THIS = Frame.ITEM_UNINITIALIZED_THIS; + + // The JVM opcode values (with the MethodVisitor method name used to visit them in comment, and + // where '-' means 'same method name as on the previous line'). + // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html. + + int NOP = 0; // visitInsn + int ACONST_NULL = 1; // - + int ICONST_M1 = 2; // - + int ICONST_0 = 3; // - + int ICONST_1 = 4; // - + int ICONST_2 = 5; // - + int ICONST_3 = 6; // - + int ICONST_4 = 7; // - + int ICONST_5 = 8; // - + int LCONST_0 = 9; // - + int LCONST_1 = 10; // - + int FCONST_0 = 11; // - + int FCONST_1 = 12; // - + int FCONST_2 = 13; // - + int DCONST_0 = 14; // - + int DCONST_1 = 15; // - + int BIPUSH = 16; // visitIntInsn + int SIPUSH = 17; // - + int LDC = 18; // visitLdcInsn + int ILOAD = 21; // visitVarInsn + int LLOAD = 22; // - + int FLOAD = 23; // - + int DLOAD = 24; // - + int ALOAD = 25; // - + int IALOAD = 46; // visitInsn + int LALOAD = 47; // - + int FALOAD = 48; // - + int DALOAD = 49; // - + int AALOAD = 50; // - + int BALOAD = 51; // - + int CALOAD = 52; // - + int SALOAD = 53; // - + int ISTORE = 54; // visitVarInsn + int LSTORE = 55; // - + int FSTORE = 56; // - + int DSTORE = 57; // - + int ASTORE = 58; // - + int IASTORE = 79; // visitInsn + int LASTORE = 80; // - + int FASTORE = 81; // - + int DASTORE = 82; // - + int AASTORE = 83; // - + int BASTORE = 84; // - + int CASTORE = 85; // - + int SASTORE = 86; // - + int POP = 87; // - + int POP2 = 88; // - + int DUP = 89; // - + int DUP_X1 = 90; // - + int DUP_X2 = 91; // - + int DUP2 = 92; // - + int DUP2_X1 = 93; // - + int DUP2_X2 = 94; // - + int SWAP = 95; // - + int IADD = 96; // - + int LADD = 97; // - + int FADD = 98; // - + int DADD = 99; // - + int ISUB = 100; // - + int LSUB = 101; // - + int FSUB = 102; // - + int DSUB = 103; // - + int IMUL = 104; // - + int LMUL = 105; // - + int FMUL = 106; // - + int DMUL = 107; // - + int IDIV = 108; // - + int LDIV = 109; // - + int FDIV = 110; // - + int DDIV = 111; // - + int IREM = 112; // - + int LREM = 113; // - + int FREM = 114; // - + int DREM = 115; // - + int INEG = 116; // - + int LNEG = 117; // - + int FNEG = 118; // - + int DNEG = 119; // - + int ISHL = 120; // - + int LSHL = 121; // - + int ISHR = 122; // - + int LSHR = 123; // - + int IUSHR = 124; // - + int LUSHR = 125; // - + int IAND = 126; // - + int LAND = 127; // - + int IOR = 128; // - + int LOR = 129; // - + int IXOR = 130; // - + int LXOR = 131; // - + int IINC = 132; // visitIincInsn + int I2L = 133; // visitInsn + int I2F = 134; // - + int I2D = 135; // - + int L2I = 136; // - + int L2F = 137; // - + int L2D = 138; // - + int F2I = 139; // - + int F2L = 140; // - + int F2D = 141; // - + int D2I = 142; // - + int D2L = 143; // - + int D2F = 144; // - + int I2B = 145; // - + int I2C = 146; // - + int I2S = 147; // - + int LCMP = 148; // - + int FCMPL = 149; // - + int FCMPG = 150; // - + int DCMPL = 151; // - + int DCMPG = 152; // - + int IFEQ = 153; // visitJumpInsn + int IFNE = 154; // - + int IFLT = 155; // - + int IFGE = 156; // - + int IFGT = 157; // - + int IFLE = 158; // - + int IF_ICMPEQ = 159; // - + int IF_ICMPNE = 160; // - + int IF_ICMPLT = 161; // - + int IF_ICMPGE = 162; // - + int IF_ICMPGT = 163; // - + int IF_ICMPLE = 164; // - + int IF_ACMPEQ = 165; // - + int IF_ACMPNE = 166; // - + int GOTO = 167; // - + int JSR = 168; // - + int RET = 169; // visitVarInsn + int TABLESWITCH = 170; // visiTableSwitchInsn + int LOOKUPSWITCH = 171; // visitLookupSwitch + int IRETURN = 172; // visitInsn + int LRETURN = 173; // - + int FRETURN = 174; // - + int DRETURN = 175; // - + int ARETURN = 176; // - + int RETURN = 177; // - + int GETSTATIC = 178; // visitFieldInsn + int PUTSTATIC = 179; // - + int GETFIELD = 180; // - + int PUTFIELD = 181; // - + int INVOKEVIRTUAL = 182; // visitMethodInsn + int INVOKESPECIAL = 183; // - + int INVOKESTATIC = 184; // - + int INVOKEINTERFACE = 185; // - + int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn + int NEW = 187; // visitTypeInsn + int NEWARRAY = 188; // visitIntInsn + int ANEWARRAY = 189; // visitTypeInsn + int ARRAYLENGTH = 190; // visitInsn + int ATHROW = 191; // - + int CHECKCAST = 192; // visitTypeInsn + int INSTANCEOF = 193; // - + int MONITORENTER = 194; // visitInsn + int MONITOREXIT = 195; // - + int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn + int IFNULL = 198; // visitJumpInsn + int IFNONNULL = 199; // - +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentVisitor.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentVisitor.class new file mode 100644 index 0000000000000000000000000000000000000000..000edf7ceef0683cbf189d613f5dfbcbbba0035d GIT binary patch literal 2183 zcmbVNU2_^`6n3BufGATU@MLg!cjyN zjA2~h@@{>vU|OExT6(i!yN!Zf-8E|7_eQm#w_Ak`qh`DH6}#owmSK4nvu%2|D=@xf zTBdhhpqML_j}@ahUx{M^u_)rqWl|uut3S{SP2Fk~)+GsnaBjX5#gxFg5g6-E&8{2m zFk(QM!qO4tW1NpMJ|ZB?jKG-zN~zg28hUftZFE|c-0H)c;drKPMR7vl#K3RUb4{yp zvtu^vh8sr~u?d_czW1zl$8l`eGwO4?W6trvW)-}HQzVe?IEGahSj?5*j8vQ-G6lhl z9Ab_`oEDhPm5z3NPr+HdFEHWRK1G2{Zuk=ln!yJwa!z38FgleObwysmc`T6Tl!|~T zvF(C_0xl9l-C(IaL*VK$%gv4Vk%EtLNg(-v`)Jv+Y)@yw1->|h)()j|baxIS1dU0l zhHyo}ReU0lmMB|~9An@o@ZIQ!cGnTp5d^r?a(mIM-h<{ouawZn39dyGi( zz*$aA2-g+d;BlFdp;o!aBGf4rx>jfgNZqn&8Ec(Z)o{1;YLhH#*{1=%pZDdA>5>sI~UldjkQC28ng$b8*a%U z9EQVEktx`C5UfXUVe(ze?<1f1eNS`Y8`aAqIp{>f|4FrQy|hDGKSmYh!V{zRQn4CJs!yju7Y7Vf~79Or!W zKF76yBQe4%@ebiOeV>AOMeg*g6B6`C7Mgd8;|o%tTaaxm{}hXl>A{zSQv@DL7{zx8 zUJv!e zF213NTqA-=(jzUF0D{F}Zb?7WIA1+{_9ns;LiiI2JbkTD$p9gUo1i!w6e)zw{{Y-0 B^y2^k literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentVisitor.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentVisitor.java new file mode 100644 index 00000000..ad0aad6b --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentVisitor.java @@ -0,0 +1,181 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A visitor to visit a record component. The methods of this class must be called in the following + * order: ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code visitAttribute} )* {@code + * visitEnd}. + * + * @author Remi Forax + * @author Eric Bruneton + */ +public abstract class RecordComponentVisitor { + /** + * The ASM API version implemented by this visitor. The value of this field must be one of {@link + * Opcodes#ASM8} or {@link Opcodes#ASM9}. + */ + protected final int api; + + /** + * The record visitor to which this visitor must delegate method calls. May be {@literal null}. + */ + protected RecordComponentVisitor delegate; + + /** + * Constructs a new {@link RecordComponentVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM8} + * or {@link Opcodes#ASM9}. + */ + protected RecordComponentVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link RecordComponentVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM8}. + * @param recordComponentVisitor the record component visitor to which this visitor must delegate + * method calls. May be null. + */ + protected RecordComponentVisitor( + final int api, final RecordComponentVisitor recordComponentVisitor) { + if (api != Opcodes.ASM9 + && api != Opcodes.ASM8 + && api != Opcodes.ASM7 + && api != Opcodes.ASM6 + && api != Opcodes.ASM5 + && api != Opcodes.ASM4) { + throw new IllegalArgumentException("Unsupported api " + api); + } + this.api = api; + this.delegate = recordComponentVisitor; + } + + /** + * The record visitor to which this visitor must delegate method calls. May be {@literal null}. + * + * @return the record visitor to which this visitor must delegate method calls, or {@literal + * null}. + */ + public RecordComponentVisitor getDelegate() { + return delegate; + } + + /** + * Visits an annotation of the record component. + * + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + if (delegate != null) { + return delegate.visitAnnotation(descriptor, visible); + } + return null; + } + + /** + * Visits an annotation on a type in the record component signature. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link + * TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See + * {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (delegate != null) { + return delegate.visitTypeAnnotation(typeRef, typePath, descriptor, visible); + } + return null; + } + + /** + * Visits a non standard attribute of the record component. + * + * @param attribute an attribute. + */ + public void visitAttribute(final Attribute attribute) { + if (delegate != null) { + delegate.visitAttribute(attribute); + } + } + + /** + * Visits the end of the record component. This method, which is the last one to be called, is + * used to inform the visitor that everything have been visited. + */ + public void visitEnd() { + if (delegate != null) { + delegate.visitEnd(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentWriter.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..d16bd064a24ee16e6a83945dce5a033efd9be86f GIT binary patch literal 4877 zcmc&&Yiu0V75=VwOmK7AS%67LOnlsZ@oZlpi3~ChCu>4=H{At<+YnTD59b1pU{le-QAUJDb_f8W@ad ziM(@P=bU@ach0%@-2CdjAN~ly2%b)$MPbX~=_7gD@h#6WD|y$O&AU^Ft+Ic&HI+B3 zbNO56%kH#QjUfr7unMgSBn-46sc=OE>zGw`z3CBmZr*h)#~-(=w(oihtwXkB``0SO z)5U@DBv!*npxr+nb3otP1O}vSC7w4xt0CqRK-%*IvOFRRHrVauohhjtTXTh zbSq>&Ijh1NbD9P^Ro`^{1OCia3f<|^!{$*lUooB8e98B0XSOg<6eBM%upS!}l8!lN z6`g78n1a$Pn+){I${GS)_Uw70q}PS3&%lMU)={-*9n)X%0#;eN$iT(;qC#)QtomaM zj&ILd0x}`k<2bHw`nKyR?1%!RP8^^~L@vda1THg>#(+XT0+D8ZdbsRarcXz_LNq=; zz8XET9Jwg&=B*0@E9MX+vj(;bl6?(G7M-KbSPJPj19>6sZy>FKzW?}q1MmXk4ngp8 zh2N|QhGLWrve7=%KUDbK0NZ8Y3PIuG1{6ZT&c{JOyVAf_xSBycV|!J9kI%H2T9Ek2 zM41}W7Lq7nD1l)E*NUigL|lc83hj<{tiEZAa=v6>53XafmU%c)k&w7rvhSfRZvyQIOO{ z|KFnJGgqkzy8^y0PWy(!#Agas(>9YZ6PPkk#x%=|h@cHa=aQ1e=xS$?5KdJUa*>LL z)P;d@1uK%iF~vUYPG~Mjmea^S@ex*ftU^X@$GT-re{leRhx|a zhin=%80FxmDzFxK+)c_Lg|6kgD5UCz5bLF|@*$KZ-z*=w*__u(Byg8PXLGql3*_c* z$RmXt31Kq`6OkuKJzeC6=NVK`NYttV)@~CD>-0|NUw8_4r6W&(kGaA>rCvUZf-!4` z$E5V6JmBdX<(yCr9z6kQ^}9J~*86RG@p^~B&$E)T(pS6Vn!H*{Z9DVbLY?9nM zKi7p@G)meQrRMp981yA~!7E!g*z$te*aTXTHrphK6^x?eSl$S0ud3)AqaxVOGHVsz zbxCx|LyEmFd2Z;Ij|;Xf@{rIiUk$ot&8u4$w7O+Ur(4!)Y}@qDg2D`Yi->9YxlC8= zO~ftxM=!L{BE0)18eQ;%CvG$!>`2;pR8U7{e^TeMs>8AX@QlD*6zgS|_j> z5Ay-@2utrrafqwCf(>BfFh@X68=`dY2r4u{=H}Ro>7K)094`Coq28yMRSB$4U~K~P z!5>!?JXC8YoFuhyrh8ALJCpeVQdxfb&)|}YMfATO&SZj_%rZK1rfb^XL}GD6hafk&h-)Mc2F1-S+RYsrgjX3m-$y%M)7$q193e0rxR3G0^Aq31 zw`y{;lpqSJx~Nt?@rD**1dE}F`%$VfzDUbOq1~OWLz~2t?B_@@6+j8z z$m9?^gJ-c;Xb1UAE#XFzzD5y^uKqDcKVb&_lo|0eI`9{K^!*aU_;rItyKCyiFoXv* zpyFVv{Vs;ZmIoQ?I(O7|&Pw2&64ZK@a1)!2Y!1eT+1q>?ttVO(d;Mq6^)g{E7xs3B zJsQy7OZvej?3*0U_KGMD1KYD_uwMoukH64*&VQ9-@~)AFzf^V!chpmKj7bUn7M=JV zE&n|&`UC%4;*Uh&PuPM#Gxh$$Q|7O@5`V)r_&dx0e_${E$$I`R9KhSS9q$mGe-Vp+ z<0Srr=kZ^SR*)E{Lg$@g`kx>&UBu^M?h+)1fyBG$RZ0Hq9HtJBP)2a_>>-7?IH_Z9 v33t|GB&8SLM;q~$91KD&8E%#2$?_P*wBT{Bw%`do$u`BANxlf4!uk&Ym56mv literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentWriter.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentWriter.java new file mode 100644 index 00000000..3098cf70 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/RecordComponentWriter.java @@ -0,0 +1,257 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +final class RecordComponentWriter extends RecordComponentVisitor { + /** Where the constants used in this RecordComponentWriter must be stored. */ + private final SymbolTable symbolTable; + + // Note: fields are ordered as in the record_component_info structure, and those related to + // attributes are ordered as in Section 4.7 of the JVMS. + + /** The name_index field of the Record attribute. */ + private final int nameIndex; + + /** The descriptor_index field of the Record attribute. */ + private final int descriptorIndex; + + /** + * The signature_index field of the Signature attribute of this record component, or 0 if there is + * no Signature attribute. + */ + private int signatureIndex; + + /** + * The last runtime visible annotation of this record component. The previous ones can be accessed + * with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleAnnotation; + + /** + * The last runtime invisible annotation of this record component. The previous ones can be + * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleAnnotation; + + /** + * The last runtime visible type annotation of this record component. The previous ones can be + * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeVisibleTypeAnnotation; + + /** + * The last runtime invisible type annotation of this record component. The previous ones can be + * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}. + */ + private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; + + /** + * The first non standard attribute of this record component. The next ones can be accessed with + * the {@link Attribute#nextAttribute} field. May be {@literal null}. + * + *

    WARNING: this list stores the attributes in the reverse order of their visit. + * firstAttribute is actually the last attribute visited in {@link #visitAttribute(Attribute)}. + * The {@link #putRecordComponentInfo(ByteVector)} method writes the attributes in the order + * defined by this list, i.e. in the reverse order specified by the user. + */ + private Attribute firstAttribute; + + /** + * Constructs a new {@link RecordComponentWriter}. + * + * @param symbolTable where the constants used in this RecordComponentWriter must be stored. + * @param name the record component name. + * @param descriptor the record component descriptor (see {@link Type}). + * @param signature the record component signature. May be {@literal null}. + */ + RecordComponentWriter( + final SymbolTable symbolTable, + final String name, + final String descriptor, + final String signature) { + super(/* latest api = */ Opcodes.ASM9); + this.symbolTable = symbolTable; + this.nameIndex = symbolTable.addConstantUtf8(name); + this.descriptorIndex = symbolTable.addConstantUtf8(descriptor); + if (signature != null) { + this.signatureIndex = symbolTable.addConstantUtf8(signature); + } + } + + // ----------------------------------------------------------------------------------------------- + // Implementation of the FieldVisitor abstract class + // ----------------------------------------------------------------------------------------------- + + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation); + } else { + return lastRuntimeInvisibleAnnotation = + AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation); + } + } + + @Override + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (visible) { + return lastRuntimeVisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation); + } else { + return lastRuntimeInvisibleTypeAnnotation = + AnnotationWriter.create( + symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation); + } + } + + @Override + public void visitAttribute(final Attribute attribute) { + // Store the attributes in the reverse order of their visit by this method. + attribute.nextAttribute = firstAttribute; + firstAttribute = attribute; + } + + @Override + public void visitEnd() { + // Nothing to do. + } + + // ----------------------------------------------------------------------------------------------- + // Utility methods + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the size of the record component JVMS structure generated by this + * RecordComponentWriter. Also adds the names of the attributes of this record component in the + * constant pool. + * + * @return the size in bytes of the record_component_info of the Record attribute. + */ + int computeRecordComponentInfoSize() { + // name_index, descriptor_index and attributes_count fields use 6 bytes. + int size = 6; + size += Attribute.computeAttributesSize(symbolTable, 0, signatureIndex); + size += + AnnotationWriter.computeAnnotationsSize( + lastRuntimeVisibleAnnotation, + lastRuntimeInvisibleAnnotation, + lastRuntimeVisibleTypeAnnotation, + lastRuntimeInvisibleTypeAnnotation); + if (firstAttribute != null) { + size += firstAttribute.computeAttributesSize(symbolTable); + } + return size; + } + + /** + * Puts the content of the record component generated by this RecordComponentWriter into the given + * ByteVector. + * + * @param output where the record_component_info structure must be put. + */ + void putRecordComponentInfo(final ByteVector output) { + output.putShort(nameIndex).putShort(descriptorIndex); + // Compute and put the attributes_count field. + // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. + int attributesCount = 0; + if (signatureIndex != 0) { + ++attributesCount; + } + if (lastRuntimeVisibleAnnotation != null) { + ++attributesCount; + } + if (lastRuntimeInvisibleAnnotation != null) { + ++attributesCount; + } + if (lastRuntimeVisibleTypeAnnotation != null) { + ++attributesCount; + } + if (lastRuntimeInvisibleTypeAnnotation != null) { + ++attributesCount; + } + if (firstAttribute != null) { + attributesCount += firstAttribute.getAttributeCount(); + } + output.putShort(attributesCount); + Attribute.putAttributes(symbolTable, 0, signatureIndex, output); + AnnotationWriter.putAnnotations( + symbolTable, + lastRuntimeVisibleAnnotation, + lastRuntimeInvisibleAnnotation, + lastRuntimeVisibleTypeAnnotation, + lastRuntimeInvisibleTypeAnnotation, + output); + if (firstAttribute != null) { + firstAttribute.putAttributes(symbolTable, output); + } + } + + /** + * Collects the attributes of this record component into the given set of attribute prototypes. + * + * @param attributePrototypes a set of attribute prototypes. + */ + final void collectAttributePrototypes(final Attribute.Set attributePrototypes) { + attributePrototypes.addAttributes(firstAttribute); + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Symbol.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Symbol.class new file mode 100644 index 0000000000000000000000000000000000000000..6d1c4f220f96a3583bdaec2f9ad2232061d8fb75 GIT binary patch literal 1921 zcma)-TXWh*6vzK-z}Q#@j2&MS+evE2rcLO*Y3-(wL15WJa*-f)dSQf7sT?daSR_rK zdifUp1bygBXUepbhkSs3s7}wyAhz*z(ie7rd;aILyV}EFe?NZ#AdjyS7(*nEsDv2C z8Pccr6Fb+oy;ja>oH{2y!}zZ2x&A$d$kujk5)+t=BOzf562r!6^HI+Ae5dQ#?OdnZ z%5?&-r%oehpP%K-XJ?I0n<3_UP3Kz%rt$zu2`TO!@$DAp83`H8lB)C6bGi%}ZB&Kn zcU`Zw!(~?_%yU`Pv(Fs9uqa_E@Oxsnd%?GNj2^-jCxcQ0=SkE3i49hLYm%FXrndABAve&FQey{79?sv{P!c40EB0hbSqPp)Dfrp{NaAPg90I^l>eRKDu01>at#_TgOMCg05&3wQ3db4qch(da=9uK6#IVrx+H)-~)vi zIxTLqa7^jd{4n|q!%FC@>NVp~slO!2h}$X~h3Y6XeUGC9Jd*Q=aw*)<9NG2^!=fXX zj|SH=%zB?;Lagw6y6LK}>Z+y6n)*=r_tE^ouv#=K59CUr{@sUqxa4lPS>&$rwR+=2v#Eut}O z6K4f}o%jubZxi1UI7j@Zz;6-1E$})}gk92k^+Q(dW zDb~kAc7D8%<=+DT8vWkjUQ9xiO;aaKBFR$J?$cOeGgxC8Y_M58Al*LVJUTwZF^zo2 zt7gHB*UhWhs0RR91 literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Symbol.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/Symbol.java new file mode 100644 index 00000000..a45f75a0 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/Symbol.java @@ -0,0 +1,291 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * An entry of the constant pool, of the BootstrapMethods attribute, or of the (ASM specific) type + * table of a class. + * + * @see JVMS + * 4.4 + * @see JVMS + * 4.7.23 + * @author Eric Bruneton + */ +abstract class Symbol { + + // Tag values for the constant pool entries (using the same order as in the JVMS). + + /** The tag value of CONSTANT_Class_info JVMS structures. */ + static final int CONSTANT_CLASS_TAG = 7; + + /** The tag value of CONSTANT_Fieldref_info JVMS structures. */ + static final int CONSTANT_FIELDREF_TAG = 9; + + /** The tag value of CONSTANT_Methodref_info JVMS structures. */ + static final int CONSTANT_METHODREF_TAG = 10; + + /** The tag value of CONSTANT_InterfaceMethodref_info JVMS structures. */ + static final int CONSTANT_INTERFACE_METHODREF_TAG = 11; + + /** The tag value of CONSTANT_String_info JVMS structures. */ + static final int CONSTANT_STRING_TAG = 8; + + /** The tag value of CONSTANT_Integer_info JVMS structures. */ + static final int CONSTANT_INTEGER_TAG = 3; + + /** The tag value of CONSTANT_Float_info JVMS structures. */ + static final int CONSTANT_FLOAT_TAG = 4; + + /** The tag value of CONSTANT_Long_info JVMS structures. */ + static final int CONSTANT_LONG_TAG = 5; + + /** The tag value of CONSTANT_Double_info JVMS structures. */ + static final int CONSTANT_DOUBLE_TAG = 6; + + /** The tag value of CONSTANT_NameAndType_info JVMS structures. */ + static final int CONSTANT_NAME_AND_TYPE_TAG = 12; + + /** The tag value of CONSTANT_Utf8_info JVMS structures. */ + static final int CONSTANT_UTF8_TAG = 1; + + /** The tag value of CONSTANT_MethodHandle_info JVMS structures. */ + static final int CONSTANT_METHOD_HANDLE_TAG = 15; + + /** The tag value of CONSTANT_MethodType_info JVMS structures. */ + static final int CONSTANT_METHOD_TYPE_TAG = 16; + + /** The tag value of CONSTANT_Dynamic_info JVMS structures. */ + static final int CONSTANT_DYNAMIC_TAG = 17; + + /** The tag value of CONSTANT_InvokeDynamic_info JVMS structures. */ + static final int CONSTANT_INVOKE_DYNAMIC_TAG = 18; + + /** The tag value of CONSTANT_Module_info JVMS structures. */ + static final int CONSTANT_MODULE_TAG = 19; + + /** The tag value of CONSTANT_Package_info JVMS structures. */ + static final int CONSTANT_PACKAGE_TAG = 20; + + // Tag values for the BootstrapMethods attribute entries (ASM specific tag). + + /** The tag value of the BootstrapMethods attribute entries. */ + static final int BOOTSTRAP_METHOD_TAG = 64; + + // Tag values for the type table entries (ASM specific tags). + + /** The tag value of a normal type entry in the (ASM specific) type table of a class. */ + static final int TYPE_TAG = 128; + + /** + * The tag value of an uninitialized type entry in the type table of a class. This type is used + * for the normal case where the NEW instruction is before the <init> constructor call (in + * bytecode offset order), i.e. when the label of the NEW instruction is resolved when the + * constructor call is visited. If the NEW instruction is after the constructor call, use the + * {@link #FORWARD_UNINITIALIZED_TYPE_TAG} tag value instead. + */ + static final int UNINITIALIZED_TYPE_TAG = 129; + + /** + * The tag value of an uninitialized type entry in the type table of a class. This type is used + * for the unusual case where the NEW instruction is after the <init> constructor call (in + * bytecode offset order), i.e. when the label of the NEW instruction is not resolved when the + * constructor call is visited. If the NEW instruction is before the constructor call, use the + * {@link #UNINITIALIZED_TYPE_TAG} tag value instead. + */ + static final int FORWARD_UNINITIALIZED_TYPE_TAG = 130; + + /** The tag value of a merged type entry in the (ASM specific) type table of a class. */ + static final int MERGED_TYPE_TAG = 131; + + // Instance fields. + + /** + * The index of this symbol in the constant pool, in the BootstrapMethods attribute, or in the + * (ASM specific) type table of a class (depending on the {@link #tag} value). + */ + final int index; + + /** + * A tag indicating the type of this symbol. Must be one of the static tag values defined in this + * class. + */ + final int tag; + + /** + * The internal name of the owner class of this symbol. Only used for {@link + * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link + * #CONSTANT_INTERFACE_METHODREF_TAG}, and {@link #CONSTANT_METHOD_HANDLE_TAG} symbols. + */ + final String owner; + + /** + * The name of the class field or method corresponding to this symbol. Only used for {@link + * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link + * #CONSTANT_INTERFACE_METHODREF_TAG}, {@link #CONSTANT_NAME_AND_TYPE_TAG}, {@link + * #CONSTANT_METHOD_HANDLE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link + * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols. + */ + final String name; + + /** + * The string value of this symbol. This is: + * + *

      + *
    • a field or method descriptor for {@link #CONSTANT_FIELDREF_TAG}, {@link + * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG}, {@link + * #CONSTANT_NAME_AND_TYPE_TAG}, {@link #CONSTANT_METHOD_HANDLE_TAG}, {@link + * #CONSTANT_METHOD_TYPE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link + * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, + *
    • an arbitrary string for {@link #CONSTANT_UTF8_TAG} and {@link #CONSTANT_STRING_TAG} + * symbols, + *
    • an internal class name for {@link #CONSTANT_CLASS_TAG}, {@link #TYPE_TAG}, {@link + * #UNINITIALIZED_TYPE_TAG} and {@link #FORWARD_UNINITIALIZED_TYPE_TAG} symbols, + *
    • {@literal null} for the other types of symbol. + *
    + */ + final String value; + + /** + * The numeric value of this symbol. This is: + * + *
      + *
    • the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link + * #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG}, + *
    • the CONSTANT_MethodHandle_info reference_kind field value for {@link + * #CONSTANT_METHOD_HANDLE_TAG} symbols, + *
    • the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link + * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, + *
    • the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for + * {@link #CONSTANT_DYNAMIC_TAG} or {@link #BOOTSTRAP_METHOD_TAG} symbols, + *
    • the bytecode offset of the NEW instruction that created an {@link + * Frame#ITEM_UNINITIALIZED} type for {@link #UNINITIALIZED_TYPE_TAG} symbols, + *
    • the index of the {@link Label} (in the {@link SymbolTable#labelTable} table) of the NEW + * instruction that created an {@link Frame#ITEM_UNINITIALIZED} type for {@link + * #FORWARD_UNINITIALIZED_TYPE_TAG} symbols, + *
    • the indices (in the class' type table) of two {@link #TYPE_TAG} source types for {@link + * #MERGED_TYPE_TAG} symbols, + *
    • 0 for the other types of symbol. + *
    + */ + final long data; + + /** + * Additional information about this symbol, generally computed lazily. Warning: the value of + * this field is ignored when comparing Symbol instances (to avoid duplicate entries in a + * SymbolTable). Therefore, this field should only contain data that can be computed from the + * other fields of this class. It contains: + * + *
      + *
    • the {@link Type#getArgumentsAndReturnSizes} of the symbol's method descriptor for {@link + * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link + * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, + *
    • the index in the InnerClasses_attribute 'classes' array (plus one) corresponding to this + * class, for {@link #CONSTANT_CLASS_TAG} symbols, + *
    • the index (in the class' type table) of the merged type of the two source types for + * {@link #MERGED_TYPE_TAG} symbols, + *
    • 0 for the other types of symbol, or if this field has not been computed yet. + *
    + */ + int info; + + /** + * Constructs a new Symbol. This constructor can't be used directly because the Symbol class is + * abstract. Instead, use the factory methods of the {@link SymbolTable} class. + * + * @param index the symbol index in the constant pool, in the BootstrapMethods attribute, or in + * the (ASM specific) type table of a class (depending on 'tag'). + * @param tag the symbol type. Must be one of the static tag values defined in this class. + * @param owner The internal name of the symbol's owner class. Maybe {@literal null}. + * @param name The name of the symbol's corresponding class field or method. Maybe {@literal + * null}. + * @param value The string value of this symbol. Maybe {@literal null}. + * @param data The numeric value of this symbol. + */ + Symbol( + final int index, + final int tag, + final String owner, + final String name, + final String value, + final long data) { + this.index = index; + this.tag = tag; + this.owner = owner; + this.name = name; + this.value = value; + this.data = data; + } + + /** + * Returns the result {@link Type#getArgumentsAndReturnSizes} on {@link #value}. + * + * @return the result {@link Type#getArgumentsAndReturnSizes} on {@link #value} (memoized in + * {@link #info} for efficiency). This should only be used for {@link + * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link + * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols. + */ + int getArgumentsAndReturnSizes() { + if (info == 0) { + info = Type.getArgumentsAndReturnSizes(value); + } + return info; + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable$Entry.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable$Entry.class new file mode 100644 index 0000000000000000000000000000000000000000..2f321bb88de5bb7bf06f7a50d8cdddf02e9df292 GIT binary patch literal 1406 zcmbV~T~8B16o%hvclt$v?oyBfejuRI1eX}^KyHY}l7}_ zQ4>EB(TIsZz#nBiGmC|Uy(nJn&e^kb=6%k*=l7qpUjTM-zkn3dSr|odWEj?Z?L*t~ zA{ltXwf&%D`^}zgMMtt}i?DAWob;Q%%aGZ2JSW;=*nUu})q7$nY*%<4`ydJ&ud_8y zW^cWbM-KTc3Pnty$gnw<_)F1r75P_q}&yz;fbwUR2cx`#ikd8!$zWgIk2CCx9 zjjG;6pW5U@;SOju+9DFv^&Z1~BDsdDB>vjd|Eh`qu1f38S=tm9r^tSxdpGQnp6Q)=1eJDOkS7JCNhHuwkP*$k! zW10(wcrh-eYxMLZ~8iejPEgHrIgX_uP1-9VCR`?EY0!Gk}* zqaS}qoJ|Ei2tDk+VVL*c%hu?Ega@F=O{f=lR3==1T z3X)TX?9Of@j~wzAYzLEY7!EtFJ1Lw3UDbabqT|EZH#Oxbb8Jwz8BC1Fp$3i>(E*J;2)eJpw7Os9Mid?;7LSP0(x)~i4vxIXL z-RNIHSSUY%l}kfd<-H-M9x0Wu W%PyrV%UDUVgf&8&jB_Yq9V_3o3Y)$F literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable.class new file mode 100644 index 0000000000000000000000000000000000000000..1c9afebc80bde4c51b3d0255b4c7e2b29ad4e098 GIT binary patch literal 22245 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 Z%F?dII2(Mpy({2%1~({}&> literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable.java new file mode 100644 index 00000000..5fc629d6 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/SymbolTable.java @@ -0,0 +1,1495 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type + * table entries of a class. + * + * @author Eric Bruneton + * @see JVMS + * 4.4 + * @see JVMS + * 4.7.23 + */ +final class SymbolTable { + + /** + * The ClassWriter to which this SymbolTable belongs. This is only used to get access to {@link + * ClassWriter#getCommonSuperClass} and to serialize custom attributes with {@link + * Attribute#write}. + */ + final ClassWriter classWriter; + + /** + * The ClassReader from which this SymbolTable was constructed, or {@literal null} if it was + * constructed from scratch. + */ + private final ClassReader sourceClassReader; + + /** The major version number of the class to which this symbol table belongs. */ + private int majorVersion; + + /** The internal name of the class to which this symbol table belongs. */ + private String className; + + /** + * The total number of {@link Entry} instances in {@link #entries}. This includes entries that are + * accessible (recursively) via {@link Entry#next}. + */ + private int entryCount; + + /** + * A hash set of all the entries in this SymbolTable (this includes the constant pool entries, the + * bootstrap method entries and the type table entries). Each {@link Entry} instance is stored at + * the array index given by its hash code modulo the array size. If several entries must be stored + * at the same array index, they are linked together via their {@link Entry#next} field. The + * factory methods of this class make sure that this table does not contain duplicated entries. + */ + private Entry[] entries; + + /** + * The number of constant pool items in {@link #constantPool}, plus 1. The first constant pool + * item has index 1, and long and double items count for two items. + */ + private int constantPoolCount; + + /** + * The content of the ClassFile's constant_pool JVMS structure corresponding to this SymbolTable. + * The ClassFile's constant_pool_count field is not included. + */ + private ByteVector constantPool; + + /** + * The number of bootstrap methods in {@link #bootstrapMethods}. Corresponds to the + * BootstrapMethods_attribute's num_bootstrap_methods field value. + */ + private int bootstrapMethodCount; + + /** + * The content of the BootstrapMethods attribute 'bootstrap_methods' array corresponding to this + * SymbolTable. Note that the first 6 bytes of the BootstrapMethods_attribute, and its + * num_bootstrap_methods field, are not included. + */ + private ByteVector bootstrapMethods; + + /** + * The actual number of elements in {@link #typeTable}. These elements are stored from index 0 to + * typeCount (excluded). The other array entries are empty. + */ + private int typeCount; + + /** + * An ASM specific type table used to temporarily store internal names that will not necessarily + * be stored in the constant pool. This type table is used by the control flow and data flow + * analysis algorithm used to compute stack map frames from scratch. This array stores {@link + * Symbol#TYPE_TAG}, {@link Symbol#UNINITIALIZED_TYPE_TAG},{@link + * Symbol#FORWARD_UNINITIALIZED_TYPE_TAG} and {@link Symbol#MERGED_TYPE_TAG} entries. The type + * symbol at index {@code i} has its {@link Symbol#index} equal to {@code i} (and vice versa). + */ + private Entry[] typeTable; + + /** + * The actual number of {@link LabelEntry} in {@link #labelTable}. These elements are stored from + * index 0 to labelCount (excluded). The other array entries are empty. These label entries are + * also stored in the {@link #labelEntries} hash set. + */ + private int labelCount; + + /** + * The labels corresponding to the "forward uninitialized" types in the ASM specific {@link + * typeTable} (see {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG}). The label entry at index {@code + * i} has its {@link LabelEntry#index} equal to {@code i} (and vice versa). + */ + private LabelEntry[] labelTable; + + /** + * A hash set of all the {@link LabelEntry} elements in the {@link #labelTable}. Each {@link + * LabelEntry} instance is stored at the array index given by its hash code modulo the array size. + * If several entries must be stored at the same array index, they are linked together via their + * {@link LabelEntry#next} field. The {@link #getOrAddLabelEntry(Label)} method ensures that this + * table does not contain duplicated entries. + */ + private LabelEntry[] labelEntries; + + /** + * Constructs a new, empty SymbolTable for the given ClassWriter. + * + * @param classWriter a ClassWriter. + */ + SymbolTable(final ClassWriter classWriter) { + this.classWriter = classWriter; + this.sourceClassReader = null; + this.entries = new Entry[256]; + this.constantPoolCount = 1; + this.constantPool = new ByteVector(); + } + + /** + * Constructs a new SymbolTable for the given ClassWriter, initialized with the constant pool and + * bootstrap methods of the given ClassReader. + * + * @param classWriter a ClassWriter. + * @param classReader the ClassReader whose constant pool and bootstrap methods must be copied to + * initialize the SymbolTable. + */ + SymbolTable(final ClassWriter classWriter, final ClassReader classReader) { + this.classWriter = classWriter; + this.sourceClassReader = classReader; + + // Copy the constant pool binary content. + byte[] inputBytes = classReader.classFileBuffer; + int constantPoolOffset = classReader.getItem(1) - 1; + int constantPoolLength = classReader.header - constantPoolOffset; + constantPoolCount = classReader.getItemCount(); + constantPool = new ByteVector(constantPoolLength); + constantPool.putByteArray(inputBytes, constantPoolOffset, constantPoolLength); + + // Add the constant pool items in the symbol table entries. Reserve enough space in 'entries' to + // avoid too many hash set collisions (entries is not dynamically resized by the addConstant* + // method calls below), and to account for bootstrap method entries. + entries = new Entry[constantPoolCount * 2]; + char[] charBuffer = new char[classReader.getMaxStringLength()]; + boolean hasBootstrapMethods = false; + int itemIndex = 1; + while (itemIndex < constantPoolCount) { + int itemOffset = classReader.getItem(itemIndex); + int itemTag = inputBytes[itemOffset - 1]; + int nameAndTypeItemOffset; + switch (itemTag) { + case Symbol.CONSTANT_FIELDREF_TAG: + case Symbol.CONSTANT_METHODREF_TAG: + case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: + nameAndTypeItemOffset = + classReader.getItem(classReader.readUnsignedShort(itemOffset + 2)); + addConstantMemberReference( + itemIndex, + itemTag, + classReader.readClass(itemOffset, charBuffer), + classReader.readUTF8(nameAndTypeItemOffset, charBuffer), + classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer)); + break; + case Symbol.CONSTANT_INTEGER_TAG: + case Symbol.CONSTANT_FLOAT_TAG: + addConstantIntegerOrFloat(itemIndex, itemTag, classReader.readInt(itemOffset)); + break; + case Symbol.CONSTANT_NAME_AND_TYPE_TAG: + addConstantNameAndType( + itemIndex, + classReader.readUTF8(itemOffset, charBuffer), + classReader.readUTF8(itemOffset + 2, charBuffer)); + break; + case Symbol.CONSTANT_LONG_TAG: + case Symbol.CONSTANT_DOUBLE_TAG: + addConstantLongOrDouble(itemIndex, itemTag, classReader.readLong(itemOffset)); + break; + case Symbol.CONSTANT_UTF8_TAG: + addConstantUtf8(itemIndex, classReader.readUtf(itemIndex, charBuffer)); + break; + case Symbol.CONSTANT_METHOD_HANDLE_TAG: + int memberRefItemOffset = + classReader.getItem(classReader.readUnsignedShort(itemOffset + 1)); + nameAndTypeItemOffset = + classReader.getItem(classReader.readUnsignedShort(memberRefItemOffset + 2)); + addConstantMethodHandle( + itemIndex, + classReader.readByte(itemOffset), + classReader.readClass(memberRefItemOffset, charBuffer), + classReader.readUTF8(nameAndTypeItemOffset, charBuffer), + classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer)); + break; + case Symbol.CONSTANT_DYNAMIC_TAG: + case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: + hasBootstrapMethods = true; + nameAndTypeItemOffset = + classReader.getItem(classReader.readUnsignedShort(itemOffset + 2)); + addConstantDynamicOrInvokeDynamicReference( + itemTag, + itemIndex, + classReader.readUTF8(nameAndTypeItemOffset, charBuffer), + classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer), + classReader.readUnsignedShort(itemOffset)); + break; + case Symbol.CONSTANT_STRING_TAG: + case Symbol.CONSTANT_CLASS_TAG: + case Symbol.CONSTANT_METHOD_TYPE_TAG: + case Symbol.CONSTANT_MODULE_TAG: + case Symbol.CONSTANT_PACKAGE_TAG: + addConstantUtf8Reference( + itemIndex, itemTag, classReader.readUTF8(itemOffset, charBuffer)); + break; + default: + throw new IllegalArgumentException(); + } + itemIndex += + (itemTag == Symbol.CONSTANT_LONG_TAG || itemTag == Symbol.CONSTANT_DOUBLE_TAG) ? 2 : 1; + } + + // Copy the BootstrapMethods, if any. + if (hasBootstrapMethods) { + copyBootstrapMethods(classReader, charBuffer); + } + } + + /** + * Read the BootstrapMethods 'bootstrap_methods' array binary content and add them as entries of + * the SymbolTable. + * + * @param classReader the ClassReader whose bootstrap methods must be copied to initialize the + * SymbolTable. + * @param charBuffer a buffer used to read strings in the constant pool. + */ + private void copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer) { + // Find attributOffset of the 'bootstrap_methods' array. + byte[] inputBytes = classReader.classFileBuffer; + int currentAttributeOffset = classReader.getFirstAttributeOffset(); + for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { + String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer); + if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { + bootstrapMethodCount = classReader.readUnsignedShort(currentAttributeOffset + 6); + break; + } + currentAttributeOffset += 6 + classReader.readInt(currentAttributeOffset + 2); + } + if (bootstrapMethodCount > 0) { + // Compute the offset and the length of the BootstrapMethods 'bootstrap_methods' array. + int bootstrapMethodsOffset = currentAttributeOffset + 8; + int bootstrapMethodsLength = classReader.readInt(currentAttributeOffset + 2) - 2; + bootstrapMethods = new ByteVector(bootstrapMethodsLength); + bootstrapMethods.putByteArray(inputBytes, bootstrapMethodsOffset, bootstrapMethodsLength); + + // Add each bootstrap method in the symbol table entries. + int currentOffset = bootstrapMethodsOffset; + for (int i = 0; i < bootstrapMethodCount; i++) { + int offset = currentOffset - bootstrapMethodsOffset; + int bootstrapMethodRef = classReader.readUnsignedShort(currentOffset); + currentOffset += 2; + int numBootstrapArguments = classReader.readUnsignedShort(currentOffset); + currentOffset += 2; + int hashCode = classReader.readConst(bootstrapMethodRef, charBuffer).hashCode(); + while (numBootstrapArguments-- > 0) { + int bootstrapArgument = classReader.readUnsignedShort(currentOffset); + currentOffset += 2; + hashCode ^= classReader.readConst(bootstrapArgument, charBuffer).hashCode(); + } + add(new Entry(i, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode & 0x7FFFFFFF)); + } + } + } + + /** + * Returns the ClassReader from which this SymbolTable was constructed. + * + * @return the ClassReader from which this SymbolTable was constructed, or {@literal null} if it + * was constructed from scratch. + */ + ClassReader getSource() { + return sourceClassReader; + } + + /** + * Returns the major version of the class to which this symbol table belongs. + * + * @return the major version of the class to which this symbol table belongs. + */ + int getMajorVersion() { + return majorVersion; + } + + /** + * Returns the internal name of the class to which this symbol table belongs. + * + * @return the internal name of the class to which this symbol table belongs. + */ + String getClassName() { + return className; + } + + /** + * Sets the major version and the name of the class to which this symbol table belongs. Also adds + * the class name to the constant pool. + * + * @param majorVersion a major ClassFile version number. + * @param className an internal class name. + * @return the constant pool index of a new or already existing Symbol with the given class name. + */ + int setMajorVersionAndClassName(final int majorVersion, final String className) { + this.majorVersion = majorVersion; + this.className = className; + return addConstantClass(className).index; + } + + /** + * Returns the number of items in this symbol table's constant_pool array (plus 1). + * + * @return the number of items in this symbol table's constant_pool array (plus 1). + */ + int getConstantPoolCount() { + return constantPoolCount; + } + + /** + * Returns the length in bytes of this symbol table's constant_pool array. + * + * @return the length in bytes of this symbol table's constant_pool array. + */ + int getConstantPoolLength() { + return constantPool.length; + } + + /** + * Puts this symbol table's constant_pool array in the given ByteVector, preceded by the + * constant_pool_count value. + * + * @param output where the JVMS ClassFile's constant_pool array must be put. + */ + void putConstantPool(final ByteVector output) { + output.putShort(constantPoolCount).putByteArray(constantPool.data, 0, constantPool.length); + } + + /** + * Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the + * attribute name in the constant pool. + * + * @return the size in bytes of this symbol table's BootstrapMethods attribute. + */ + int computeBootstrapMethodsSize() { + if (bootstrapMethods != null) { + addConstantUtf8(Constants.BOOTSTRAP_METHODS); + return 8 + bootstrapMethods.length; + } else { + return 0; + } + } + + /** + * Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the + * 6 attribute header bytes and the num_bootstrap_methods value. + * + * @param output where the JVMS BootstrapMethods attribute must be put. + */ + void putBootstrapMethods(final ByteVector output) { + if (bootstrapMethods != null) { + output + .putShort(addConstantUtf8(Constants.BOOTSTRAP_METHODS)) + .putInt(bootstrapMethods.length + 2) + .putShort(bootstrapMethodCount) + .putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); + } + } + + // ----------------------------------------------------------------------------------------------- + // Generic symbol table entries management. + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the list of entries which can potentially have the given hash code. + * + * @param hashCode a {@link Entry#hashCode} value. + * @return the list of entries which can potentially have the given hash code. The list is stored + * via the {@link Entry#next} field. + */ + private Entry get(final int hashCode) { + return entries[hashCode % entries.length]; + } + + /** + * Puts the given entry in the {@link #entries} hash set. This method does not check + * whether {@link #entries} already contains a similar entry or not. {@link #entries} is resized + * if necessary to avoid hash collisions (multiple entries needing to be stored at the same {@link + * #entries} array index) as much as possible, with reasonable memory usage. + * + * @param entry an Entry (which must not already be contained in {@link #entries}). + * @return the given entry + */ + private Entry put(final Entry entry) { + if (entryCount > (entries.length * 3) / 4) { + int currentCapacity = entries.length; + int newCapacity = currentCapacity * 2 + 1; + Entry[] newEntries = new Entry[newCapacity]; + for (int i = currentCapacity - 1; i >= 0; --i) { + Entry currentEntry = entries[i]; + while (currentEntry != null) { + int newCurrentEntryIndex = currentEntry.hashCode % newCapacity; + Entry nextEntry = currentEntry.next; + currentEntry.next = newEntries[newCurrentEntryIndex]; + newEntries[newCurrentEntryIndex] = currentEntry; + currentEntry = nextEntry; + } + } + entries = newEntries; + } + entryCount++; + int index = entry.hashCode % entries.length; + entry.next = entries[index]; + return entries[index] = entry; + } + + /** + * Adds the given entry in the {@link #entries} hash set. This method does not check + * whether {@link #entries} already contains a similar entry or not, and does not resize + * {@link #entries} if necessary. + * + * @param entry an Entry (which must not already be contained in {@link #entries}). + */ + private void add(final Entry entry) { + entryCount++; + int index = entry.hashCode % entries.length; + entry.next = entries[index]; + entries[index] = entry; + } + + // ----------------------------------------------------------------------------------------------- + // Constant pool entries management. + // ----------------------------------------------------------------------------------------------- + + /** + * Adds a number or string constant to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param value the value of the constant to be added to the constant pool. This parameter must be + * an {@link Integer}, {@link Byte}, {@link Character}, {@link Short}, {@link Boolean}, {@link + * Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle}. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstant(final Object value) { + if (value instanceof Integer) { + return addConstantInteger(((Integer) value).intValue()); + } else if (value instanceof Byte) { + return addConstantInteger(((Byte) value).intValue()); + } else if (value instanceof Character) { + return addConstantInteger(((Character) value).charValue()); + } else if (value instanceof Short) { + return addConstantInteger(((Short) value).intValue()); + } else if (value instanceof Boolean) { + return addConstantInteger(((Boolean) value).booleanValue() ? 1 : 0); + } else if (value instanceof Float) { + return addConstantFloat(((Float) value).floatValue()); + } else if (value instanceof Long) { + return addConstantLong(((Long) value).longValue()); + } else if (value instanceof Double) { + return addConstantDouble(((Double) value).doubleValue()); + } else if (value instanceof String) { + return addConstantString((String) value); + } else if (value instanceof Type) { + Type type = (Type) value; + int typeSort = type.getSort(); + if (typeSort == Type.OBJECT) { + return addConstantClass(type.getInternalName()); + } else if (typeSort == Type.METHOD) { + return addConstantMethodType(type.getDescriptor()); + } else { // type is a primitive or array type. + return addConstantClass(type.getDescriptor()); + } + } else if (value instanceof Handle) { + Handle handle = (Handle) value; + return addConstantMethodHandle( + handle.getTag(), + handle.getOwner(), + handle.getName(), + handle.getDesc(), + handle.isInterface()); + } else if (value instanceof ConstantDynamic) { + ConstantDynamic constantDynamic = (ConstantDynamic) value; + return addConstantDynamic( + constantDynamic.getName(), + constantDynamic.getDescriptor(), + constantDynamic.getBootstrapMethod(), + constantDynamic.getBootstrapMethodArgumentsUnsafe()); + } else { + throw new IllegalArgumentException("value " + value); + } + } + + /** + * Adds a CONSTANT_Class_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param value the internal name of a class. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantClass(final String value) { + return addConstantUtf8Reference(Symbol.CONSTANT_CLASS_TAG, value); + } + + /** + * Adds a CONSTANT_Fieldref_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param owner the internal name of a class. + * @param name a field name. + * @param descriptor a field descriptor. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantFieldref(final String owner, final String name, final String descriptor) { + return addConstantMemberReference(Symbol.CONSTANT_FIELDREF_TAG, owner, name, descriptor); + } + + /** + * Adds a CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to the constant pool of this + * symbol table. Does nothing if the constant pool already contains a similar item. + * + * @param owner the internal name of a class. + * @param name a method name. + * @param descriptor a method descriptor. + * @param isInterface whether owner is an interface or not. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantMethodref( + final String owner, final String name, final String descriptor, final boolean isInterface) { + int tag = isInterface ? Symbol.CONSTANT_INTERFACE_METHODREF_TAG : Symbol.CONSTANT_METHODREF_TAG; + return addConstantMemberReference(tag, owner, name, descriptor); + } + + /** + * Adds a CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to + * the constant pool of this symbol table. Does nothing if the constant pool already contains a + * similar item. + * + * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG} + * or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}. + * @param owner the internal name of a class. + * @param name a field or method name. + * @param descriptor a field or method descriptor. + * @return a new or already existing Symbol with the given value. + */ + private Entry addConstantMemberReference( + final int tag, final String owner, final String name, final String descriptor) { + int hashCode = hash(tag, owner, name, descriptor); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == tag + && entry.hashCode == hashCode + && entry.owner.equals(owner) + && entry.name.equals(name) + && entry.value.equals(descriptor)) { + return entry; + } + entry = entry.next; + } + constantPool.put122( + tag, addConstantClass(owner).index, addConstantNameAndType(name, descriptor)); + return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, 0, hashCode)); + } + + /** + * Adds a new CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info + * to the constant pool of this symbol table. + * + * @param index the constant pool index of the new Symbol. + * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG} + * or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}. + * @param owner the internal name of a class. + * @param name a field or method name. + * @param descriptor a field or method descriptor. + */ + private void addConstantMemberReference( + final int index, + final int tag, + final String owner, + final String name, + final String descriptor) { + add(new Entry(index, tag, owner, name, descriptor, 0, hash(tag, owner, name, descriptor))); + } + + /** + * Adds a CONSTANT_String_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param value a string. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantString(final String value) { + return addConstantUtf8Reference(Symbol.CONSTANT_STRING_TAG, value); + } + + /** + * Adds a CONSTANT_Integer_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param value an int. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantInteger(final int value) { + return addConstantIntegerOrFloat(Symbol.CONSTANT_INTEGER_TAG, value); + } + + /** + * Adds a CONSTANT_Float_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param value a float. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantFloat(final float value) { + return addConstantIntegerOrFloat(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value)); + } + + /** + * Adds a CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol table. + * Does nothing if the constant pool already contains a similar item. + * + * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}. + * @param value an int or float. + * @return a constant pool constant with the given tag and primitive values. + */ + private Symbol addConstantIntegerOrFloat(final int tag, final int value) { + int hashCode = hash(tag, value); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) { + return entry; + } + entry = entry.next; + } + constantPool.putByte(tag).putInt(value); + return put(new Entry(constantPoolCount++, tag, value, hashCode)); + } + + /** + * Adds a new CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol + * table. + * + * @param index the constant pool index of the new Symbol. + * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}. + * @param value an int or float. + */ + private void addConstantIntegerOrFloat(final int index, final int tag, final int value) { + add(new Entry(index, tag, value, hash(tag, value))); + } + + /** + * Adds a CONSTANT_Long_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param value a long. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantLong(final long value) { + return addConstantLongOrDouble(Symbol.CONSTANT_LONG_TAG, value); + } + + /** + * Adds a CONSTANT_Double_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param value a double. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantDouble(final double value) { + return addConstantLongOrDouble(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value)); + } + + /** + * Adds a CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol table. + * Does nothing if the constant pool already contains a similar item. + * + * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}. + * @param value a long or double. + * @return a constant pool constant with the given tag and primitive values. + */ + private Symbol addConstantLongOrDouble(final int tag, final long value) { + int hashCode = hash(tag, value); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) { + return entry; + } + entry = entry.next; + } + int index = constantPoolCount; + constantPool.putByte(tag).putLong(value); + constantPoolCount += 2; + return put(new Entry(index, tag, value, hashCode)); + } + + /** + * Adds a new CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol + * table. + * + * @param index the constant pool index of the new Symbol. + * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}. + * @param value a long or double. + */ + private void addConstantLongOrDouble(final int index, final int tag, final long value) { + add(new Entry(index, tag, value, hash(tag, value))); + } + + /** + * Adds a CONSTANT_NameAndType_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param name a field or method name. + * @param descriptor a field or method descriptor. + * @return a new or already existing Symbol with the given value. + */ + int addConstantNameAndType(final String name, final String descriptor) { + final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG; + int hashCode = hash(tag, name, descriptor); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == tag + && entry.hashCode == hashCode + && entry.name.equals(name) + && entry.value.equals(descriptor)) { + return entry.index; + } + entry = entry.next; + } + constantPool.put122(tag, addConstantUtf8(name), addConstantUtf8(descriptor)); + return put(new Entry(constantPoolCount++, tag, name, descriptor, hashCode)).index; + } + + /** + * Adds a new CONSTANT_NameAndType_info to the constant pool of this symbol table. + * + * @param index the constant pool index of the new Symbol. + * @param name a field or method name. + * @param descriptor a field or method descriptor. + */ + private void addConstantNameAndType(final int index, final String name, final String descriptor) { + final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG; + add(new Entry(index, tag, name, descriptor, hash(tag, name, descriptor))); + } + + /** + * Adds a CONSTANT_Utf8_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param value a string. + * @return a new or already existing Symbol with the given value. + */ + int addConstantUtf8(final String value) { + int hashCode = hash(Symbol.CONSTANT_UTF8_TAG, value); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == Symbol.CONSTANT_UTF8_TAG + && entry.hashCode == hashCode + && entry.value.equals(value)) { + return entry.index; + } + entry = entry.next; + } + constantPool.putByte(Symbol.CONSTANT_UTF8_TAG).putUTF8(value); + return put(new Entry(constantPoolCount++, Symbol.CONSTANT_UTF8_TAG, value, hashCode)).index; + } + + /** + * Adds a new CONSTANT_String_info to the constant pool of this symbol table. + * + * @param index the constant pool index of the new Symbol. + * @param value a string. + */ + private void addConstantUtf8(final int index, final String value) { + add(new Entry(index, Symbol.CONSTANT_UTF8_TAG, value, hash(Symbol.CONSTANT_UTF8_TAG, value))); + } + + /** + * Adds a CONSTANT_MethodHandle_info to the constant pool of this symbol table. Does nothing if + * the constant pool already contains a similar item. + * + * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link + * Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link + * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link + * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of a class of interface. + * @param name a field or method name. + * @param descriptor a field or method descriptor. + * @param isInterface whether owner is an interface or not. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantMethodHandle( + final int referenceKind, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG; + // Note that we don't need to include isInterface in the hash computation, because it is + // redundant with owner (we can't have the same owner with different isInterface values). + int hashCode = hash(tag, owner, name, descriptor, referenceKind); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == tag + && entry.hashCode == hashCode + && entry.data == referenceKind + && entry.owner.equals(owner) + && entry.name.equals(name) + && entry.value.equals(descriptor)) { + return entry; + } + entry = entry.next; + } + if (referenceKind <= Opcodes.H_PUTSTATIC) { + constantPool.put112(tag, referenceKind, addConstantFieldref(owner, name, descriptor).index); + } else { + constantPool.put112( + tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index); + } + return put( + new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode)); + } + + /** + * Adds a new CONSTANT_MethodHandle_info to the constant pool of this symbol table. + * + * @param index the constant pool index of the new Symbol. + * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link + * Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link + * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link + * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of a class of interface. + * @param name a field or method name. + * @param descriptor a field or method descriptor. + */ + private void addConstantMethodHandle( + final int index, + final int referenceKind, + final String owner, + final String name, + final String descriptor) { + final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG; + int hashCode = hash(tag, owner, name, descriptor, referenceKind); + add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode)); + } + + /** + * Adds a CONSTANT_MethodType_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param methodDescriptor a method descriptor. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantMethodType(final String methodDescriptor) { + return addConstantUtf8Reference(Symbol.CONSTANT_METHOD_TYPE_TAG, methodDescriptor); + } + + /** + * Adds a CONSTANT_Dynamic_info to the constant pool of this symbol table. Also adds the related + * bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the constant + * pool already contains a similar item. + * + * @param name a method name. + * @param descriptor a field descriptor. + * @param bootstrapMethodHandle a bootstrap method handle. + * @param bootstrapMethodArguments the bootstrap method arguments. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantDynamic( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments); + return addConstantDynamicOrInvokeDynamicReference( + Symbol.CONSTANT_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index); + } + + /** + * Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Also adds the + * related bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param name a method name. + * @param descriptor a method descriptor. + * @param bootstrapMethodHandle a bootstrap method handle. + * @param bootstrapMethodArguments the bootstrap method arguments. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantInvokeDynamic( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments); + return addConstantDynamicOrInvokeDynamicReference( + Symbol.CONSTANT_INVOKE_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index); + } + + /** + * Adds a CONSTANT_Dynamic or a CONSTANT_InvokeDynamic_info to the constant pool of this symbol + * table. Does nothing if the constant pool already contains a similar item. + * + * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link + * Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}. + * @param name a method name. + * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG) or a method descriptor for + * CONSTANT_INVOKE_DYNAMIC_TAG. + * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute. + * @return a new or already existing Symbol with the given value. + */ + private Symbol addConstantDynamicOrInvokeDynamicReference( + final int tag, final String name, final String descriptor, final int bootstrapMethodIndex) { + int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == tag + && entry.hashCode == hashCode + && entry.data == bootstrapMethodIndex + && entry.name.equals(name) + && entry.value.equals(descriptor)) { + return entry; + } + entry = entry.next; + } + constantPool.put122(tag, bootstrapMethodIndex, addConstantNameAndType(name, descriptor)); + return put( + new Entry( + constantPoolCount++, tag, null, name, descriptor, bootstrapMethodIndex, hashCode)); + } + + /** + * Adds a new CONSTANT_Dynamic_info or CONSTANT_InvokeDynamic_info to the constant pool of this + * symbol table. + * + * @param tag one of {@link Symbol#CONSTANT_DYNAMIC_TAG} or {@link + * Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}. + * @param index the constant pool index of the new Symbol. + * @param name a method name. + * @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG or a method descriptor for + * CONSTANT_INVOKE_DYNAMIC_TAG. + * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute. + */ + private void addConstantDynamicOrInvokeDynamicReference( + final int tag, + final int index, + final String name, + final String descriptor, + final int bootstrapMethodIndex) { + int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex); + add(new Entry(index, tag, null, name, descriptor, bootstrapMethodIndex, hashCode)); + } + + /** + * Adds a CONSTANT_Module_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param moduleName a fully qualified name (using dots) of a module. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantModule(final String moduleName) { + return addConstantUtf8Reference(Symbol.CONSTANT_MODULE_TAG, moduleName); + } + + /** + * Adds a CONSTANT_Package_info to the constant pool of this symbol table. Does nothing if the + * constant pool already contains a similar item. + * + * @param packageName the internal name of a package. + * @return a new or already existing Symbol with the given value. + */ + Symbol addConstantPackage(final String packageName) { + return addConstantUtf8Reference(Symbol.CONSTANT_PACKAGE_TAG, packageName); + } + + /** + * Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info, + * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does + * nothing if the constant pool already contains a similar item. + * + * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link + * Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link + * Symbol#CONSTANT_PACKAGE_TAG}. + * @param value an internal class name, an arbitrary string, a method descriptor, a module or a + * package name, depending on tag. + * @return a new or already existing Symbol with the given value. + */ + private Symbol addConstantUtf8Reference(final int tag, final String value) { + int hashCode = hash(tag, value); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == tag && entry.hashCode == hashCode && entry.value.equals(value)) { + return entry; + } + entry = entry.next; + } + constantPool.put12(tag, addConstantUtf8(value)); + return put(new Entry(constantPoolCount++, tag, value, hashCode)); + } + + /** + * Adds a new CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info, + * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. + * + * @param index the constant pool index of the new Symbol. + * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link + * Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link + * Symbol#CONSTANT_PACKAGE_TAG}. + * @param value an internal class name, an arbitrary string, a method descriptor, a module or a + * package name, depending on tag. + */ + private void addConstantUtf8Reference(final int index, final int tag, final String value) { + add(new Entry(index, tag, value, hash(tag, value))); + } + + // ----------------------------------------------------------------------------------------------- + // Bootstrap method entries management. + // ----------------------------------------------------------------------------------------------- + + /** + * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if + * the BootstrapMethods already contains a similar bootstrap method. + * + * @param bootstrapMethodHandle a bootstrap method handle. + * @param bootstrapMethodArguments the bootstrap method arguments. + * @return a new or already existing Symbol with the given value. + */ + Symbol addBootstrapMethod( + final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) { + ByteVector bootstrapMethodsAttribute = bootstrapMethods; + if (bootstrapMethodsAttribute == null) { + bootstrapMethodsAttribute = bootstrapMethods = new ByteVector(); + } + + // The bootstrap method arguments can be Constant_Dynamic values, which reference other + // bootstrap methods. We must therefore add the bootstrap method arguments to the constant pool + // and BootstrapMethods attribute first, so that the BootstrapMethods attribute is not modified + // while adding the given bootstrap method to it, in the rest of this method. + int numBootstrapArguments = bootstrapMethodArguments.length; + int[] bootstrapMethodArgumentIndexes = new int[numBootstrapArguments]; + for (int i = 0; i < numBootstrapArguments; i++) { + bootstrapMethodArgumentIndexes[i] = addConstant(bootstrapMethodArguments[i]).index; + } + + // Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to + // compare it with existing ones, and will be reverted below if there is already a similar + // bootstrap method. + int bootstrapMethodOffset = bootstrapMethodsAttribute.length; + bootstrapMethodsAttribute.putShort( + addConstantMethodHandle( + bootstrapMethodHandle.getTag(), + bootstrapMethodHandle.getOwner(), + bootstrapMethodHandle.getName(), + bootstrapMethodHandle.getDesc(), + bootstrapMethodHandle.isInterface()) + .index); + + bootstrapMethodsAttribute.putShort(numBootstrapArguments); + for (int i = 0; i < numBootstrapArguments; i++) { + bootstrapMethodsAttribute.putShort(bootstrapMethodArgumentIndexes[i]); + } + + // Compute the length and the hash code of the bootstrap method. + int bootstrapMethodlength = bootstrapMethodsAttribute.length - bootstrapMethodOffset; + int hashCode = bootstrapMethodHandle.hashCode(); + for (Object bootstrapMethodArgument : bootstrapMethodArguments) { + hashCode ^= bootstrapMethodArgument.hashCode(); + } + hashCode &= 0x7FFFFFFF; + + // Add the bootstrap method to the symbol table or revert the above changes. + return addBootstrapMethod(bootstrapMethodOffset, bootstrapMethodlength, hashCode); + } + + /** + * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if + * the BootstrapMethods already contains a similar bootstrap method (more precisely, reverts the + * content of {@link #bootstrapMethods} to remove the last, duplicate bootstrap method). + * + * @param offset the offset of the last bootstrap method in {@link #bootstrapMethods}, in bytes. + * @param length the length of this bootstrap method in {@link #bootstrapMethods}, in bytes. + * @param hashCode the hash code of this bootstrap method. + * @return a new or already existing Symbol with the given value. + */ + private Symbol addBootstrapMethod(final int offset, final int length, final int hashCode) { + final byte[] bootstrapMethodsData = bootstrapMethods.data; + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == Symbol.BOOTSTRAP_METHOD_TAG && entry.hashCode == hashCode) { + int otherOffset = (int) entry.data; + boolean isSameBootstrapMethod = true; + for (int i = 0; i < length; ++i) { + if (bootstrapMethodsData[offset + i] != bootstrapMethodsData[otherOffset + i]) { + isSameBootstrapMethod = false; + break; + } + } + if (isSameBootstrapMethod) { + bootstrapMethods.length = offset; // Revert to old position. + return entry; + } + } + entry = entry.next; + } + return put(new Entry(bootstrapMethodCount++, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode)); + } + + // ----------------------------------------------------------------------------------------------- + // Type table entries management. + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the type table element whose index is given. + * + * @param typeIndex a type table index. + * @return the type table element whose index is given. + */ + Symbol getType(final int typeIndex) { + return typeTable[typeIndex]; + } + + /** + * Returns the label corresponding to the "forward uninitialized" type table element whose index + * is given. + * + * @param typeIndex the type table index of a "forward uninitialized" type table element. + * @return the label corresponding of the NEW instruction which created this "forward + * uninitialized" type. + */ + Label getForwardUninitializedLabel(final int typeIndex) { + return labelTable[(int) typeTable[typeIndex].data].label; + } + + /** + * Adds a type in the type table of this symbol table. Does nothing if the type table already + * contains a similar type. + * + * @param value an internal class name. + * @return the index of a new or already existing type Symbol with the given value. + */ + int addType(final String value) { + int hashCode = hash(Symbol.TYPE_TAG, value); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == Symbol.TYPE_TAG && entry.hashCode == hashCode && entry.value.equals(value)) { + return entry.index; + } + entry = entry.next; + } + return addTypeInternal(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode)); + } + + /** + * Adds an uninitialized type in the type table of this symbol table. Does nothing if the type + * table already contains a similar type. + * + * @param value an internal class name. + * @param bytecodeOffset the bytecode offset of the NEW instruction that created this + * uninitialized type value. + * @return the index of a new or already existing type #@link Symbol} with the given value. + */ + int addUninitializedType(final String value, final int bytecodeOffset) { + int hashCode = hash(Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == Symbol.UNINITIALIZED_TYPE_TAG + && entry.hashCode == hashCode + && entry.data == bytecodeOffset + && entry.value.equals(value)) { + return entry.index; + } + entry = entry.next; + } + return addTypeInternal( + new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode)); + } + + /** + * Adds a "forward uninitialized" type in the type table of this symbol table. Does nothing if the + * type table already contains a similar type. + * + * @param value an internal class name. + * @param label the label of the NEW instruction that created this uninitialized type value. If + * the label is resolved, use the {@link #addUninitializedType} method instead. + * @return the index of a new or already existing type {@link Symbol} with the given value. + */ + int addForwardUninitializedType(final String value, final Label label) { + int labelIndex = getOrAddLabelEntry(label).index; + int hashCode = hash(Symbol.FORWARD_UNINITIALIZED_TYPE_TAG, value, labelIndex); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == Symbol.FORWARD_UNINITIALIZED_TYPE_TAG + && entry.hashCode == hashCode + && entry.data == labelIndex + && entry.value.equals(value)) { + return entry.index; + } + entry = entry.next; + } + return addTypeInternal( + new Entry(typeCount, Symbol.FORWARD_UNINITIALIZED_TYPE_TAG, value, labelIndex, hashCode)); + } + + /** + * Adds a merged type in the type table of this symbol table. Does nothing if the type table + * already contains a similar type. + * + * @param typeTableIndex1 a {@link Symbol#TYPE_TAG} type, specified by its index in the type + * table. + * @param typeTableIndex2 another {@link Symbol#TYPE_TAG} type, specified by its index in the type + * table. + * @return the index of a new or already existing {@link Symbol#TYPE_TAG} type Symbol, + * corresponding to the common super class of the given types. + */ + int addMergedType(final int typeTableIndex1, final int typeTableIndex2) { + long data = + typeTableIndex1 < typeTableIndex2 + ? typeTableIndex1 | (((long) typeTableIndex2) << 32) + : typeTableIndex2 | (((long) typeTableIndex1) << 32); + int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2); + Entry entry = get(hashCode); + while (entry != null) { + if (entry.tag == Symbol.MERGED_TYPE_TAG && entry.hashCode == hashCode && entry.data == data) { + return entry.info; + } + entry = entry.next; + } + String type1 = typeTable[typeTableIndex1].value; + String type2 = typeTable[typeTableIndex2].value; + int commonSuperTypeIndex = addType(classWriter.getCommonSuperClass(type1, type2)); + put(new Entry(typeCount, Symbol.MERGED_TYPE_TAG, data, hashCode)).info = commonSuperTypeIndex; + return commonSuperTypeIndex; + } + + /** + * Adds the given type Symbol to {@link #typeTable}. + * + * @param entry a {@link Symbol#TYPE_TAG} or {@link Symbol#UNINITIALIZED_TYPE_TAG} type symbol. + * The index of this Symbol must be equal to the current value of {@link #typeCount}. + * @return the index in {@link #typeTable} where the given type was added, which is also equal to + * entry's index by hypothesis. + */ + private int addTypeInternal(final Entry entry) { + if (typeTable == null) { + typeTable = new Entry[16]; + } + if (typeCount == typeTable.length) { + Entry[] newTypeTable = new Entry[2 * typeTable.length]; + System.arraycopy(typeTable, 0, newTypeTable, 0, typeTable.length); + typeTable = newTypeTable; + } + typeTable[typeCount++] = entry; + return put(entry).index; + } + + /** + * Returns the {@link LabelEntry} corresponding to the given label. Creates a new one if there is + * no such entry. + * + * @param label the {@link Label} of a NEW instruction which created an uninitialized type, in the + * case where this NEW instruction is after the <init> constructor call (in bytecode + * offset order). See {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG}. + * @return the {@link LabelEntry} corresponding to {@code label}. + */ + private LabelEntry getOrAddLabelEntry(final Label label) { + if (labelEntries == null) { + labelEntries = new LabelEntry[16]; + labelTable = new LabelEntry[16]; + } + int hashCode = System.identityHashCode(label); + LabelEntry labelEntry = labelEntries[hashCode % labelEntries.length]; + while (labelEntry != null && labelEntry.label != label) { + labelEntry = labelEntry.next; + } + if (labelEntry != null) { + return labelEntry; + } + + if (labelCount > (labelEntries.length * 3) / 4) { + int currentCapacity = labelEntries.length; + int newCapacity = currentCapacity * 2 + 1; + LabelEntry[] newLabelEntries = new LabelEntry[newCapacity]; + for (int i = currentCapacity - 1; i >= 0; --i) { + LabelEntry currentEntry = labelEntries[i]; + while (currentEntry != null) { + int newCurrentEntryIndex = System.identityHashCode(currentEntry.label) % newCapacity; + LabelEntry nextEntry = currentEntry.next; + currentEntry.next = newLabelEntries[newCurrentEntryIndex]; + newLabelEntries[newCurrentEntryIndex] = currentEntry; + currentEntry = nextEntry; + } + } + labelEntries = newLabelEntries; + } + if (labelCount == labelTable.length) { + LabelEntry[] newLabelTable = new LabelEntry[2 * labelTable.length]; + System.arraycopy(labelTable, 0, newLabelTable, 0, labelTable.length); + labelTable = newLabelTable; + } + + labelEntry = new LabelEntry(labelCount, label); + int index = hashCode % labelEntries.length; + labelEntry.next = labelEntries[index]; + labelEntries[index] = labelEntry; + labelTable[labelCount++] = labelEntry; + return labelEntry; + } + + // ----------------------------------------------------------------------------------------------- + // Static helper methods to compute hash codes. + // ----------------------------------------------------------------------------------------------- + + private static int hash(final int tag, final int value) { + return 0x7FFFFFFF & (tag + value); + } + + private static int hash(final int tag, final long value) { + return 0x7FFFFFFF & (tag + (int) value + (int) (value >>> 32)); + } + + private static int hash(final int tag, final String value) { + return 0x7FFFFFFF & (tag + value.hashCode()); + } + + private static int hash(final int tag, final String value1, final int value2) { + return 0x7FFFFFFF & (tag + value1.hashCode() + value2); + } + + private static int hash(final int tag, final String value1, final String value2) { + return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode()); + } + + private static int hash( + final int tag, final String value1, final String value2, final int value3) { + return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * (value3 + 1)); + } + + private static int hash( + final int tag, final String value1, final String value2, final String value3) { + return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode()); + } + + private static int hash( + final int tag, + final String value1, + final String value2, + final String value3, + final int value4) { + return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4); + } + + /** + * An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields + * which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid + * duplicate symbols). See {@link #entries}. + * + * @author Eric Bruneton + */ + private static final class Entry extends Symbol { + + /** The hash code of this entry. */ + final int hashCode; + + /** + * Another entry (and so on recursively) having the same hash code (modulo the size of {@link + * #entries}) as this one. + */ + Entry next; + + Entry( + final int index, + final int tag, + final String owner, + final String name, + final String value, + final long data, + final int hashCode) { + super(index, tag, owner, name, value, data); + this.hashCode = hashCode; + } + + Entry(final int index, final int tag, final String value, final int hashCode) { + super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0); + this.hashCode = hashCode; + } + + Entry(final int index, final int tag, final String value, final long data, final int hashCode) { + super(index, tag, /* owner = */ null, /* name = */ null, value, data); + this.hashCode = hashCode; + } + + Entry( + final int index, final int tag, final String name, final String value, final int hashCode) { + super(index, tag, /* owner = */ null, name, value, /* data = */ 0); + this.hashCode = hashCode; + } + + Entry(final int index, final int tag, final long data, final int hashCode) { + super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data); + this.hashCode = hashCode; + } + } + + /** + * A label corresponding to a "forward uninitialized" type in the ASM specific {@link + * SymbolTable#typeTable} (see {@link Symbol#FORWARD_UNINITIALIZED_TYPE_TAG}). + * + * @author Eric Bruneton + */ + private static final class LabelEntry { + + /** The index of this label entry in the {@link SymbolTable#labelTable} array. */ + final int index; + + /** The value of this label entry. */ + final Label label; + + /** + * Another entry (and so on recursively) having the same hash code (modulo the size of {@link + * SymbolTable#labelEntries}}) as this one. + */ + LabelEntry next; + + LabelEntry(final int index, final Label label) { + this.index = index; + this.label = label; + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/Type.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/Type.class new file mode 100644 index 0000000000000000000000000000000000000000..cbc62d02d5a964804ca45f7c0e943bafe7f01d43 GIT binary patch literal 12281 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 RrR%zhf523#lcNol_For {@link #OBJECT} types, this field also contains the descriptor: the characters in + * [{@link #valueBegin},{@link #valueEnd}) contain the internal name, and those in [{@link + * #valueBegin} - 1, {@link #valueEnd} + 1) contain the descriptor. + */ + private final String valueBuffer; + + /** + * The beginning index, inclusive, of the value of this Java field or method type in {@link + * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, + * and a field or method descriptor in the other cases. + */ + private final int valueBegin; + + /** + * The end index, exclusive, of the value of this Java field or method type in {@link + * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, + * and a field or method descriptor in the other cases. + */ + private final int valueEnd; + + /** + * Constructs a reference type. + * + * @param sort the sort of this type, see {@link #sort}. + * @param valueBuffer a buffer containing the value of this field or method type. + * @param valueBegin the beginning index, inclusive, of the value of this field or method type in + * valueBuffer. + * @param valueEnd the end index, exclusive, of the value of this field or method type in + * valueBuffer. + */ + private Type(final int sort, final String valueBuffer, final int valueBegin, final int valueEnd) { + this.sort = sort; + this.valueBuffer = valueBuffer; + this.valueBegin = valueBegin; + this.valueEnd = valueEnd; + } + + // ----------------------------------------------------------------------------------------------- + // Methods to get Type(s) from a descriptor, a reflected Method or Constructor, other types, etc. + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the {@link Type} corresponding to the given type descriptor. + * + * @param typeDescriptor a field or method type descriptor. + * @return the {@link Type} corresponding to the given type descriptor. + */ + public static Type getType(final String typeDescriptor) { + return getTypeInternal(typeDescriptor, 0, typeDescriptor.length()); + } + + /** + * Returns the {@link Type} corresponding to the given class. + * + * @param clazz a class. + * @return the {@link Type} corresponding to the given class. + */ + public static Type getType(final Class clazz) { + if (clazz.isPrimitive()) { + if (clazz == Integer.TYPE) { + return INT_TYPE; + } else if (clazz == Void.TYPE) { + return VOID_TYPE; + } else if (clazz == Boolean.TYPE) { + return BOOLEAN_TYPE; + } else if (clazz == Byte.TYPE) { + return BYTE_TYPE; + } else if (clazz == Character.TYPE) { + return CHAR_TYPE; + } else if (clazz == Short.TYPE) { + return SHORT_TYPE; + } else if (clazz == Double.TYPE) { + return DOUBLE_TYPE; + } else if (clazz == Float.TYPE) { + return FLOAT_TYPE; + } else if (clazz == Long.TYPE) { + return LONG_TYPE; + } else { + throw new AssertionError(); + } + } else { + return getType(getDescriptor(clazz)); + } + } + + /** + * Returns the method {@link Type} corresponding to the given constructor. + * + * @param constructor a {@link Constructor} object. + * @return the method {@link Type} corresponding to the given constructor. + */ + public static Type getType(final Constructor constructor) { + return getType(getConstructorDescriptor(constructor)); + } + + /** + * Returns the method {@link Type} corresponding to the given method. + * + * @param method a {@link Method} object. + * @return the method {@link Type} corresponding to the given method. + */ + public static Type getType(final Method method) { + return getType(getMethodDescriptor(method)); + } + + /** + * Returns the type of the elements of this array type. This method should only be used for an + * array type. + * + * @return Returns the type of the elements of this array type. + */ + public Type getElementType() { + final int numDimensions = getDimensions(); + return getTypeInternal(valueBuffer, valueBegin + numDimensions, valueEnd); + } + + /** + * Returns the {@link Type} corresponding to the given internal name. + * + * @param internalName an internal name (see {@link Type#getInternalName()}). + * @return the {@link Type} corresponding to the given internal name. + */ + public static Type getObjectType(final String internalName) { + return new Type( + internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length()); + } + + /** + * Returns the {@link Type} corresponding to the given method descriptor. Equivalent to + * Type.getType(methodDescriptor). + * + * @param methodDescriptor a method descriptor. + * @return the {@link Type} corresponding to the given method descriptor. + */ + public static Type getMethodType(final String methodDescriptor) { + return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length()); + } + + /** + * Returns the method {@link Type} corresponding to the given argument and return types. + * + * @param returnType the return type of the method. + * @param argumentTypes the argument types of the method. + * @return the method {@link Type} corresponding to the given argument and return types. + */ + public static Type getMethodType(final Type returnType, final Type... argumentTypes) { + return getType(getMethodDescriptor(returnType, argumentTypes)); + } + + /** + * Returns the argument types of methods of this type. This method should only be used for method + * types. + * + * @return the argument types of methods of this type. + */ + public Type[] getArgumentTypes() { + return getArgumentTypes(getDescriptor()); + } + + /** + * Returns the {@link Type} values corresponding to the argument types of the given method + * descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the {@link Type} values corresponding to the argument types of the given method + * descriptor. + */ + public static Type[] getArgumentTypes(final String methodDescriptor) { + // First step: compute the number of argument types in methodDescriptor. + int numArgumentTypes = getArgumentCount(methodDescriptor); + + // Second step: create a Type instance for each argument type. + Type[] argumentTypes = new Type[numArgumentTypes]; + // Skip the first character, which is always a '('. + int currentOffset = 1; + // Parse and create the argument types, one at each loop iteration. + int currentArgumentTypeIndex = 0; + while (methodDescriptor.charAt(currentOffset) != ')') { + final int currentArgumentTypeOffset = currentOffset; + while (methodDescriptor.charAt(currentOffset) == '[') { + currentOffset++; + } + if (methodDescriptor.charAt(currentOffset++) == 'L') { + // Skip the argument descriptor content. + int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); + currentOffset = Math.max(currentOffset, semiColumnOffset + 1); + } + argumentTypes[currentArgumentTypeIndex++] = + getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset); + } + return argumentTypes; + } + + /** + * Returns the {@link Type} values corresponding to the argument types of the given method. + * + * @param method a method. + * @return the {@link Type} values corresponding to the argument types of the given method. + */ + public static Type[] getArgumentTypes(final Method method) { + Class[] classes = method.getParameterTypes(); + Type[] types = new Type[classes.length]; + for (int i = classes.length - 1; i >= 0; --i) { + types[i] = getType(classes[i]); + } + return types; + } + + /** + * Returns the return type of methods of this type. This method should only be used for method + * types. + * + * @return the return type of methods of this type. + */ + public Type getReturnType() { + return getReturnType(getDescriptor()); + } + + /** + * Returns the {@link Type} corresponding to the return type of the given method descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the {@link Type} corresponding to the return type of the given method descriptor. + */ + public static Type getReturnType(final String methodDescriptor) { + return getTypeInternal( + methodDescriptor, getReturnTypeOffset(methodDescriptor), methodDescriptor.length()); + } + + /** + * Returns the {@link Type} corresponding to the return type of the given method. + * + * @param method a method. + * @return the {@link Type} corresponding to the return type of the given method. + */ + public static Type getReturnType(final Method method) { + return getType(method.getReturnType()); + } + + /** + * Returns the start index of the return type of the given method descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the start index of the return type of the given method descriptor. + */ + static int getReturnTypeOffset(final String methodDescriptor) { + // Skip the first character, which is always a '('. + int currentOffset = 1; + // Skip the argument types, one at a each loop iteration. + while (methodDescriptor.charAt(currentOffset) != ')') { + while (methodDescriptor.charAt(currentOffset) == '[') { + currentOffset++; + } + if (methodDescriptor.charAt(currentOffset++) == 'L') { + // Skip the argument descriptor content. + int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); + currentOffset = Math.max(currentOffset, semiColumnOffset + 1); + } + } + return currentOffset + 1; + } + + /** + * Returns the {@link Type} corresponding to the given field or method descriptor. + * + * @param descriptorBuffer a buffer containing the field or method descriptor. + * @param descriptorBegin the beginning index, inclusive, of the field or method descriptor in + * descriptorBuffer. + * @param descriptorEnd the end index, exclusive, of the field or method descriptor in + * descriptorBuffer. + * @return the {@link Type} corresponding to the given type descriptor. + */ + private static Type getTypeInternal( + final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) { + switch (descriptorBuffer.charAt(descriptorBegin)) { + case 'V': + return VOID_TYPE; + case 'Z': + return BOOLEAN_TYPE; + case 'C': + return CHAR_TYPE; + case 'B': + return BYTE_TYPE; + case 'S': + return SHORT_TYPE; + case 'I': + return INT_TYPE; + case 'F': + return FLOAT_TYPE; + case 'J': + return LONG_TYPE; + case 'D': + return DOUBLE_TYPE; + case '[': + return new Type(ARRAY, descriptorBuffer, descriptorBegin, descriptorEnd); + case 'L': + return new Type(OBJECT, descriptorBuffer, descriptorBegin + 1, descriptorEnd - 1); + case '(': + return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd); + default: + throw new IllegalArgumentException("Invalid descriptor: " + descriptorBuffer); + } + } + + // ----------------------------------------------------------------------------------------------- + // Methods to get class names, internal names or descriptors. + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the binary name of the class corresponding to this type. This method must not be used + * on method types. + * + * @return the binary name of the class corresponding to this type. + */ + public String getClassName() { + switch (sort) { + case VOID: + return "void"; + case BOOLEAN: + return "boolean"; + case CHAR: + return "char"; + case BYTE: + return "byte"; + case SHORT: + return "short"; + case INT: + return "int"; + case FLOAT: + return "float"; + case LONG: + return "long"; + case DOUBLE: + return "double"; + case ARRAY: + StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName()); + for (int i = getDimensions(); i > 0; --i) { + stringBuilder.append("[]"); + } + return stringBuilder.toString(); + case OBJECT: + case INTERNAL: + return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.'); + default: + throw new AssertionError(); + } + } + + /** + * Returns the internal name of the class corresponding to this object or array type. The internal + * name of a class is its fully qualified name (as returned by Class.getName(), where '.' are + * replaced by '/'). This method should only be used for an object or array type. + * + * @return the internal name of the class corresponding to this object type. + */ + public String getInternalName() { + return valueBuffer.substring(valueBegin, valueEnd); + } + + /** + * Returns the internal name of the given class. The internal name of a class is its fully + * qualified name, as returned by Class.getName(), where '.' are replaced by '/'. + * + * @param clazz an object or array class. + * @return the internal name of the given class. + */ + public static String getInternalName(final Class clazz) { + return clazz.getName().replace('.', '/'); + } + + /** + * Returns the descriptor corresponding to this type. + * + * @return the descriptor corresponding to this type. + */ + public String getDescriptor() { + if (sort == OBJECT) { + return valueBuffer.substring(valueBegin - 1, valueEnd + 1); + } else if (sort == INTERNAL) { + return 'L' + valueBuffer.substring(valueBegin, valueEnd) + ';'; + } else { + return valueBuffer.substring(valueBegin, valueEnd); + } + } + + /** + * Returns the descriptor corresponding to the given class. + * + * @param clazz an object class, a primitive class or an array class. + * @return the descriptor corresponding to the given class. + */ + public static String getDescriptor(final Class clazz) { + StringBuilder stringBuilder = new StringBuilder(); + appendDescriptor(clazz, stringBuilder); + return stringBuilder.toString(); + } + + /** + * Returns the descriptor corresponding to the given constructor. + * + * @param constructor a {@link Constructor} object. + * @return the descriptor of the given constructor. + */ + public static String getConstructorDescriptor(final Constructor constructor) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append('('); + Class[] parameters = constructor.getParameterTypes(); + for (Class parameter : parameters) { + appendDescriptor(parameter, stringBuilder); + } + return stringBuilder.append(")V").toString(); + } + + /** + * Returns the descriptor corresponding to the given argument and return types. + * + * @param returnType the return type of the method. + * @param argumentTypes the argument types of the method. + * @return the descriptor corresponding to the given argument and return types. + */ + public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append('('); + for (Type argumentType : argumentTypes) { + argumentType.appendDescriptor(stringBuilder); + } + stringBuilder.append(')'); + returnType.appendDescriptor(stringBuilder); + return stringBuilder.toString(); + } + + /** + * Returns the descriptor corresponding to the given method. + * + * @param method a {@link Method} object. + * @return the descriptor of the given method. + */ + public static String getMethodDescriptor(final Method method) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append('('); + Class[] parameters = method.getParameterTypes(); + for (Class parameter : parameters) { + appendDescriptor(parameter, stringBuilder); + } + stringBuilder.append(')'); + appendDescriptor(method.getReturnType(), stringBuilder); + return stringBuilder.toString(); + } + + /** + * Appends the descriptor corresponding to this type to the given string buffer. + * + * @param stringBuilder the string builder to which the descriptor must be appended. + */ + private void appendDescriptor(final StringBuilder stringBuilder) { + if (sort == OBJECT) { + stringBuilder.append(valueBuffer, valueBegin - 1, valueEnd + 1); + } else if (sort == INTERNAL) { + stringBuilder.append('L').append(valueBuffer, valueBegin, valueEnd).append(';'); + } else { + stringBuilder.append(valueBuffer, valueBegin, valueEnd); + } + } + + /** + * Appends the descriptor of the given class to the given string builder. + * + * @param clazz the class whose descriptor must be computed. + * @param stringBuilder the string builder to which the descriptor must be appended. + */ + private static void appendDescriptor(final Class clazz, final StringBuilder stringBuilder) { + Class currentClass = clazz; + while (currentClass.isArray()) { + stringBuilder.append('['); + currentClass = currentClass.getComponentType(); + } + if (currentClass.isPrimitive()) { + char descriptor; + if (currentClass == Integer.TYPE) { + descriptor = 'I'; + } else if (currentClass == Void.TYPE) { + descriptor = 'V'; + } else if (currentClass == Boolean.TYPE) { + descriptor = 'Z'; + } else if (currentClass == Byte.TYPE) { + descriptor = 'B'; + } else if (currentClass == Character.TYPE) { + descriptor = 'C'; + } else if (currentClass == Short.TYPE) { + descriptor = 'S'; + } else if (currentClass == Double.TYPE) { + descriptor = 'D'; + } else if (currentClass == Float.TYPE) { + descriptor = 'F'; + } else if (currentClass == Long.TYPE) { + descriptor = 'J'; + } else { + throw new AssertionError(); + } + stringBuilder.append(descriptor); + } else { + stringBuilder.append('L').append(getInternalName(currentClass)).append(';'); + } + } + + // ----------------------------------------------------------------------------------------------- + // Methods to get the sort, dimension, size, and opcodes corresponding to a Type or descriptor. + // ----------------------------------------------------------------------------------------------- + + /** + * Returns the sort of this type. + * + * @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link + * #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or + * {@link #METHOD}. + */ + public int getSort() { + return sort == INTERNAL ? OBJECT : sort; + } + + /** + * Returns the number of dimensions of this array type. This method should only be used for an + * array type. + * + * @return the number of dimensions of this array type. + */ + public int getDimensions() { + int numDimensions = 1; + while (valueBuffer.charAt(valueBegin + numDimensions) == '[') { + numDimensions++; + } + return numDimensions; + } + + /** + * Returns the size of values of this type. This method must not be used for method types. + * + * @return the size of values of this type, i.e., 2 for {@code long} and {@code double}, 0 for + * {@code void} and 1 otherwise. + */ + public int getSize() { + switch (sort) { + case VOID: + return 0; + case BOOLEAN: + case CHAR: + case BYTE: + case SHORT: + case INT: + case FLOAT: + case ARRAY: + case OBJECT: + case INTERNAL: + return 1; + case LONG: + case DOUBLE: + return 2; + default: + throw new AssertionError(); + } + } + + /** + * Returns the number of arguments of this method type. This method should only be used for method + * types. + * + * @return the number of arguments of this method type. Each argument counts for 1, even long and + * double ones. The implicit @literal{this} argument is not counted. + */ + public int getArgumentCount() { + return getArgumentCount(getDescriptor()); + } + + /** + * Returns the number of arguments in the given method descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the number of arguments in the given method descriptor. Each argument counts for 1, + * even long and double ones. The implicit @literal{this} argument is not counted. + */ + public static int getArgumentCount(final String methodDescriptor) { + int argumentCount = 0; + // Skip the first character, which is always a '('. + int currentOffset = 1; + // Parse the argument types, one at a each loop iteration. + while (methodDescriptor.charAt(currentOffset) != ')') { + while (methodDescriptor.charAt(currentOffset) == '[') { + currentOffset++; + } + if (methodDescriptor.charAt(currentOffset++) == 'L') { + // Skip the argument descriptor content. + int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); + currentOffset = Math.max(currentOffset, semiColumnOffset + 1); + } + ++argumentCount; + } + return argumentCount; + } + + /** + * Returns the size of the arguments and of the return value of methods of this type. This method + * should only be used for method types. + * + * @return the size of the arguments of the method (plus one for the implicit this argument), + * argumentsSize, and the size of its return value, returnSize, packed into a single int i = + * {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code + * i >> 2}, and returnSize to {@code i & 0x03}). Long and double values have size 2, + * the others have size 1. + */ + public int getArgumentsAndReturnSizes() { + return getArgumentsAndReturnSizes(getDescriptor()); + } + + /** + * Computes the size of the arguments and of the return value of a method. + * + * @param methodDescriptor a method descriptor. + * @return the size of the arguments of the method (plus one for the implicit this argument), + * argumentsSize, and the size of its return value, returnSize, packed into a single int i = + * {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code + * i >> 2}, and returnSize to {@code i & 0x03}). Long and double values have size 2, + * the others have size 1. + */ + public static int getArgumentsAndReturnSizes(final String methodDescriptor) { + int argumentsSize = 1; + // Skip the first character, which is always a '('. + int currentOffset = 1; + int currentChar = methodDescriptor.charAt(currentOffset); + // Parse the argument types and compute their size, one at a each loop iteration. + while (currentChar != ')') { + if (currentChar == 'J' || currentChar == 'D') { + currentOffset++; + argumentsSize += 2; + } else { + while (methodDescriptor.charAt(currentOffset) == '[') { + currentOffset++; + } + if (methodDescriptor.charAt(currentOffset++) == 'L') { + // Skip the argument descriptor content. + int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); + currentOffset = Math.max(currentOffset, semiColumnOffset + 1); + } + argumentsSize += 1; + } + currentChar = methodDescriptor.charAt(currentOffset); + } + currentChar = methodDescriptor.charAt(currentOffset + 1); + if (currentChar == 'V') { + return argumentsSize << 2; + } else { + int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1; + return argumentsSize << 2 | returnSize; + } + } + + /** + * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for + * method types. + * + * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, + * IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and + * IRETURN. + * @return an opcode that is similar to the given opcode, but adapted to this {@link Type}. For + * example, if this type is {@code float} and {@code opcode} is IRETURN, this method returns + * FRETURN. + */ + public int getOpcode(final int opcode) { + if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { + switch (sort) { + case BOOLEAN: + case BYTE: + return opcode + (Opcodes.BALOAD - Opcodes.IALOAD); + case CHAR: + return opcode + (Opcodes.CALOAD - Opcodes.IALOAD); + case SHORT: + return opcode + (Opcodes.SALOAD - Opcodes.IALOAD); + case INT: + return opcode; + case FLOAT: + return opcode + (Opcodes.FALOAD - Opcodes.IALOAD); + case LONG: + return opcode + (Opcodes.LALOAD - Opcodes.IALOAD); + case DOUBLE: + return opcode + (Opcodes.DALOAD - Opcodes.IALOAD); + case ARRAY: + case OBJECT: + case INTERNAL: + return opcode + (Opcodes.AALOAD - Opcodes.IALOAD); + case METHOD: + case VOID: + throw new UnsupportedOperationException(); + default: + throw new AssertionError(); + } + } else { + switch (sort) { + case VOID: + if (opcode != Opcodes.IRETURN) { + throw new UnsupportedOperationException(); + } + return Opcodes.RETURN; + case BOOLEAN: + case BYTE: + case CHAR: + case SHORT: + case INT: + return opcode; + case FLOAT: + return opcode + (Opcodes.FRETURN - Opcodes.IRETURN); + case LONG: + return opcode + (Opcodes.LRETURN - Opcodes.IRETURN); + case DOUBLE: + return opcode + (Opcodes.DRETURN - Opcodes.IRETURN); + case ARRAY: + case OBJECT: + case INTERNAL: + if (opcode != Opcodes.ILOAD && opcode != Opcodes.ISTORE && opcode != Opcodes.IRETURN) { + throw new UnsupportedOperationException(); + } + return opcode + (Opcodes.ARETURN - Opcodes.IRETURN); + case METHOD: + throw new UnsupportedOperationException(); + default: + throw new AssertionError(); + } + } + } + + // ----------------------------------------------------------------------------------------------- + // Equals, hashCode and toString. + // ----------------------------------------------------------------------------------------------- + + /** + * Tests if the given object is equal to this type. + * + * @param object the object to be compared to this type. + * @return {@literal true} if the given object is equal to this type. + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (!(object instanceof Type)) { + return false; + } + Type other = (Type) object; + if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) { + return false; + } + int begin = valueBegin; + int end = valueEnd; + int otherBegin = other.valueBegin; + int otherEnd = other.valueEnd; + // Compare the values. + if (end - begin != otherEnd - otherBegin) { + return false; + } + for (int i = begin, j = otherBegin; i < end; i++, j++) { + if (valueBuffer.charAt(i) != other.valueBuffer.charAt(j)) { + return false; + } + } + return true; + } + + /** + * Returns a hash code value for this type. + * + * @return a hash code value for this type. + */ + @Override + public int hashCode() { + int hashCode = 13 * (sort == INTERNAL ? OBJECT : sort); + if (sort >= ARRAY) { + for (int i = valueBegin, end = valueEnd; i < end; i++) { + hashCode = 17 * (hashCode + valueBuffer.charAt(i)); + } + } + return hashCode; + } + + /** + * Returns a string representation of this type. + * + * @return the descriptor of this type. + */ + @Override + public String toString() { + return getDescriptor(); + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/TypePath.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/TypePath.class new file mode 100644 index 0000000000000000000000000000000000000000..878b1915faeffe6f9fb05069e64419475e170776 GIT binary patch literal 2853 zcmb7GU2_v<6n@?&X_~O1p->8>l>#bh8XGED#X>dx0E7LqEv=zyyKS~@N}ANo76C7q zalCQ##w#801Ms7YsGucPnUPTu98}bC1~2qRN5|nWFbw#-yGdK7BZbcF?)#pcecp4P z^PIE2aP5mP0W`pHBM&ww>A`(5fp*-qp{tgc+$}Hq?!n&^x;s-eCru)Af%?pLS6gDwRY7Q5m;hmmkp_;p~jP% zE|Aw-FYy*DD1=vFan7Y}Xeh1mWD#+r2uqz43f5vB zqZ=Gi^)OSB@C_3FE(LdEy?}%8)ztzaf8@5%ov094J6oklBB2ediLgFAF{UMrroDsO zxDih!-SETa;(AE^AvS_Tua6TO8pJw zb4F)30Fu1|)GJgb!3wirx#T2TlSJDlK_qSe1LDLZ0xM>J4X4wZE?H^Pby@c9ut}^( z6*QwopukAwSg6!3&QI>OPursk%Wrq(X* z*%E0(O&Z;5VnVaAFCpNLw6->N^mRqso1{gsJ$fR|jSb^Jb=R|d(0+t54ZzUJYfo+jmPO}osdr-AZ?;5=GvV_ z6>N_%W|Wxk_07ASk(CNe0mu@~FDy@%lm z+W7OGJ(GBehAL^WXARHN5Re8()-X!Lh9l_ZWAj_+lDk-qL&9#o0hT_iET5&t4zGKp z*xqk?PF}x6bM0Z|Ph!z&_@mPZoC)R^JFEa^Oq17pf>Wrp@mA$Xyxesf1yR#5jSVN5 ztj(0k9+YwY3PtcLJUB?%9D)z8VGUl#I=sQ}*PGPbVQj_`mf$FMfHC83YVaLsc$ej$ z#D2Vo19%@V;24oUpyfC|!iPACkMTJ^!B_YcXEB8zkik!w#vl01EKMCr-_Os$AWJNj zeGoBXO4(k<5Tz?c{2S#fyU2%&6!9qKu@2|3n>HH~^eBgCk+_Cp;Y5kJ%6}QW-m6$9 zf-dJ3xUaw|<;>4Zw$LkxF7Xerwi{X7nyAk)GK~jXthx>b$}-q|j1K&3w;pD@lye>6 zwTV|<(A%5AR@S;Y=&iC=>w{h*N?Tb_VuUkj^wwGy7GyhX6gfl5OkO_}%wWeX{dMd= z;A^J;4O2SHPu#cE`FT?P9k$^D1OJ|Z{K!#p5xej+DfoqH{|bY?`*F#nF~F3HNYj`} z3X{urkAoikAA_lTkwTJJo=MqK6kJ0Q39AtmE|+TwnR0MyjpJ#HB|Jw!Ia>mO^H3@& z+fpXBI@iA&9V7Pst(CcLX$Gx5a_m@oT23tBPa^z9J^jtP{euepYX&MukB@^$1|>&A ZfK|4JP{6FMFvH`x@c0;sPLDjK{{!>CcuD{O literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/TypePath.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/TypePath.java new file mode 100644 index 00000000..ea1025dd --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/TypePath.java @@ -0,0 +1,232 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * The path to a type argument, wildcard bound, array element type, or static inner type within an + * enclosing type. + * + * @author Eric Bruneton + */ +public final class TypePath { + + /** A type path step that steps into the element type of an array type. See {@link #getStep}. */ + public static final int ARRAY_ELEMENT = 0; + + /** A type path step that steps into the nested type of a class type. See {@link #getStep}. */ + public static final int INNER_TYPE = 1; + + /** A type path step that steps into the bound of a wildcard type. See {@link #getStep}. */ + public static final int WILDCARD_BOUND = 2; + + /** A type path step that steps into a type argument of a generic type. See {@link #getStep}. */ + public static final int TYPE_ARGUMENT = 3; + + /** + * The byte array where the 'type_path' structure - as defined in the Java Virtual Machine + * Specification (JVMS) - corresponding to this TypePath is stored. The first byte of the + * structure in this array is given by {@link #typePathOffset}. + * + * @see JVMS + * 4.7.20.2 + */ + private final byte[] typePathContainer; + + /** The offset of the first byte of the type_path JVMS structure in {@link #typePathContainer}. */ + private final int typePathOffset; + + /** + * Constructs a new TypePath. + * + * @param typePathContainer a byte array containing a type_path JVMS structure. + * @param typePathOffset the offset of the first byte of the type_path structure in + * typePathContainer. + */ + TypePath(final byte[] typePathContainer, final int typePathOffset) { + this.typePathContainer = typePathContainer; + this.typePathOffset = typePathOffset; + } + + /** + * Returns the length of this path, i.e. its number of steps. + * + * @return the length of this path. + */ + public int getLength() { + // path_length is stored in the first byte of a type_path. + return typePathContainer[typePathOffset]; + } + + /** + * Returns the value of the given step of this path. + * + * @param index an index between 0 and {@link #getLength()}, exclusive. + * @return one of {@link #ARRAY_ELEMENT}, {@link #INNER_TYPE}, {@link #WILDCARD_BOUND}, or {@link + * #TYPE_ARGUMENT}. + */ + public int getStep(final int index) { + // Returns the type_path_kind of the path element of the given index. + return typePathContainer[typePathOffset + 2 * index + 1]; + } + + /** + * Returns the index of the type argument that the given step is stepping into. This method should + * only be used for steps whose value is {@link #TYPE_ARGUMENT}. + * + * @param index an index between 0 and {@link #getLength()}, exclusive. + * @return the index of the type argument that the given step is stepping into. + */ + public int getStepArgument(final int index) { + // Returns the type_argument_index of the path element of the given index. + return typePathContainer[typePathOffset + 2 * index + 2]; + } + + /** + * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath + * object. + * + * @param typePath a type path in string form, in the format used by {@link #toString()}. May be + * {@literal null} or empty. + * @return the corresponding TypePath object, or {@literal null} if the path is empty. + */ + public static TypePath fromString(final String typePath) { + if (typePath == null || typePath.length() == 0) { + return null; + } + int typePathLength = typePath.length(); + ByteVector output = new ByteVector(typePathLength); + output.putByte(0); + int typePathIndex = 0; + while (typePathIndex < typePathLength) { + char c = typePath.charAt(typePathIndex++); + if (c == '[') { + output.put11(ARRAY_ELEMENT, 0); + } else if (c == '.') { + output.put11(INNER_TYPE, 0); + } else if (c == '*') { + output.put11(WILDCARD_BOUND, 0); + } else if (c >= '0' && c <= '9') { + int typeArg = c - '0'; + while (typePathIndex < typePathLength) { + c = typePath.charAt(typePathIndex++); + if (c >= '0' && c <= '9') { + typeArg = typeArg * 10 + c - '0'; + } else if (c == ';') { + break; + } else { + throw new IllegalArgumentException(); + } + } + output.put11(TYPE_ARGUMENT, typeArg); + } else { + throw new IllegalArgumentException(); + } + } + output.data[0] = (byte) (output.length / 2); + return new TypePath(output.data, 0); + } + + /** + * Returns a string representation of this type path. {@link #ARRAY_ELEMENT} steps are represented + * with '[', {@link #INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND} steps with '*' and {@link + * #TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'. + */ + @Override + public String toString() { + int length = getLength(); + StringBuilder result = new StringBuilder(length * 2); + for (int i = 0; i < length; ++i) { + switch (getStep(i)) { + case ARRAY_ELEMENT: + result.append('['); + break; + case INNER_TYPE: + result.append('.'); + break; + case WILDCARD_BOUND: + result.append('*'); + break; + case TYPE_ARGUMENT: + result.append(getStepArgument(i)).append(';'); + break; + default: + throw new AssertionError(); + } + } + return result.toString(); + } + + /** + * Puts the type_path JVMS structure corresponding to the given TypePath into the given + * ByteVector. + * + * @param typePath a TypePath instance, or {@literal null} for empty paths. + * @param output where the type path must be put. + */ + static void put(final TypePath typePath, final ByteVector output) { + if (typePath == null) { + output.putByte(0); + } else { + int length = typePath.typePathContainer[typePath.typePathOffset] * 2 + 1; + output.putByteArray(typePath.typePathContainer, typePath.typePathOffset, length); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/TypeReference.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/TypeReference.class new file mode 100644 index 0000000000000000000000000000000000000000..d0886027b3c2c5d76ab21d1a45b222a7f5efb0c5 GIT binary patch literal 4178 zcmc(i-&0#f6vxluSALK}5`H$+{;uUmB`w%$rPk)hO-UOPya}PyDqg|`0^x>+n-*Hc z_QiL{XP-Oc_@Iu$jCFKI-<;8L{0r3gzB}WLcy_Z~Hfa#>#fOCbo;~~7vuAhDh9Cd_ z`da`9!DA=XK&=hxTu=`U2=009p61VK#;iXvHLqt(goZ0wBWqqosO|1aJHQSO8#rCi z2rh(k^V19dtYPW}L(BQ|g;{@|kGii<`L*Rme`<9}SM?dapc@$-!DDKLS>0sTfH564 zX7UIabrQ3Q&EJer*B$Li*SaaTT7a#s+IH6JU|&IQ+bVTX@75ML;V}4Y(B*<7@B%{5 z9>D}xO+8IZ$`=sqOGPs|moL!z`f1A8zK0I6NsqbUIGfQ%6h>vXlP);LYz<_K8YVNH zalwml7NMR@7X}dg-O&S0WrH4slRG;S&E@o2Ef*-v78iBHR8}(jl9|mLPUwbOgw{|j zkW5adCPtOX(SRBlQBsPEa43{FmQBqt(^{^mQ(6HK+Ng6l5w37%oybOTka8=f#KTEu zbR+nx(I&VNFcVeJl5S#Nly){iE$ok2SQUU5hAB_K#c~1F@^bDqr;~v$;6l%Qp!342rbI3 zkTRNzCgSDXAc8X*Po@I#kdlZnN{B8&Tp4H0Fy%0mpk8$>luD?RsuEFDg*;iOLKn$e zhh&e?0S^U|Dduw>;j|2h#?urvkAm-DK)pUTqQtrHFv2mx`!}~J!YLVP#Z=m6nRo-? zXk~=Yd);L5=BMfAHpjAt9xpCV>4lUwl_QHcmd|Lpv{uM6EsS;MTy~kR)L!?gtS$`E zMKVi;g7RkQ_se<_F6`rimJK0b-7>%1hXrj^D`<;4l_{wh4eaMOR&t$7j1)Dd^%crs zB|Vrg8q?AggEYn7H~zUfrWi)d(MEG5i%XRD@=|Kgnlr+si(Df4!lIU|woC@FDuonV zlfGR(1g4d(rmz~)%*>qR=QV{bn9FAtgl{MFWmR01BFW!QC0=;hsMaU>KG4%ahqF!8 zek)Aj=c}~yJc>>agKQ^2*gD8ov0};FTCK40X{#)vRZP3R2;pugGcT104l3L!T8~c8 z1QqYSPW8?MGt`r&qLeS11VHFJz(6XCNmI)#jA%>ZPC1kLVj-hPvi#PS9fN-MHoysb zKWnI>bkLL22QI4a=SbDSOQicH?I(R+(icb%NP3X;%aXoG`jVtyA^obPFOz;v(nF-L zNcwfsS0()h>1&b>kPb>ZL^>>Kg>*#H*GUgcI!gM6q;HarNqU5IT+#{Bqmq7;v?}Q& z>6E0$NT($|4qo=FhjQCOIi{a0^nHs|gmTUD@9fx-3Y|oaFUY zUp#h6m}VXtP(bs$U|M{;M02JLvmm0$?Sg6D4RgK>vnVizwWmQk7i>?PtPQBLp?H;3 zO6RP}N_-RKiATSt46xGOPSRv1N#v5%EJln^^B zxwi{~hfx{D2UQXG4}$oxDq_V#42onpSTa1YwO$#+#}dF{Wn$F=`1u(DsAqu6!B3>Y z^BxWfx>5{1B#ESXsvxhr-}ZfF!>*Vo7BE0K4fF|1AjCcv;B!td;7z<%>G}P z|Hqi^HOPPIF~PD=9~G^&4d@(y0)y1EAGHlQO{T`D&^@sU zz2C7nsFuGL{q$-9et}`!z!BWUQGALM_zm8{?{Nx$KplU=BL0jk_zOP5U-<^}+JTS7 fdk557gZF5Q*NN(chQBb}*l73K$nri}YT(g79d8!l literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/TypeReference.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/TypeReference.java new file mode 100644 index 00000000..512dc8fc --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/TypeReference.java @@ -0,0 +1,467 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A reference to a type appearing in a class, field or method declaration, or on an instruction. + * Such a reference designates the part of the class where the referenced type is appearing (e.g. an + * 'extends', 'implements' or 'throws' clause, a 'new' instruction, a 'catch' clause, a type cast, a + * local variable declaration, etc). + * + * @author Eric Bruneton + */ +public class TypeReference { + + /** + * The sort of type references that target a type parameter of a generic class. See {@link + * #getSort}. + */ + public static final int CLASS_TYPE_PARAMETER = 0x00; + + /** + * The sort of type references that target a type parameter of a generic method. See {@link + * #getSort}. + */ + public static final int METHOD_TYPE_PARAMETER = 0x01; + + /** + * The sort of type references that target the super class of a class or one of the interfaces it + * implements. See {@link #getSort}. + */ + public static final int CLASS_EXTENDS = 0x10; + + /** + * The sort of type references that target a bound of a type parameter of a generic class. See + * {@link #getSort}. + */ + public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; + + /** + * The sort of type references that target a bound of a type parameter of a generic method. See + * {@link #getSort}. + */ + public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; + + /** The sort of type references that target the type of a field. See {@link #getSort}. */ + public static final int FIELD = 0x13; + + /** The sort of type references that target the return type of a method. See {@link #getSort}. */ + public static final int METHOD_RETURN = 0x14; + + /** + * The sort of type references that target the receiver type of a method. See {@link #getSort}. + */ + public static final int METHOD_RECEIVER = 0x15; + + /** + * The sort of type references that target the type of a formal parameter of a method. See {@link + * #getSort}. + */ + public static final int METHOD_FORMAL_PARAMETER = 0x16; + + /** + * The sort of type references that target the type of an exception declared in the throws clause + * of a method. See {@link #getSort}. + */ + public static final int THROWS = 0x17; + + /** + * The sort of type references that target the type of a local variable in a method. See {@link + * #getSort}. + */ + public static final int LOCAL_VARIABLE = 0x40; + + /** + * The sort of type references that target the type of a resource variable in a method. See {@link + * #getSort}. + */ + public static final int RESOURCE_VARIABLE = 0x41; + + /** + * The sort of type references that target the type of the exception of a 'catch' clause in a + * method. See {@link #getSort}. + */ + public static final int EXCEPTION_PARAMETER = 0x42; + + /** + * The sort of type references that target the type declared in an 'instanceof' instruction. See + * {@link #getSort}. + */ + public static final int INSTANCEOF = 0x43; + + /** + * The sort of type references that target the type of the object created by a 'new' instruction. + * See {@link #getSort}. + */ + public static final int NEW = 0x44; + + /** + * The sort of type references that target the receiver type of a constructor reference. See + * {@link #getSort}. + */ + public static final int CONSTRUCTOR_REFERENCE = 0x45; + + /** + * The sort of type references that target the receiver type of a method reference. See {@link + * #getSort}. + */ + public static final int METHOD_REFERENCE = 0x46; + + /** + * The sort of type references that target the type declared in an explicit or implicit cast + * instruction. See {@link #getSort}. + */ + public static final int CAST = 0x47; + + /** + * The sort of type references that target a type parameter of a generic constructor in a + * constructor call. See {@link #getSort}. + */ + public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + + /** + * The sort of type references that target a type parameter of a generic method in a method call. + * See {@link #getSort}. + */ + public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + + /** + * The sort of type references that target a type parameter of a generic constructor in a + * constructor reference. See {@link #getSort}. + */ + public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + + /** + * The sort of type references that target a type parameter of a generic method in a method + * reference. See {@link #getSort}. + */ + public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; + + /** + * The target_type and target_info structures - as defined in the Java Virtual Machine + * Specification (JVMS) - corresponding to this type reference. target_type uses one byte, and all + * the target_info union fields use up to 3 bytes (except localvar_target, handled with the + * specific method {@link MethodVisitor#visitLocalVariableAnnotation}). Thus, both structures can + * be stored in an int. + * + *

    This int field stores target_type (called the TypeReference 'sort' in the public API of this + * class) in its most significant byte, followed by the target_info fields. Depending on + * target_type, 1, 2 or even 3 least significant bytes of this field are unused. target_info + * fields which reference bytecode offsets are set to 0 (these offsets are ignored in ClassReader, + * and recomputed in MethodWriter). + * + * @see JVMS + * 4.7.20 + * @see JVMS + * 4.7.20.1 + */ + private final int targetTypeAndInfo; + + /** + * Constructs a new TypeReference. + * + * @param typeRef the int encoded value of the type reference, as received in a visit method + * related to type annotations, such as {@link ClassVisitor#visitTypeAnnotation}. + */ + public TypeReference(final int typeRef) { + this.targetTypeAndInfo = typeRef; + } + + /** + * Returns a type reference of the given sort. + * + * @param sort one of {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link + * #LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE}, {@link #INSTANCEOF}, {@link #NEW}, {@link + * #CONSTRUCTOR_REFERENCE}, or {@link #METHOD_REFERENCE}. + * @return a type reference of the given sort. + */ + public static TypeReference newTypeReference(final int sort) { + return new TypeReference(sort << 24); + } + + /** + * Returns a reference to a type parameter of a generic class or method. + * + * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}. + * @param paramIndex the type parameter index. + * @return a reference to the given generic class or method type parameter. + */ + public static TypeReference newTypeParameterReference(final int sort, final int paramIndex) { + return new TypeReference((sort << 24) | (paramIndex << 16)); + } + + /** + * Returns a reference to a type parameter bound of a generic class or method. + * + * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}. + * @param paramIndex the type parameter index. + * @param boundIndex the type bound index within the above type parameters. + * @return a reference to the given generic class or method type parameter bound. + */ + public static TypeReference newTypeParameterBoundReference( + final int sort, final int paramIndex, final int boundIndex) { + return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8)); + } + + /** + * Returns a reference to the super class or to an interface of the 'implements' clause of a + * class. + * + * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to + * reference the super class of the class. + * @return a reference to the given super type of a class. + */ + public static TypeReference newSuperTypeReference(final int itfIndex) { + return new TypeReference((CLASS_EXTENDS << 24) | ((itfIndex & 0xFFFF) << 8)); + } + + /** + * Returns a reference to the type of a formal parameter of a method. + * + * @param paramIndex the formal parameter index. + * @return a reference to the type of the given method formal parameter. + */ + public static TypeReference newFormalParameterReference(final int paramIndex) { + return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16)); + } + + /** + * Returns a reference to the type of an exception, in a 'throws' clause of a method. + * + * @param exceptionIndex the index of an exception in a 'throws' clause of a method. + * @return a reference to the type of the given exception. + */ + public static TypeReference newExceptionReference(final int exceptionIndex) { + return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); + } + + /** + * Returns a reference to the type of the exception declared in a 'catch' clause of a method. + * + * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are + * visited with visitTryCatchBlock). + * @return a reference to the type of the given exception. + */ + public static TypeReference newTryCatchReference(final int tryCatchBlockIndex) { + return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8)); + } + + /** + * Returns a reference to the type of a type argument in a constructor or method call or + * reference. + * + * @param sort one of {@link #CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link + * #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link + * #METHOD_REFERENCE_TYPE_ARGUMENT}. + * @param argIndex the type argument index. + * @return a reference to the type of the given type argument. + */ + public static TypeReference newTypeArgumentReference(final int sort, final int argIndex) { + return new TypeReference((sort << 24) | argIndex); + } + + /** + * Returns the sort of this type reference. + * + * @return one of {@link #CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER}, {@link + * #CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND}, {@link #METHOD_TYPE_PARAMETER_BOUND}, + * {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link + * #METHOD_FORMAL_PARAMETER}, {@link #THROWS}, {@link #LOCAL_VARIABLE}, {@link + * #RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER}, {@link #INSTANCEOF}, {@link #NEW}, + * {@link #CONSTRUCTOR_REFERENCE}, {@link #METHOD_REFERENCE}, {@link #CAST}, {@link + * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link + * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}. + */ + public int getSort() { + return targetTypeAndInfo >>> 24; + } + + /** + * Returns the index of the type parameter referenced by this type reference. This method must + * only be used for type references whose sort is {@link #CLASS_TYPE_PARAMETER}, {@link + * #METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link + * #METHOD_TYPE_PARAMETER_BOUND}. + * + * @return a type parameter index. + */ + public int getTypeParameterIndex() { + return (targetTypeAndInfo & 0x00FF0000) >> 16; + } + + /** + * Returns the index of the type parameter bound, within the type parameter {@link + * #getTypeParameterIndex}, referenced by this type reference. This method must only be used for + * type references whose sort is {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link + * #METHOD_TYPE_PARAMETER_BOUND}. + * + * @return a type parameter bound index. + */ + public int getTypeParameterBoundIndex() { + return (targetTypeAndInfo & 0x0000FF00) >> 8; + } + + /** + * Returns the index of the "super type" of a class that is referenced by this type reference. + * This method must only be used for type references whose sort is {@link #CLASS_EXTENDS}. + * + * @return the index of an interface in the 'implements' clause of a class, or -1 if this type + * reference references the type of the super class. + */ + public int getSuperTypeIndex() { + return (short) ((targetTypeAndInfo & 0x00FFFF00) >> 8); + } + + /** + * Returns the index of the formal parameter whose type is referenced by this type reference. This + * method must only be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER}. + * + * @return a formal parameter index. + */ + public int getFormalParameterIndex() { + return (targetTypeAndInfo & 0x00FF0000) >> 16; + } + + /** + * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced + * by this type reference. This method must only be used for type references whose sort is {@link + * #THROWS}. + * + * @return the index of an exception in the 'throws' clause of a method. + */ + public int getExceptionIndex() { + return (targetTypeAndInfo & 0x00FFFF00) >> 8; + } + + /** + * Returns the index of the try catch block (using the order in which they are visited with + * visitTryCatchBlock), whose 'catch' type is referenced by this type reference. This method must + * only be used for type references whose sort is {@link #EXCEPTION_PARAMETER} . + * + * @return the index of an exception in the 'throws' clause of a method. + */ + public int getTryCatchBlockIndex() { + return (targetTypeAndInfo & 0x00FFFF00) >> 8; + } + + /** + * Returns the index of the type argument referenced by this type reference. This method must only + * be used for type references whose sort is {@link #CAST}, {@link + * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link + * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}. + * + * @return a type parameter index. + */ + public int getTypeArgumentIndex() { + return targetTypeAndInfo & 0xFF; + } + + /** + * Returns the int encoded value of this type reference, suitable for use in visit methods related + * to type annotations, like visitTypeAnnotation. + * + * @return the int encoded value of this type reference. + */ + public int getValue() { + return targetTypeAndInfo; + } + + /** + * Puts the given target_type and target_info JVMS structures into the given ByteVector. + * + * @param targetTypeAndInfo a target_type and a target_info structures encoded as in {@link + * #targetTypeAndInfo}. LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported. + * @param output where the type reference must be put. + */ + static void putTarget(final int targetTypeAndInfo, final ByteVector output) { + switch (targetTypeAndInfo >>> 24) { + case CLASS_TYPE_PARAMETER: + case METHOD_TYPE_PARAMETER: + case METHOD_FORMAL_PARAMETER: + output.putShort(targetTypeAndInfo >>> 16); + break; + case FIELD: + case METHOD_RETURN: + case METHOD_RECEIVER: + output.putByte(targetTypeAndInfo >>> 24); + break; + case CAST: + case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case METHOD_INVOCATION_TYPE_ARGUMENT: + case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: + case METHOD_REFERENCE_TYPE_ARGUMENT: + output.putInt(targetTypeAndInfo); + break; + case CLASS_EXTENDS: + case CLASS_TYPE_PARAMETER_BOUND: + case METHOD_TYPE_PARAMETER_BOUND: + case THROWS: + case EXCEPTION_PARAMETER: + case INSTANCEOF: + case NEW: + case CONSTRUCTOR_REFERENCE: + case METHOD_REFERENCE: + output.put12(targetTypeAndInfo >>> 24, (targetTypeAndInfo & 0xFFFF00) >> 8); + break; + default: + throw new IllegalArgumentException(); + } + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.class new file mode 100644 index 0000000000000000000000000000000000000000..6aa63488dd5007f84ce5f9cd38b48a1aac9c4613 GIT binary patch literal 10675 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 V(m_uP4lVqp2J=}pS=Lok{uhFnz%Bp) literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java new file mode 100644 index 00000000..0d57c484 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java @@ -0,0 +1,702 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import jdk.internal.org.objectweb.asm.ConstantDynamic; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; + +/** + * A {@link MethodVisitor} to insert before, after and around advices in methods and constructors. + * For constructors, the code keeps track of the elements on the stack in order to detect when the + * super class constructor is called (note that there can be multiple such calls in different + * branches). {@code onMethodEnter} is called after each super class constructor call, because the + * object cannot be used before it is properly initialized. + * + * @author Eugene Kuleshov + * @author Eric Bruneton + */ +public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes { + + /** The "uninitialized this" value. */ + private static final Object UNINITIALIZED_THIS = new Object(); + + /** Any value other than "uninitialized this". */ + private static final Object OTHER = new Object(); + + /** Prefix of the error message when invalid opcodes are found. */ + private static final String INVALID_OPCODE = "Invalid opcode "; + + /** The access flags of the visited method. */ + protected int methodAccess; + + /** The descriptor of the visited method. */ + protected String methodDesc; + + /** Whether the visited method is a constructor. */ + private final boolean isConstructor; + + /** + * Whether the super class constructor has been called (if the visited method is a constructor), + * at the current instruction. There can be multiple call sites to the super constructor (e.g. for + * Java code such as {@code super(expr ? value1 : value2);}), in different branches. When scanning + * the bytecode linearly, we can move from one branch where the super constructor has been called + * to another where it has not been called yet. Therefore, this value can change from false to + * true, and vice-versa. + */ + private boolean superClassConstructorCalled; + + /** + * The values on the current execution stack frame (long and double are represented by two + * elements). Each value is either {@link #UNINITIALIZED_THIS} (for the uninitialized this value), + * or {@link #OTHER} (for any other value). This field is only maintained for constructors, in + * branches where the super class constructor has not been called yet. + */ + private List stackFrame; + + /** + * The stack map frames corresponding to the labels of the forward jumps made *before* the super + * class constructor has been called (note that the Java Virtual Machine forbids backward jumps + * before the super class constructor is called). Note that by definition (cf. the 'before'), when + * we reach a label from this map, {@link #superClassConstructorCalled} must be reset to false. + * This field is only maintained for constructors. + */ + private Map> forwardJumpStackFrames; + + /** + * Constructs a new {@link AdviceAdapter}. + * + * @param api the ASM API version implemented by this visitor. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + * @param methodVisitor the method visitor to which this adapter delegates calls. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param descriptor the method's descriptor (see {@link Type Type}). + */ + protected AdviceAdapter( + final int api, + final MethodVisitor methodVisitor, + final int access, + final String name, + final String descriptor) { + super(api, methodVisitor, access, name, descriptor); + methodAccess = access; + methodDesc = descriptor; + isConstructor = "".equals(name); + } + + @Override + public void visitCode() { + super.visitCode(); + if (isConstructor) { + stackFrame = new ArrayList<>(); + forwardJumpStackFrames = new HashMap<>(); + } else { + onMethodEnter(); + } + } + + @Override + public void visitLabel(final Label label) { + super.visitLabel(label); + if (isConstructor && forwardJumpStackFrames != null) { + List labelStackFrame = forwardJumpStackFrames.get(label); + if (labelStackFrame != null) { + stackFrame = labelStackFrame; + superClassConstructorCalled = false; + forwardJumpStackFrames.remove(label); + } + } + } + + @Override + public void visitInsn(final int opcode) { + if (isConstructor && !superClassConstructorCalled) { + int stackSize; + switch (opcode) { + case IRETURN: + case FRETURN: + case ARETURN: + case LRETURN: + case DRETURN: + throw new IllegalArgumentException("Invalid return in constructor"); + case RETURN: // empty stack + onMethodExit(opcode); + endConstructorBasicBlockWithoutSuccessor(); + break; + case ATHROW: // 1 before n/a after + popValue(); + onMethodExit(opcode); + endConstructorBasicBlockWithoutSuccessor(); + break; + case NOP: + case LALOAD: // remove 2 add 2 + case DALOAD: // remove 2 add 2 + case LNEG: + case DNEG: + case FNEG: + case INEG: + case L2D: + case D2L: + case F2I: + case I2B: + case I2C: + case I2S: + case I2F: + case ARRAYLENGTH: + break; + case ACONST_NULL: + case ICONST_M1: + case ICONST_0: + case ICONST_1: + case ICONST_2: + case ICONST_3: + case ICONST_4: + case ICONST_5: + case FCONST_0: + case FCONST_1: + case FCONST_2: + case F2L: // 1 before 2 after + case F2D: + case I2L: + case I2D: + pushValue(OTHER); + break; + case LCONST_0: + case LCONST_1: + case DCONST_0: + case DCONST_1: + pushValue(OTHER); + pushValue(OTHER); + break; + case IALOAD: // remove 2 add 1 + case FALOAD: // remove 2 add 1 + case AALOAD: // remove 2 add 1 + case BALOAD: // remove 2 add 1 + case CALOAD: // remove 2 add 1 + case SALOAD: // remove 2 add 1 + case POP: + case IADD: + case FADD: + case ISUB: + case LSHL: // 3 before 2 after + case LSHR: // 3 before 2 after + case LUSHR: // 3 before 2 after + case L2I: // 2 before 1 after + case L2F: // 2 before 1 after + case D2I: // 2 before 1 after + case D2F: // 2 before 1 after + case FSUB: + case FMUL: + case FDIV: + case FREM: + case FCMPL: // 2 before 1 after + case FCMPG: // 2 before 1 after + case IMUL: + case IDIV: + case IREM: + case ISHL: + case ISHR: + case IUSHR: + case IAND: + case IOR: + case IXOR: + case MONITORENTER: + case MONITOREXIT: + popValue(); + break; + case POP2: + case LSUB: + case LMUL: + case LDIV: + case LREM: + case LADD: + case LAND: + case LOR: + case LXOR: + case DADD: + case DMUL: + case DSUB: + case DDIV: + case DREM: + popValue(); + popValue(); + break; + case IASTORE: + case FASTORE: + case AASTORE: + case BASTORE: + case CASTORE: + case SASTORE: + case LCMP: // 4 before 1 after + case DCMPL: + case DCMPG: + popValue(); + popValue(); + popValue(); + break; + case LASTORE: + case DASTORE: + popValue(); + popValue(); + popValue(); + popValue(); + break; + case DUP: + pushValue(peekValue()); + break; + case DUP_X1: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1)); + break; + case DUP_X2: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1)); + break; + case DUP2: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1)); + stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1)); + break; + case DUP2_X1: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1)); + stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1)); + break; + case DUP2_X2: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 4, stackFrame.get(stackSize - 1)); + stackFrame.add(stackSize - 4, stackFrame.get(stackSize - 1)); + break; + case SWAP: + stackSize = stackFrame.size(); + stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1)); + stackFrame.remove(stackSize); + break; + default: + throw new IllegalArgumentException(INVALID_OPCODE + opcode); + } + } else { + switch (opcode) { + case RETURN: + case IRETURN: + case FRETURN: + case ARETURN: + case LRETURN: + case DRETURN: + case ATHROW: + onMethodExit(opcode); + break; + default: + break; + } + } + super.visitInsn(opcode); + } + + @Override + public void visitVarInsn(final int opcode, final int varIndex) { + super.visitVarInsn(opcode, varIndex); + if (isConstructor && !superClassConstructorCalled) { + switch (opcode) { + case ILOAD: + case FLOAD: + pushValue(OTHER); + break; + case LLOAD: + case DLOAD: + pushValue(OTHER); + pushValue(OTHER); + break; + case ALOAD: + pushValue(varIndex == 0 ? UNINITIALIZED_THIS : OTHER); + break; + case ASTORE: + case ISTORE: + case FSTORE: + popValue(); + break; + case LSTORE: + case DSTORE: + popValue(); + popValue(); + break; + case RET: + endConstructorBasicBlockWithoutSuccessor(); + break; + default: + throw new IllegalArgumentException(INVALID_OPCODE + opcode); + } + } + } + + @Override + public void visitFieldInsn( + final int opcode, final String owner, final String name, final String descriptor) { + super.visitFieldInsn(opcode, owner, name, descriptor); + if (isConstructor && !superClassConstructorCalled) { + char firstDescriptorChar = descriptor.charAt(0); + boolean longOrDouble = firstDescriptorChar == 'J' || firstDescriptorChar == 'D'; + switch (opcode) { + case GETSTATIC: + pushValue(OTHER); + if (longOrDouble) { + pushValue(OTHER); + } + break; + case PUTSTATIC: + popValue(); + if (longOrDouble) { + popValue(); + } + break; + case PUTFIELD: + popValue(); + popValue(); + if (longOrDouble) { + popValue(); + } + break; + case GETFIELD: + if (longOrDouble) { + pushValue(OTHER); + } + break; + default: + throw new IllegalArgumentException(INVALID_OPCODE + opcode); + } + } + } + + @Override + public void visitIntInsn(final int opcode, final int operand) { + super.visitIntInsn(opcode, operand); + if (isConstructor && !superClassConstructorCalled && opcode != NEWARRAY) { + pushValue(OTHER); + } + } + + @Override + public void visitLdcInsn(final Object value) { + super.visitLdcInsn(value); + if (isConstructor && !superClassConstructorCalled) { + pushValue(OTHER); + if (value instanceof Double + || value instanceof Long + || (value instanceof ConstantDynamic && ((ConstantDynamic) value).getSize() == 2)) { + pushValue(OTHER); + } + } + } + + @Override + public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { + super.visitMultiANewArrayInsn(descriptor, numDimensions); + if (isConstructor && !superClassConstructorCalled) { + for (int i = 0; i < numDimensions; i++) { + popValue(); + } + pushValue(OTHER); + } + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + super.visitTypeInsn(opcode, type); + // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack. + if (isConstructor && !superClassConstructorCalled && opcode == NEW) { + pushValue(OTHER); + } + } + + @Override + public void visitMethodInsn( + final int opcodeAndSource, + final String owner, + final String name, + final String descriptor, + final boolean isInterface) { + if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) { + // Redirect the call to the deprecated version of this method. + super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface); + return; + } + super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface); + int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK; + + doVisitMethodInsn(opcode, name, descriptor); + } + + private void doVisitMethodInsn(final int opcode, final String name, final String descriptor) { + if (isConstructor && !superClassConstructorCalled) { + for (Type argumentType : Type.getArgumentTypes(descriptor)) { + popValue(); + if (argumentType.getSize() == 2) { + popValue(); + } + } + switch (opcode) { + case INVOKEINTERFACE: + case INVOKEVIRTUAL: + popValue(); + break; + case INVOKESPECIAL: + Object value = popValue(); + if (value == UNINITIALIZED_THIS + && !superClassConstructorCalled + && name.equals("")) { + superClassConstructorCalled = true; + onMethodEnter(); + } + break; + default: + break; + } + + Type returnType = Type.getReturnType(descriptor); + if (returnType != Type.VOID_TYPE) { + pushValue(OTHER); + if (returnType.getSize() == 2) { + pushValue(OTHER); + } + } + } + } + + @Override + public void visitInvokeDynamicInsn( + final String name, + final String descriptor, + final Handle bootstrapMethodHandle, + final Object... bootstrapMethodArguments) { + super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); + doVisitMethodInsn(Opcodes.INVOKEDYNAMIC, name, descriptor); + } + + @Override + public void visitJumpInsn(final int opcode, final Label label) { + super.visitJumpInsn(opcode, label); + if (isConstructor && !superClassConstructorCalled) { + switch (opcode) { + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case IFNULL: + case IFNONNULL: + popValue(); + break; + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ACMPEQ: + case IF_ACMPNE: + popValue(); + popValue(); + break; + case JSR: + pushValue(OTHER); + break; + case GOTO: + endConstructorBasicBlockWithoutSuccessor(); + break; + default: + break; + } + addForwardJump(label); + } + } + + @Override + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { + super.visitLookupSwitchInsn(dflt, keys, labels); + if (isConstructor && !superClassConstructorCalled) { + popValue(); + addForwardJumps(dflt, labels); + endConstructorBasicBlockWithoutSuccessor(); + } + } + + @Override + public void visitTableSwitchInsn( + final int min, final int max, final Label dflt, final Label... labels) { + super.visitTableSwitchInsn(min, max, dflt, labels); + if (isConstructor && !superClassConstructorCalled) { + popValue(); + addForwardJumps(dflt, labels); + endConstructorBasicBlockWithoutSuccessor(); + } + } + + @Override + public void visitTryCatchBlock( + final Label start, final Label end, final Label handler, final String type) { + super.visitTryCatchBlock(start, end, handler, type); + // By definition of 'forwardJumpStackFrames', 'handler' should be pushed only if there is an + // instruction between 'start' and 'end' at which the super class constructor is not yet + // called. Unfortunately, try catch blocks must be visited before their labels, so we have no + // way to know this at this point. Instead, we suppose that the super class constructor has not + // been called at the start of *any* exception handler. If this is wrong, normally there should + // not be a second super class constructor call in the exception handler (an object can't be + // initialized twice), so this is not issue (in the sense that there is no risk to emit a wrong + // 'onMethodEnter'). + if (isConstructor && !forwardJumpStackFrames.containsKey(handler)) { + List handlerStackFrame = new ArrayList<>(); + handlerStackFrame.add(OTHER); + forwardJumpStackFrames.put(handler, handlerStackFrame); + } + } + + private void addForwardJumps(final Label dflt, final Label[] labels) { + addForwardJump(dflt); + for (Label label : labels) { + addForwardJump(label); + } + } + + private void addForwardJump(final Label label) { + if (forwardJumpStackFrames.containsKey(label)) { + return; + } + forwardJumpStackFrames.put(label, new ArrayList<>(stackFrame)); + } + + private void endConstructorBasicBlockWithoutSuccessor() { + // The next instruction is not reachable from this instruction. If it is dead code, we + // should not try to simulate stack operations, and there is no need to insert advices + // here. If it is reachable with a backward jump, the only possible case is that the super + // class constructor has already been called (backward jumps are forbidden before it is + // called). If it is reachable with a forward jump, there are two sub-cases. Either the + // super class constructor has already been called when reaching the next instruction, or + // it has not been called. But in this case there must be a forwardJumpStackFrames entry + // for a Label designating the next instruction, and superClassConstructorCalled will be + // reset to false there. We can therefore always reset this field to true here. + superClassConstructorCalled = true; + } + + private Object popValue() { + return stackFrame.remove(stackFrame.size() - 1); + } + + private Object peekValue() { + return stackFrame.get(stackFrame.size() - 1); + } + + private void pushValue(final Object value) { + stackFrame.add(value); + } + + /** + * Generates the "before" advice for the visited method. The default implementation of this method + * does nothing. Subclasses can use or change all the local variables, but should not change state + * of the stack. This method is called at the beginning of the method or after super class + * constructor has been called (in constructors). + */ + protected void onMethodEnter() {} + + /** + * Generates the "after" advice for the visited method. The default implementation of this method + * does nothing. Subclasses can use or change all the local variables, but should not change state + * of the stack. This method is called at the end of the method, just before return and athrow + * instructions. The top element on the stack contains the return value or the exception instance. + * For example: + * + *
    +      * public void onMethodExit(final int opcode) {
    +      *   if (opcode == RETURN) {
    +      *     visitInsn(ACONST_NULL);
    +      *   } else if (opcode == ARETURN || opcode == ATHROW) {
    +      *     dup();
    +      *   } else {
    +      *     if (opcode == LRETURN || opcode == DRETURN) {
    +      *       dup2();
    +      *     } else {
    +      *       dup();
    +      *     }
    +      *     box(Type.getReturnType(this.methodDesc));
    +      *   }
    +      *   visitIntInsn(SIPUSH, opcode);
    +      *   visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
    +      * }
    +      *
    +      * // An actual call back method.
    +      * public static void onExit(final Object exitValue, final int opcode) {
    +      *   ...
    +      * }
    +      * 
    + * + * @param opcode one of {@link Opcodes#RETURN}, {@link Opcodes#IRETURN}, {@link Opcodes#FRETURN}, + * {@link Opcodes#ARETURN}, {@link Opcodes#LRETURN}, {@link Opcodes#DRETURN} or {@link + * Opcodes#ATHROW}. + */ + protected void onMethodExit(final int opcode) {} +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.class new file mode 100644 index 0000000000000000000000000000000000000000..9e8343973c2897d2cfca4a0cd395390d64db2260 GIT binary patch literal 14861 zcmb_j34B!5)j#*%w@ijd5)u*!lR!j>VG@X-MobV5n+C&D!XlvJkPI*qCShj6rUj{r zqSjpmHx`jts-KFQfLO7M@@ci7+D*GzwRVv%wssLp;rpNa-b^MCiC@3+%gwv*F6W$k z_IqAdnZ3@@w*#g|n~YiVe1 z4968^5c$a@%O=|)A7u!t>|tv|^Ri{l(Rf7-Ag^8%j@2}VT7XB8H6{{`B*qGgl-AZ= z6th3Ivt^Ux*eoin()Y>701X3`i*8P$3lwGMiUMncF#OXYp8U z(;%EuAEq@CX{xA+#X_s=BJqTu22w5q8SK#MGz6k*YHkQMfhXB66uq2RR`aS7htA+t zW;_vUSZdQSL47)*UL1-qnG$O8Q>hEH+@aw#0tB^2S^kkwQ)ErJapvllFyLpU!N;a* zANl+=l1ABdmP2RLIbCGt9s|^cm$z!_@=DVV=}NSE*t`r9bgo0A={z8vHMMqX?abPm zy4raYCoGtGacwziXtTDU(BIBIv&^($is5fv<2*(>@krr5(puSyf#ybmdxZI&DctaL8Fpt^K zObsmy+jOO%{+$L@6OV^uY(x`dvF4bc7EmsWqQRj?KBEzbvarrAa%eFv5tOkkw5rZi zPEl*qRe}b0Li5Zs$?uef`lv}z-3cD4xH;Oix;WIpRva%5uWAWJ8^evoi(()%UR)Xv zhl{lnm=O*&hGQcpUOK&I>VyT8X4FiXSU=295sI>bHw)^bhDmv9FRc4Sm_BwGOSLYm@q}{qdAg0(@5BGcbZwRxOjh;?Q->e;>x-{Ti0Cle@v84Rj-f zqRFU@#-or}X)QxHX`@3o(=AZO@Tzb_YXS%F2WV;M?!u|BI&>S|F39mfL1`G8CP1_D zPKWO5TrfKn;{{CFJr3RL`mE5xa8ul-`veW?!8Gf5sh>7cF1x<_S&la{tOp%>h#nRs zm#q*qq9=>&>V}yi+Z@_XJCgF&SOg7&xu4pf>xBqcEbN^QJxaU4=m?A^q>U^;X=K_B z*Lve{S&z}zY})P6*XeP%x=xpsTmt4V3B{*|SGhi79`E=shn}RTAg8Dv?rOlED)yp1 z^o&i5fkxVn*$CXdgWf&|2KAyRN+RyGsq+ zi28y<-=G(vs;Q%!F< z^frAT>*Bl)2A_7aQ*qs-A3F3S#+}*H8eh`s#`(bSIP@<4L{PqGe=C}oh9|6!hL%Md z+;fN0#r?S~?Mc%whL3FuS9jz7Tp|C=p`X()l6o<@by%UvJ+ zLr~G@0CbnwbQu1v2WaDw#V111gr^36`i$l>bB{XoFZRT)?bb%3n!7x6+z})MvI5tt zLpXK)%1EMNi7Uhz+W&tMDfXBQB|Rpv3grkxn6Ma)wXV5&X=_VYv|mhh=5yryBGhSB z6}BUM0{5YQ8ts(UrbMJ>YIvnis@?PEcVjX-IF1y(9N~!GNU<80gkm)?V-B0+`7~LM z$QHPC;JdS(q-otJH0+ZzQ}b%U)BOQ_D>0|iX-h4`Htu( z`a?J1!)AmNt+6O;u%Pq0Asp`Q)ZFH+$aqJJ0gec8HfS}4ql*(uc&Nw`0|l-#8S&PI zaeae?@8WFbWOl%}iqjl1n0>1i3omP40h78=3~|KJR2q#e6ZS67U}t=zPvAyVFu8t4 z#f*tFi$k$+akM#69B*xDLAD)kM2alR98s=w=&7^n>ey4f!9-OsQD>gyyFIb^s5j%l z#pZ2swx%|X)|5B$iAv-j^XK`*Xnv0Oi7I}M^NBJ1toI4rpym8ppSX~plYC+vKPUJE zt|W5)WLr#vPIg+qi+o&bqzOr^UreN2pQyzhs5ZI+H?c+>50}8=1Xx{+S#gOY>ckW< zD%8>vjy4J!-o4~f*=ra0)eK@9gP1O;uxkW6dEpF4)bky|muPk;ePR|I$b6R097kN5 zR3w)-+7$x)JO+H?#j#|P(I6L{AXn_Y!R3Y1pw znH_3s1s_Z}9e!rH=xd^l_06rZ28{HI#C4ruQHbC27B)90;)z(O#Z^%^Z9%r%6K*fT zM2+DD2+5iNt6E%FO)`+VARM4BgIs!9gzv76i)oKD;z(&?e zJT1-6k;%@eWalh|f&^lW6^U~3i7C=CQuqBX%O^!Rqv(4=QDg+`G@XWsmXC6=O(=8G z5Cps{@Fv9qyrcA&_AdGIoqE3#^Cf;kqrmJSBiK&<9P?4?wV$%*c2LfNr?EtdM*Pkp1HZRWZ@M3ZK7dR7Ln4fk zu`U>~NG!%10CG_jsL&HjK!DV}2*#A|U43h15Zq4#L2B`HbXsS3D7vK>4L(O@McKZ!_fu(3 zMS;;yXKta~;Inkv9;)0&Rg&hkQ6|5ayKe>NUb>*lF0fy$^r^~>yo@~G4tle|&dV58 zUOe%Cz-BGlgo>eBbOydAj<_{Md-lw8KUiYMUWTlqlE&MhH$5NS7;sC1Fd+59D0`e zVR|sNL$~&#D!dP3ejZiL7icaWKxynHdWv2_ao`|&uhJXz8of!c;~x12eT*CRAMkdB z-hv$87JmAHD4-vTLi({Nqj$szTzM<$fEYtR7qz%|vI@B6k6!oog%j*$HsfC#Q2x+*7%q1|jI8v}AH_1;gBxj9QaXxV{apm2DewwV^@=PT6T zWh;CcIz#snI&DOtftRDpVhQuG7R_F|8q(ph^*rA>w!Twhl`uuZ zW!a?PQWpK52GAejMgBxV`h+U!FH}RHQXTybn)r9RlKw#n+$L|rEws~UHzxT^8^v;$ z&*;TGqunUtBB70TqiDq#8|_9q17ohynxwKy@*ptOMd7Gmpil$JLZC`DwrIc(8d+8} zs>&!YFkDqEF!sZkN z1;)<7)sv5KHZbAaiC7_4f;35IiB+yzP^DOn9{;NpYd|iWYNfauPE(3&(07s}aIR7- z3Vhp9bdSwdqCwJ5lHPIH~cL{uIObkOy|fD-L=Q=kt$zMcGdJiSvt z4s4^|LBakAzlL@SYyfML@BwxPIWUaVL@z244wZ>aeWHBrE6YSt237$76)5bWTk)HzVRTY6F;m+}4s0QpdW*gqMX|dhg(A~M!BE6HAd|p= zny-i9yTHIwAEzmXhjT6^u>W0ujv0i)yA&J9A8JPps zg$Ny)WU!4xLzI3V$7FIO`4n9KbPooe8(L3SL1_E8(IVK`-3Mvpe%b^_xp}I#S_GIa z&(YmHH9X~eA9#g&VdR0~?X;C=_R%APreeNLAT$m{=LrFqxT(s(Y*~SUu=2D*kU9Qd zFi_q>9Z;EaPe?91v=NITWQ(B?K?$l6XV73#O2fr4I$H#3j2KSy;4~MD3c5;+q!uxX zR*JJUyVwHqp+VP)>mk;85Hj~zV5?FrT$N(sDwsGNsAil)YRpl}u<5ZQNHzplc|DOg z0VZ2;4(LTv&_Vk_G6&9+6l*lTOrM8uwN)uvuq%Z(CxtgB>9{eQ%mQ+>yEcFsC0`e_ z%!YMvKs^M`9mx6C4(b;`O$L!W%Oxcb`N_ARPU{Ey96P?Y(!%o74pIi&+TBkFnbd=M zRv+5Cl{O=rd9BLkw~lRe^YEMs9sk!C*ogkS$idD5RlYW|%B$R9&!Duc-9cw?KQCh+ zy)LQ1-bH=f_X6KOdJ_WGq4X`CAz;Gw&+ew7Cv3ud*G-zlAGqY=xUL#p1@Dbq6zrTx zg<=xEDql>ch>sQG61c89lvAca6{gWRF`XuhFVS={gF<2^MZ_$Mi8<6N=F$c+k2Z<< zv=jZ^a9{i3-o7iYq<7JO4?_A#ETWIaVlA#UaDvUieFL1Qk5gLW) zN6l#i*0D=IloIeEaU(k?9!m-MP)fjuJOT5Ln_#adT=xrFCEUn-I{Ax^!j_NHIquJ`Gjz3uvS9&v z2ygj_2?2z(VzB~IWo4TFmZXkXqL0GIE73>cEVe{!6gO)JS|V-%3`5(JB9RY1poZ>| zx&|i5etD2K`JZ-1iMCV5g{$EbuYnDJ8Q&e(;*S{CX;;UQ&UM;@QnU?9+14O!@vcpS zj)9;9AHzI4mV*u^dq}XX!}V4NVN0AXr@6K=*R^#9Dc3*W0B^bhLFz{8FE%2`-mIDA z2B;w^LWXGcZh!*%{y>j!04{p52gsQXA2Is(x=5?+oAegn{3?3umP-T#NCMTVT;Sf7I)uc)xH9Rh7L&7b0grzcAa6 zXjPb8P>do>cst2FCKuC ze~=o*L$p*pjNEZ6T`jiJbz(bgZwGA_kKhyOP6U}<^rU!<_KC02x5RFGReT*;^%Jn} zC-Fh$DJ>&bmg}fo+^XXx*q@TtN7{;AY2{I7PIkZSepyFpfbeA^@s(M9`Ra+!44(RM z!pHI(sDuAMb$Ab?!g?RNKF~GY(Dy^}EVTGJXmC4RSVxK=KuM7?P=|81tbyXIn#lFI zhVxGY#@2auUIeT<{u~STq1`&qVn%nSRBn#rYU>Ly?{9$1FH%2o0RHo(G?Ok$AufVc zT#r=*H15T;NZhW2Cm}T63uz%F@s|ycm^j`!oCetGbO;GjzTN{V-$5jQ8J^}9c$$OY z?SE@h+{7l3A|;^FG7kdcPBB)SX+RSIGvaR?9s#pG8Ds~`3Oj@a{4W=lbrXwU2iM=A zEb+ZGj%TN^Wor+{*s{f4`rv{;c(^#k>2U1ukyKf(+J(Q;)`HHn^6c!%Tgi{d1f+Oo zdP=7~aDka;b%@MP$KhtT@8JCJB9r+kvY4MBg#8Tp`p-30e97ZHJXt5GOnKPKl!vW^ zp}2K|N^y^u%T$Vc(c_$?5~i~RS%QtQcpuEi*8aDF)Nw>09}>T0-2l~tP54Pm2UQRA z^f~jXh67r1b{$m!&itF-Tf{tqZu ze27ZOukhDezfO}~MT$!mx|qYVtI*|~l&>EFrNOsrkEW!rFYjum0d~7yMw89`fKF(T z^1#JD1)y&B;b#RDhak4!Ya&j*h{V})G`sP)jHTlct+55)R6O)-ILwmKpND>Xvg(p7 zYaIWzCI|U3r&A~L<`aI+jqRc^8719XQm4dbQy!G( z82NDz>kBsLOF?%?MR&>!+ARIFMLM)i_NMJJiylLk|D^0gPsv>BkbUVznMVg?Kl+aB zPY2}y`jHIKyRwMhmxIzI{y~c8A0S|IZ84u-cYTId$vo=S_d?kIQCfrFDEDM$+I^s> z{8t{H3S0oOuo304$WvlB8uy7}iABjPv&D<#V2#_Y66ATf8CbFk@CZP&KPpcFI=?W` zIJVGetTghBqU|o0JVOJYbG>oA?f9WierZ1`OUN(JpiEgx1#%b-#j{M7X}o-^%SGD7 z)eH_k>Ggp7*$i<@8jL^H;{cY47MC2dq# z$Z-L=6v9HUpsB}vK?BduBaXuDg5(IYWCc0$OdNA0RAUs4kY`aPo@3-WR3j^Cx;&RI zmFLmrvRWUVOUWZpqh5|Wpbv*T3%LYeUFu7} zXar!s_8p*u{~d$_9gcP;TGc7q1k7qUd=zaz`WQ<#br=;CK3CfFKZQF9$AH^1)}p09xu0xsea3BQo6x?F_BtBqF^kda z(eCo-eF0CL!+ih$|E}f9GWD9~$3Hx{Cq5Z3^DOOY^(M0Vqm4j2-<$V%Y=LGy=Z&ZM zpN7v`=d@|(Ay4k{5>~zS%0$Y=G^7f)G z+dU32#x^OFdZ5b;;#1AN6O={#Jh@0~p!i;LQM&Gky;=Y#Zru?qzHwF~UalA|t_Q<4O@uVaHy{vWi7N`4+}6C>Q!?%-*9kQp$iP4wlQ_HLy! zd_KNVdZLgMPQF;fDADl!6juqN^Uy+QOVP%o!KP^rS}QdE99`k~4tnS6-t*|4r+ZJK zSFL-y&^urE9z^c~-Mb6D8r{1Iz45xYmLutYF>!8(xF}a#+%6`=o~O2pFX_<53dZ?T|LW#>38q@{+WdIOJ1FvhsIF!ETC`m6NEg6e+ zCeA@dqfC9+n{lrz;FIa^&J=ctejsU>ouS}MaTCKsvIa+jbCbdB} ztFOuyb&p)G?vt%*n_QtDk*n3?a*cXMUai{YTD4!UQ{R%;s#oQD^}4)Xy(Mo@@5l}6 zJ$a-0KyFmOkvFS9$XnFkokWfaRzMv1)77%n#(BjpyOO5Sfw zmJb+nE9r79DQQ2OGx ze9d@H{>XS<{@D12eAoE4{E6|Z{HgIj@@K}|@)yQC@;&1h@|VW1zcEeuTeFw^o!LizZ1$6f%p&=FvsnJoERlaQ%jGBLDEVh|wET-XR(@(u zkbgBVl7Ba+$bXpi@-uU;JZvtIN6fJNr@2%fHJ8hOnJeWna}EC9`&uQ;4N97~DrMfK z40E$G&4-m`?o_t9TlvhVREF8E{N_I8mena2Wp7P+)bYNYvhHOf4!s?B3+jAg3xEuR{1^;Q$CzG|WsP?M~IYO-~@y2J{qI%}kw zVx6s~S!2|6>jG78O;9tfOVliDhMH~7QkPou)Lbj1=2?yEax0>)uv*jtYo)rZaM>MH9twbZ&-HCdZg)OtuYTieuf>roZ69#aYH3Ds)tQ7f$H)GF(Fwc0wM z)>z+C*H~|=FI(SN>#TRwwYE=v#m-XK**WS4yFhKQ3)M~b>1v~0qHeK=t6S|e)ou2< z>UO(I-D%gTyX*<-9{Un?uRT@WXU|fb?Mv1Dc0xUDuU1>_d(<}jKDEPsP(5O|sh#$2 zwab1|wb{?A$LtQZ+y1_K+4@5VazlZqCDx2 zU7H&FHtI|6*gLqHyS-na%H{4jj1R-^*l~Q<)MF<8hn#pA@GP?gV|vys$Cx`i1xdX- zR*${z*j%i0cU+4<^>k-9fKqq%R_t(R@4}9)fNYxwK!LmNWzeVBApvj$nKSsm*;*3&cX instruction delegates to + * the next visitor in the chain, if any, and then simulates the effect of this instruction on the + * stack map frame, represented by {@link #locals} and {@link #stack}. The next visitor in the chain + * can get the state of the stack map frame before each instruction by reading the value of + * these fields in its visitX methods (this requires a reference to the AnalyzerAdapter that + * is before it in the chain). If this adapter is used with a class that does not contain stack map + * table attributes (i.e., pre Java 6 classes) then this adapter may not be able to compute the + * stack map frame for each instruction. In this case no exception is thrown but the {@link #locals} + * and {@link #stack} fields will be null for these instructions. + * + * @author Eric Bruneton + */ +public class AnalyzerAdapter extends MethodVisitor { + + /** + * The local variable slots for the current execution frame. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and + * double are represented by two elements, the second one being TOP). Reference types are + * represented by String objects (representing internal names, see {@link + * Type#getInternalName()}), and uninitialized types by Label objects (this label designates the + * NEW instruction that created this uninitialized value). This field is {@literal null} for + * unreachable instructions. + */ + public List locals; + + /** + * The operand stack slots for the current execution frame. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link Opcodes#UNINITIALIZED_THIS} (long and + * double are represented by two elements, the second one being TOP). Reference types are + * represented by String objects (representing internal names, see {@link + * Type#getInternalName()}), and uninitialized types by Label objects (this label designates the + * NEW instruction that created this uninitialized value). This field is {@literal null} for + * unreachable instructions. + */ + public List stack; + + /** The labels that designate the next instruction to be visited. May be {@literal null}. */ + private List

    Note: a precondition and postcondition of this method is that all labels must have a null + * {@link #nextListElement}. + * + * @param subroutineCaller a basic block that ends with a jsr to the basic block corresponding to + * this label. This label is supposed to correspond to the start of a subroutine. + */ + final void addSubroutineRetSuccessors(final Label subroutineCaller) { + // Data flow algorithm: put this basic block in a list blocks to process (which are blocks + // belonging to a subroutine starting with this label) and, while there are blocks to process, + // remove one from the list, put it in a list of blocks that have been processed, add a return + // edge to the successor of subroutineCaller if applicable, and add its successor basic blocks + // in the control flow graph to the list of blocks to process (if not already done). + Label listOfProcessedBlocks = EMPTY_LIST; + Label listOfBlocksToProcess = this; + listOfBlocksToProcess.nextListElement = EMPTY_LIST; + while (listOfBlocksToProcess != EMPTY_LIST) { + // Move a basic block from the list of blocks to process to the list of processed blocks. + Label basicBlock = listOfBlocksToProcess; + listOfBlocksToProcess = basicBlock.nextListElement; + basicBlock.nextListElement = listOfProcessedBlocks; + listOfProcessedBlocks = basicBlock; + + // Add an edge from this block to the successor of the caller basic block, if this block is + // the end of a subroutine and if this block and subroutineCaller do not belong to the same + // subroutine. + if ((basicBlock.flags & FLAG_SUBROUTINE_END) != 0 + && basicBlock.subroutineId != subroutineCaller.subroutineId) { + basicBlock.outgoingEdges = + new Edge( + basicBlock.outputStackSize, + // By construction, the first outgoing edge of a basic block that ends with a jsr + // instruction leads to the jsr continuation block, i.e. where execution continues + // when ret is called (see {@link #FLAG_SUBROUTINE_CALLER}). + subroutineCaller.outgoingEdges.successor, + basicBlock.outgoingEdges); + } + // Add its successors to the list of blocks to process. Note that {@link #pushSuccessors} does + // not push basic blocks which are already in a list. Here this means either in the list of + // blocks to process, or in the list of already processed blocks. This second list is + // important to make sure we don't reprocess an already processed block. + listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess); + } + // Reset the {@link #nextListElement} of all the basic blocks that have been processed to null, + // so that this method can be called again with a different subroutine or subroutine caller. + while (listOfProcessedBlocks != EMPTY_LIST) { + Label newListOfProcessedBlocks = listOfProcessedBlocks.nextListElement; + listOfProcessedBlocks.nextListElement = null; + listOfProcessedBlocks = newListOfProcessedBlocks; + } + } + + /** + * Adds the successors of this label in the method's control flow graph (except those + * corresponding to a jsr target, and those already in a list of labels) to the given list of + * blocks to process, and returns the new list. + * + * @param listOfLabelsToProcess a list of basic blocks to process, linked together with their + * {@link #nextListElement} field. + * @return the new list of blocks to process. + */ + private Label pushSuccessors(final Label listOfLabelsToProcess) { + Label newListOfLabelsToProcess = listOfLabelsToProcess; + Edge outgoingEdge = outgoingEdges; + while (outgoingEdge != null) { + // By construction, the second outgoing edge of a basic block that ends with a jsr instruction + // leads to the jsr target (see {@link #FLAG_SUBROUTINE_CALLER}). + boolean isJsrTarget = + (flags & Label.FLAG_SUBROUTINE_CALLER) != 0 && outgoingEdge == outgoingEdges.nextEdge; + if (!isJsrTarget && outgoingEdge.successor.nextListElement == null) { + // Add this successor to the list of blocks to process, if it does not already belong to a + // list of labels. + outgoingEdge.successor.nextListElement = newListOfLabelsToProcess; + newListOfLabelsToProcess = outgoingEdge.successor; + } + outgoingEdge = outgoingEdge.nextEdge; + } + return newListOfLabelsToProcess; + } + + // ----------------------------------------------------------------------------------------------- + // Overridden Object methods + // ----------------------------------------------------------------------------------------------- + + /** + * Returns a string representation of this label. + * + * @return a string representation of this label. + */ + @Override + public String toString() { + return "L" + System.identityHashCode(this); + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodTooLargeException.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodTooLargeException.class new file mode 100644 index 0000000000000000000000000000000000000000..a877d4c0af4e88b37fd24e413b9ff05e9c1d4ed3 GIT binary patch literal 1287 zcmbVLTTc@~6#k}n$|6{~D56wRY!}LUK}AX+p=eT5;Q?%d7m{svD2v;jW_PQNZ~hqH zc+kW`qKQAiKjS|zp4n}HwDrY@ojK?1Ip_Q4n=`-ueE$icfR#8x3=@a?dtI}1yQXb> zj%nA{o2F%OCkcj#f+%7Pu@%!cy;X*ACR zm^lM2+6HfJHNCC2R@A+LHLctz9Qx)unrBScBcaIX76)zV#eQ?GN9tLMmh33EfiO^K1L`)bNu8NQ|9 zwjVaQTXoEaCmb2RqacGUX;Bph-!?x|Ushxoak*paR+&34o$6(AgTl`lh6=)VJ>B-o zy4B>-z1EQx`MpLzmiwH#mtJqAm@U&p6bPGPxMbRVvstfjXGgDC{s~2uNa#d`{7x|9 z9hfe|QtAIR%rhu8?iJ2-93nRmJkVA88>b>M49fIVb!b{ipX9b^I#vG6lr*RQaa{{? zU~rFA9;dev#UxbB(Lm3W7eWpxISgc{=BtL6jh&141vOZ*jW2SoAG^+_!k9ySUZ2cnMF4i&XkN?b)L)+MoIsFZ)^f EznnP^KL7v# literal 0 HcmV?d00001 diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodTooLargeException.java b/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodTooLargeException.java new file mode 100644 index 00000000..a2c9cee1 --- /dev/null +++ b/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodTooLargeException.java @@ -0,0 +1,131 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * Exception thrown when the Code attribute of a method produced by a {@link ClassWriter} is too + * large. + * + * @author Jason Zaugg + */ +public final class MethodTooLargeException extends IndexOutOfBoundsException { + private static final long serialVersionUID = 6807380416709738314L; + + private final String className; + private final String methodName; + private final String descriptor; + private final int codeSize; + + /** + * Constructs a new {@link MethodTooLargeException}. + * + * @param className the internal name of the owner class (see {@link Type#getInternalName()}). + * @param methodName the name of the method. + * @param descriptor the descriptor of the method. + * @param codeSize the size of the method's Code attribute, in bytes. + */ + public MethodTooLargeException( + final String className, + final String methodName, + final String descriptor, + final int codeSize) { + super("Method too large: " + className + "." + methodName + " " + descriptor); + this.className = className; + this.methodName = methodName; + this.descriptor = descriptor; + this.codeSize = codeSize; + } + + /** + * Returns the internal name of the owner class. + * + * @return the internal name of the owner class (see {@link Type#getInternalName()}). + */ + public String getClassName() { + return className; + } + + /** + * Returns the name of the method. + * + * @return the name of the method. + */ + public String getMethodName() { + return methodName; + } + + /** + * Returns the descriptor of the method. + * + * @return the descriptor of the method. + */ + public String getDescriptor() { + return descriptor; + } + + /** + * Returns the size of the method's Code attribute, in bytes. + * + * @return the size of the method's Code attribute, in bytes. + */ + public int getCodeSize() { + return codeSize; + } +} diff --git a/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodVisitor.class b/tests/test_data/std/jdk/internal/org/objectweb/asm/MethodVisitor.class new file mode 100644 index 0000000000000000000000000000000000000000..15b1796f1d5b99c4c3943f6a2ff0c597c77a4535 GIT binary patch literal 9035 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 | {@code visitLabel} | {@code visitInsnAnnotation} | {@code + * visitTryCatchBlock} | {@code visitTryCatchAnnotation} | {@code visitLocalVariable} | {@code + * visitLocalVariableAnnotation} | {@code visitLineNumber} )* {@code visitMaxs} ] {@code visitEnd}. + * In addition, the {@code visitXInsn} and {@code visitLabel} methods must be called in the + * sequential order of the bytecode instructions of the visited code, {@code visitInsnAnnotation} + * must be called after the annotated instruction, {@code visitTryCatchBlock} must be called + * before the labels passed as arguments have been visited, {@code + * visitTryCatchBlockAnnotation} must be called after the corresponding try catch block has + * been visited, and the {@code visitLocalVariable}, {@code visitLocalVariableAnnotation} and {@code + * visitLineNumber} methods must be called after the labels passed as arguments have been + * visited. + * + * @author Eric Bruneton + */ +public abstract class MethodVisitor { + + private static final String REQUIRES_ASM5 = "This feature requires ASM5"; + + /** + * The ASM API version implemented by this visitor. The value of this field must be one of the + * {@code ASM}x values in {@link Opcodes}. + */ + protected final int api; + + /** + * The method visitor to which this visitor must delegate method calls. May be {@literal null}. + */ + protected MethodVisitor mv; + + /** + * Constructs a new {@link MethodVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + */ + protected MethodVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link MethodVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one of the {@code + * ASM}x values in {@link Opcodes}. + * @param methodVisitor the method visitor to which this visitor must delegate method calls. May + * be null. + */ + protected MethodVisitor(final int api, final MethodVisitor methodVisitor) { + if (api != Opcodes.ASM9 + && api != Opcodes.ASM8 + && api != Opcodes.ASM7 + && api != Opcodes.ASM6 + && api != Opcodes.ASM5 + && api != Opcodes.ASM4) { + throw new IllegalArgumentException("Unsupported api " + api); + } + this.api = api; + this.mv = methodVisitor; + } + + /** + * The method visitor to which this visitor must delegate method calls. May be {@literal null}. + * + * @return the method visitor to which this visitor must delegate method calls, or {@literal + * null}. + */ + public MethodVisitor getDelegate() { + return mv; + } + + // ----------------------------------------------------------------------------------------------- + // Parameters, annotations and non standard attributes + // ----------------------------------------------------------------------------------------------- + + /** + * Visits a parameter of this method. + * + * @param name parameter name or {@literal null} if none is provided. + * @param access the parameter's access flags, only {@code ACC_FINAL}, {@code ACC_SYNTHETIC} + * or/and {@code ACC_MANDATED} are allowed (see {@link Opcodes}). + */ + public void visitParameter(final String name, final int access) { + if (api < Opcodes.ASM5) { + throw new UnsupportedOperationException(REQUIRES_ASM5); + } + if (mv != null) { + mv.visitParameter(name, access); + } + } + + /** + * Visits the default value of this annotation interface method. + * + * @return a visitor to the visit the actual default value of this annotation interface method, or + * {@literal null} if this visitor is not interested in visiting this default value. The + * 'name' parameters passed to the methods of this annotation visitor are ignored. Moreover, + * exactly one visit method must be called on this annotation visitor, followed by visitEnd. + */ + public AnnotationVisitor visitAnnotationDefault() { + if (mv != null) { + return mv.visitAnnotationDefault(); + } + return null; + } + + /** + * Visits an annotation of this method. + * + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + if (mv != null) { + return mv.visitAnnotation(descriptor, visible); + } + return null; + } + + /** + * Visits an annotation on a type in the method signature. + * + * @param typeRef a reference to the annotated type. The sort of this type reference must be + * {@link TypeReference#METHOD_TYPE_PARAMETER}, {@link + * TypeReference#METHOD_TYPE_PARAMETER_BOUND}, {@link TypeReference#METHOD_RETURN}, {@link + * TypeReference#METHOD_RECEIVER}, {@link TypeReference#METHOD_FORMAL_PARAMETER} or {@link + * TypeReference#THROWS}. See {@link TypeReference}. + * @param typePath the path to the annotated type argument, wildcard bound, array element type, or + * static inner type within 'typeRef'. May be {@literal null} if the annotation targets + * 'typeRef' as a whole. + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitTypeAnnotation( + final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { + if (api < Opcodes.ASM5) { + throw new UnsupportedOperationException(REQUIRES_ASM5); + } + if (mv != null) { + return mv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); + } + return null; + } + + /** + * Visits the number of method parameters that can have annotations. By default (i.e. when this + * method is not called), all the method parameters defined by the method descriptor can have + * annotations. + * + * @param parameterCount the number of method parameters than can have annotations. This number + * must be less or equal than the number of parameter types in the method descriptor. It can + * be strictly less when a method has synthetic parameters and when these parameters are + * ignored when computing parameter indices for the purpose of parameter annotations (see + * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18). + * @param visible {@literal true} to define the number of method parameters that can have + * annotations visible at runtime, {@literal false} to define the number of method parameters + * that can have annotations invisible at runtime. + */ + public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) { + if (mv != null) { + mv.visitAnnotableParameterCount(parameterCount, visible); + } + } + + /** + * Visits an annotation of a parameter this method. + * + * @param parameter the parameter index. This index must be strictly smaller than the number of + * parameters in the method descriptor, and strictly smaller than the parameter count + * specified in {@link #visitAnnotableParameterCount}. Important note: a parameter index i + * is not required to correspond to the i'th parameter descriptor in the method + * descriptor, in particular in case of synthetic parameters (see + * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18). + * @param descriptor the class descriptor of the annotation class. + * @param visible {@literal true} if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not + * interested in visiting this annotation. + */ + public AnnotationVisitor visitParameterAnnotation( + final int parameter, final String descriptor, final boolean visible) { + if (mv != null) { + return mv.visitParameterAnnotation(parameter, descriptor, visible); + } + return null; + } + + /** + * Visits a non standard attribute of this method. + * + * @param attribute an attribute. + */ + public void visitAttribute(final Attribute attribute) { + if (mv != null) { + mv.visitAttribute(attribute); + } + } + + /** Starts the visit of the method's code, if any (i.e. non abstract method). */ + public void visitCode() { + if (mv != null) { + mv.visitCode(); + } + } + + /** + * Visits the current state of the local variables and operand stack elements. This method must(*) + * be called just before any instruction i that follows an unconditional branch + * instruction such as GOTO or THROW, that is the target of a jump instruction, or that starts an + * exception handler block. The visited types must describe the values of the local variables and + * of the operand stack elements just before i is executed.
    + *
    + * (*) this is mandatory only for classes whose version is greater than or equal to {@link + * Opcodes#V1_6}.
    + *
    + * The frames of a method must be given either in expanded form, or in compressed form (all frames + * must use the same format, i.e. you must not mix expanded and compressed frames within a single + * method): + * + *