OpenJDK / amber / amber
changeset 55170:cfe047f11020 patterns-stage-1
Automatic merge with default
author | mcimadamore |
---|---|
date | Thu, 28 Feb 2019 22:05:33 +0100 |
parents | 1e4a2079302b 1542e63eb537 |
children | 966f6454ccd8 db99258b6011 285e83b11b53 |
files | src/hotspot/share/prims/evmCompat.cpp src/hotspot/share/utilities/intHisto.cpp src/hotspot/share/utilities/intHisto.hpp src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/COPYING src/jdk.javadoc/share/classes/com/sun/javadoc/AnnotatedType.java src/jdk.javadoc/share/classes/com/sun/javadoc/AnnotationDesc.java src/jdk.javadoc/share/classes/com/sun/javadoc/AnnotationTypeDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/AnnotationTypeElementDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/AnnotationValue.java src/jdk.javadoc/share/classes/com/sun/javadoc/ClassDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/ConstructorDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/Doc.java src/jdk.javadoc/share/classes/com/sun/javadoc/DocErrorReporter.java src/jdk.javadoc/share/classes/com/sun/javadoc/Doclet.java src/jdk.javadoc/share/classes/com/sun/javadoc/ExecutableMemberDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/FieldDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/LanguageVersion.java src/jdk.javadoc/share/classes/com/sun/javadoc/MemberDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/MethodDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/PackageDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/ParamTag.java src/jdk.javadoc/share/classes/com/sun/javadoc/Parameter.java src/jdk.javadoc/share/classes/com/sun/javadoc/ParameterizedType.java src/jdk.javadoc/share/classes/com/sun/javadoc/ProgramElementDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/RootDoc.java src/jdk.javadoc/share/classes/com/sun/javadoc/SeeTag.java src/jdk.javadoc/share/classes/com/sun/javadoc/SerialFieldTag.java src/jdk.javadoc/share/classes/com/sun/javadoc/SourcePosition.java src/jdk.javadoc/share/classes/com/sun/javadoc/Tag.java src/jdk.javadoc/share/classes/com/sun/javadoc/ThrowsTag.java src/jdk.javadoc/share/classes/com/sun/javadoc/Type.java src/jdk.javadoc/share/classes/com/sun/javadoc/TypeVariable.java src/jdk.javadoc/share/classes/com/sun/javadoc/WildcardType.java src/jdk.javadoc/share/classes/com/sun/javadoc/package-info.java src/jdk.javadoc/share/classes/com/sun/tools/doclets/standard/Standard.java src/jdk.javadoc/share/classes/com/sun/tools/doclets/standard/package-info.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/Main.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/AbstractTypeImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/AnnotatedTypeImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/AnnotationDescImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/AnnotationTypeDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/AnnotationTypeElementDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/AnnotationValueImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ClassDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/Comment.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ConstructorDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/DocEnv.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/DocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/DocLocale.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/DocletInvoker.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ExecutableMemberDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/FieldDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavaScriptScanner.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavadocClassFinder.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavadocEnter.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavadocMemberEnter.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavadocTodo.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/JavadocTool.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/MemberDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/Messager.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/MethodDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ModifierFilter.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/PackageDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ParamTagImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ParameterImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ParameterizedTypeImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/PrimitiveType.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ProgramElementDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/RootDocImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/SeeTagImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/SerialFieldTagImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/SerializedForm.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/SourcePositionImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/Start.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/TagImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ThrowsTagImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/ToolOption.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/TypeMaker.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/TypeVariableImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/WildcardTypeImpl.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/package-info.java src/jdk.javadoc/share/classes/com/sun/tools/javadoc/resources/javadoc.properties src/jdk.javadoc/share/classes/com/sun/tools/javadoc/resources/javadoc_ja.properties src/jdk.javadoc/share/classes/com/sun/tools/javadoc/resources/javadoc_zh_CN.properties src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Headings.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MarkerComments.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripDebugPlugin.java test/hotspot/gtest/memory/test_virtualSpaceNode.cpp test/jdk/tools/jlink/plugins/StripDebugPluginTest.java test/langtools/jdk/javadoc/lib/javadoc/tester/ShowHeadings.java test/langtools/jdk/javadoc/tool/api/basic/GetTask_DocletClassTest.java test/langtools/tools/javadoc/6176978/T6176978.java test/langtools/tools/javadoc/6176978/X.java test/langtools/tools/javadoc/6227454/Test.java test/langtools/tools/javadoc/6942366/T6942366.java test/langtools/tools/javadoc/6942366/Test.java test/langtools/tools/javadoc/6942366/p/Base.java test/langtools/tools/javadoc/6958836/Test.java test/langtools/tools/javadoc/6964914/Error.java test/langtools/tools/javadoc/6964914/JavacWarning.java test/langtools/tools/javadoc/6964914/JavadocWarning.java test/langtools/tools/javadoc/6964914/Test.java test/langtools/tools/javadoc/6964914/TestStdDoclet.java test/langtools/tools/javadoc/6964914/TestUserDoclet.java test/langtools/tools/javadoc/8025693/Test.java test/langtools/tools/javadoc/8147801/T8147801.java test/langtools/tools/javadoc/8147801/jarsrc/lib/Lib1.java test/langtools/tools/javadoc/8147801/jarsrc/lib/Lib2.java test/langtools/tools/javadoc/8147801/p/Test.java test/langtools/tools/javadoc/AddOpensTest.java test/langtools/tools/javadoc/BadOptionsTest.java test/langtools/tools/javadoc/BooleanConst.java test/langtools/tools/javadoc/BreakIteratorWarning.java test/langtools/tools/javadoc/CheckResourceKeys.java test/langtools/tools/javadoc/CompletionError.java test/langtools/tools/javadoc/EncodingTest.java test/langtools/tools/javadoc/FlagsTooEarly.java test/langtools/tools/javadoc/InlineTagsWithBraces.java test/langtools/tools/javadoc/LangVers.java test/langtools/tools/javadoc/MaxWarns.java test/langtools/tools/javadoc/MethodLinks.java test/langtools/tools/javadoc/NoStar.java test/langtools/tools/javadoc/ReleaseOption.java test/langtools/tools/javadoc/ReleaseOptionSource.java test/langtools/tools/javadoc/T4994049/FileWithTabs.java test/langtools/tools/javadoc/T4994049/T4994049.java test/langtools/tools/javadoc/T6968833.java test/langtools/tools/javadoc/XWerror.java test/langtools/tools/javadoc/annotations/annotateMethodsFields/Main.java test/langtools/tools/javadoc/annotations/annotateMethodsFields/expected.out test/langtools/tools/javadoc/annotations/annotateMethodsFields/pkg1/A.java test/langtools/tools/javadoc/annotations/annotateMethodsFields/pkg1/B.java test/langtools/tools/javadoc/annotations/annotateMethodsFields/pkg1/E.java test/langtools/tools/javadoc/annotations/annotatePackage/Main.java test/langtools/tools/javadoc/annotations/annotatePackage/expected.out test/langtools/tools/javadoc/annotations/annotatePackage/pkg1/A.java test/langtools/tools/javadoc/annotations/annotatePackage/pkg1/package-info.java test/langtools/tools/javadoc/annotations/annotatePackage/pkg1/package.html test/langtools/tools/javadoc/annotations/annotatePackage/pkg2/B.java test/langtools/tools/javadoc/annotations/annotatePackage/pkg2/package.html test/langtools/tools/javadoc/annotations/annotateParams/Main.java test/langtools/tools/javadoc/annotations/annotateParams/expected.out test/langtools/tools/javadoc/annotations/annotateParams/pkg1/A.java test/langtools/tools/javadoc/annotations/annotateParams/pkg1/C.java test/langtools/tools/javadoc/annotations/badVals/Main.java test/langtools/tools/javadoc/annotations/badVals/pkg1/A.java test/langtools/tools/javadoc/annotations/defaults/Main.java test/langtools/tools/javadoc/annotations/defaults/expected.out test/langtools/tools/javadoc/annotations/defaults/pkg1/A.java test/langtools/tools/javadoc/annotations/defaults/pkg1/B.java test/langtools/tools/javadoc/annotations/elementTypes/Main.java test/langtools/tools/javadoc/annotations/elementTypes/expected.out test/langtools/tools/javadoc/annotations/elementTypes/pkg1/A.java test/langtools/tools/javadoc/annotations/elementTypes/pkg1/B.java test/langtools/tools/javadoc/annotations/missing/Main.java test/langtools/tools/javadoc/annotations/missing/somepackage/MissingAnnotationClass.java test/langtools/tools/javadoc/annotations/shortcuts/Main.java test/langtools/tools/javadoc/annotations/shortcuts/expected.out test/langtools/tools/javadoc/annotations/shortcuts/pkg1/A.java test/langtools/tools/javadoc/annotations/shortcuts/pkg1/Array.java test/langtools/tools/javadoc/annotations/shortcuts/pkg1/Marker.java test/langtools/tools/javadoc/annotations/shortcuts/pkg1/Value.java test/langtools/tools/javadoc/api/basic/APITest.java test/langtools/tools/javadoc/api/basic/DocletPathTest.java test/langtools/tools/javadoc/api/basic/DocumentationToolLocationTest.java test/langtools/tools/javadoc/api/basic/GetSourceVersionsTest.java test/langtools/tools/javadoc/api/basic/GetTask_DiagListenerTest.java test/langtools/tools/javadoc/api/basic/GetTask_DocletClassTest.java test/langtools/tools/javadoc/api/basic/GetTask_FileManagerTest.java test/langtools/tools/javadoc/api/basic/GetTask_FileObjectsTest.java test/langtools/tools/javadoc/api/basic/GetTask_OptionsTest.java test/langtools/tools/javadoc/api/basic/GetTask_WriterTest.java test/langtools/tools/javadoc/api/basic/Task_reuseTest.java test/langtools/tools/javadoc/api/basic/pkg/C.java test/langtools/tools/javadoc/api/basic/taglets/UnderlineTaglet.java test/langtools/tools/javadoc/completionFailure/CompletionFailure.java test/langtools/tools/javadoc/completionFailure/pkg/A.java test/langtools/tools/javadoc/completionFailure/pkg/B.java test/langtools/tools/javadoc/dupOk/DupOk.java test/langtools/tools/javadoc/dupOk/sp1/p/A.java test/langtools/tools/javadoc/dupOk/sp2/p/A.java test/langtools/tools/javadoc/dupOk/sp2/p/B.java test/langtools/tools/javadoc/enum/docComments/Main.java test/langtools/tools/javadoc/enum/docComments/pkg1/Operation.java test/langtools/tools/javadoc/enum/enumType/Main.java test/langtools/tools/javadoc/enum/enumType/expected.out test/langtools/tools/javadoc/enum/enumType/pkg1/QuotablePerson.java test/langtools/tools/javadoc/generics/genericClass/Main.java test/langtools/tools/javadoc/generics/genericClass/expected.out test/langtools/tools/javadoc/generics/genericClass/pkg1/A.java test/langtools/tools/javadoc/generics/genericInnerAndOuter/Main.java test/langtools/tools/javadoc/generics/genericInnerAndOuter/expected.out test/langtools/tools/javadoc/generics/genericInnerAndOuter/pkg1/O.java test/langtools/tools/javadoc/generics/genericInnerAndOuter/pkg1/X.java test/langtools/tools/javadoc/generics/genericInterface/Main.java test/langtools/tools/javadoc/generics/genericInterface/expected.out test/langtools/tools/javadoc/generics/genericInterface/pkg1/A.java test/langtools/tools/javadoc/generics/genericMethod/Main.java test/langtools/tools/javadoc/generics/genericMethod/expected.out test/langtools/tools/javadoc/generics/genericMethod/pkg1/A.java test/langtools/tools/javadoc/generics/genericSuper/Main.java test/langtools/tools/javadoc/generics/genericSuper/expected.out test/langtools/tools/javadoc/generics/genericSuper/pkg1/A.java test/langtools/tools/javadoc/generics/supertypes/Main.java test/langtools/tools/javadoc/generics/supertypes/expected.out test/langtools/tools/javadoc/generics/supertypes/pkg1/A.java test/langtools/tools/javadoc/generics/supertypes/pkg1/B.java test/langtools/tools/javadoc/generics/throwsGeneric/Main.java test/langtools/tools/javadoc/generics/throwsGeneric/expected.out test/langtools/tools/javadoc/generics/throwsGeneric/pkg1/A.java test/langtools/tools/javadoc/generics/tparamCycle/Main.java test/langtools/tools/javadoc/generics/tparamCycle/pkg1/LikeEnum.java test/langtools/tools/javadoc/generics/tparamTagOnMethod/Main.java test/langtools/tools/javadoc/generics/tparamTagOnMethod/expected.out test/langtools/tools/javadoc/generics/tparamTagOnMethod/pkg1/A.java test/langtools/tools/javadoc/generics/tparamTagOnType/Main.java test/langtools/tools/javadoc/generics/tparamTagOnType/expected.out test/langtools/tools/javadoc/generics/tparamTagOnType/pkg1/A.java test/langtools/tools/javadoc/generics/wildcards/Main.java test/langtools/tools/javadoc/generics/wildcards/expected.out test/langtools/tools/javadoc/generics/wildcards/pkg1/A.java test/langtools/tools/javadoc/imports/I.java test/langtools/tools/javadoc/imports/MissingImport.java test/langtools/tools/javadoc/lib/OldToolTester.java test/langtools/tools/javadoc/lib/ToyDoclet.java test/langtools/tools/javadoc/nestedClass/NestedClass.java test/langtools/tools/javadoc/nestedClass/NestedClassB.java test/langtools/tools/javadoc/nonConstExprs/Test.java test/langtools/tools/javadoc/outputRedirect/Test.java test/langtools/tools/javadoc/outputRedirect/p/OutputRedirect.java test/langtools/tools/javadoc/parser/7091528/T7091528.java test/langtools/tools/javadoc/parser/7091528/p/C1.java test/langtools/tools/javadoc/parser/7091528/p/C3.java test/langtools/tools/javadoc/parser/7091528/p/q/C2.java test/langtools/tools/javadoc/sourceOnly/Test.java test/langtools/tools/javadoc/sourceOnly/p/NonSource.jasm test/langtools/tools/javadoc/sourceOnly/p/SourceOnly.java test/langtools/tools/javadoc/sourceOption/SourceOption.java test/langtools/tools/javadoc/sourceOption/p/LambdaConstructTest.java test/langtools/tools/javadoc/subpackageIgnore/SubpackageIgnore.java test/langtools/tools/javadoc/subpackageIgnore/pkg1/not-subpkg/SomeJavaFile.java test/langtools/tools/javadoc/varArgs/Main.java test/langtools/tools/javadoc/varArgs/expected.out test/langtools/tools/javadoc/varArgs/pkg1/A.java |
diffstat | 538 files changed, 5770 insertions(+), 30560 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Fri Feb 22 14:51:06 2019 +0100 +++ b/.hgtags Thu Feb 28 22:05:33 2019 +0100 @@ -546,3 +546,4 @@ 4ce47bc1fb92cf94c6e3d1f49d582f02dcb851ab jdk-12+32 c081f3ea6b9300265a4a34e38f970b1e3ddaae9f jdk-13+9 b67884871b5fff79c5ef3eb8ac74dd48d71ea9b1 jdk-12+33 +8e069f7b4fabfe05d9f500783e6d56cb0196d25c jdk-13+10
--- a/make/data/cldr/common/main/my.xml Fri Feb 22 14:51:06 2019 +0100 +++ b/make/data/cldr/common/main/my.xml Thu Feb 28 22:05:33 2019 +0100 @@ -1446,17 +1446,14 @@ <pattern>z HH:mm:ss</pattern> </timeFormat> </timeFormatLength> - <!--Pattern for medium and short replaced with CLDR 29's patterns - as character 'B' is currently not supported in SimpleDateFormat and java.time.DateTimeFormatter - classes. This is a restriction until JDK-8209175 is resolved.--> <timeFormatLength type="medium"> <timeFormat> - <pattern>HH:mm:ss</pattern> + <pattern>B HH:mm:ss</pattern> </timeFormat> </timeFormatLength> <timeFormatLength type="short"> <timeFormat> - <pattern>H:mm</pattern> + <pattern>B H:mm</pattern> </timeFormat> </timeFormatLength> </timeFormats>
--- a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java Fri Feb 22 14:51:06 2019 +0100 +++ b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -523,36 +523,46 @@ for (String k : patternKeys) { if (myMap.containsKey(calendarPrefix + k)) { int len = patternKeys.length; - List<String> rawPatterns = new ArrayList<>(len); - List<String> patterns = new ArrayList<>(len); + List<String> dateTimePatterns = new ArrayList<>(len); + List<String> sdfPatterns = new ArrayList<>(len); for (int i = 0; i < len; i++) { String key = calendarPrefix + patternKeys[i]; String pattern = (String) myMap.remove(key); if (pattern == null) { pattern = (String) parentsMap.remove(key); } - rawPatterns.add(i, pattern); if (pattern != null) { - patterns.add(i, translateDateFormatLetters(calendarType, pattern)); + // Perform date-time format pattern conversion which is + // applicable to both SimpleDateFormat and j.t.f.DateTimeFormatter. + // For example, character 'B' is mapped with 'a', as 'B' is not + // supported in either SimpleDateFormat or j.t.f.DateTimeFormatter + String transPattern = translateDateFormatLetters(calendarType, pattern, this::convertDateTimePatternLetter); + dateTimePatterns.add(i, transPattern); + // Additionally, perform SDF specific date-time format pattern conversion + sdfPatterns.add(i, translateDateFormatLetters(calendarType, transPattern, this::convertSDFLetter)); } else { - patterns.add(i, null); + dateTimePatterns.add(i, null); + sdfPatterns.add(i, null); } } - // If patterns is empty or has any nulls, discard patterns. - if (patterns.isEmpty()) { + // If empty, discard patterns + if (sdfPatterns.isEmpty()) { return; } String key = calendarPrefix + name; - if (!rawPatterns.equals(patterns)) { - myMap.put("java.time." + key, rawPatterns.toArray(new String[len])); + + // If additional changes are made in the SDF specific conversion, + // keep the commonly converted patterns as java.time patterns + if (!dateTimePatterns.equals(sdfPatterns)) { + myMap.put("java.time." + key, dateTimePatterns.toArray(String[]::new)); } - myMap.put(key, patterns.toArray(new String[len])); + myMap.put(key, sdfPatterns.toArray(new String[len])); break; } } } - private String translateDateFormatLetters(CalendarType calendarType, String cldrFormat) { + private String translateDateFormatLetters(CalendarType calendarType, String cldrFormat, ConvertDateTimeLetters converter) { String pattern = cldrFormat; int length = pattern.length(); boolean inQuote = false; @@ -571,7 +581,7 @@ if (nextc == '\'') { i++; if (count != 0) { - convert(calendarType, lastLetter, count, jrePattern); + converter.convert(calendarType, lastLetter, count, jrePattern); lastLetter = 0; count = 0; } @@ -581,7 +591,7 @@ } if (!inQuote) { if (count != 0) { - convert(calendarType, lastLetter, count, jrePattern); + converter.convert(calendarType, lastLetter, count, jrePattern); lastLetter = 0; count = 0; } @@ -598,7 +608,7 @@ } if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) { if (count != 0) { - convert(calendarType, lastLetter, count, jrePattern); + converter.convert(calendarType, lastLetter, count, jrePattern); lastLetter = 0; count = 0; } @@ -611,7 +621,7 @@ count++; continue; } - convert(calendarType, lastLetter, count, jrePattern); + converter.convert(calendarType, lastLetter, count, jrePattern); lastLetter = c; count = 1; } @@ -621,7 +631,7 @@ } if (count != 0) { - convert(calendarType, lastLetter, count, jrePattern); + converter.convert(calendarType, lastLetter, count, jrePattern); } if (cldrFormat.contentEquals(jrePattern)) { return cldrFormat; @@ -676,71 +686,91 @@ } } - private void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) { + /** + * Perform a generic conversion of CLDR date-time format pattern letter based + * on the support given by the SimpleDateFormat and the j.t.f.DateTimeFormatter + * for date-time formatting. + */ + private void convertDateTimePatternLetter(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) { switch (cldrLetter) { - case 'G': - if (calendarType != CalendarType.GREGORIAN) { - // Adjust the number of 'G's for JRE SimpleDateFormat - if (count == 5) { - // CLDR narrow -> JRE short - count = 1; - } else if (count == 1) { - // CLDR abbr -> JRE long - count = 4; + case 'u': + // Change cldr letter 'u' to 'y', as 'u' is interpreted as + // "Extended year (numeric)" in CLDR/LDML, + // which is not supported in SimpleDateFormat and + // j.t.f.DateTimeFormatter, so it is replaced with 'y' + // as the best approximation + appendN('y', count, sb); + break; + case 'B': + // 'B' character (day period) is not supported by + // SimpleDateFormat and j.t.f.DateTimeFormatter, + // this is a workaround in which 'B' character + // appearing in CLDR date-time pattern is replaced + // with 'a' character and hence resolved with am/pm strings. + // This workaround is based on the the fallback mechanism + // specified in LDML spec for 'B' character, when a locale + // does not have data for day period ('B') + appendN('a', count, sb); + break; + default: + appendN(cldrLetter, count, sb); + break; + + } + } + + /** + * Perform a conversion of CLDR date-time format pattern letter which is + * specific to the SimpleDateFormat. + */ + private void convertSDFLetter(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) { + switch (cldrLetter) { + case 'G': + if (calendarType != CalendarType.GREGORIAN) { + // Adjust the number of 'G's for JRE SimpleDateFormat + if (count == 5) { + // CLDR narrow -> JRE short + count = 1; + } else if (count == 1) { + // CLDR abbr -> JRE long + count = 4; + } } - } - appendN(cldrLetter, count, sb); - break; + appendN(cldrLetter, count, sb); + break; - // TODO: support 'c' and 'e' in JRE SimpleDateFormat - // Use 'u' and 'E' for now. - case 'c': - case 'e': - switch (count) { - case 1: - sb.append('u'); + // TODO: support 'c' and 'e' in JRE SimpleDateFormat + // Use 'u' and 'E' for now. + case 'c': + case 'e': + switch (count) { + case 1: + sb.append('u'); + break; + case 3: + case 4: + appendN('E', count, sb); + break; + case 5: + appendN('E', 3, sb); + break; + } break; - case 3: - case 4: - appendN('E', count, sb); + + case 'v': + case 'V': + appendN('z', count, sb); break; - case 5: - appendN('E', 3, sb); + + case 'Z': + if (count == 4 || count == 5) { + sb.append("XXX"); + } break; - } - break; - case 'l': - // 'l' is deprecated as a pattern character. Should be ignored. - break; - - case 'u': - // Use 'y' for now. - appendN('y', count, sb); - break; - - case 'v': - case 'V': - appendN('z', count, sb); - break; - - case 'Z': - if (count == 4 || count == 5) { - sb.append("XXX"); - } - break; - - case 'U': - case 'q': - case 'Q': - case 'g': - case 'j': - case 'A': - throw new InternalError(String.format("Unsupported letter: '%c', count=%d, id=%s%n", - cldrLetter, count, id)); - default: - appendN(cldrLetter, count, sb); - break; + default: + appendN(cldrLetter, count, sb); + break; } } @@ -758,4 +788,9 @@ } return false; } + + @FunctionalInterface + private interface ConvertDateTimeLetters { + void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb); + } }
--- a/make/lib/Awt2dLibraries.gmk Fri Feb 22 14:51:06 2019 +0100 +++ b/make/lib/Awt2dLibraries.gmk Thu Feb 28 22:05:33 2019 +0100 @@ -613,7 +613,8 @@ type-limits missing-field-initializers implicit-fallthrough \ strict-aliasing undef unused-function, \ DISABLED_WARNINGS_CXX_gcc := reorder delete-non-virtual-dtor strict-overflow \ - maybe-uninitialized, \ + maybe-uninitialized \ + missing-attributes class-memaccess, \ DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \ tautological-constant-out-of-range-compare int-to-pointer-cast \ sign-compare undef missing-field-initializers, \
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -2209,13 +2209,15 @@ rf(Vn, 5), rf(Vd, 0); \ } - INSN(addv, 0, 0b100001); - INSN(subv, 1, 0b100001); - INSN(mulv, 0, 0b100111); - INSN(mlav, 0, 0b100101); - INSN(mlsv, 1, 0b100101); - INSN(sshl, 0, 0b010001); - INSN(ushl, 1, 0b010001); + INSN(addv, 0, 0b100001); + INSN(subv, 1, 0b100001); + INSN(mulv, 0, 0b100111); + INSN(mlav, 0, 0b100101); + INSN(mlsv, 1, 0b100101); + INSN(sshl, 0, 0b010001); + INSN(ushl, 1, 0b010001); + INSN(umullv, 1, 0b110000); + INSN(umlalv, 1, 0b100000); #undef INSN @@ -2227,13 +2229,14 @@ rf(Vn, 5), rf(Vd, 0); \ } - INSN(absr, 0, 0b100000101110); - INSN(negr, 1, 0b100000101110); - INSN(notr, 1, 0b100000010110); - INSN(addv, 0, 0b110001101110); - INSN(cls, 0, 0b100000010010); - INSN(clz, 1, 0b100000010010); - INSN(cnt, 0, 0b100000010110); + INSN(absr, 0, 0b100000101110); + INSN(negr, 1, 0b100000101110); + INSN(notr, 1, 0b100000010110); + INSN(addv, 0, 0b110001101110); + INSN(cls, 0, 0b100000010010); + INSN(clz, 1, 0b100000010010); + INSN(cnt, 0, 0b100000010110); + INSN(uaddlv, 1, 0b110000001110); #undef INSN
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -3257,11 +3257,14 @@ Register buff = c_rarg1; Register len = c_rarg2; Register nmax = r4; - Register base = r5; + Register base = r5; Register count = r6; Register temp0 = rscratch1; Register temp1 = rscratch2; - Register temp2 = r7; + FloatRegister vbytes = v0; + FloatRegister vs1acc = v1; + FloatRegister vs2acc = v2; + FloatRegister vtable = v3; // Max number of bytes we can process before having to take the mod // 0x15B0 is 5552 in decimal, the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 @@ -3271,6 +3274,10 @@ __ mov(base, BASE); __ mov(nmax, NMAX); + // Load accumulation coefficients for the upper 16 bits + __ lea(temp0, ExternalAddress((address) StubRoutines::aarch64::_adler_table)); + __ ld1(vtable, __ T16B, Address(temp0)); + // s1 is initialized to the lower 16 bits of adler // s2 is initialized to the upper 16 bits of adler __ ubfx(s2, adler, 16, 16); // s2 = ((adler >> 16) & 0xffff) @@ -3311,53 +3318,8 @@ __ bind(L_nmax_loop); - __ ldp(temp0, temp1, Address(__ post(buff, 16))); - - __ add(s1, s1, temp0, ext::uxtb); - __ ubfx(temp2, temp0, 8, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 16, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 24, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 32, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 40, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 48, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ add(s2, s2, s1); - __ add(s1, s1, temp0, Assembler::LSR, 56); - __ add(s2, s2, s1); - - __ add(s1, s1, temp1, ext::uxtb); - __ ubfx(temp2, temp1, 8, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 16, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 24, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 32, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 40, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 48, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ add(s2, s2, s1); - __ add(s1, s1, temp1, Assembler::LSR, 56); - __ add(s2, s2, s1); + generate_updateBytesAdler32_accum(s1, s2, buff, temp0, temp1, + vbytes, vs1acc, vs2acc, vtable); __ subs(count, count, 16); __ br(Assembler::HS, L_nmax_loop); @@ -3400,53 +3362,8 @@ __ bind(L_by16_loop); - __ ldp(temp0, temp1, Address(__ post(buff, 16))); - - __ add(s1, s1, temp0, ext::uxtb); - __ ubfx(temp2, temp0, 8, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 16, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 24, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 32, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 40, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp0, 48, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ add(s2, s2, s1); - __ add(s1, s1, temp0, Assembler::LSR, 56); - __ add(s2, s2, s1); - - __ add(s1, s1, temp1, ext::uxtb); - __ ubfx(temp2, temp1, 8, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 16, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 24, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 32, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 40, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ ubfx(temp2, temp1, 48, 8); - __ add(s2, s2, s1); - __ add(s1, s1, temp2); - __ add(s2, s2, s1); - __ add(s1, s1, temp1, Assembler::LSR, 56); - __ add(s2, s2, s1); + generate_updateBytesAdler32_accum(s1, s2, buff, temp0, temp1, + vbytes, vs1acc, vs2acc, vtable); __ subs(len, len, 16); __ br(Assembler::HS, L_by16_loop); @@ -3500,6 +3417,43 @@ return start; } + void generate_updateBytesAdler32_accum(Register s1, Register s2, Register buff, + Register temp0, Register temp1, FloatRegister vbytes, + FloatRegister vs1acc, FloatRegister vs2acc, FloatRegister vtable) { + // Below is a vectorized implementation of updating s1 and s2 for 16 bytes. + // We use b1, b2, ..., b16 to denote the 16 bytes loaded in each iteration. + // In non-vectorized code, we update s1 and s2 as: + // s1 <- s1 + b1 + // s2 <- s2 + s1 + // s1 <- s1 + b2 + // s2 <- s2 + b1 + // ... + // s1 <- s1 + b16 + // s2 <- s2 + s1 + // Putting above assignments together, we have: + // s1_new = s1 + b1 + b2 + ... + b16 + // s2_new = s2 + (s1 + b1) + (s1 + b1 + b2) + ... + (s1 + b1 + b2 + ... + b16) + // = s2 + s1 * 16 + (b1 * 16 + b2 * 15 + ... + b16 * 1) + // = s2 + s1 * 16 + (b1, b2, ... b16) dot (16, 15, ... 1) + __ ld1(vbytes, __ T16B, Address(__ post(buff, 16))); + + // s2 = s2 + s1 * 16 + __ add(s2, s2, s1, Assembler::LSL, 4); + + // vs1acc = b1 + b2 + b3 + ... + b16 + // vs2acc = (b1 * 16) + (b2 * 15) + (b3 * 14) + ... + (b16 * 1) + __ umullv(vs2acc, __ T8B, vtable, vbytes); + __ umlalv(vs2acc, __ T16B, vtable, vbytes); + __ uaddlv(vs1acc, __ T16B, vbytes); + __ uaddlv(vs2acc, __ T8H, vs2acc); + + // s1 = s1 + vs1acc, s2 = s2 + vs2acc + __ fmovd(temp0, vs1acc); + __ fmovd(temp1, vs2acc); + __ add(s1, s1, temp0); + __ add(s2, s2, temp1); + } + /** * Arguments: *
--- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -287,6 +287,11 @@ 0xD502ED78UL, 0xAE7D62EDUL, // byte swap of word swap }; +// Accumulation coefficients for adler32 upper 16 bits +jubyte StubRoutines::aarch64::_adler_table[] __attribute__ ((aligned(64))) = { + 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 +}; + juint StubRoutines::aarch64::_npio2_hw[] __attribute__ ((aligned(64))) = { // first, various coefficient values: 0.5, invpio2, pio2_1, pio2_1t, pio2_2, // pio2_2t, pio2_3, pio2_3t
--- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -186,6 +186,7 @@ private: static juint _crc_table[]; + static jubyte _adler_table[]; // begin trigonometric tables block. See comments in .cpp file static juint _npio2_hw[]; static jdouble _two_over_pi[];
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -2981,7 +2981,7 @@ { Label notVolatile; __ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile); - __ membar(MacroAssembler::StoreStore); + __ membar(MacroAssembler::StoreStore | MacroAssembler::LoadStore); __ bind(notVolatile); }
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -258,8 +258,10 @@ if (FLAG_IS_DEFAULT(UseCRC32)) { UseCRC32 = (auxv & HWCAP_CRC32) != 0; } + if (UseCRC32 && (auxv & HWCAP_CRC32) == 0) { warning("UseCRC32 specified, but not supported on this CPU"); + FLAG_SET_DEFAULT(UseCRC32, false); } if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { @@ -277,6 +279,7 @@ } else { if (UseLSE) { warning("UseLSE specified, but not supported on this CPU"); + FLAG_SET_DEFAULT(UseLSE, false); } } @@ -291,9 +294,11 @@ } else { if (UseAES) { warning("UseAES specified, but not supported on this CPU"); + FLAG_SET_DEFAULT(UseAES, false); } if (UseAESIntrinsics) { warning("UseAESIntrinsics specified, but not supported on this CPU"); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); } }
--- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -33,7 +33,7 @@ enum platform_dependent_constants { code_size1 = 20000 LP64_ONLY(+10000), // simply increase if too small (assembler will crash if too small) - code_size2 = 35300 LP64_ONLY(+10000) // simply increase if too small (assembler will crash if too small) + code_size2 = 35300 LP64_ONLY(+11000) // simply increase if too small (assembler will crash if too small) }; class x86 {
--- a/src/hotspot/os/aix/os_aix.inline.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/aix/os_aix.inline.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -27,6 +27,7 @@ #define OS_AIX_OS_AIX_INLINE_HPP #include "runtime/os.hpp" +#include "os_posix.inline.hpp" // System includes
--- a/src/hotspot/os/bsd/os_bsd.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/bsd/os_bsd.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -37,6 +37,7 @@ #include "memory/filemap.hpp" #include "oops/oop.inline.hpp" #include "os_bsd.inline.hpp" +#include "os_posix.inline.hpp" #include "os_share_bsd.hpp" #include "prims/jniFastGetField.hpp" #include "prims/jvm_misc.hpp"
--- a/src/hotspot/os/bsd/os_bsd.inline.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/bsd/os_bsd.inline.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -26,6 +26,7 @@ #define OS_BSD_OS_BSD_INLINE_HPP #include "runtime/os.hpp" +#include "os_posix.inline.hpp" // System includes
--- a/src/hotspot/os/linux/os_linux.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/linux/os_linux.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -38,6 +38,7 @@ #include "memory/filemap.hpp" #include "oops/oop.inline.hpp" #include "os_linux.inline.hpp" +#include "os_posix.inline.hpp" #include "os_share_linux.hpp" #include "osContainer_linux.hpp" #include "prims/jniFastGetField.hpp" @@ -1358,11 +1359,9 @@ void os::abort(bool dump_core, void* siginfo, const void* context) { os::shutdown(); if (dump_core) { -#ifndef ZERO if (DumpPrivateMappingsInCore) { ClassLoader::close_jrt_image(); } -#endif #ifndef PRODUCT fdStream out(defaultStream::output_fd()); out.print_raw("Current thread is ");
--- a/src/hotspot/os/linux/os_perf_linux.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/linux/os_perf_linux.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1062,7 +1062,7 @@ snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter); - int fd = open(buf, O_RDONLY); + int fd = os::open(buf, O_RDONLY, 0); if (fd == -1) { return -1; }
--- a/src/hotspot/os/linux/perfMemory_linux.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/linux/perfMemory_linux.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -97,8 +97,8 @@ int result; - RESTARTABLE(::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE), - result);; + RESTARTABLE(os::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR), + result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not create Perfdata save file: %s: %s\n", @@ -871,7 +871,7 @@ // Cannot use O_TRUNC here; truncation of an existing file has to happen // after the is_file_secure() check below. int result; - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); + RESTARTABLE(os::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { if (errno == ELOOP) { @@ -949,7 +949,7 @@ // open the file int result; - RESTARTABLE(::open(filename, oflags), result); + RESTARTABLE(os::open(filename, oflags, 0), result); if (result == OS_ERR) { if (errno == ENOENT) { THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
--- a/src/hotspot/os/posix/os_posix.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/posix/os_posix.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -191,10 +191,6 @@ os::native_path(fullname); - sigset_t set, oldset; - int ret = sigfillset(&set); - assert_with_errno(ret == 0, "sigfillset returned error"); - // set the file creation mask. mode_t file_mode = S_IRUSR | S_IWUSR; @@ -208,7 +204,7 @@ } // delete the name from the filesystem. When 'fd' is closed, the file (and space) will be deleted. - ret = unlink(fullname); + int ret = unlink(fullname); assert_with_errno(ret == 0, "unlink returned error"); os::free(fullname); @@ -2219,22 +2215,6 @@ assert_status(status == 0, status, "mutex_destroy"); } -void os::PlatformMonitor::lock() { - int status = pthread_mutex_lock(&_mutex); - assert_status(status == 0, status, "mutex_lock"); -} - -void os::PlatformMonitor::unlock() { - int status = pthread_mutex_unlock(&_mutex); - assert_status(status == 0, status, "mutex_unlock"); -} - -bool os::PlatformMonitor::try_lock() { - int status = pthread_mutex_trylock(&_mutex); - assert_status(status == 0 || status == EBUSY, status, "mutex_trylock"); - return status == 0; -} - // Must already be locked int os::PlatformMonitor::wait(jlong millis) { assert(millis >= 0, "negative timeout"); @@ -2263,14 +2243,4 @@ } } -void os::PlatformMonitor::notify() { - int status = pthread_cond_signal(&_cond); - assert_status(status == 0, status, "cond_signal"); -} - -void os::PlatformMonitor::notify_all() { - int status = pthread_cond_broadcast(&_cond); - assert_status(status == 0, status, "cond_broadcast"); -} - #endif // !SOLARIS
--- a/src/hotspot/os/posix/os_posix.inline.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/posix/os_posix.inline.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -42,6 +42,39 @@ inline int os::Posix::clock_getres(clockid_t clock_id, struct timespec *tp) { return _clock_getres != NULL ? _clock_getres(clock_id, tp) : -1; } + #endif // SUPPORTS_CLOCK_MONOTONIC +#ifndef SOLARIS + +// Platform Monitor implementation + +inline void os::PlatformMonitor::lock() { + int status = pthread_mutex_lock(&_mutex); + assert_status(status == 0, status, "mutex_lock"); +} + +inline void os::PlatformMonitor::unlock() { + int status = pthread_mutex_unlock(&_mutex); + assert_status(status == 0, status, "mutex_unlock"); +} + +inline bool os::PlatformMonitor::try_lock() { + int status = pthread_mutex_trylock(&_mutex); + assert_status(status == 0 || status == EBUSY, status, "mutex_trylock"); + return status == 0; +} + +inline void os::PlatformMonitor::notify() { + int status = pthread_cond_signal(&_cond); + assert_status(status == 0, status, "cond_signal"); +} + +inline void os::PlatformMonitor::notify_all() { + int status = pthread_cond_broadcast(&_cond); + assert_status(status == 0, status, "cond_broadcast"); +} + +#endif // !SOLARIS + #endif // OS_POSIX_OS_POSIX_INLINE_HPP
--- a/src/hotspot/os/solaris/os_perf_solaris.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/solaris/os_perf_solaris.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -74,7 +74,7 @@ int fd = -1; - if ((fd = open(path, O_RDONLY)) < 0) { + if ((fd = os::open(path, O_RDONLY, 0)) < 0) { return OS_ERR; } if (pread(fd, info, s, o) != s) {
--- a/src/hotspot/os/windows/os_windows.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/windows/os_windows.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -602,7 +602,7 @@ HANDLE interrupt_event = CreateEvent(NULL, true, false, NULL); if (interrupt_event == NULL) { delete osthread; - return NULL; + return false; } osthread->set_interrupt_event(interrupt_event); osthread->set_interrupted(false); @@ -676,7 +676,7 @@ CloseHandle(osthread->interrupt_event()); thread->set_osthread(NULL); delete osthread; - return NULL; + return false; } Atomic::inc(&os::win32::_os_thread_count); @@ -5320,27 +5320,6 @@ // Platform Monitor implementation -os::PlatformMonitor::PlatformMonitor() { - InitializeConditionVariable(&_cond); - InitializeCriticalSection(&_mutex); -} - -os::PlatformMonitor::~PlatformMonitor() { - DeleteCriticalSection(&_mutex); -} - -void os::PlatformMonitor::lock() { - EnterCriticalSection(&_mutex); -} - -void os::PlatformMonitor::unlock() { - LeaveCriticalSection(&_mutex); -} - -bool os::PlatformMonitor::try_lock() { - return TryEnterCriticalSection(&_mutex); -} - // Must already be locked int os::PlatformMonitor::wait(jlong millis) { assert(millis >= 0, "negative timeout"); @@ -5359,14 +5338,6 @@ return ret; } -void os::PlatformMonitor::notify() { - WakeConditionVariable(&_cond); -} - -void os::PlatformMonitor::notify_all() { - WakeAllConditionVariable(&_cond); -} - // Run the specified command in a separate process. Return its exit value, // or -1 on failure (e.g. can't create a new process). int os::fork_and_exec(char* cmd, bool use_vfork_if_available) {
--- a/src/hotspot/os/windows/os_windows.inline.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os/windows/os_windows.inline.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -86,4 +86,35 @@ win32::exit_process_or_thread(win32::EPT_PROCESS, num); } +// Platform Monitor implementation + +inline os::PlatformMonitor::PlatformMonitor() { + InitializeConditionVariable(&_cond); + InitializeCriticalSection(&_mutex); +} + +inline os::PlatformMonitor::~PlatformMonitor() { + DeleteCriticalSection(&_mutex); +} + +inline void os::PlatformMonitor::lock() { + EnterCriticalSection(&_mutex); +} + +inline void os::PlatformMonitor::unlock() { + LeaveCriticalSection(&_mutex); +} + +inline bool os::PlatformMonitor::try_lock() { + return TryEnterCriticalSection(&_mutex); +} + +inline void os::PlatformMonitor::notify() { + WakeConditionVariable(&_cond); +} + +inline void os::PlatformMonitor::notify_all() { + WakeAllConditionVariable(&_cond); +} + #endif // OS_WINDOWS_OS_WINDOWS_INLINE_HPP
--- a/src/hotspot/os_cpu/linux_x86/gc/z/zBackingFile_linux_x86.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/os_cpu/linux_x86/gc/z/zBackingFile_linux_x86.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -191,7 +191,7 @@ // Try to create an anonymous file using the O_TMPFILE flag. Note that this // flag requires kernel >= 3.11. If this fails we fall back to open/unlink. - const int fd_anon = open(path.get(), O_TMPFILE|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR); + const int fd_anon = os::open(path.get(), O_TMPFILE|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR); if (fd_anon == -1) { ZErrno err; log_debug(gc, init)("Failed to create anonymous file in %s (%s)", path.get(), @@ -217,7 +217,7 @@ snprintf(filename, sizeof(filename), "%s/%s.%d", path.get(), name, os::current_process_id()); // Create file - const int fd = open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR); + const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR); if (fd == -1) { ZErrno err; log_error(gc, init)("Failed to create file %s (%s)", filename, err.to_string());
--- a/src/hotspot/share/ci/ciEnv.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/ci/ciEnv.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1253,7 +1253,7 @@ static char buffer[O_BUFLEN]; int ret = jio_snprintf(buffer, O_BUFLEN, "replay_pid%p_compid%d.log", os::current_process_id(), compile_id); if (ret > 0) { - int fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666); + int fd = os::open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666); if (fd != -1) { FILE* replay_data_file = os::open(fd, "w"); if (replay_data_file != NULL) { @@ -1271,7 +1271,7 @@ static char buffer[O_BUFLEN]; int ret = jio_snprintf(buffer, O_BUFLEN, "inline_pid%p_compid%d.log", os::current_process_id(), compile_id); if (ret > 0) { - int fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666); + int fd = os::open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666); if (fd != -1) { FILE* inline_data_file = os::open(fd, "w"); if (inline_data_file != NULL) {
--- a/src/hotspot/share/classfile/classFileParser.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/classFileParser.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -60,6 +60,7 @@ #include "runtime/arguments.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" +#include "runtime/os.hpp" #include "runtime/perfData.hpp" #include "runtime/reflection.hpp" #include "runtime/safepointVerifiers.hpp" @@ -5747,8 +5748,8 @@ int class_name_len = _class_name->utf8_length(); int symbol_len = host_pkg_len + 1 + class_name_len; char* new_anon_name = NEW_RESOURCE_ARRAY(char, symbol_len + 1); - int n = snprintf(new_anon_name, symbol_len + 1, "%s/%.*s", - host_pkg_name, class_name_len, _class_name->base()); + int n = os::snprintf(new_anon_name, symbol_len + 1, "%s/%.*s", + host_pkg_name, class_name_len, _class_name->base()); assert(n == symbol_len, "Unexpected number of characters in string"); // Decrement old _class_name to avoid leaking.
--- a/src/hotspot/share/classfile/classLoader.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/classLoader.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -620,13 +620,14 @@ update_module_path_entry_list(path, THREAD); } +#endif // INCLUDE_CDS + void ClassLoader::close_jrt_image() { - assert(ClassLoader::has_jrt_entry(), "Not applicable for exploded builds"); + // Not applicable for exploded builds + if (!ClassLoader::has_jrt_entry()) return; _jrt_entry->close_jimage(); } -#endif // INCLUDE_CDS - // Construct the array of module/path pairs as specified to --patch-module // for the boot loader to search ahead of the jimage, if the class being // loaded is defined to a module that has been specified to --patch-module.
--- a/src/hotspot/share/classfile/classLoader.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/classLoader.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -247,12 +247,12 @@ static void load_zip_library(); static void load_jimage_library(); + + public: static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st, bool throw_exception, bool is_boot_append, TRAPS); - public: - // If the package for the fully qualified class name is in the boot // loader's package entry table then add_package() sets the classpath_index // field so that get_system_package() will know to return a non-null value
--- a/src/hotspot/share/classfile/classLoaderExt.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/classLoaderExt.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -208,7 +208,7 @@ ResourceMark rm(THREAD); size_t libname_len = dir_len + name_len; char* libname = NEW_RESOURCE_ARRAY(char, libname_len + 1); - int n = snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start); + int n = os::snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start); assert((size_t)n == libname_len, "Unexpected number of characters in string"); trace_class_path("library = ", libname); ClassLoader::update_class_path_entry_list(libname, true, false);
--- a/src/hotspot/share/classfile/compactHashtable.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/compactHashtable.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -198,7 +198,7 @@ quit("Unable to get hashtable dump file size", filename); } _size = st.st_size; - _fd = open(filename, O_RDONLY | O_BINARY, 0); + _fd = os::open(filename, O_RDONLY | O_BINARY, 0); if (_fd < 0) { quit("Unable to open hashtable dump file", filename); }
--- a/src/hotspot/share/classfile/javaClasses.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/javaClasses.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -3635,7 +3635,7 @@ // distinct loaders) to ensure the metadata is kept alive. // This mirror may be different than the one in clazz field. new_resolved_method->obj_field_put(_vmholder_offset, m->method_holder()->java_mirror()); - resolved_method = ResolvedMethodTable::add_method(Handle(THREAD, new_resolved_method)); + resolved_method = ResolvedMethodTable::add_method(m, Handle(THREAD, new_resolved_method)); } return resolved_method; }
--- a/src/hotspot/share/classfile/klassFactory.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/klassFactory.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* -* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2015, 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 @@ -46,22 +46,22 @@ InstanceKlass* ik, Symbol* class_name, Handle class_loader, - Handle protection_domain, TRAPS) { + Handle protection_domain, + const ClassFileStream *cfs, + TRAPS) { #if INCLUDE_CDS && INCLUDE_JVMTI assert(ik != NULL, "sanity"); assert(ik->is_shared(), "expecting a shared class"); - if (JvmtiExport::should_post_class_file_load_hook()) { assert(THREAD->is_Java_thread(), "must be JavaThread"); // Post the CFLH JvmtiCachedClassFileData* cached_class_file = NULL; - JvmtiCachedClassFileData* archived_class_data = ik->get_archived_class_data(); - assert(archived_class_data != NULL, "shared class has no archived class data"); - unsigned char* ptr = - VM_RedefineClasses::get_cached_class_file_bytes(archived_class_data); - unsigned char* end_ptr = - ptr + VM_RedefineClasses::get_cached_class_file_len(archived_class_data); + if (cfs == NULL) { + cfs = FileMapInfo::open_stream_for_jvmti(ik, CHECK_NULL); + } + unsigned char* ptr = (unsigned char*)cfs->buffer(); + unsigned char* end_ptr = ptr + cfs->length(); unsigned char* old_ptr = ptr; JvmtiExport::post_class_file_load_hook(class_name, class_loader, @@ -75,25 +75,9 @@ ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); int path_index = ik->shared_classpath_index(); - const char* pathname; - if (path_index < 0) { - // shared classes loaded by user defined class loader - // do not have shared_classpath_index - ModuleEntry* mod_entry = ik->module(); - if (mod_entry != NULL && (mod_entry->location() != NULL)) { - ResourceMark rm; - pathname = (const char*)(mod_entry->location()->as_C_string()); - } else { - pathname = ""; - } - } else { - SharedClassPathEntry* ent = - (SharedClassPathEntry*)FileMapInfo::shared_path(path_index); - pathname = ent == NULL ? NULL : ent->name(); - } ClassFileStream* stream = new ClassFileStream(ptr, end_ptr - ptr, - pathname, + cfs->source(), ClassFileStream::verify); ClassFileParser parser(stream, class_name, @@ -236,24 +220,6 @@ #if INCLUDE_CDS if (DumpSharedSpaces) { ClassLoader::record_result(result, stream, THREAD); -#if INCLUDE_JVMTI - assert(cached_class_file == NULL, "Sanity"); - // Archive the class stream data into the optional data section - JvmtiCachedClassFileData *p; - int len; - const unsigned char *bytes; - // event based tracing might set cached_class_file - if ((bytes = result->get_cached_class_file_bytes()) != NULL) { - len = result->get_cached_class_file_len(); - } else { - len = stream->length(); - bytes = stream->buffer(); - } - p = (JvmtiCachedClassFileData*)os::malloc(offset_of(JvmtiCachedClassFileData, data) + len, mtInternal); - p->length = len; - memcpy(p->data, bytes, len); - result->set_archived_class_data(p); -#endif // INCLUDE_JVMTI } #endif // INCLUDE_CDS
--- a/src/hotspot/share/classfile/klassFactory.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/klassFactory.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -80,7 +80,9 @@ InstanceKlass* ik, Symbol* class_name, Handle class_loader, - Handle protection_domain, TRAPS); + Handle protection_domain, + const ClassFileStream *cfs, + TRAPS); }; #endif // SHARE_CLASSFILE_KLASSFACTORY_HPP
--- a/src/hotspot/share/classfile/symbolTable.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/symbolTable.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -436,18 +436,16 @@ } } -void SymbolTable::add(ClassLoaderData* loader_data, const constantPoolHandle& cp, - int names_count, const char** names, int* lengths, - int* cp_indices, unsigned int* hashValues, TRAPS) { +void SymbolTable::new_symbols(ClassLoaderData* loader_data, const constantPoolHandle& cp, + int names_count, const char** names, int* lengths, + int* cp_indices, unsigned int* hashValues, TRAPS) { bool c_heap = !loader_data->is_the_null_class_loader_data(); for (int i = 0; i < names_count; i++) { const char *name = names[i]; int len = lengths[i]; unsigned int hash = hashValues[i]; - Symbol* sym = SymbolTable::the_table()->lookup_common(name, len, hash); - if (sym == NULL) { - sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, c_heap, CHECK); - } + assert(SymbolTable::the_table()->lookup_shared(name, len, hash) == NULL, "must have checked already"); + Symbol* sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, c_heap, CHECK); assert(sym->refcount() != 0, "lookup should have incremented the count"); cp->symbol_at_put(cp_indices[i], sym); }
--- a/src/hotspot/share/classfile/symbolTable.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/symbolTable.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -144,18 +144,11 @@ Symbol* do_add_if_needed(const char* name, int len, uintx hash, bool heap, TRAPS); // Adding elements - static void add(ClassLoaderData* loader_data, - const constantPoolHandle& cp, int names_count, - const char** names, int* lengths, int* cp_indices, - unsigned int* hashValues, TRAPS); - static void new_symbols(ClassLoaderData* loader_data, const constantPoolHandle& cp, int names_count, const char** name, int* lengths, int* cp_indices, unsigned int* hashValues, - TRAPS) { - add(loader_data, cp, names_count, name, lengths, cp_indices, hashValues, THREAD); - } + TRAPS); static Symbol* lookup_shared(const char* name, int len, unsigned int hash); Symbol* lookup_dynamic(const char* name, int len, unsigned int hash);
--- a/src/hotspot/share/classfile/systemDictionary.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/systemDictionary.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1174,7 +1174,7 @@ TRAPS) { InstanceKlass* ik = SystemDictionaryShared::find_builtin_class(class_name); if (ik != NULL && ik->is_shared_boot_class()) { - return load_shared_class(ik, Handle(), Handle(), THREAD); + return load_shared_class(ik, Handle(), Handle(), NULL, THREAD); } return NULL; } @@ -1274,7 +1274,9 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik, Handle class_loader, - Handle protection_domain, TRAPS) { + Handle protection_domain, + const ClassFileStream *cfs, + TRAPS) { if (ik != NULL) { Symbol* class_name = ik->name(); @@ -1321,7 +1323,7 @@ } InstanceKlass* new_ik = KlassFactory::check_shared_class_file_load_hook( - ik, class_name, class_loader, protection_domain, CHECK_NULL); + ik, class_name, class_loader, protection_domain, cfs, CHECK_NULL); if (new_ik != NULL) { // The class is changed by CFLH. Return the new class. The shared class is // not used.
--- a/src/hotspot/share/classfile/systemDictionary.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/systemDictionary.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -628,6 +628,7 @@ static InstanceKlass* load_shared_class(InstanceKlass* ik, Handle class_loader, Handle protection_domain, + const ClassFileStream *cfs, TRAPS); static InstanceKlass* load_shared_boot_class(Symbol* class_name, TRAPS);
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -803,7 +803,7 @@ SystemDictionary::is_platform_class_loader(class_loader()))) { Handle protection_domain = SystemDictionaryShared::init_security_info(class_loader, ik, CHECK_NULL); - return load_shared_class(ik, class_loader, protection_domain, THREAD); + return load_shared_class(ik, class_loader, protection_domain, NULL, THREAD); } } return NULL; @@ -873,13 +873,15 @@ } return acquire_class_for_current_thread(record->_klass, class_loader, - protection_domain, THREAD); + protection_domain, cfs, + THREAD); } InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread( InstanceKlass *ik, Handle class_loader, Handle protection_domain, + const ClassFileStream *cfs, TRAPS) { ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); @@ -900,7 +902,8 @@ loader_data->add_class(ik); // Load and check super/interfaces, restore unsharable info - InstanceKlass* shared_klass = load_shared_class(ik, class_loader, protection_domain, THREAD); + InstanceKlass* shared_klass = load_shared_class(ik, class_loader, protection_domain, + cfs, THREAD); if (shared_klass == NULL || HAS_PENDING_EXCEPTION) { // TODO: clean up <ik> so it can be used again return NULL;
--- a/src/hotspot/share/classfile/systemDictionaryShared.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -207,6 +207,7 @@ InstanceKlass *ik, Handle class_loader, Handle protection_domain, + const ClassFileStream* cfs, TRAPS); static DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k); static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin);
--- a/src/hotspot/share/classfile/verifier.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/classfile/verifier.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -2982,14 +2982,14 @@ // add one dimension to component length++; arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length + 1); - int n = snprintf(arr_sig_str, length + 1, "[%s", component_name); + int n = os::snprintf(arr_sig_str, length + 1, "[%s", component_name); assert(n == length, "Unexpected number of characters in string"); } else { // it's an object or interface const char* component_name = component_type.name()->as_utf8(); // add one dimension to component with 'L' prepended and ';' postpended. length = (int)strlen(component_name) + 3; arr_sig_str = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, length + 1); - int n = snprintf(arr_sig_str, length + 1, "[L%s;", component_name); + int n = os::snprintf(arr_sig_str, length + 1, "[L%s;", component_name); assert(n == length, "Unexpected number of characters in string"); } Symbol* arr_sig = create_temporary_symbol(
--- a/src/hotspot/share/code/nmethod.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/code/nmethod.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1370,6 +1370,8 @@ assert(_speculation_log == NULL, "should have been nulled out when transitioned to zombie"); #endif + Universe::heap()->flush_nmethod(this); + CodeBlob::flush(); CodeCache::free(this); }
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -48,7 +48,6 @@ #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/intHisto.hpp" #include "utilities/stack.inline.hpp" #include "utilities/ticks.hpp"
--- a/src/hotspot/share/gc/shared/collectedHeap.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -521,6 +521,7 @@ // Override with specific mechanism for each specialized heap type. virtual void register_nmethod(nmethod* nm) {} virtual void unregister_nmethod(nmethod* nm) {} + virtual void flush_nmethod(nmethod* nm) {} virtual void verify_nmethod(nmethod* nmethod) {} void trace_heap_before_gc(const GCTracer* gc_tracer);
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -482,7 +482,9 @@ class ShenandoahInitGCLABClosure : public ThreadClosure { public: void do_thread(Thread* thread) { - if (thread != NULL && (thread->is_Java_thread() || thread->is_Worker_thread())) { + assert(thread != NULL, "Sanity"); + assert(!thread->is_Java_thread(), "Don't expect JavaThread this early"); + if (thread->is_Worker_thread()) { ShenandoahThreadLocalData::initialize_gclab(thread); } } @@ -494,8 +496,6 @@ ShenandoahInitGCLABClosure init_gclabs; Threads::threads_do(&init_gclabs); - _workers->threads_do(&init_gclabs); - _safepoint_workers->threads_do(&init_gclabs); // gclab can not be initialized early during VM startup, as it can not determinate its max_size. // Now, we will let WorkGang to initialize gclab when new worker is created.
--- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as @@ -122,6 +122,7 @@ static void initialize_gclab(Thread* thread) { assert (thread->is_Java_thread() || thread->is_Worker_thread(), "Only Java and GC worker threads are allowed to get GCLABs"); + assert(data(thread)->_gclab == NULL, "Only initialize once"); data(thread)->_gclab = new PLAB(PLAB::min_size()); data(thread)->_gclab_size = 0; }
--- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -27,12 +27,12 @@ #include "gc/z/zGlobals.hpp" #include "gc/z/zLock.inline.hpp" #include "gc/z/zOopClosures.hpp" -#include "gc/z/zNMethodTable.hpp" +#include "gc/z/zNMethod.hpp" #include "gc/z/zThreadLocalData.hpp" #include "logging/log.hpp" bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { - ZLocker<ZReentrantLock> locker(ZNMethodTable::lock_for_nmethod(nm)); + ZLocker<ZReentrantLock> locker(ZNMethod::lock_for_nmethod(nm)); log_trace(nmethod, barrier)("Entered critical zone for %p", nm); if (!is_armed(nm)) {
--- a/src/hotspot/share/gc/z/zCollectedHeap.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -27,7 +27,7 @@ #include "gc/z/zCollectedHeap.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zHeap.inline.hpp" -#include "gc/z/zNMethodTable.hpp" +#include "gc/z/zNMethod.hpp" #include "gc/z/zServiceability.hpp" #include "gc/z/zStat.hpp" #include "gc/z/zUtils.inline.hpp" @@ -255,11 +255,15 @@ } void ZCollectedHeap::register_nmethod(nmethod* nm) { - ZNMethodTable::register_nmethod(nm); + ZNMethod::register_nmethod(nm); } void ZCollectedHeap::unregister_nmethod(nmethod* nm) { - ZNMethodTable::unregister_nmethod(nm); + ZNMethod::unregister_nmethod(nm); +} + +void ZCollectedHeap::flush_nmethod(nmethod* nm) { + ZNMethod::flush_nmethod(nm); } void ZCollectedHeap::verify_nmethod(nmethod* nm) {
--- a/src/hotspot/share/gc/z/zCollectedHeap.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -105,6 +105,7 @@ virtual void register_nmethod(nmethod* nm); virtual void unregister_nmethod(nmethod* nm); + virtual void flush_nmethod(nmethod* nm); virtual void verify_nmethod(nmethod* nmethod); virtual WorkGang* get_safepoint_workers();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zNMethod.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -0,0 +1,386 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "code/relocInfo.hpp" +#include "code/nmethod.hpp" +#include "code/icBuffer.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetNMethod.hpp" +#include "gc/z/zGlobals.hpp" +#include "gc/z/zLock.inline.hpp" +#include "gc/z/zNMethod.hpp" +#include "gc/z/zNMethodData.hpp" +#include "gc/z/zNMethodTable.hpp" +#include "gc/z/zOopClosures.inline.hpp" +#include "gc/z/zTask.hpp" +#include "gc/z/zWorkers.hpp" +#include "logging/log.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/iterator.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" +#include "utilities/debug.hpp" + +static ZNMethodData* gc_data(const nmethod* nm) { + return nm->gc_data<ZNMethodData>(); +} + +static void set_gc_data(nmethod* nm, ZNMethodData* data) { + return nm->set_gc_data<ZNMethodData>(data); +} + +void ZNMethod::attach_gc_data(nmethod* nm) { + GrowableArray<oop*> immediate_oops; + bool non_immediate_oops = false; + + // Find all oops relocations + RelocIterator iter(nm); + while (iter.next()) { + if (iter.type() != relocInfo::oop_type) { + // Not an oop + continue; + } + + oop_Relocation* r = iter.oop_reloc(); + + if (!r->oop_is_immediate()) { + // Non-immediate oop found + non_immediate_oops = true; + continue; + } + + if (r->oop_value() != NULL) { + // Non-NULL immediate oop found. NULL oops can safely be + // ignored since the method will be re-registered if they + // are later patched to be non-NULL. + immediate_oops.push(r->oop_addr()); + } + } + + // Attach GC data to nmethod + ZNMethodData* data = gc_data(nm); + if (data == NULL) { + data = new ZNMethodData(); + set_gc_data(nm, data); + } + + // Attach oops in GC data + ZNMethodDataOops* const new_oops = ZNMethodDataOops::create(immediate_oops, non_immediate_oops); + ZNMethodDataOops* const old_oops = data->swap_oops(new_oops); + ZNMethodDataOops::destroy(old_oops); +} + +ZReentrantLock* ZNMethod::lock_for_nmethod(nmethod* nm) { + return gc_data(nm)->lock(); +} + +void ZNMethod::log_register(const nmethod* nm) { + LogTarget(Trace, gc, nmethod) log; + if (!log.is_enabled()) { + return; + } + + const ZNMethodDataOops* const oops = gc_data(nm)->oops(); + + log.print("Register NMethod: %s.%s (" PTR_FORMAT "), " + "Compiler: %s, Oops: %d, ImmediateOops: " SIZE_FORMAT ", NonImmediateOops: %s", + nm->method()->method_holder()->external_name(), + nm->method()->name()->as_C_string(), + p2i(nm), + nm->compiler_name(), + nm->oops_count() - 1, + oops->immediates_count(), + oops->has_non_immediates() ? "Yes" : "No"); + + LogTarget(Trace, gc, nmethod, oops) log_oops; + if (!log_oops.is_enabled()) { + return; + } + + // Print nmethod oops table + { + oop* const begin = nm->oops_begin(); + oop* const end = nm->oops_end(); + for (oop* p = begin; p < end; p++) { + log_oops.print(" Oop[" SIZE_FORMAT "] " PTR_FORMAT " (%s)", + (p - begin), p2i(*p), (*p)->klass()->external_name()); + } + } + + // Print nmethod immediate oops + { + oop** const begin = oops->immediates_begin(); + oop** const end = oops->immediates_end(); + for (oop** p = begin; p < end; p++) { + log_oops.print(" ImmediateOop[" SIZE_FORMAT "] " PTR_FORMAT " @ " PTR_FORMAT " (%s)", + (p - begin), p2i(**p), p2i(*p), (**p)->klass()->external_name()); + } + } +} + +void ZNMethod::log_unregister(const nmethod* nm) { + LogTarget(Debug, gc, nmethod) log; + if (!log.is_enabled()) { + return; + } + + log.print("Unregister NMethod: %s.%s (" PTR_FORMAT ")", + nm->method()->method_holder()->external_name(), + nm->method()->name()->as_C_string(), + p2i(nm)); +} + +void ZNMethod::register_nmethod(nmethod* nm) { + ResourceMark rm; + + // Create and attach gc data + attach_gc_data(nm); + + log_register(nm); + + ZNMethodTable::register_nmethod(nm); + + // Disarm nmethod entry barrier + disarm_nmethod(nm); +} + +void ZNMethod::unregister_nmethod(nmethod* nm) { + assert(CodeCache_lock->owned_by_self(), "Lock must be held"); + + if (Thread::current()->is_Code_cache_sweeper_thread()) { + // The sweeper must wait for any ongoing iteration to complete + // before it can unregister an nmethod. + ZNMethodTable::wait_until_iteration_done(); + } + + ResourceMark rm; + + log_unregister(nm); + + ZNMethodTable::unregister_nmethod(nm); +} + +void ZNMethod::flush_nmethod(nmethod* nm) { + // Destroy GC data + delete gc_data(nm); +} + +void ZNMethod::disarm_nmethod(nmethod* nm) { + BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod(); + if (bs != NULL) { + bs->disarm(nm); + } +} + +void ZNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) { + // Process oops table + { + oop* const begin = nm->oops_begin(); + oop* const end = nm->oops_end(); + for (oop* p = begin; p < end; p++) { + if (*p != Universe::non_oop_word()) { + cl->do_oop(p); + } + } + } + + ZNMethodDataOops* const oops = gc_data(nm)->oops(); + + // Process immediate oops + { + oop** const begin = oops->immediates_begin(); + oop** const end = oops->immediates_end(); + for (oop** p = begin; p < end; p++) { + if (**p != Universe::non_oop_word()) { + cl->do_oop(*p); + } + } + } + + // Process non-immediate oops + if (oops->has_non_immediates()) { + nm->fix_oop_relocations(); + } +} + +class ZNMethodToOopsDoClosure : public NMethodClosure { +private: + OopClosure* _cl; + +public: + ZNMethodToOopsDoClosure(OopClosure* cl) : + _cl(cl) {} + + virtual void do_nmethod(nmethod* nm) { + ZNMethod::nmethod_oops_do(nm, _cl); + } +}; + +void ZNMethod::oops_do_begin() { + ZNMethodTable::nmethods_do_begin(); +} + +void ZNMethod::oops_do_end() { + ZNMethodTable::nmethods_do_end(); +} + +void ZNMethod::oops_do(OopClosure* cl) { + ZNMethodToOopsDoClosure nmethod_cl(cl); + ZNMethodTable::nmethods_do(&nmethod_cl); +} + +class ZNMethodUnlinkClosure : public NMethodClosure { +private: + bool _unloading_occurred; + volatile bool _failed; + + void set_failed() { + Atomic::store(true, &_failed); + } + +public: + ZNMethodUnlinkClosure(bool unloading_occurred) : + _unloading_occurred(unloading_occurred), + _failed(false) {} + + virtual void do_nmethod(nmethod* nm) { + if (failed()) { + return; + } + + if (!nm->is_alive()) { + return; + } + + ZLocker<ZReentrantLock> locker(ZNMethod::lock_for_nmethod(nm)); + + if (nm->is_unloading()) { + // Unlinking of the dependencies must happen before the + // handshake separating unlink and purge. + nm->flush_dependencies(false /* delete_immediately */); + + // We don't need to take the lock when unlinking nmethods from + // the Method, because it is only concurrently unlinked by + // the entry barrier, which acquires the per nmethod lock. + nm->unlink_from_method(false /* acquire_lock */); + return; + } + + // Heal oops and disarm + ZNMethodOopClosure cl; + ZNMethod::nmethod_oops_do(nm, &cl); + ZNMethod::disarm_nmethod(nm); + + // Clear compiled ICs and exception caches + if (!nm->unload_nmethod_caches(_unloading_occurred)) { + set_failed(); + } + } + + bool failed() const { + return Atomic::load(&_failed); + } +}; + +class ZNMethodUnlinkTask : public ZTask { +private: + ZNMethodUnlinkClosure _cl; + ICRefillVerifier* _verifier; + +public: + ZNMethodUnlinkTask(bool unloading_occurred, ICRefillVerifier* verifier) : + ZTask("ZNMethodUnlinkTask"), + _cl(unloading_occurred), + _verifier(verifier) { + ZNMethodTable::nmethods_do_begin(); + } + + ~ZNMethodUnlinkTask() { + ZNMethodTable::nmethods_do_end(); + } + + virtual void work() { + ICRefillVerifierMark mark(_verifier); + ZNMethodTable::nmethods_do(&_cl); + } + + bool success() const { + return !_cl.failed(); + } +}; + +void ZNMethod::unlink(ZWorkers* workers, bool unloading_occurred) { + for (;;) { + ICRefillVerifier verifier; + + { + ZNMethodUnlinkTask task(unloading_occurred, &verifier); + workers->run_concurrent(&task); + if (task.success()) { + return; + } + } + + // Cleaning failed because we ran out of transitional IC stubs, + // so we have to refill and try again. Refilling requires taking + // a safepoint, so we temporarily leave the suspendible thread set. + SuspendibleThreadSetLeaver sts; + InlineCacheBuffer::refill_ic_stubs(); + } +} + +class ZNMethodPurgeClosure : public NMethodClosure { +public: + virtual void do_nmethod(nmethod* nm) { + if (nm->is_alive() && nm->is_unloading()) { + nm->make_unloaded(); + } + } +}; + +class ZNMethodPurgeTask : public ZTask { +private: + ZNMethodPurgeClosure _cl; + +public: + ZNMethodPurgeTask() : + ZTask("ZNMethodPurgeTask"), + _cl() { + ZNMethodTable::nmethods_do_begin(); + } + + ~ZNMethodPurgeTask() { + ZNMethodTable::nmethods_do_end(); + } + + virtual void work() { + ZNMethodTable::nmethods_do(&_cl); + } +}; + +void ZNMethod::purge(ZWorkers* workers) { + ZNMethodPurgeTask task; + workers->run_concurrent(&task); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zNMethod.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZNMETHOD_HPP +#define SHARE_GC_Z_ZNMETHOD_HPP + +#include "memory/allocation.hpp" + +class nmethod; +class OopClosure; +class ZReentrantLock; +class ZWorkers; + +class ZNMethod : public AllStatic { +private: + static void attach_gc_data(nmethod* nm); + + static void log_register(const nmethod* nm); + static void log_unregister(const nmethod* nm); + +public: + static void register_nmethod(nmethod* nm); + static void unregister_nmethod(nmethod* nm); + static void flush_nmethod(nmethod* nm); + + static void disarm_nmethod(nmethod* nm); + + static void nmethod_oops_do(nmethod* nm, OopClosure* cl); + + static void oops_do_begin(); + static void oops_do_end(); + static void oops_do(OopClosure* cl); + + static ZReentrantLock* lock_for_nmethod(nmethod* nm); + + static void unlink(ZWorkers* workers, bool unloading_occurred); + static void purge(ZWorkers* workers); +}; + +#endif // SHARE_GC_Z_ZNMETHOD_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zNMethodAllocator.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -0,0 +1,69 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zArray.inline.hpp" +#include "gc/z/zNMethodAllocator.hpp" +#include "memory/allocation.hpp" + +ZArray<void*> ZNMethodAllocator::_deferred_frees; +bool ZNMethodAllocator::_defer_frees(false); + +void ZNMethodAllocator::immediate_free(void* data) { + FREE_C_HEAP_ARRAY(uint8_t, data); +} + +void ZNMethodAllocator::deferred_free(void* data) { + _deferred_frees.add(data); +} + +void* ZNMethodAllocator::allocate(size_t size) { + return NEW_C_HEAP_ARRAY(uint8_t, size, mtGC); +} + +void ZNMethodAllocator::free(void* data) { + if (data == NULL) { + return; + } + + if (_defer_frees) { + deferred_free(data); + } else { + immediate_free(data); + } +} + +void ZNMethodAllocator::activate_deferred_frees() { + assert(_deferred_frees.is_empty(), "precondition"); + _defer_frees = true; +} + +void ZNMethodAllocator::deactivate_and_process_deferred_frees() { + _defer_frees = false; + + ZArrayIterator<void*> iter(&_deferred_frees); + for (void* data; iter.next(&data);) { + immediate_free(data); + } + _deferred_frees.clear(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zNMethodAllocator.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -0,0 +1,46 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZNMETHODALLOCATOR_HPP +#define SHARE_GC_Z_ZNMETHODALLOCATOR_HPP + +#include "memory/allocation.hpp" +#include "gc/z/zArray.hpp" + +class ZNMethodAllocator : public AllStatic { +private: + static ZArray<void*> _deferred_frees; + static bool _defer_frees; + + static void immediate_free(void* data); + static void deferred_free(void* data); + +public: + static void* allocate(size_t size); + static void free(void* data); + + static void activate_deferred_frees(); + static void deactivate_and_process_deferred_frees(); +}; + +#endif // SHARE_GC_Z_ZNMETHODALLOCATOR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zNMethodData.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zLock.inline.hpp" +#include "gc/z/zNMethodData.hpp" +#include "memory/allocation.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" +#include "utilities/growableArray.hpp" + +size_t ZNMethodDataOops::header_size() { + const size_t size = sizeof(ZNMethodDataOops); + assert(is_aligned(size, sizeof(oop*)), "Header misaligned"); + return size; +} + +ZNMethodDataOops* ZNMethodDataOops::create(const GrowableArray<oop*>& immediates, bool has_non_immediates) { + // Allocate memory for the ZNMethodDataOops object + // plus the immediate oop* array that follows right after. + const size_t size = ZNMethodDataOops::header_size() + (sizeof(oop*) * immediates.length()); + void* const mem = NEW_C_HEAP_ARRAY(uint8_t, size, mtGC); + return ::new (mem) ZNMethodDataOops(immediates, has_non_immediates); +} + +void ZNMethodDataOops::destroy(ZNMethodDataOops* oops) { + FREE_C_HEAP_ARRAY(uint8_t, oops); +} + +ZNMethodDataOops::ZNMethodDataOops(const GrowableArray<oop*>& immediates, bool has_non_immediates) : + _nimmediates(immediates.length()), + _has_non_immediates(has_non_immediates) { + // Save all immediate oops + for (size_t i = 0; i < _nimmediates; i++) { + immediates_begin()[i] = immediates.at(i); + } +} + +size_t ZNMethodDataOops::immediates_count() const { + return _nimmediates; +} + +oop** ZNMethodDataOops::immediates_begin() const { + // The immediate oop* array starts immediately after this object + return (oop**)((uintptr_t)this + header_size()); +} + +oop** ZNMethodDataOops::immediates_end() const { + return immediates_begin() + immediates_count(); +} + +bool ZNMethodDataOops::has_non_immediates() const { + return _has_non_immediates; +} + +ZNMethodData::ZNMethodData() : + _lock(), + _oops(NULL) {} + +ZNMethodData::~ZNMethodData() { + ZNMethodDataOops::destroy(_oops); +} + +ZReentrantLock* ZNMethodData::lock() { + return &_lock; +} + +ZNMethodDataOops* ZNMethodData::oops() const { + return OrderAccess::load_acquire(&_oops); +} + +ZNMethodDataOops* ZNMethodData::swap_oops(ZNMethodDataOops* new_oops) { + ZLocker<ZReentrantLock> locker(&_lock); + ZNMethodDataOops* const old_oops = _oops; + _oops = new_oops; + return old_oops; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zNMethodData.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "gc/z/zLock.hpp" +#include "memory/allocation.hpp" +#include "oops/oopsHierarchy.hpp" +#include "utilities/globalDefinitions.hpp" + +#ifndef SHARE_GC_Z_ZNMETHODDATA_HPP +#define SHARE_GC_Z_ZNMETHODDATA_HPP + +class nmethod; +template <typename T> class GrowableArray; + +class ZNMethodDataOops { +private: + const size_t _nimmediates; + bool _has_non_immediates; + + static size_t header_size(); + + ZNMethodDataOops(const GrowableArray<oop*>& immediates, bool has_non_immediates); + +public: + static ZNMethodDataOops* create(const GrowableArray<oop*>& immediates, bool has_non_immediates); + static void destroy(ZNMethodDataOops* oops); + + size_t immediates_count() const; + oop** immediates_begin() const; + oop** immediates_end() const; + + bool has_non_immediates() const; +}; + +class ZNMethodData : public CHeapObj<mtGC> { +private: + ZReentrantLock _lock; + ZNMethodDataOops* volatile _oops; + +public: + ZNMethodData(); + ~ZNMethodData(); + + ZReentrantLock* lock(); + + ZNMethodDataOops* oops() const; + ZNMethodDataOops* swap_oops(ZNMethodDataOops* oops); +}; + +#endif // SHARE_GC_Z_ZNMETHODDATA_HPP
--- a/src/hotspot/share/gc/z/zNMethodTable.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/z/zNMethodTable.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -27,205 +27,38 @@ #include "code/icBuffer.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetNMethod.hpp" -#include "gc/z/zArray.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zHash.inline.hpp" #include "gc/z/zLock.inline.hpp" +#include "gc/z/zNMethodAllocator.hpp" +#include "gc/z/zNMethodData.hpp" #include "gc/z/zNMethodTable.hpp" +#include "gc/z/zNMethodTableEntry.hpp" +#include "gc/z/zNMethodTableIteration.hpp" #include "gc/z/zOopClosures.inline.hpp" #include "gc/z/zTask.hpp" #include "gc/z/zWorkers.hpp" #include "logging/log.hpp" -#include "memory/allocation.inline.hpp" +#include "memory/allocation.hpp" +#include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "runtime/atomic.hpp" #include "runtime/orderAccess.hpp" -#include "runtime/os.hpp" #include "utilities/debug.hpp" -class ZNMethodDataImmediateOops { -private: - const size_t _nimmediate_oops; - - static size_t header_size(); - - ZNMethodDataImmediateOops(const GrowableArray<oop*>& immediate_oops); - -public: - static ZNMethodDataImmediateOops* create(const GrowableArray<oop*>& immediate_oops); - static void destroy(ZNMethodDataImmediateOops* data_immediate_oops); - - size_t immediate_oops_count() const; - oop** immediate_oops_begin() const; - oop** immediate_oops_end() const; -}; - -size_t ZNMethodDataImmediateOops::header_size() { - const size_t size = sizeof(ZNMethodDataImmediateOops); - assert(is_aligned(size, sizeof(oop*)), "Header misaligned"); - return size; -} - -ZNMethodDataImmediateOops* ZNMethodDataImmediateOops::create(const GrowableArray<oop*>& immediate_oops) { - // Allocate memory for the ZNMethodDataImmediateOops object - // plus the immediate oop* array that follows right after. - const size_t size = ZNMethodDataImmediateOops::header_size() + (sizeof(oop*) * immediate_oops.length()); - void* const data_immediate_oops = NEW_C_HEAP_ARRAY(uint8_t, size, mtGC); - return ::new (data_immediate_oops) ZNMethodDataImmediateOops(immediate_oops); -} - -void ZNMethodDataImmediateOops::destroy(ZNMethodDataImmediateOops* data_immediate_oops) { - ZNMethodTable::safe_delete(data_immediate_oops); -} - -ZNMethodDataImmediateOops::ZNMethodDataImmediateOops(const GrowableArray<oop*>& immediate_oops) : - _nimmediate_oops(immediate_oops.length()) { - // Save all immediate oops - for (size_t i = 0; i < _nimmediate_oops; i++) { - immediate_oops_begin()[i] = immediate_oops.at(i); - } -} - -size_t ZNMethodDataImmediateOops::immediate_oops_count() const { - return _nimmediate_oops; -} - -oop** ZNMethodDataImmediateOops::immediate_oops_begin() const { - // The immediate oop* array starts immediately after this object - return (oop**)((uintptr_t)this + header_size()); -} - -oop** ZNMethodDataImmediateOops::immediate_oops_end() const { - return immediate_oops_begin() + immediate_oops_count(); -} - -class ZNMethodData { -private: - ZReentrantLock _lock; - ZNMethodDataImmediateOops* volatile _immediate_oops; - - ZNMethodData(nmethod* nm); - -public: - static ZNMethodData* create(nmethod* nm); - static void destroy(ZNMethodData* data); - - ZReentrantLock* lock(); - - ZNMethodDataImmediateOops* immediate_oops() const; - ZNMethodDataImmediateOops* swap_immediate_oops(const GrowableArray<oop*>& immediate_oops); -}; - -ZNMethodData* ZNMethodData::create(nmethod* nm) { - void* const method = NEW_C_HEAP_ARRAY(uint8_t, sizeof(ZNMethodData), mtGC); - return ::new (method) ZNMethodData(nm); -} - -void ZNMethodData::destroy(ZNMethodData* data) { - ZNMethodDataImmediateOops::destroy(data->immediate_oops()); - ZNMethodTable::safe_delete(data); -} - -ZNMethodData::ZNMethodData(nmethod* nm) : - _lock(), - _immediate_oops(NULL) {} - -ZReentrantLock* ZNMethodData::lock() { - return &_lock; -} - -ZNMethodDataImmediateOops* ZNMethodData::immediate_oops() const { - return OrderAccess::load_acquire(&_immediate_oops); -} - -ZNMethodDataImmediateOops* ZNMethodData::swap_immediate_oops(const GrowableArray<oop*>& immediate_oops) { - ZNMethodDataImmediateOops* const data_immediate_oops = - immediate_oops.is_empty() ? NULL : ZNMethodDataImmediateOops::create(immediate_oops); - return Atomic::xchg(data_immediate_oops, &_immediate_oops); -} - -static ZNMethodData* gc_data(const nmethod* nm) { - return nm->gc_data<ZNMethodData>(); -} - -static void set_gc_data(nmethod* nm, ZNMethodData* data) { - return nm->set_gc_data<ZNMethodData>(data); -} - ZNMethodTableEntry* ZNMethodTable::_table = NULL; size_t ZNMethodTable::_size = 0; -ZLock ZNMethodTable::_iter_lock; -ZNMethodTableEntry* ZNMethodTable::_iter_table = NULL; -size_t ZNMethodTable::_iter_table_size = 0; -ZArray<void*> ZNMethodTable::_iter_deferred_deletes; size_t ZNMethodTable::_nregistered = 0; size_t ZNMethodTable::_nunregistered = 0; -volatile size_t ZNMethodTable::_claimed = 0; +ZNMethodTableIteration ZNMethodTable::_iteration; -void ZNMethodTable::safe_delete(void* data) { - if (data == NULL) { - return; - } - - ZLocker<ZLock> locker(&_iter_lock); - if (_iter_table != NULL) { - // Iteration in progress, defer delete - _iter_deferred_deletes.add(data); - } else { - // Iteration not in progress, delete now - FREE_C_HEAP_ARRAY(uint8_t, data); - } +ZNMethodTableEntry* ZNMethodTable::create(size_t size) { + void* const mem = ZNMethodAllocator::allocate(size * sizeof(ZNMethodTableEntry)); + return ::new (mem) ZNMethodTableEntry[size]; } -ZNMethodTableEntry ZNMethodTable::create_entry(nmethod* nm) { - GrowableArray<oop*> immediate_oops; - bool non_immediate_oops = false; - - // Find all oops relocations - RelocIterator iter(nm); - while (iter.next()) { - if (iter.type() != relocInfo::oop_type) { - // Not an oop - continue; - } - - oop_Relocation* r = iter.oop_reloc(); - - if (!r->oop_is_immediate()) { - // Non-immediate oop found - non_immediate_oops = true; - continue; - } - - if (r->oop_value() != NULL) { - // Non-NULL immediate oop found. NULL oops can safely be - // ignored since the method will be re-registered if they - // are later patched to be non-NULL. - immediate_oops.push(r->oop_addr()); - } - } - - // Attach GC data to nmethod - ZNMethodData* data = gc_data(nm); - if (data == NULL) { - data = ZNMethodData::create(nm); - set_gc_data(nm, data); - } - - // Attach immediate oops in GC data - ZNMethodDataImmediateOops* const old_data_immediate_oops = data->swap_immediate_oops(immediate_oops); - ZNMethodDataImmediateOops::destroy(old_data_immediate_oops); - - // Create entry - return ZNMethodTableEntry(nm, non_immediate_oops, !immediate_oops.is_empty()); -} - -ZReentrantLock* ZNMethodTable::lock_for_nmethod(nmethod* nm) { - ZNMethodData* const data = gc_data(nm); - if (data == NULL) { - return NULL; - } - return data->lock(); +void ZNMethodTable::destroy(ZNMethodTableEntry* table) { + ZNMethodAllocator::free(table); } size_t ZNMethodTable::first_index(const nmethod* nm, size_t size) { @@ -241,8 +74,8 @@ return (prev_index + 1) & mask; } -bool ZNMethodTable::register_entry(ZNMethodTableEntry* table, size_t size, ZNMethodTableEntry entry) { - const nmethod* const nm = entry.method(); +bool ZNMethodTable::register_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm) { + const ZNMethodTableEntry entry(nm); size_t index = first_index(nm, size); for (;;) { @@ -265,11 +98,6 @@ } void ZNMethodTable::unregister_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm) { - if (size == 0) { - // Table is empty - return; - } - size_t index = first_index(nm, size); for (;;) { @@ -279,10 +107,6 @@ if (table_entry.registered() && table_entry.method() == nm) { // Remove entry table[index] = ZNMethodTableEntry(true /* unregistered */); - - // Destroy GC data - ZNMethodData::destroy(gc_data(nm)); - set_gc_data(nm, NULL); return; } @@ -291,7 +115,8 @@ } void ZNMethodTable::rebuild(size_t new_size) { - ZLocker<ZLock> locker(&_iter_lock); + assert(CodeCache_lock->owned_by_self(), "Lock must be held"); + assert(is_power_of_2(new_size), "Invalid size"); log_debug(gc, nmethod)("Rebuilding NMethod Table: " @@ -303,20 +128,18 @@ _nunregistered, percent_of(_nunregistered, _size), 0.0); // Allocate new table - ZNMethodTableEntry* const new_table = new ZNMethodTableEntry[new_size]; + ZNMethodTableEntry* const new_table = ZNMethodTable::create(new_size); // Transfer all registered entries for (size_t i = 0; i < _size; i++) { const ZNMethodTableEntry entry = _table[i]; if (entry.registered()) { - register_entry(new_table, new_size, entry); + register_entry(new_table, new_size, entry.method()); } } - if (_iter_table != _table) { - // Delete old table - delete [] _table; - } + // Free old table + ZNMethodTable::destroy(_table); // Install new table _table = new_table; @@ -353,61 +176,6 @@ } } -void ZNMethodTable::log_register(const nmethod* nm, ZNMethodTableEntry entry) { - LogTarget(Trace, gc, nmethod) log; - if (!log.is_enabled()) { - return; - } - - log.print("Register NMethod: %s.%s (" PTR_FORMAT "), " - "Compiler: %s, Oops: %d, ImmediateOops: " SIZE_FORMAT ", NonImmediateOops: %s", - nm->method()->method_holder()->external_name(), - nm->method()->name()->as_C_string(), - p2i(nm), - nm->compiler_name(), - nm->oops_count() - 1, - entry.immediate_oops() ? gc_data(nm)->immediate_oops()->immediate_oops_count() : 0, - entry.non_immediate_oops() ? "Yes" : "No"); - - LogTarget(Trace, gc, nmethod, oops) log_oops; - if (!log_oops.is_enabled()) { - return; - } - - // Print nmethod oops table - oop* const begin = nm->oops_begin(); - oop* const end = nm->oops_end(); - for (oop* p = begin; p < end; p++) { - log_oops.print(" Oop[" SIZE_FORMAT "] " PTR_FORMAT " (%s)", - (p - begin), p2i(*p), (*p)->klass()->external_name()); - } - - if (entry.immediate_oops()) { - // Print nmethod immediate oops - const ZNMethodDataImmediateOops* const nmi = gc_data(nm)->immediate_oops(); - if (nmi != NULL) { - oop** const begin = nmi->immediate_oops_begin(); - oop** const end = nmi->immediate_oops_end(); - for (oop** p = begin; p < end; p++) { - log_oops.print(" ImmediateOop[" SIZE_FORMAT "] " PTR_FORMAT " @ " PTR_FORMAT " (%s)", - (p - begin), p2i(**p), p2i(*p), (**p)->klass()->external_name()); - } - } - } -} - -void ZNMethodTable::log_unregister(const nmethod* nm) { - LogTarget(Debug, gc, nmethod) log; - if (!log.is_enabled()) { - return; - } - - log.print("Unregister NMethod: %s.%s (" PTR_FORMAT ")", - nm->method()->method_holder()->external_name(), - nm->method()->name()->as_C_string(), - p2i(nm)); -} - size_t ZNMethodTable::registered_nmethods() { return _nregistered; } @@ -418,48 +186,29 @@ void ZNMethodTable::register_nmethod(nmethod* nm) { assert(CodeCache_lock->owned_by_self(), "Lock must be held"); - ResourceMark rm; // Grow/Shrink/Prune table if needed rebuild_if_needed(); - // Create entry - const ZNMethodTableEntry entry = create_entry(nm); - - log_register(nm, entry); - // Insert new entry - if (register_entry(_table, _size, entry)) { + if (register_entry(_table, _size, nm)) { // New entry registered. When register_entry() instead returns // false the nmethod was already in the table so we do not want // to increase number of registered entries in that case. _nregistered++; } - - // Disarm nmethod entry barrier - disarm_nmethod(nm); } -void ZNMethodTable::sweeper_wait_for_iteration() { - // The sweeper must wait for any ongoing iteration to complete - // before it can unregister an nmethod. - if (!Thread::current()->is_Code_cache_sweeper_thread()) { - return; - } +void ZNMethodTable::wait_until_iteration_done() { + assert(CodeCache_lock->owned_by_self(), "Lock must be held"); - while (_iter_table != NULL) { - MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - os::naked_short_sleep(1); + while (_iteration.in_progress()) { + CodeCache_lock->wait(Monitor::_no_safepoint_check_flag); } } void ZNMethodTable::unregister_nmethod(nmethod* nm) { assert(CodeCache_lock->owned_by_self(), "Lock must be held"); - ResourceMark rm; - - sweeper_wait_for_iteration(); - - log_unregister(nm); // Remove entry unregister_entry(_table, _size, nm); @@ -467,248 +216,29 @@ _nregistered--; } -void ZNMethodTable::disarm_nmethod(nmethod* nm) { - BarrierSetNMethod* const bs = BarrierSet::barrier_set()->barrier_set_nmethod(); - if (bs != NULL) { - bs->disarm(nm); - } +void ZNMethodTable::nmethods_do_begin() { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + // Make sure we don't free data while iterating + ZNMethodAllocator::activate_deferred_frees(); + + // Prepare iteration + _iteration.nmethods_do_begin(_table, _size); } -void ZNMethodTable::nmethod_entries_do_begin() { +void ZNMethodTable::nmethods_do_end() { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - ZLocker<ZLock> locker(&_iter_lock); - // Prepare iteration - _iter_table = _table; - _iter_table_size = _size; - _claimed = 0; - assert(_iter_deferred_deletes.is_empty(), "Should be emtpy"); + // Finish iteration + _iteration.nmethods_do_end(); + + // Process deferred frees + ZNMethodAllocator::deactivate_and_process_deferred_frees(); + + // Notify iteration done + CodeCache_lock->notify_all(); } -void ZNMethodTable::nmethod_entries_do_end() { - MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - ZLocker<ZLock> locker(&_iter_lock); - - // Finish iteration - if (_iter_table != _table) { - delete [] _iter_table; - } - _iter_table = NULL; - assert(_claimed >= _iter_table_size, "Failed to claim all table entries"); - - // Process deferred deletes - ZArrayIterator<void*> iter(&_iter_deferred_deletes); - for (void* data; iter.next(&data);) { - FREE_C_HEAP_ARRAY(uint8_t, data); - } - _iter_deferred_deletes.clear(); +void ZNMethodTable::nmethods_do(NMethodClosure* cl) { + _iteration.nmethods_do(cl); } - -void ZNMethodTable::entry_oops_do(ZNMethodTableEntry entry, OopClosure* cl) { - nmethod* const nm = entry.method(); - - // Process oops table - oop* const begin = nm->oops_begin(); - oop* const end = nm->oops_end(); - for (oop* p = begin; p < end; p++) { - if (*p != Universe::non_oop_word()) { - cl->do_oop(p); - } - } - - // Process immediate oops - if (entry.immediate_oops()) { - const ZNMethodDataImmediateOops* const nmi = gc_data(nm)->immediate_oops(); - if (nmi != NULL) { - oop** const begin = nmi->immediate_oops_begin(); - oop** const end = nmi->immediate_oops_end(); - for (oop** p = begin; p < end; p++) { - if (**p != Universe::non_oop_word()) { - cl->do_oop(*p); - } - } - } - } - - // Process non-immediate oops - if (entry.non_immediate_oops()) { - nmethod* const nm = entry.method(); - nm->fix_oop_relocations(); - } -} - -class ZNMethodTableEntryToOopsDo : public ZNMethodTableEntryClosure { -private: - OopClosure* _cl; - -public: - ZNMethodTableEntryToOopsDo(OopClosure* cl) : - _cl(cl) {} - - void do_nmethod_entry(ZNMethodTableEntry entry) { - ZNMethodTable::entry_oops_do(entry, _cl); - } -}; - -void ZNMethodTable::oops_do(OopClosure* cl) { - ZNMethodTableEntryToOopsDo entry_cl(cl); - nmethod_entries_do(&entry_cl); -} - -void ZNMethodTable::nmethod_entries_do(ZNMethodTableEntryClosure* cl) { - for (;;) { - // Claim table partition. Each partition is currently sized to span - // two cache lines. This number is just a guess, but seems to work well. - const size_t partition_size = (ZCacheLineSize * 2) / sizeof(ZNMethodTableEntry); - const size_t partition_start = MIN2(Atomic::add(partition_size, &_claimed) - partition_size, _iter_table_size); - const size_t partition_end = MIN2(partition_start + partition_size, _iter_table_size); - if (partition_start == partition_end) { - // End of table - break; - } - - // Process table partition - for (size_t i = partition_start; i < partition_end; i++) { - const ZNMethodTableEntry entry = _iter_table[i]; - if (entry.registered()) { - cl->do_nmethod_entry(entry); - } - } - } -} - -class ZNMethodTableUnlinkClosure : public ZNMethodTableEntryClosure { -private: - bool _unloading_occurred; - volatile bool _failed; - - void set_failed() { - Atomic::store(true, &_failed); - } - -public: - ZNMethodTableUnlinkClosure(bool unloading_occurred) : - _unloading_occurred(unloading_occurred), - _failed(false) {} - - virtual void do_nmethod_entry(ZNMethodTableEntry entry) { - if (failed()) { - return; - } - - nmethod* const nm = entry.method(); - if (!nm->is_alive()) { - return; - } - - ZLocker<ZReentrantLock> locker(ZNMethodTable::lock_for_nmethod(nm)); - - if (nm->is_unloading()) { - // Unlinking of the dependencies must happen before the - // handshake separating unlink and purge. - nm->flush_dependencies(false /* delete_immediately */); - - // We don't need to take the lock when unlinking nmethods from - // the Method, because it is only concurrently unlinked by - // the entry barrier, which acquires the per nmethod lock. - nm->unlink_from_method(false /* acquire_lock */); - return; - } - - // Heal oops and disarm - ZNMethodOopClosure cl; - ZNMethodTable::entry_oops_do(entry, &cl); - ZNMethodTable::disarm_nmethod(nm); - - // Clear compiled ICs and exception caches - if (!nm->unload_nmethod_caches(_unloading_occurred)) { - set_failed(); - } - } - - bool failed() const { - return Atomic::load(&_failed); - } -}; - -class ZNMethodTableUnlinkTask : public ZTask { -private: - ZNMethodTableUnlinkClosure _cl; - ICRefillVerifier* _verifier; - -public: - ZNMethodTableUnlinkTask(bool unloading_occurred, ICRefillVerifier* verifier) : - ZTask("ZNMethodTableUnlinkTask"), - _cl(unloading_occurred), - _verifier(verifier) { - ZNMethodTable::nmethod_entries_do_begin(); - } - - ~ZNMethodTableUnlinkTask() { - ZNMethodTable::nmethod_entries_do_end(); - } - - virtual void work() { - ICRefillVerifierMark mark(_verifier); - ZNMethodTable::nmethod_entries_do(&_cl); - } - - bool success() const { - return !_cl.failed(); - } -}; - -void ZNMethodTable::unlink(ZWorkers* workers, bool unloading_occurred) { - for (;;) { - ICRefillVerifier verifier; - - { - ZNMethodTableUnlinkTask task(unloading_occurred, &verifier); - workers->run_concurrent(&task); - if (task.success()) { - return; - } - } - - // Cleaning failed because we ran out of transitional IC stubs, - // so we have to refill and try again. Refilling requires taking - // a safepoint, so we temporarily leave the suspendible thread set. - SuspendibleThreadSetLeaver sts; - InlineCacheBuffer::refill_ic_stubs(); - } -} - -class ZNMethodTablePurgeClosure : public ZNMethodTableEntryClosure { -public: - virtual void do_nmethod_entry(ZNMethodTableEntry entry) { - nmethod* const nm = entry.method(); - if (nm->is_alive() && nm->is_unloading()) { - nm->make_unloaded(); - } - } -}; - -class ZNMethodTablePurgeTask : public ZTask { -private: - ZNMethodTablePurgeClosure _cl; - -public: - ZNMethodTablePurgeTask() : - ZTask("ZNMethodTablePurgeTask"), - _cl() { - ZNMethodTable::nmethod_entries_do_begin(); - } - - ~ZNMethodTablePurgeTask() { - ZNMethodTable::nmethod_entries_do_end(); - } - - virtual void work() { - ZNMethodTable::nmethod_entries_do(&_cl); - } -}; - -void ZNMethodTable::purge(ZWorkers* workers) { - ZNMethodTablePurgeTask task; - workers->run_concurrent(&task); -}
--- a/src/hotspot/share/gc/z/zNMethodTable.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/z/zNMethodTable.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -24,66 +24,46 @@ #ifndef SHARE_GC_Z_ZNMETHODTABLE_HPP #define SHARE_GC_Z_ZNMETHODTABLE_HPP -#include "gc/z/zArray.hpp" -#include "gc/z/zGlobals.hpp" -#include "gc/z/zLock.hpp" -#include "gc/z/zNMethodTableEntry.hpp" +#include "gc/z/zNMethodTableIteration.hpp" #include "memory/allocation.hpp" +class nmethod; +class NMethodClosure; +class ZNMethodTableEntry; class ZWorkers; -class ZNMethodTableEntryClosure { -public: - virtual void do_nmethod_entry(ZNMethodTableEntry entry) = 0; -}; - class ZNMethodTable : public AllStatic { private: - static ZNMethodTableEntry* _table; - static size_t _size; - static ZLock _iter_lock; - static ZNMethodTableEntry* _iter_table; - static size_t _iter_table_size; - static ZArray<void*> _iter_deferred_deletes; - static size_t _nregistered; - static size_t _nunregistered; - static volatile size_t _claimed ATTRIBUTE_ALIGNED(ZCacheLineSize); + static ZNMethodTableEntry* _table; + static size_t _size; + static size_t _nregistered; + static size_t _nunregistered; + static ZNMethodTableIteration _iteration; - static ZNMethodTableEntry create_entry(nmethod* nm); + static ZNMethodTableEntry* create(size_t size); + static void destroy(ZNMethodTableEntry* table); static size_t first_index(const nmethod* nm, size_t size); static size_t next_index(size_t prev_index, size_t size); - static void sweeper_wait_for_iteration(); - - static bool register_entry(ZNMethodTableEntry* table, size_t size, ZNMethodTableEntry entry); + static bool register_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm); static void unregister_entry(ZNMethodTableEntry* table, size_t size, nmethod* nm); static void rebuild(size_t new_size); static void rebuild_if_needed(); - static void log_register(const nmethod* nm, ZNMethodTableEntry entry); - static void log_unregister(const nmethod* nm); - public: - static void safe_delete(void* data); - static size_t registered_nmethods(); static size_t unregistered_nmethods(); static void register_nmethod(nmethod* nm); static void unregister_nmethod(nmethod* nm); - static void disarm_nmethod(nmethod* nm); - static ZReentrantLock* lock_for_nmethod(nmethod* nm); + static void wait_until_iteration_done(); - static void oops_do(OopClosure* cl); - - static void entry_oops_do(ZNMethodTableEntry entry, OopClosure* cl); - - static void nmethod_entries_do_begin(); - static void nmethod_entries_do_end(); - static void nmethod_entries_do(ZNMethodTableEntryClosure* cl); + static void nmethods_do_begin(); + static void nmethods_do_end(); + static void nmethods_do(NMethodClosure* cl); static void unlink(ZWorkers* workers, bool unloading_occurred); static void purge(ZWorkers* workers);
--- a/src/hotspot/share/gc/z/zNMethodTableEntry.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/z/zNMethodTableEntry.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -32,16 +32,16 @@ // -------------------------- // // 6 -// 3 3 2 1 0 -// +--------------------------------------------------------------------+-+-+-+ -// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111|1|1|1| -// +--------------------------------------------------------------------+-+-+-+ -// | | | | -// | 2-2 Non-immediate Oops Flag (1-bits) * | | -// | | | -// | 1-1 Immediate Oops/Unregistered Flag (1-bits) * | -// | | -// | 0-0 Registered Flag (1-bits) * +// 3 2 1 0 +// +---------------------------------------------------------------------+-+-+ +// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 111111|1|1| +// +---------------------------------------------------------------------+-+-+ +// | | | +// | | | +// | | | +// | 1-1 Unregistered Flag (1-bits) * | +// | | +// | 0-0 Registered Flag (1-bits) * // | // * 63-3 NMethod Address (61-bits) // @@ -52,22 +52,20 @@ private: typedef ZBitField<uint64_t, bool, 0, 1> field_registered; typedef ZBitField<uint64_t, bool, 1, 1> field_unregistered; - typedef ZBitField<uint64_t, bool, 1, 1> field_immediate_oops; - typedef ZBitField<uint64_t, bool, 2, 1> field_non_immediate_oops; - typedef ZBitField<uint64_t, nmethod*, 3, 61, 3> field_method; + typedef ZBitField<uint64_t, nmethod*, 2, 62, 2> field_method; uint64_t _entry; public: explicit ZNMethodTableEntry(bool unregistered = false) : - _entry(field_unregistered::encode(unregistered) | - field_registered::encode(false)) {} + _entry(field_registered::encode(false) | + field_unregistered::encode(unregistered) | + field_method::encode(NULL)) {} - ZNMethodTableEntry(nmethod* method, bool non_immediate_oops, bool immediate_oops) : - _entry(field_method::encode(method) | - field_non_immediate_oops::encode(non_immediate_oops) | - field_immediate_oops::encode(immediate_oops) | - field_registered::encode(true)) {} + explicit ZNMethodTableEntry(nmethod* method) : + _entry(field_registered::encode(true) | + field_unregistered::encode(false) | + field_method::encode(method)) {} bool registered() const { return field_registered::decode(_entry); @@ -77,14 +75,6 @@ return field_unregistered::decode(_entry); } - bool immediate_oops() const { - return field_immediate_oops::decode(_entry); - } - - bool non_immediate_oops() const { - return field_non_immediate_oops::decode(_entry); - } - nmethod* method() const { return field_method::decode(_entry); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zNMethodTableIteration.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zNMethodTableEntry.hpp" +#include "gc/z/zNMethodTableIteration.hpp" +#include "memory/iterator.hpp" +#include "runtime/atomic.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +ZNMethodTableIteration::ZNMethodTableIteration() : + _table(NULL), + _size(0), + _claimed(0) {} + +bool ZNMethodTableIteration::in_progress() const { + return _table != NULL; +} + +void ZNMethodTableIteration::nmethods_do_begin(ZNMethodTableEntry* table, size_t size) { + assert(!in_progress(), "precondition"); + + _table = table; + _size = size; + _claimed = 0; +} + +void ZNMethodTableIteration::nmethods_do_end() { + assert(_claimed >= _size, "Failed to claim all table entries"); + + // Finish iteration + _table = NULL; +} + +void ZNMethodTableIteration::nmethods_do(NMethodClosure* cl) { + for (;;) { + // Claim table partition. Each partition is currently sized to span + // two cache lines. This number is just a guess, but seems to work well. + const size_t partition_size = (ZCacheLineSize * 2) / sizeof(ZNMethodTableEntry); + const size_t partition_start = MIN2(Atomic::add(partition_size, &_claimed) - partition_size, _size); + const size_t partition_end = MIN2(partition_start + partition_size, _size); + if (partition_start == partition_end) { + // End of table + break; + } + + // Process table partition + for (size_t i = partition_start; i < partition_end; i++) { + const ZNMethodTableEntry entry = _table[i]; + if (entry.registered()) { + cl->do_nmethod(entry.method()); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/z/zNMethodTableIteration.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -0,0 +1,48 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZNMETHODTABLEITERATION_HPP +#define SHARE_GC_Z_ZNMETHODTABLEITERATION_HPP + +#include "gc/z/zGlobals.hpp" + +class NMethodClosure; +class ZNMethodTableEntry; + +class ZNMethodTableIteration { +private: + ZNMethodTableEntry* _table; + size_t _size; + volatile size_t _claimed ATTRIBUTE_ALIGNED(ZCacheLineSize); + +public: + ZNMethodTableIteration(); + + bool in_progress() const; + + void nmethods_do_begin(ZNMethodTableEntry* table, size_t size); + void nmethods_do_end(); + void nmethods_do(NMethodClosure* cl); +}; + +#endif // SHARE_GC_Z_ZNMETHODTABLEITERATION_HPP
--- a/src/hotspot/share/gc/z/zRootsIterator.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/z/zRootsIterator.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -33,7 +33,7 @@ #include "gc/shared/suspendibleThreadSet.hpp" #include "gc/z/zBarrierSetNMethod.hpp" #include "gc/z/zGlobals.hpp" -#include "gc/z/zNMethodTable.hpp" +#include "gc/z/zNMethod.hpp" #include "gc/z/zOopClosures.inline.hpp" #include "gc/z/zRootsIterator.hpp" #include "gc/z/zStat.hpp" @@ -184,7 +184,7 @@ if (ClassUnloading) { nmethod::oops_do_marking_prologue(); } else { - ZNMethodTable::nmethod_entries_do_begin(); + ZNMethod::oops_do_begin(); } } @@ -194,7 +194,7 @@ if (ClassUnloading) { nmethod::oops_do_marking_epilogue(); } else { - ZNMethodTable::nmethod_entries_do_end(); + ZNMethod::oops_do_end(); } JvmtiExport::gc_epilogue(); @@ -242,7 +242,7 @@ void ZRootsIterator::do_code_cache(ZRootsIteratorClosure* cl) { ZStatTimer timer(ZSubPhasePauseRootsCodeCache); - ZNMethodTable::oops_do(cl); + ZNMethod::oops_do(cl); } void ZRootsIterator::oops_do(ZRootsIteratorClosure* cl, bool visit_jvmti_weak_export) {
--- a/src/hotspot/share/gc/z/zUnload.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/gc/z/zUnload.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -30,7 +30,7 @@ #include "gc/shared/gcBehaviours.hpp" #include "gc/shared/suspendibleThreadSet.hpp" #include "gc/z/zLock.inline.hpp" -#include "gc/z/zNMethodTable.hpp" +#include "gc/z/zNMethod.hpp" #include "gc/z/zOopClosures.hpp" #include "gc/z/zStat.hpp" #include "gc/z/zUnload.hpp" @@ -65,43 +65,30 @@ }; class ZIsUnloadingBehaviour : public IsUnloadingBehaviour { -private: - bool is_unloading(nmethod* nm) const { +public: + virtual bool is_unloading(CompiledMethod* method) const { + nmethod* const nm = method->as_nmethod(); + ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); + ZLocker<ZReentrantLock> locker(lock); ZIsUnloadingOopClosure cl; nm->oops_do(&cl, true /* allow_zombie */); return cl.is_unloading(); } - -public: - virtual bool is_unloading(CompiledMethod* method) const { - nmethod* const nm = method->as_nmethod(); - ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm); - if (lock == NULL) { - return is_unloading(nm); - } else { - ZLocker<ZReentrantLock> locker(lock); - return is_unloading(nm); - } - } }; class ZCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { public: virtual bool lock(CompiledMethod* method) { nmethod* const nm = method->as_nmethod(); - ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm); - if (lock != NULL) { - lock->lock(); - } + ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); + lock->lock(); return true; } virtual void unlock(CompiledMethod* method) { nmethod* const nm = method->as_nmethod(); - ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm); - if (lock != NULL) { - lock->unlock(); - } + ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); + lock->unlock(); } virtual bool is_safe(CompiledMethod* method) { @@ -110,8 +97,8 @@ } nmethod* const nm = method->as_nmethod(); - ZReentrantLock* const lock = ZNMethodTable::lock_for_nmethod(nm); - return lock == NULL || lock->is_owned(); + ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); + return lock->is_owned(); } }; @@ -149,7 +136,7 @@ Klass::clean_weak_klass_links(unloading_occurred); - ZNMethodTable::unlink(_workers, unloading_occurred); + ZNMethod::unlink(_workers, unloading_occurred); DependencyContext::cleaning_end(); } @@ -157,7 +144,7 @@ void ZUnload::purge() { { SuspendibleThreadSetJoiner sts; - ZNMethodTable::purge(_workers); + ZNMethod::purge(_workers); } ClassLoaderDataGraph::purge();
--- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -114,7 +114,7 @@ NO_TRANSITION_END NO_TRANSITION(void, jfr_set_file_notification(JNIEnv* env, jobject jvm, jlong threshold)) - JfrChunkRotation::set_threshold((intptr_t)threshold); + JfrChunkRotation::set_threshold(threshold); NO_TRANSITION_END NO_TRANSITION(void, jfr_set_sample_threads(JNIEnv* env, jobject jvm, jboolean sampleThreads))
--- a/src/hotspot/share/jfr/metadata/metadata.xml Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/metadata/metadata.xml Thu Feb 28 22:05:33 2019 +0100 @@ -533,12 +533,6 @@ <Field type="int" name="iterations" label="Iterations" description="Number of state check iterations" /> </Event> - <Event name="SafepointWaitBlocked" category="Java Virtual Machine, Runtime, Safepoint" label="Safepoint Wait Blocked" description="Safepointing begin waiting on running threads to block" - thread="true"> - <Field type="ulong" name="safepointId" label="Safepoint Identifier" relation="SafepointId" /> - <Field type="int" name="runningThreadCount" label="Running Threads" description="The number running of threads wait for safe point" /> - </Event> - <Event name="SafepointCleanup" category="Java Virtual Machine, Runtime, Safepoint" label="Safepoint Cleanup" description="Safepointing begin running cleanup tasks" thread="true"> <Field type="ulong" name="safepointId" label="Safepoint Identifier" relation="SafepointId" />
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -44,13 +44,13 @@ } } -static void write_checkpoint_header(u1* pos, jlong size, jlong time, bool flushpoint, juint type_count) { +static void write_checkpoint_header(u1* pos, int64_t size, jlong time, bool flushpoint, u4 type_count) { assert(pos != NULL, "invariant"); JfrBigEndianWriter be_writer(pos, sizeof(JfrCheckpointEntry)); be_writer.write(size); be_writer.write(time); be_writer.write(JfrTicks::now().value() - time); - be_writer.write(flushpoint ? (juint)1 : (juint)0); + be_writer.write(flushpoint ? (u4)1 : (u4)0); be_writer.write(type_count); assert(be_writer.is_valid(), "invariant"); } @@ -71,7 +71,7 @@ assert(this->is_valid(), "invariant"); assert(count() > 0, "invariant"); assert(this->used_size() > sizeof(JfrCheckpointEntry), "invariant"); - const jlong size = this->current_offset(); + const int64_t size = this->current_offset(); assert(size + this->start_pos() == this->current_pos(), "invariant"); write_checkpoint_header(const_cast<u1*>(this->start_pos()), size, _time, is_flushpoint(), count()); release(); @@ -85,11 +85,11 @@ return _flushpoint; } -juint JfrCheckpointWriter::count() const { +u4 JfrCheckpointWriter::count() const { return _count; } -void JfrCheckpointWriter::set_count(juint count) { +void JfrCheckpointWriter::set_count(u4 count) { _count = count; } @@ -111,7 +111,7 @@ } void JfrCheckpointWriter::write_key(u8 key) { - write<u8>(key); + write(key); } void JfrCheckpointWriter::increment() { @@ -119,10 +119,10 @@ } void JfrCheckpointWriter::write_count(u4 nof_entries) { - write<u4>((u4)nof_entries); + write(nof_entries); } -void JfrCheckpointWriter::write_count(u4 nof_entries, jlong offset) { +void JfrCheckpointWriter::write_count(u4 nof_entries, int64_t offset) { write_padded_at_offset(nof_entries, offset); }
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -49,21 +49,21 @@ typedef EventWriterHost<BigEndianEncoder, CompressedIntegerEncoder, JfrTransactionalCheckpointWriter> JfrCheckpointWriterBase; struct JfrCheckpointContext { - jlong offset; - juint count; + int64_t offset; + u4 count; }; class JfrCheckpointWriter : public JfrCheckpointWriterBase { friend class JfrSerializerRegistration; private: JfrTicks _time; - jlong _offset; - juint _count; + int64_t _offset; + u4 _count; bool _flushpoint; bool _header; - juint count() const; - void set_count(juint count); + u4 count() const; + void set_count(u4 count); void increment(); void set_flushpoint(bool flushpoint); bool is_flushpoint() const; @@ -75,7 +75,7 @@ ~JfrCheckpointWriter(); void write_type(JfrTypeId type_id); void write_count(u4 nof_entries); - void write_count(u4 nof_entries, jlong offset); + void write_count(u4 nof_entries, int64_t offset); void write_key(u8 key); const JfrCheckpointContext context() const; void set_context(const JfrCheckpointContext ctx);
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -65,7 +65,7 @@ private: JfrCheckpointWriter& _writer; JfrCheckpointContext _ctx; - const intptr_t _count_position; + const int64_t _count_position; Thread* const _curthread; u4 _count;
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -35,7 +35,7 @@ WriterImpl _impl; JfrCheckpointWriter* _writer; JfrCheckpointContext _ctx; - jlong _count_offset; + int64_t _count_offset; int _count; bool _skip_header; public:
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkRotation.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkRotation.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -29,7 +29,7 @@ #include "runtime/handles.inline.hpp" static jobject chunk_monitor = NULL; -static intptr_t threshold = 0; +static int64_t threshold = 0; static bool rotate = false; static jobject install_chunk_monitor(Thread* thread) { @@ -62,7 +62,6 @@ // already in progress return; } - assert(!rotate, "invariant"); if (writer.size_written() > threshold) { rotate = true; notify(); @@ -77,6 +76,6 @@ rotate = false; } -void JfrChunkRotation::set_threshold(intptr_t bytes) { +void JfrChunkRotation::set_threshold(int64_t bytes) { threshold = bytes; }
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkRotation.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkRotation.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -36,7 +36,7 @@ class JfrChunkRotation : AllStatic { public: static void evaluate(const JfrChunkWriter& writer); - static void set_threshold(intptr_t bytes); + static void set_threshold(int64_t bytes); static bool should_rotate(); static void on_rotation(); };
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkState.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkState.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -53,19 +53,19 @@ set_previous_checkpoint_offset(0); } -void JfrChunkState::set_previous_checkpoint_offset(jlong offset) { +void JfrChunkState::set_previous_checkpoint_offset(int64_t offset) { _previous_checkpoint_offset = offset; } -jlong JfrChunkState::previous_checkpoint_offset() const { +int64_t JfrChunkState::previous_checkpoint_offset() const { return _previous_checkpoint_offset; } -jlong JfrChunkState::previous_start_ticks() const { +int64_t JfrChunkState::previous_start_ticks() const { return _previous_start_ticks; } -jlong JfrChunkState::previous_start_nanos() const { +int64_t JfrChunkState::previous_start_nanos() const { return _previous_start_nanos; } @@ -92,7 +92,7 @@ save_current_and_update_start_ticks(); } -jlong JfrChunkState::last_chunk_duration() const { +int64_t JfrChunkState::last_chunk_duration() const { return _start_nanos - _previous_start_nanos; }
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkState.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkState.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -25,7 +25,6 @@ #ifndef SHARE_JFR_RECORDER_REPOSITORY_JFRCHUNKSTATE_HPP #define SHARE_JFR_RECORDER_REPOSITORY_JFRCHUNKSTATE_HPP -#include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrTypes.hpp" @@ -33,11 +32,11 @@ friend class JfrChunkWriter; private: char* _path; - jlong _start_ticks; - jlong _start_nanos; - jlong _previous_start_ticks; - jlong _previous_start_nanos; - jlong _previous_checkpoint_offset; + int64_t _start_ticks; + int64_t _start_nanos; + int64_t _previous_start_ticks; + int64_t _previous_start_nanos; + int64_t _previous_checkpoint_offset; void update_start_ticks(); void update_start_nanos(); @@ -47,11 +46,11 @@ JfrChunkState(); ~JfrChunkState(); void reset(); - jlong previous_checkpoint_offset() const; - void set_previous_checkpoint_offset(jlong offset); - jlong previous_start_ticks() const; - jlong previous_start_nanos() const; - jlong last_chunk_duration() const; + int64_t previous_checkpoint_offset() const; + void set_previous_checkpoint_offset(int64_t offset); + int64_t previous_start_ticks() const; + int64_t previous_start_nanos() const; + int64_t last_chunk_duration() const; void update_time_to_now(); void set_path(const char* path); const char* path() const;
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -32,9 +32,8 @@ #include "runtime/os.hpp" #include "runtime/os.inline.hpp" -const u2 JFR_VERSION_MAJOR = 2; -const u2 JFR_VERSION_MINOR = 0; - +static const u2 JFR_VERSION_MAJOR = 2; +static const u2 JFR_VERSION_MINOR = 0; static const size_t MAGIC_LEN = 4; static const size_t FILEHEADER_SLOT_SIZE = 8; static const size_t CHUNK_SIZE_OFFSET = 8; @@ -79,14 +78,14 @@ return is_open; } -size_t JfrChunkWriter::close(intptr_t metadata_offset) { +size_t JfrChunkWriter::close(int64_t metadata_offset) { write_header(metadata_offset); this->flush(); this->close_fd(); - return size_written(); + return (size_t)size_written(); } -void JfrChunkWriter::write_header(intptr_t metadata_offset) { +void JfrChunkWriter::write_header(int64_t metadata_offset) { assert(this->is_valid(), "invariant"); // Chunk size this->write_be_at_offset(size_written(), CHUNK_SIZE_OFFSET); @@ -106,15 +105,15 @@ _chunkstate->set_path(chunk_path); } -intptr_t JfrChunkWriter::size_written() const { +int64_t JfrChunkWriter::size_written() const { return this->is_valid() ? this->current_offset() : 0; } -intptr_t JfrChunkWriter::previous_checkpoint_offset() const { +int64_t JfrChunkWriter::previous_checkpoint_offset() const { return _chunkstate->previous_checkpoint_offset(); } -void JfrChunkWriter::set_previous_checkpoint_offset(intptr_t offset) { +void JfrChunkWriter::set_previous_checkpoint_offset(int64_t offset) { _chunkstate->set_previous_checkpoint_offset(offset); }
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -41,16 +41,16 @@ JfrChunkState* _chunkstate; bool open(); - size_t close(intptr_t metadata_offset); - void write_header(intptr_t metadata_offset); + size_t close(int64_t metadata_offset); + void write_header(int64_t metadata_offset); void set_chunk_path(const char* chunk_path); public: JfrChunkWriter(); bool initialize(); - intptr_t size_written() const; - intptr_t previous_checkpoint_offset() const; - void set_previous_checkpoint_offset(intptr_t offset); + int64_t size_written() const; + int64_t previous_checkpoint_offset() const; + void set_previous_checkpoint_offset(int64_t offset); void time_stamp_chunk_now(); };
--- a/src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -147,10 +147,10 @@ iso8601_to_date_time(buffer); } -static jlong file_size(fio_fd fd) { +static int64_t file_size(fio_fd fd) { assert(fd != invalid_fd, "invariant"); - const jlong current_offset = os::current_file_offset(fd); - const jlong size = os::lseek(fd, 0, SEEK_END); + const int64_t current_offset = os::current_file_offset(fd); + const int64_t size = os::lseek(fd, 0, SEEK_END); os::seek_to_file_offset(fd, current_offset); return size; } @@ -218,7 +218,7 @@ if (invalid_fd == entry_fd) { return NULL; } - const jlong entry_size = file_size(entry_fd); + const int64_t entry_size = file_size(entry_fd); os::close(entry_fd); if (0 == entry_size) { return NULL; @@ -260,6 +260,7 @@ } } #endif + bool RepositoryIterator::has_next() const { return (_files != NULL && _iterator < _files->length()); } @@ -275,21 +276,27 @@ if (file_copy_block == NULL) { return; } - jlong bytes_written_total = 0; + int64_t bytes_written_total = 0; while (iterator.has_next()) { fio_fd current_fd = invalid_fd; const char* const fqn = iterator.next(); if (fqn != NULL) { current_fd = open_existing(fqn); if (current_fd != invalid_fd) { - const jlong current_filesize = file_size(current_fd); + const int64_t current_filesize = file_size(current_fd); assert(current_filesize > 0, "invariant"); - jlong bytes_read = 0; - jlong bytes_written = 0; + int64_t bytes_read = 0; + int64_t bytes_written = 0; while (bytes_read < current_filesize) { - bytes_read += (jlong)os::read_at(current_fd, file_copy_block, size_of_file_copy_block, bytes_read); - assert(bytes_read - bytes_written <= (jlong)size_of_file_copy_block, "invariant"); - bytes_written += (jlong)os::write(emergency_fd, file_copy_block, bytes_read - bytes_written); + const ssize_t read_result = os::read_at(current_fd, file_copy_block, size_of_file_copy_block, bytes_read); + if (-1 == read_result) { + log_info(jfr) ( // For user, should not be "jfr, system" + "Unable to recover JFR data"); + break; + } + bytes_read += (int64_t)read_result; + assert(bytes_read - bytes_written <= (int64_t)size_of_file_copy_block, "invariant"); + bytes_written += (int64_t)os::write(emergency_fd, file_copy_block, bytes_read - bytes_written); assert(bytes_read == bytes_written, "invariant"); } os::close(current_fd); @@ -468,6 +475,6 @@ return _chunkwriter->open(); } -size_t JfrRepository::close_chunk(jlong metadata_offset) { +size_t JfrRepository::close_chunk(int64_t metadata_offset) { return _chunkwriter->close(metadata_offset); }
--- a/src/hotspot/share/jfr/recorder/repository/jfrRepository.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/repository/jfrRepository.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -55,7 +55,7 @@ bool set_path(const char* path); void set_chunk_path(const char* path); bool open_chunk(bool vm_error = false); - size_t close_chunk(jlong metadata_offset); + size_t close_chunk(int64_t metadata_offset); void on_vm_error(); static void notify_on_new_chunk_path(); static JfrChunkWriter& chunkwriter();
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -130,18 +130,18 @@ bool not_acquired() const { return !_acquired; } }; -static intptr_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) { - const intptr_t prev_cp_offset = cw.previous_checkpoint_offset(); - const intptr_t prev_cp_relative_offset = 0 == prev_cp_offset ? 0 : prev_cp_offset - cw.current_offset(); +static int64_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) { + const int64_t prev_cp_offset = cw.previous_checkpoint_offset(); + const int64_t prev_cp_relative_offset = 0 == prev_cp_offset ? 0 : prev_cp_offset - cw.current_offset(); cw.reserve(sizeof(u4)); cw.write<u8>(EVENT_CHECKPOINT); cw.write(JfrTicks::now()); - cw.write<jlong>((jlong)0); + cw.write((int64_t)0); cw.write(prev_cp_relative_offset); // write previous checkpoint offset delta cw.write<bool>(false); // flushpoint - cw.write<u4>((u4)1); // nof types in this checkpoint - cw.write<u8>(type_id); - const intptr_t number_of_elements_offset = cw.current_offset(); + cw.write((u4)1); // nof types in this checkpoint + cw.write(type_id); + const int64_t number_of_elements_offset = cw.current_offset(); cw.reserve(sizeof(u4)); return number_of_elements_offset; } @@ -161,8 +161,8 @@ } bool process() { // current_cp_offset is also offset for the event size header field - const intptr_t current_cp_offset = _cw.current_offset(); - const intptr_t num_elements_offset = write_checkpoint_event_prologue(_cw, _type_id); + const int64_t current_cp_offset = _cw.current_offset(); + const int64_t num_elements_offset = write_checkpoint_event_prologue(_cw, _type_id); // invocation _content_functor.process(); const u4 number_of_elements = (u4)_content_functor.processed(); @@ -468,9 +468,9 @@ JfrMetadataEvent::lock(); } -static jlong write_metadata_event(JfrChunkWriter& chunkwriter) { +static int64_t write_metadata_event(JfrChunkWriter& chunkwriter) { assert(chunkwriter.is_valid(), "invariant"); - const jlong metadata_offset = chunkwriter.current_offset(); + const int64_t metadata_offset = chunkwriter.current_offset(); JfrMetadataEvent::write(chunkwriter, metadata_offset); return metadata_offset; }
--- a/src/hotspot/share/jfr/writers/jfrEventWriterHost.inline.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/writers/jfrEventWriterHost.inline.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -49,7 +49,7 @@ inline intptr_t EventWriterHost<BE, IE, WriterPolicyImpl>::end_write(void) { assert(this->is_acquired(), "state corruption, calling end with writer with non-acquired state!"); - return this->is_valid() ? this->used_offset() : 0; + return this->is_valid() ? (intptr_t)this->used_offset() : 0; } template <typename BE, typename IE, typename WriterPolicyImpl>
--- a/src/hotspot/share/jfr/writers/jfrPosition.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/writers/jfrPosition.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -48,8 +48,8 @@ public: size_t available_size() const; - intptr_t used_offset() const; - intptr_t current_offset() const; + int64_t used_offset() const; + int64_t current_offset() const; size_t used_size() const; void reset(); };
--- a/src/hotspot/share/jfr/writers/jfrPosition.inline.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/writers/jfrPosition.inline.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -80,12 +80,12 @@ } template <typename AP> -inline intptr_t Position<AP>::used_offset() const { +inline int64_t Position<AP>::used_offset() const { return _current_pos - _start_pos; } template <typename AP> -inline intptr_t Position<AP>::current_offset() const { +inline int64_t Position<AP>::current_offset() const { return this->used_offset(); }
--- a/src/hotspot/share/jfr/writers/jfrStreamWriterHost.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -33,9 +33,9 @@ public: typedef typename Adapter::StorageType StorageType; private: - intptr_t _stream_pos; + int64_t _stream_pos; fio_fd _fd; - intptr_t current_stream_position() const; + int64_t current_stream_position() const; protected: StreamWriterHost(StorageType* storage, Thread* thread); @@ -47,8 +47,8 @@ bool has_valid_fd() const; public: - intptr_t current_offset() const; - void seek(intptr_t offset); + int64_t current_offset() const; + void seek(int64_t offset); void flush(); void write_unbuffered(const void* src, size_t len); bool is_valid() const;
--- a/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -44,7 +44,7 @@ } template <typename Adapter, typename AP> -inline intptr_t StreamWriterHost<Adapter, AP>::current_stream_position() const { +inline int64_t StreamWriterHost<Adapter, AP>::current_stream_position() const { return this->used_offset() + _stream_pos; } @@ -73,7 +73,7 @@ inline void StreamWriterHost<Adapter, AP>::flush(size_t size) { assert(size > 0, "invariant"); assert(this->is_valid(), "invariant"); - _stream_pos += os::write(_fd, this->start_pos(), (int)size); + _stream_pos += os::write(_fd, this->start_pos(), (unsigned int)size); StorageHost<Adapter, AP>::reset(); assert(0 == this->used_offset(), "invariant"); } @@ -84,12 +84,12 @@ } template <typename Adapter, typename AP> -inline intptr_t StreamWriterHost<Adapter, AP>::current_offset() const { +inline int64_t StreamWriterHost<Adapter, AP>::current_offset() const { return current_stream_position(); } template <typename Adapter, typename AP> -void StreamWriterHost<Adapter, AP>::seek(intptr_t offset) { +void StreamWriterHost<Adapter, AP>::seek(int64_t offset) { this->flush(); assert(0 == this->used_offset(), "can only seek from beginning"); _stream_pos = os::seek_to_file_offset(_fd, offset); @@ -110,7 +110,7 @@ this->flush(); assert(0 == this->used_offset(), "can only seek from beginning"); while (len > 0) { - const int n = MIN2<int>((int)len, INT_MAX); + const unsigned int n = MIN2((unsigned int)len, (unsigned int)INT_MAX); _stream_pos += os::write(_fd, buf, n); len -= n; }
--- a/src/hotspot/share/jfr/writers/jfrWriterHost.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/writers/jfrWriterHost.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -91,12 +91,12 @@ void bytes(const void* buf, size_t len); void write_utf8_u2_len(const char* value); template <typename T> - void write_padded_at_offset(T value, intptr_t offset); + void write_padded_at_offset(T value, int64_t offset); template <typename T> - void write_at_offset(T value, intptr_t offset); + void write_at_offset(T value, int64_t offset); template <typename T> - void write_be_at_offset(T value, intptr_t offset); - intptr_t reserve(size_t size); + void write_be_at_offset(T value, int64_t offset); + int64_t reserve(size_t size); }; #endif // SHARE_JFR_WRITERS_JFRWRITERHOST_HPP
--- a/src/hotspot/share/jfr/writers/jfrWriterHost.inline.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/jfr/writers/jfrWriterHost.inline.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -196,7 +196,7 @@ template <typename BE, typename IE, typename WriterPolicyImpl> inline void WriterHost<BE, IE, WriterPolicyImpl>::write(double value) { - be_write(*(uintptr_t*)&(value)); + be_write(*(u8*)&(value)); } template <typename BE, typename IE, typename WriterPolicyImpl> @@ -317,9 +317,9 @@ } template <typename BE, typename IE, typename WriterPolicyImpl> -inline intptr_t WriterHost<BE, IE, WriterPolicyImpl>::reserve(size_t size) { +inline int64_t WriterHost<BE, IE, WriterPolicyImpl>::reserve(size_t size) { if (ensure_size(size) != NULL) { - intptr_t reserved_offset = this->current_offset(); + const int64_t reserved_offset = this->current_offset(); this->set_current_pos(size); return reserved_offset; } @@ -329,9 +329,9 @@ template <typename BE, typename IE, typename WriterPolicyImpl> template <typename T> -inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded_at_offset(T value, intptr_t offset) { +inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded_at_offset(T value, int64_t offset) { if (this->is_valid()) { - const intptr_t current = this->current_offset(); + const int64_t current = this->current_offset(); this->seek(offset); write_padded(value); this->seek(current); // restore @@ -340,9 +340,9 @@ template <typename BE, typename IE, typename WriterPolicyImpl> template <typename T> -inline void WriterHost<BE, IE, WriterPolicyImpl>::write_at_offset(T value, intptr_t offset) { +inline void WriterHost<BE, IE, WriterPolicyImpl>::write_at_offset(T value, int64_t offset) { if (this->is_valid()) { - const intptr_t current = this->current_offset(); + const int64_t current = this->current_offset(); this->seek(offset); write(value); this->seek(current); // restore @@ -351,9 +351,9 @@ template <typename BE, typename IE, typename WriterPolicyImpl> template <typename T> -inline void WriterHost<BE, IE, WriterPolicyImpl>::write_be_at_offset(T value, intptr_t offset) { +inline void WriterHost<BE, IE, WriterPolicyImpl>::write_be_at_offset(T value, int64_t offset) { if (this->is_valid()) { - const intptr_t current = this->current_offset(); + const int64_t current = this->current_offset(); this->seek(offset); be_write(value); this->seek(current); // restore
--- a/src/hotspot/share/memory/filemap.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/memory/filemap.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -45,6 +45,7 @@ #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/java.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/os.inline.hpp" #include "runtime/vm_version.hpp" #include "services/memTracker.hpp" @@ -501,6 +502,16 @@ } _validating_shared_path_table = false; + +#if INCLUDE_JVMTI + if (_classpath_entries_for_jvmti != NULL) { + os::free(_classpath_entries_for_jvmti); + } + size_t sz = sizeof(ClassPathEntry*) * _shared_path_table_size; + _classpath_entries_for_jvmti = (ClassPathEntry**)os::malloc(sz, mtClass); + memset(_classpath_entries_for_jvmti, 0, sz); +#endif + return true; } @@ -550,7 +561,7 @@ // Read the FileMapInfo information from the file. bool FileMapInfo::open_for_read() { _full_path = Arguments::GetSharedArchivePath(); - int fd = open(_full_path, O_RDONLY | O_BINARY, 0); + int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0); if (fd < 0) { if (errno == ENOENT) { // Not locating the shared archive is ok. @@ -585,7 +596,7 @@ // Use remove() to delete the existing file because, on Unix, this will // allow processes that have it open continued access to the file. remove(_full_path); - int fd = open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444); + int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444); if (fd < 0) { fail_stop("Unable to create shared archive file %s: (%s).", _full_path, os::strerror(errno)); @@ -1440,3 +1451,57 @@ fail_stop("%s", msg); } } + +#if INCLUDE_JVMTI +ClassPathEntry** FileMapInfo::_classpath_entries_for_jvmti = NULL; + +ClassPathEntry* FileMapInfo::get_classpath_entry_for_jvmti(int i, TRAPS) { + ClassPathEntry* ent = _classpath_entries_for_jvmti[i]; + if (ent == NULL) { + if (i == 0) { + ent = ClassLoader:: get_jrt_entry(); + assert(ent != NULL, "must be"); + } else { + SharedClassPathEntry* scpe = shared_path(i); + assert(scpe->is_jar(), "must be"); // other types of scpe will not produce archived classes + + const char* path = scpe->name(); + struct stat st; + if (os::stat(path, &st) != 0) { + char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); ; + jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path); + THROW_MSG_(vmSymbols::java_io_IOException(), msg, NULL); + } else { + ent = ClassLoader::create_class_path_entry(path, &st, /*throw_exception=*/true, false, CHECK_NULL); + } + } + + MutexLocker mu(CDSClassFileStream_lock, THREAD); + if (_classpath_entries_for_jvmti[i] == NULL) { + _classpath_entries_for_jvmti[i] = ent; + } else { + // Another thread has beat me to creating this entry + delete ent; + ent = _classpath_entries_for_jvmti[i]; + } + } + + return ent; +} + +ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, TRAPS) { + int path_index = ik->shared_classpath_index(); + assert(path_index >= 0, "should be called for shared built-in classes only"); + assert(path_index < (int)_shared_path_table_size, "sanity"); + + ClassPathEntry* cpe = get_classpath_entry_for_jvmti(path_index, CHECK_NULL); + assert(cpe != NULL, "must be"); + + Symbol* name = ik->name(); + const char* const class_name = name->as_C_string(); + const char* const file_name = ClassLoader::file_name_for_class_name(class_name, + name->utf8_length()); + return cpe->open_stream(file_name, THREAD); +} + +#endif
--- a/src/hotspot/share/memory/filemap.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/memory/filemap.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -302,6 +302,10 @@ bool validate_shared_path_table(); static void update_shared_classpath(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS); +#if INCLUDE_JVMTI + static ClassFileStream* open_stream_for_jvmti(InstanceKlass* ik, TRAPS); +#endif + static SharedClassPathEntry* shared_path(int index) { if (index < 0) { return NULL; @@ -348,6 +352,11 @@ } address decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode); + +#if INCLUDE_JVMTI + static ClassPathEntry** _classpath_entries_for_jvmti; + static ClassPathEntry* get_classpath_entry_for_jvmti(int i, TRAPS); +#endif }; #endif // SHARE_MEMORY_FILEMAP_HPP
--- a/src/hotspot/share/memory/iterator.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/memory/iterator.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -263,6 +263,11 @@ virtual void do_code_blob(CodeBlob* cb); }; +class NMethodClosure : public Closure { + public: + virtual void do_nmethod(nmethod* n) = 0; +}; + // MonitorClosure is used for iterating over monitors in the monitors cache class ObjectMonitor;
--- a/src/hotspot/share/memory/metaspaceShared.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/memory/metaspaceShared.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -207,7 +207,7 @@ }; -DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md"), _od_region("od"); +DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md"); size_t _total_closed_archive_region_size = 0, _total_open_archive_region_size = 0; char* MetaspaceShared::misc_code_space_alloc(size_t num_bytes) { @@ -598,23 +598,6 @@ } } -static void relocate_cached_class_file() { - for (int i = 0; i < _global_klass_objects->length(); i++) { - Klass* k = _global_klass_objects->at(i); - if (k->is_instance_klass()) { - InstanceKlass* ik = InstanceKlass::cast(k); - JvmtiCachedClassFileData* p = ik->get_archived_class_data(); - if (p != NULL) { - int size = offset_of(JvmtiCachedClassFileData, data) + p->length; - JvmtiCachedClassFileData* q = (JvmtiCachedClassFileData*)_od_region.allocate(size); - q->length = p->length; - memcpy(q->data, p->data, p->length); - ik->set_archived_class_data(q); - } - } - } -} - // Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables. // (In GCC this is the field <Type>::_vptr, i.e., first word in the object.) // @@ -1438,15 +1421,11 @@ char* vtbl_list = _md_region.top(); MetaspaceShared::allocate_cpp_vtable_clones(); - _md_region.pack(&_od_region); + _md_region.pack(); - // Relocate the archived class file data into the od region - relocate_cached_class_file(); - _od_region.pack(); - - // The 5 core spaces are allocated consecutively mc->rw->ro->md->od, so there total size + // The 4 core spaces are allocated consecutively mc->rw->ro->md, so there total size // is just the spaces between the two ends. - size_t core_spaces_size = _od_region.end() - _mc_region.base(); + size_t core_spaces_size = _md_region.end() - _mc_region.base(); assert(core_spaces_size == (size_t)align_up(core_spaces_size, Metaspace::reserve_alignment()), "should already be aligned"); @@ -1488,7 +1467,6 @@ write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false); write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false); write_region(mapinfo, MetaspaceShared::md, &_md_region, /*read_only=*/false,/*allow_exec=*/false); - write_region(mapinfo, MetaspaceShared::od, &_od_region, /*read_only=*/true, /*allow_exec=*/false); _total_closed_archive_region_size = mapinfo->write_archive_heap_regions( _closed_archive_heap_regions, @@ -1535,12 +1513,10 @@ // Print statistics of all the regions const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() + _mc_region.reserved() + _md_region.reserved() + - _od_region.reserved() + _total_closed_archive_region_size + _total_open_archive_region_size; const size_t total_bytes = _ro_region.used() + _rw_region.used() + _mc_region.used() + _md_region.used() + - _od_region.used() + _total_closed_archive_region_size + _total_open_archive_region_size; const double total_u_perc = percent_of(total_bytes, total_reserved); @@ -1549,7 +1525,6 @@ _rw_region.print(total_reserved); _ro_region.print(total_reserved); _md_region.print(total_reserved); - _od_region.print(total_reserved); print_heap_region_stats(_closed_archive_heap_regions, "ca", total_reserved); print_heap_region_stats(_open_archive_heap_regions, "oa", total_reserved); @@ -1931,33 +1906,30 @@ char* rw_base = NULL; char* rw_top; char* mc_base = NULL; char* mc_top; char* md_base = NULL; char* md_top; - char* od_base = NULL; char* od_top; // Map each shared region if ((mc_base = mapinfo->map_region(mc, &mc_top)) != NULL && (rw_base = mapinfo->map_region(rw, &rw_top)) != NULL && (ro_base = mapinfo->map_region(ro, &ro_top)) != NULL && (md_base = mapinfo->map_region(md, &md_top)) != NULL && - (od_base = mapinfo->map_region(od, &od_top)) != NULL && (image_alignment == (size_t)os::vm_allocation_granularity()) && mapinfo->validate_shared_path_table()) { // Success -- set up MetaspaceObj::_shared_metaspace_{base,top} for // fast checking in MetaspaceShared::is_in_shared_metaspace() and // MetaspaceObj::is_shared(). // - // We require that mc->rw->ro->md->od to be laid out consecutively, with no + // We require that mc->rw->ro->md to be laid out consecutively, with no // gaps between them. That way, we can ensure that the OS won't be able to // allocate any new memory spaces inside _shared_metaspace_{base,top}, which // would mess up the simple comparision in MetaspaceShared::is_in_shared_metaspace(). - assert(mc_base < ro_base && mc_base < rw_base && mc_base < md_base && mc_base < od_base, "must be"); - assert(od_top > ro_top && od_top > rw_top && od_top > md_top && od_top > mc_top , "must be"); + assert(mc_base < ro_base && mc_base < rw_base && mc_base < md_base, "must be"); + assert(md_top > ro_top && md_top > rw_top && md_top > mc_top , "must be"); assert(mc_top == rw_base, "must be"); assert(rw_top == ro_base, "must be"); assert(ro_top == md_base, "must be"); - assert(md_top == od_base, "must be"); _core_spaces_size = mapinfo->core_spaces_size(); - MetaspaceObj::set_shared_metaspace_range((void*)mc_base, (void*)od_top); + MetaspaceObj::set_shared_metaspace_range((void*)mc_base, (void*)md_top); return true; } else { // If there was a failure in mapping any of the spaces, unmap the ones @@ -1966,7 +1938,6 @@ if (rw_base != NULL) mapinfo->unmap_region(rw); if (mc_base != NULL) mapinfo->unmap_region(mc); if (md_base != NULL) mapinfo->unmap_region(md); - if (od_base != NULL) mapinfo->unmap_region(od); #ifndef _WINDOWS // Release the entire mapped region shared_rs.release(); @@ -2049,7 +2020,6 @@ _rw_region.print_out_of_space_msg(name, needed_bytes); _ro_region.print_out_of_space_msg(name, needed_bytes); _md_region.print_out_of_space_msg(name, needed_bytes); - _od_region.print_out_of_space_msg(name, needed_bytes); vm_exit_during_initialization(err_msg("Unable to allocate from '%s' region", name), "Please reduce the number of shared classes.");
--- a/src/hotspot/share/memory/metaspaceShared.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/memory/metaspaceShared.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -69,14 +69,10 @@ ro = 2, // read-only shared space in the heap md = 3, // miscellaneous data for initializing tables, etc. num_core_spaces = 4, // number of non-string regions - - // optional mapped spaces - // Currently it only contains class file data. - od = num_core_spaces, - num_non_heap_spaces = od + 1, + num_non_heap_spaces = 4, // mapped java heap regions - first_closed_archive_heap_region = od + 1, + first_closed_archive_heap_region = md + 1, max_closed_archive_heap_region = 2, last_closed_archive_heap_region = first_closed_archive_heap_region + max_closed_archive_heap_region - 1, first_open_archive_heap_region = last_closed_archive_heap_region + 1,
--- a/src/hotspot/share/memory/universe.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/memory/universe.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -107,6 +107,7 @@ LatestMethodCache* Universe::_finalizer_register_cache = NULL; LatestMethodCache* Universe::_loader_addClass_cache = NULL; LatestMethodCache* Universe::_throw_illegal_access_error_cache = NULL; +LatestMethodCache* Universe::_throw_no_such_method_error_cache = NULL; LatestMethodCache* Universe::_do_stack_walk_cache = NULL; oop Universe::_out_of_memory_error_java_heap = NULL; oop Universe::_out_of_memory_error_metaspace = NULL; @@ -230,6 +231,7 @@ _finalizer_register_cache->metaspace_pointers_do(it); _loader_addClass_cache->metaspace_pointers_do(it); _throw_illegal_access_error_cache->metaspace_pointers_do(it); + _throw_no_such_method_error_cache->metaspace_pointers_do(it); _do_stack_walk_cache->metaspace_pointers_do(it); } @@ -271,6 +273,7 @@ _finalizer_register_cache->serialize(f); _loader_addClass_cache->serialize(f); _throw_illegal_access_error_cache->serialize(f); + _throw_no_such_method_error_cache->serialize(f); _do_stack_walk_cache->serialize(f); } @@ -689,6 +692,7 @@ Universe::_finalizer_register_cache = new LatestMethodCache(); Universe::_loader_addClass_cache = new LatestMethodCache(); Universe::_throw_illegal_access_error_cache = new LatestMethodCache(); + Universe::_throw_no_such_method_error_cache = new LatestMethodCache(); Universe::_do_stack_walk_cache = new LatestMethodCache(); #if INCLUDE_CDS @@ -935,6 +939,11 @@ "throwIllegalAccessError", vmSymbols::void_method_signature(), true, CHECK); + initialize_known_method(_throw_no_such_method_error_cache, + SystemDictionary::internal_Unsafe_klass(), + "throwNoSuchMethodError", + vmSymbols::void_method_signature(), true, CHECK); + // Set up method for registering loaded classes in class loader vector initialize_known_method(_loader_addClass_cache, SystemDictionary::ClassLoader_klass(),
--- a/src/hotspot/share/memory/universe.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/memory/universe.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -138,6 +138,7 @@ static LatestMethodCache* _finalizer_register_cache; // static method for registering finalizable objects static LatestMethodCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static LatestMethodCache* _throw_illegal_access_error_cache; // Unsafe.throwIllegalAccessError() method + static LatestMethodCache* _throw_no_such_method_error_cache; // Unsafe.throwNoSuchMethodError() method static LatestMethodCache* _do_stack_walk_cache; // method for stack walker callback // preallocated error objects (no backtrace) @@ -322,6 +323,7 @@ static Method* loader_addClass_method() { return _loader_addClass_cache->get_method(); } static Method* throw_illegal_access_error() { return _throw_illegal_access_error_cache->get_method(); } + static Method* throw_no_such_method_error() { return _throw_no_such_method_error_cache->get_method(); } static Method* do_stack_walk_method() { return _do_stack_walk_cache->get_method(); }
--- a/src/hotspot/share/oops/cpCache.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/oops/cpCache.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -591,7 +591,7 @@ // a constant pool cache entry should never contain old or obsolete methods bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() { - Method* m = get_interesting_method_entry(NULL); + Method* m = get_interesting_method_entry(); // return false if m refers to a non-deleted old or obsolete method if (m != NULL) { assert(m->is_valid() && m->is_method(), "m is a valid method"); @@ -601,7 +601,7 @@ } } -Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) { +Method* ConstantPoolCacheEntry::get_interesting_method_entry() { if (!is_method_entry()) { // not a method entry so not interesting by default return NULL; @@ -622,12 +622,9 @@ } } assert(m != NULL && m->is_method(), "sanity check"); - if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) { - // robustness for above sanity checks or method is not in - // the interesting class + if (m == NULL || !m->is_method()) { return NULL; } - // the method is in the interesting class so the entry is interesting return m; } #endif // INCLUDE_JVMTI @@ -777,10 +774,10 @@ // RedefineClasses() API support: // If any entry of this ConstantPoolCache points to any of // old_methods, replace it with the corresponding new_method. -void ConstantPoolCache::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { +void ConstantPoolCache::adjust_method_entries(bool * trace_name_printed) { for (int i = 0; i < length(); i++) { ConstantPoolCacheEntry* entry = entry_at(i); - Method* old_method = entry->get_interesting_method_entry(holder); + Method* old_method = entry->get_interesting_method_entry(); if (old_method == NULL || !old_method->is_old()) { continue; // skip uninteresting entries } @@ -789,11 +786,7 @@ entry->initialize_entry(entry->constant_pool_index()); continue; } - Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); - - assert(new_method != NULL, "method_with_idnum() should not be NULL"); - assert(old_method != new_method, "sanity check"); - + Method* new_method = old_method->get_new_method(); entry_at(i)->adjust_method_entry(old_method, new_method, trace_name_printed); } } @@ -801,7 +794,7 @@ // the constant pool cache should never contain old or obsolete methods bool ConstantPoolCache::check_no_old_or_obsolete_entries() { for (int i = 1; i < length(); i++) { - if (entry_at(i)->get_interesting_method_entry(NULL) != NULL && + if (entry_at(i)->get_interesting_method_entry() != NULL && !entry_at(i)->check_no_old_or_obsolete_entries()) { return false; } @@ -811,7 +804,7 @@ void ConstantPoolCache::dump_cache() { for (int i = 1; i < length(); i++) { - if (entry_at(i)->get_interesting_method_entry(NULL) != NULL) { + if (entry_at(i)->get_interesting_method_entry() != NULL) { entry_at(i)->print(tty, i); } }
--- a/src/hotspot/share/oops/cpCache.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/oops/cpCache.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -376,7 +376,7 @@ void adjust_method_entry(Method* old_method, Method* new_method, bool* trace_name_printed); bool check_no_old_or_obsolete_entries(); - Method* get_interesting_method_entry(Klass* k); + Method* get_interesting_method_entry(); #endif // INCLUDE_JVMTI // Debugging & Printing @@ -496,7 +496,7 @@ // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. - void adjust_method_entries(InstanceKlass* holder, bool* trace_name_printed); + void adjust_method_entries(bool* trace_name_printed); bool check_no_old_or_obsolete_entries(); void dump_cache(); #endif // INCLUDE_JVMTI
--- a/src/hotspot/share/oops/instanceKlass.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/oops/instanceKlass.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -2353,6 +2353,7 @@ #if INCLUDE_JVMTI guarantee(_breakpoints == NULL, "must be"); guarantee(_previous_versions == NULL, "must be"); + _cached_class_file = NULL; #endif _init_thread = NULL; @@ -2509,7 +2510,7 @@ } // deallocate the cached class file - if (_cached_class_file != NULL && !MetaspaceShared::is_in_shared_metaspace(_cached_class_file)) { + if (_cached_class_file != NULL) { os::free(_cached_class_file); _cached_class_file = NULL; } @@ -2916,22 +2917,18 @@ // not yet in the vtable due to concurrent subclass define and superinterface // redefinition // Note: those in the vtable, should have been updated via adjust_method_entries -void InstanceKlass::adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed) { +void InstanceKlass::adjust_default_methods(bool* trace_name_printed) { // search the default_methods for uses of either obsolete or EMCP methods if (default_methods() != NULL) { for (int index = 0; index < default_methods()->length(); index ++) { Method* old_method = default_methods()->at(index); - if (old_method == NULL || old_method->method_holder() != holder || !old_method->is_old()) { + if (old_method == NULL || !old_method->is_old()) { continue; // skip uninteresting entries } assert(!old_method->is_deleted(), "default methods may not be deleted"); - - Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); - - assert(new_method != NULL, "method_with_idnum() should not be NULL"); - assert(old_method != new_method, "sanity check"); - + Method* new_method = old_method->get_new_method(); default_methods()->at_put(index, new_method); + if (log_is_enabled(Info, redefine, class, update)) { ResourceMark rm; if (!(*trace_name_printed)) { @@ -3970,12 +3967,7 @@ #if INCLUDE_JVMTI JvmtiCachedClassFileData* InstanceKlass::get_cached_class_file() { - if (MetaspaceShared::is_in_shared_metaspace(_cached_class_file)) { - // Ignore the archived class stream data - return NULL; - } else { - return _cached_class_file; - } + return _cached_class_file; } jint InstanceKlass::get_cached_class_file_len() { @@ -3985,19 +3977,4 @@ unsigned char * InstanceKlass::get_cached_class_file_bytes() { return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file); } - -#if INCLUDE_CDS -JvmtiCachedClassFileData* InstanceKlass::get_archived_class_data() { - if (DumpSharedSpaces) { - return _cached_class_file; - } else { - assert(this->is_shared(), "class should be shared"); - if (MetaspaceShared::is_in_shared_metaspace(_cached_class_file)) { - return _cached_class_file; - } else { - return NULL; - } - } -} #endif -#endif
--- a/src/hotspot/share/oops/instanceKlass.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/oops/instanceKlass.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -847,14 +847,6 @@ JvmtiCachedClassFieldMap* jvmti_cached_class_field_map() const { return _jvmti_cached_class_field_map; } - -#if INCLUDE_CDS - void set_archived_class_data(JvmtiCachedClassFileData* data) { - _cached_class_file = data; - } - - JvmtiCachedClassFileData * get_archived_class_data(); -#endif // INCLUDE_CDS #else // INCLUDE_JVMTI static void purge_previous_versions(InstanceKlass* ik) { return; }; @@ -1149,7 +1141,7 @@ Method* method_at_itable(Klass* holder, int index, TRAPS); #if INCLUDE_JVMTI - void adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed); + void adjust_default_methods(bool* trace_name_printed); #endif // INCLUDE_JVMTI void clean_weak_instanceklass_links();
--- a/src/hotspot/share/oops/klassVtable.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/oops/klassVtable.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -942,21 +942,18 @@ } // search the vtable for uses of either obsolete or EMCP methods -void klassVtable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { +void klassVtable::adjust_method_entries(bool * trace_name_printed) { int prn_enabled = 0; for (int index = 0; index < length(); index++) { Method* old_method = unchecked_method_at(index); - if (old_method == NULL || old_method->method_holder() != holder || !old_method->is_old()) { + if (old_method == NULL || !old_method->is_old()) { continue; // skip uninteresting entries } assert(!old_method->is_deleted(), "vtable methods may not be deleted"); - Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); + Method* new_method = old_method->get_new_method(); + put_method_at(new_method, index); - assert(new_method != NULL, "method_with_idnum() should not be NULL"); - assert(old_method != new_method, "sanity check"); - - put_method_at(new_method, index); // For default methods, need to update the _default_methods array // which can only have one method entry for a given signature bool updated_default = false; @@ -1272,21 +1269,16 @@ #if INCLUDE_JVMTI // search the itable for uses of either obsolete or EMCP methods -void klassItable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { +void klassItable::adjust_method_entries(bool * trace_name_printed) { itableMethodEntry* ime = method_entry(0); for (int i = 0; i < _size_method_table; i++, ime++) { Method* old_method = ime->method(); - if (old_method == NULL || old_method->method_holder() != holder || !old_method->is_old()) { + if (old_method == NULL || !old_method->is_old()) { continue; // skip uninteresting entries } assert(!old_method->is_deleted(), "itable methods may not be deleted"); - - Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); - - assert(new_method != NULL, "method_with_idnum() should not be NULL"); - assert(old_method != new_method, "sanity check"); - + Method* new_method = old_method->get_new_method(); ime->initialize(new_method); if (log_is_enabled(Info, redefine, class, update)) {
--- a/src/hotspot/share/oops/klassVtable.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/oops/klassVtable.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -103,7 +103,7 @@ // printed the klass name so that other routines in the adjust_* // group don't print the klass name. bool adjust_default_method(int vtable_index, Method* old_method, Method* new_method); - void adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed); + void adjust_method_entries(bool* trace_name_printed); bool check_no_old_or_obsolete_entries(); void dump_vtable(); #endif // INCLUDE_JVMTI @@ -322,7 +322,7 @@ // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. - void adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed); + void adjust_method_entries(bool* trace_name_printed); bool check_no_old_or_obsolete_entries(); void dump_itable(); #endif // INCLUDE_JVMTI
--- a/src/hotspot/share/oops/method.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/oops/method.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -2120,7 +2120,8 @@ // Can't assert the method_holder is the same because the new method has the // scratch method holder. assert(resolve_jmethod_id(jmid)->method_holder()->class_loader() - == new_method->method_holder()->class_loader(), + == new_method->method_holder()->class_loader() || + new_method->method_holder()->class_loader() == NULL, // allow Unsafe substitution "changing to a different class loader"); // Just change the method in place, jmethodID pointer doesn't change. *((Method**)jmid) = new_method;
--- a/src/hotspot/share/oops/method.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/oops/method.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -974,6 +974,15 @@ // Deallocation function for redefine classes or if an error occurs void deallocate_contents(ClassLoaderData* loader_data); + Method* get_new_method() const { + InstanceKlass* holder = method_holder(); + Method* new_method = holder->method_with_idnum(orig_method_idnum()); + + assert(new_method != NULL, "method_with_idnum() should not be NULL"); + assert(this != new_method, "sanity check"); + return new_method; + } + // Printing #ifndef PRODUCT void print_on(outputStream* st) const;
--- a/src/hotspot/share/prims/evmCompat.cpp Fri Feb 22 14:51:06 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 1999, 2010, 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. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "utilities/debug.hpp" - -// This file contains definitions for functions that exist -// in the ExactVM, but not in HotSpot. They are stubbed out -// here to prevent linker errors when attempting to use HotSpot -// with the ExactVM jdk. - -extern "C" void JVM_Process_DestroyProcess(void); -extern "C" void JVM_Process_ForkAndExec(void); -extern "C" void JVM_Process_WaitForProcessExit(void); -extern "C" void gc(void); - -void JVM_Process_DestroyProcess(void) { - ShouldNotReachHere(); -} - -void JVM_Process_ForkAndExec(void) { - ShouldNotReachHere(); -} - -void JVM_Process_WaitForProcessExit(void) { - ShouldNotReachHere(); -} - -void gc(void) { - ShouldNotReachHere(); -}
--- a/src/hotspot/share/prims/jni.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/prims/jni.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -3953,9 +3953,6 @@ } #endif - // Tracks the time application was running before GC - RuntimeService::record_application_start(); - // Notify JVMTI if (JvmtiExport::should_post_thread_life()) { JvmtiExport::post_thread_start(thread);
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -62,10 +62,11 @@ Method** VM_RedefineClasses::_matching_new_methods = NULL; Method** VM_RedefineClasses::_deleted_methods = NULL; Method** VM_RedefineClasses::_added_methods = NULL; -int VM_RedefineClasses::_matching_methods_length = 0; -int VM_RedefineClasses::_deleted_methods_length = 0; -int VM_RedefineClasses::_added_methods_length = 0; -Klass* VM_RedefineClasses::_the_class = NULL; +int VM_RedefineClasses::_matching_methods_length = 0; +int VM_RedefineClasses::_deleted_methods_length = 0; +int VM_RedefineClasses::_added_methods_length = 0; +bool VM_RedefineClasses::_has_redefined_Object = false; +bool VM_RedefineClasses::_has_null_class_loader = false; VM_RedefineClasses::VM_RedefineClasses(jint class_count, @@ -76,6 +77,9 @@ _class_load_kind = class_load_kind; _any_class_has_resolved_methods = false; _res = JVMTI_ERROR_NONE; + _the_class = NULL; + _has_redefined_Object = false; + _has_null_class_loader = false; } static inline InstanceKlass* get_ik(jclass def) { @@ -214,11 +218,12 @@ // Flush all compiled code that depends on the classes redefined. flush_dependent_code(); - // Clean out MethodData pointing to old Method* + // Adjust constantpool caches and vtables for all classes + // that reference methods of the evolved classes. // Have to do this after all classes are redefined and all methods that // are redefined are marked as old. - MethodDataCleaner clean_weak_method_links; - ClassLoaderDataGraph::classes_do(&clean_weak_method_links); + AdjustAndCleanMetadata adjust_and_clean_metadata(thread); + ClassLoaderDataGraph::classes_do(&adjust_and_clean_metadata); // JSR-292 support if (_any_class_has_resolved_methods) { @@ -3415,25 +3420,35 @@ // Unevolving classes may point to methods of the_class directly // from their constant pool caches, itables, and/or vtables. We // use the ClassLoaderDataGraph::classes_do() facility and this helper -// to fix up these pointers. +// to fix up these pointers. MethodData also points to old methods and +// must be cleaned. // Adjust cpools and vtables closure -void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) { +void VM_RedefineClasses::AdjustAndCleanMetadata::do_klass(Klass* k) { // This is a very busy routine. We don't want too much tracing // printed out. bool trace_name_printed = false; - InstanceKlass *the_class = InstanceKlass::cast(_the_class); // If the class being redefined is java.lang.Object, we need to fix all // array class vtables also - if (k->is_array_klass() && _the_class == SystemDictionary::Object_klass()) { - k->vtable().adjust_method_entries(the_class, &trace_name_printed); + if (k->is_array_klass() && _has_redefined_Object) { + k->vtable().adjust_method_entries(&trace_name_printed); } else if (k->is_instance_klass()) { HandleMark hm(_thread); InstanceKlass *ik = InstanceKlass::cast(k); + // Clean MethodData of this class's methods so they don't refer to + // old methods that are no longer running. + Array<Method*>* methods = ik->methods(); + int num_methods = methods->length(); + for (int index = 0; index < num_methods; ++index) { + if (methods->at(index)->method_data() != NULL) { + methods->at(index)->method_data()->clean_weak_method_links(); + } + } + // HotSpot specific optimization! HotSpot does not currently // support delegation from the bootstrap class loader to a // user-defined class loader. This means that if the bootstrap @@ -3446,57 +3461,29 @@ // If the current class being redefined has a user-defined class // loader as its defining class loader, then we can skip all // classes loaded by the bootstrap class loader. - bool is_user_defined = (_the_class->class_loader() != NULL); - if (is_user_defined && ik->class_loader() == NULL) { + if (!_has_null_class_loader && ik->class_loader() == NULL) { return; } - // Fix the vtable embedded in the_class and subclasses of the_class, - // if one exists. We discard scratch_class and we don't keep an - // InstanceKlass around to hold obsolete methods so we don't have - // any other InstanceKlass embedded vtables to update. The vtable - // holds the Method*s for virtual (but not final) methods. - // Default methods, or concrete methods in interfaces are stored - // in the vtable, so if an interface changes we need to check - // adjust_method_entries() for every InstanceKlass, which will also - // adjust the default method vtable indices. - // We also need to adjust any default method entries that are - // not yet in the vtable, because the vtable setup is in progress. - // This must be done after we adjust the default_methods and - // default_vtable_indices for methods already in the vtable. - // If redefining Unsafe, walk all the vtables looking for entries. - if (ik->vtable_length() > 0 && (_the_class->is_interface() - || _the_class == SystemDictionary::internal_Unsafe_klass() - || ik->is_subtype_of(_the_class))) { - // ik->vtable() creates a wrapper object; rm cleans it up - ResourceMark rm(_thread); - - ik->vtable().adjust_method_entries(the_class, &trace_name_printed); - ik->adjust_default_methods(the_class, &trace_name_printed); + // Adjust all vtables, default methods and itables, to clean out old methods. + ResourceMark rm(_thread); + if (ik->vtable_length() > 0) { + ik->vtable().adjust_method_entries(&trace_name_printed); + ik->adjust_default_methods(&trace_name_printed); } - // If the current class has an itable and we are either redefining an - // interface or if the current class is a subclass of the_class, then - // we potentially have to fix the itable. If we are redefining an - // interface, then we have to call adjust_method_entries() for - // every InstanceKlass that has an itable since there isn't a - // subclass relationship between an interface and an InstanceKlass. - // If redefining Unsafe, walk all the itables looking for entries. - if (ik->itable_length() > 0 && (_the_class->is_interface() - || _the_class == SystemDictionary::internal_Unsafe_klass() - || ik->is_subclass_of(_the_class))) { - ResourceMark rm(_thread); - ik->itable().adjust_method_entries(the_class, &trace_name_printed); + if (ik->itable_length() > 0) { + ik->itable().adjust_method_entries(&trace_name_printed); } // The constant pools in other classes (other_cp) can refer to - // methods in the_class. We have to update method information in + // old methods. We have to update method information in // other_cp's cache. If other_cp has a previous version, then we // have to repeat the process for each previous version. The // constant pool cache holds the Method*s for non-virtual // methods and for virtual, final methods. // - // Special case: if the current class is the_class, then new_cp + // Special case: if the current class being redefined, then new_cp // has already been attached to the_class and old_cp has already // been added as a previous version. The new_cp doesn't have any // cached references to old methods so it doesn't need to be @@ -3505,12 +3492,12 @@ constantPoolHandle other_cp; ConstantPoolCache* cp_cache; - if (ik != _the_class) { + if (!ik->is_being_redefined()) { // this klass' constant pool cache may need adjustment other_cp = constantPoolHandle(ik->constants()); cp_cache = other_cp->cache(); if (cp_cache != NULL) { - cp_cache->adjust_method_entries(the_class, &trace_name_printed); + cp_cache->adjust_method_entries(&trace_name_printed); } } @@ -3520,23 +3507,7 @@ pv_node = pv_node->previous_versions()) { cp_cache = pv_node->constants()->cache(); if (cp_cache != NULL) { - cp_cache->adjust_method_entries(pv_node, &trace_name_printed); - } - } - } -} - -// Clean method data for this class -void VM_RedefineClasses::MethodDataCleaner::do_klass(Klass* k) { - if (k->is_instance_klass()) { - InstanceKlass *ik = InstanceKlass::cast(k); - // Clean MethodData of this class's methods so they don't refer to - // old methods that are no longer running. - Array<Method*>* methods = ik->methods(); - int num_methods = methods->length(); - for (int index = 0; index < num_methods; ++index) { - if (methods->at(index)->method_data() != NULL) { - methods->at(index)->method_data()->clean_weak_method_links(); + cp_cache->adjust_method_entries(&trace_name_printed); } } } @@ -3554,6 +3525,15 @@ "should be replaced"); } } + // Update deleted jmethodID + for (int j = 0; j < _deleted_methods_length; ++j) { + Method* old_method = _deleted_methods[j]; + jmethodID jmid = old_method->find_jmethod_id_or_null(); + if (jmid != NULL) { + // Change the jmethodID to point to NSME. + Method::change_method_associated_with_jmethod_id(jmid, Universe::throw_no_such_method_error()); + } + } } int VM_RedefineClasses::check_methods_and_mark_as_obsolete() { @@ -3972,6 +3952,10 @@ InstanceKlass* the_class = get_ik(the_jclass); + // Set some flags to control and optimize adjusting method entries + _has_redefined_Object |= the_class == SystemDictionary::Object_klass(); + _has_null_class_loader |= the_class->class_loader() == NULL; + // Remove all breakpoints in methods of this class JvmtiBreakpoints& jvmti_breakpoints = JvmtiCurrentBreakpoints::get_jvmti_breakpoints(); jvmti_breakpoints.clearall_in_class_at_safepoint(the_class); @@ -4193,11 +4177,6 @@ _timer_rsc_phase2.start(); } - // Adjust constantpool caches and vtables for all classes - // that reference methods of the evolved class. - AdjustCpoolCacheAndVtable adjust_cpool_cache_and_vtable(THREAD); - ClassLoaderDataGraph::classes_do(&adjust_cpool_cache_and_vtable); - if (the_class->oop_map_cache() != NULL) { // Flush references to any obsolete methods from the oop map cache // so that obsolete methods are not pinned.
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -338,20 +338,22 @@ class VM_RedefineClasses: public VM_Operation { private: // These static fields are needed by ClassLoaderDataGraph::classes_do() - // facility and the AdjustCpoolCacheAndVtable helper: + // facility and the CheckClass and AdjustAndCleanMetadata helpers. static Array<Method*>* _old_methods; static Array<Method*>* _new_methods; - static Method** _matching_old_methods; - static Method** _matching_new_methods; - static Method** _deleted_methods; - static Method** _added_methods; + static Method** _matching_old_methods; + static Method** _matching_new_methods; + static Method** _deleted_methods; + static Method** _added_methods; static int _matching_methods_length; static int _deleted_methods_length; static int _added_methods_length; - static Klass* _the_class; + static bool _has_redefined_Object; + static bool _has_null_class_loader; // The instance fields are used to pass information from // doit_prologue() to doit() and doit_epilogue(). + Klass* _the_class; jint _class_count; const jvmtiClassDefinition *_class_defs; // ptr to _class_count defs @@ -513,20 +515,14 @@ // Unevolving classes may point to methods of the_class directly // from their constant pool caches, itables, and/or vtables. We // use the ClassLoaderDataGraph::classes_do() facility and this helper - // to fix up these pointers. - class AdjustCpoolCacheAndVtable : public KlassClosure { + // to fix up these pointers and clean MethodData out. + class AdjustAndCleanMetadata : public KlassClosure { Thread* _thread; public: - AdjustCpoolCacheAndVtable(Thread* t) : _thread(t) {} + AdjustAndCleanMetadata(Thread* t) : _thread(t) {} void do_klass(Klass* k); }; - // Clean MethodData out - class MethodDataCleaner : public KlassClosure { - public: - MethodDataCleaner() {} - void do_klass(Klass* k); - }; public: VM_RedefineClasses(jint class_count, const jvmtiClassDefinition *class_defs,
--- a/src/hotspot/share/prims/resolvedMethodTable.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/prims/resolvedMethodTable.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -120,18 +120,21 @@ return entry; } -oop ResolvedMethodTable::add_method(Handle resolved_method_name) { +oop ResolvedMethodTable::add_method(const methodHandle& m, Handle resolved_method_name) { MutexLocker ml(ResolvedMethodTable_lock); DEBUG_ONLY(NoSafepointVerifier nsv); + Method* method = m(); // Check if method has been redefined while taking out ResolvedMethodTable_lock, if so - // use new method. - Method* method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(resolved_method_name()); - assert(method->is_method(), "must be method"); + // use new method. The old method won't be deallocated because it's passed in as a Handle. if (method->is_old()) { // Replace method with redefined version InstanceKlass* holder = method->method_holder(); method = holder->method_with_idnum(method->method_idnum()); + if (method == NULL) { + // Replace deleted method with NSME. + method = Universe::throw_no_such_method_error(); + } java_lang_invoke_ResolvedMethodName::set_vmtarget(resolved_method_name(), method); } // Set flag in class to indicate this InstanceKlass has entries in the table @@ -226,18 +229,9 @@ if (old_method->is_old()) { - if (old_method->is_deleted()) { - // leave deleted method in ResolvedMethod for now (this is a bug that we don't mark - // these on_stack) - continue; - } - - InstanceKlass* holder = old_method->method_holder(); - Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum()); - assert(holder == new_method->method_holder(), "call after swapping redefined guts"); - assert(new_method != NULL, "method_with_idnum() should not be NULL"); - assert(old_method != new_method, "sanity check"); - + Method* new_method = (old_method->is_deleted()) ? + Universe::throw_no_such_method_error() : + old_method->get_new_method(); java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, new_method); ResourceMark rm;
--- a/src/hotspot/share/prims/resolvedMethodTable.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/prims/resolvedMethodTable.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -89,7 +89,7 @@ // Called from java_lang_invoke_ResolvedMethodName static oop find_method(Method* method); - static oop add_method(Handle rmethod_name); + static oop add_method(const methodHandle& method, Handle rmethod_name); static bool has_work() { return _dead_entries; } static void trigger_cleanup();
--- a/src/hotspot/share/runtime/init.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/runtime/init.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -174,10 +174,7 @@ ObjectSynchronizer::audit_and_print_stats(true /* on_exit */); } perfMemory_exit(); - if (log_is_enabled(Debug, safepoint, stats)) { - // Print the collected safepoint statistics. - SafepointSynchronize::print_stat_on_exit(); - } + SafepointTracing::statistics_exit_log(); if (PrintStringTableStatistics) { SymbolTable::dump(tty); StringTable::dump(tty);
--- a/src/hotspot/share/runtime/mutexLocker.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/runtime/mutexLocker.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -150,6 +150,9 @@ #if INCLUDE_NMT Mutex* NMTQuery_lock = NULL; #endif +#if INCLUDE_CDS && INCLUDE_JVMTI +Mutex* CDSClassFileStream_lock = NULL; +#endif #define MAX_NUM_MUTEX 128 static Monitor * _mutex_array[MAX_NUM_MUTEX]; @@ -339,6 +342,9 @@ #if INCLUDE_NMT def(NMTQuery_lock , PaddedMutex , max_nonleaf, false, Monitor::_safepoint_check_always); #endif +#if INCLUDE_CDS && INCLUDE_JVMTI + def(CDSClassFileStream_lock , PaddedMutex , max_nonleaf, false, Monitor::_safepoint_check_always); +#endif } GCMutexLocker::GCMutexLocker(Monitor * mutex) {
--- a/src/hotspot/share/runtime/mutexLocker.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/runtime/mutexLocker.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -133,6 +133,9 @@ #if INCLUDE_NMT extern Mutex* NMTQuery_lock; // serialize NMT Dcmd queries #endif +#if INCLUDE_CDS && INCLUDE_JVMTI +extern Mutex* CDSClassFileStream_lock; // FileMapInfo::open_stream_for_jvmti +#endif #if INCLUDE_JFR extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table extern Monitor* JfrMsg_lock; // protects JFR messaging
--- a/src/hotspot/share/runtime/safepoint.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/runtime/safepoint.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -103,16 +103,6 @@ } } -static void post_safepoint_wait_blocked_event(EventSafepointWaitBlocked& event, - uint64_t safepoint_id, - int initial_threads_waiting_to_block) { - if (event.should_commit()) { - event.set_safepointId(safepoint_id); - event.set_runningThreadCount(initial_threads_waiting_to_block); - event.commit(); - } -} - static void post_safepoint_cleanup_task_event(EventSafepointCleanupTask& event, uint64_t safepoint_id, const char* name) { @@ -138,27 +128,21 @@ volatile uint64_t SafepointSynchronize::_safepoint_counter = 0; const uint64_t SafepointSynchronize::InactiveSafepointCounter = 0; int SafepointSynchronize::_current_jni_active_count = 0; -long SafepointSynchronize::_end_of_last_safepoint = 0; WaitBarrier* SafepointSynchronize::_wait_barrier; -// We need a place to save the desc since it is released before we need it. -static char stopped_description[64] = ""; -static bool _vm_is_waiting = false; - static volatile bool PageArmed = false; // safepoint polling page is RO|RW vs PROT_NONE static bool timeout_error_printed = false; // Statistic related -julong SafepointSynchronize::_coalesced_vmop_count = 0; static jlong _safepoint_begin_time = 0; -static float _ts_of_current_safepoint = 0.0f; static volatile int _nof_threads_hit_polling_page = 0; void SafepointSynchronize::init(Thread* vmthread) { // WaitBarrier should never be destroyed since we will have // threads waiting on it while exiting. _wait_barrier = new WaitBarrier(vmthread); + SafepointTracing::init(); } void SafepointSynchronize::increment_jni_active_count() { @@ -244,16 +228,13 @@ DEBUG_ONLY(assert_list_is_valid(tss_head, still_running);) *initial_running = still_running; - if (log_is_enabled(Debug, safepoint, stats)) { - begin_statistics(nof_threads, still_running); - } int iterations = 1; // The first iteration is above. while (still_running > 0) { // Check if this has taken too long: if (SafepointTimeout && safepoint_limit_time < os::javaTimeNanos()) { - print_safepoint_timeout(_spinning_timeout); + print_safepoint_timeout(); } if (int(iterations) == -1) { // overflow - something is wrong. // We can only overflow here when we are using global @@ -291,9 +272,6 @@ assert(tss_head == NULL, "Must be empty"); - if (log_is_enabled(Debug, safepoint, stats)) { - update_statistics_on_spin_end(); - } return iterations; } @@ -303,8 +281,11 @@ // stopped by different mechanisms: // // 1. Running interpreted - // The interpreter dispatch table is changed to force it to - // check for a safepoint condition between bytecodes. + // When executing branching/returning byte codes interpreter + // checks if the poll is armed, if so blocks in SS::block(). + // When using global polling the interpreter dispatch table + // is changed to force it to check for a safepoint condition + // between bytecodes. // 2. Running in native code // When returning from the native code, a Java thread must check // the safepoint _state to see if we must block. If the @@ -322,9 +303,9 @@ // block condition until the safepoint operation is complete. // 5. In VM or Transitioning between states // If a Java thread is currently running in the VM or transitioning - // between states, the safepointing code will wait for the thread to - // block itself when it attempts transitions to a new state. - // + // between states, the safepointing code will poll the thread state + // until the thread blocks itself when it attempts transitions to a + // new state or locking a safepoint checked monitor. // We must never miss a thread with correct safepoint id, so we must make sure we arm // the wait barrier for the next safepoint id/counter. @@ -363,17 +344,10 @@ // Roll all threads forward to a safepoint and suspend them all void SafepointSynchronize::begin() { - EventSafepointBegin begin_event; assert(Thread::current()->is_VM_thread(), "Only VM thread may execute a safepoint"); - strncpy(stopped_description, VMThread::vm_safepoint_description(), sizeof(stopped_description) - 1); - stopped_description[sizeof(stopped_description) - 1] = '\0'; - - if (log_is_enabled(Debug, safepoint, stats)) { - _safepoint_begin_time = os::javaTimeNanos(); - _ts_of_current_safepoint = tty->time_stamp().seconds(); - _nof_threads_hit_polling_page = 0; - } + EventSafepointBegin begin_event; + SafepointTracing::begin(VMThread::vm_op_type()); Universe::heap()->safepoint_synchronize_begin(); @@ -385,10 +359,10 @@ int nof_threads = Threads::number_of_threads(); + _nof_threads_hit_polling_page = 0; + log_debug(safepoint)("Safepoint synchronization initiated using %s wait barrier. (%d threads)", _wait_barrier->description(), nof_threads); - RuntimeService::record_safepoint_begin(); - // Reset the count of active JNI critical threads _current_jni_active_count = 0; @@ -399,9 +373,9 @@ if (SafepointTimeout) { // Set the limit time, so that it can be compared to see if this has taken // too long to complete. - safepoint_limit_time = os::javaTimeNanos() + (jlong)SafepointTimeoutDelay * MICROUNITS; + safepoint_limit_time = SafepointTracing::start_of_safepoint() + (jlong)SafepointTimeoutDelay * (NANOUNITS / MILLIUNITS); + timeout_error_printed = false; } - timeout_error_printed = false; EventSafepointStateSynchronization sync_event; int initial_running = 0; @@ -413,20 +387,13 @@ int iterations = synchronize_threads(safepoint_limit_time, nof_threads, &initial_running); assert(_waiting_to_block == 0, "No thread should be running"); - post_safepoint_synchronize_event(sync_event, _safepoint_counter, initial_running, - _waiting_to_block, iterations); - - // Keep event from now. - EventSafepointWaitBlocked wait_blocked_event; - #ifndef PRODUCT - if (SafepointTimeout) { + if (safepoint_limit_time != 0) { jlong current_time = os::javaTimeNanos(); if (safepoint_limit_time < current_time) { log_warning(safepoint)("# SafepointSynchronize: Finished after " INT64_FORMAT_W(6) " ms", - (int64_t)((current_time - safepoint_limit_time) / MICROUNITS + - (jlong)SafepointTimeoutDelay)); + (int64_t)(current_time - SafepointTracing::start_of_safepoint()) / (NANOUNITS / MILLIUNITS)); } } #endif @@ -438,8 +405,6 @@ OrderAccess::fence(); - post_safepoint_wait_blocked_event(wait_blocked_event, _safepoint_counter, 0); - #ifdef ASSERT // Make sure all the threads were visited. for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur = jtiwh.next(); ) { @@ -450,12 +415,12 @@ // Update the count of active JNI critical regions GCLocker::set_jni_lock_count(_current_jni_active_count); - log_info(safepoint)("Entering safepoint region: %s", stopped_description); + post_safepoint_synchronize_event(sync_event, + _safepoint_counter, + initial_running, + _waiting_to_block, iterations); - RuntimeService::record_safepoint_synchronized(); - if (log_is_enabled(Debug, safepoint, stats)) { - update_statistics_on_sync_end(os::javaTimeNanos()); - } + SafepointTracing::synchronized(nof_threads, initial_running, _nof_threads_hit_polling_page); // We do the safepoint cleanup first since a GC related safepoint // needs cleanup to be completed before running the GC op. @@ -463,12 +428,8 @@ do_cleanup_tasks(); post_safepoint_cleanup_event(cleanup_event, _safepoint_counter); - if (log_is_enabled(Debug, safepoint, stats)) { - // Record how much time spend on the above cleanup tasks - update_statistics_on_cleanup_end(os::javaTimeNanos()); - } - post_safepoint_begin_event(begin_event, _safepoint_counter, nof_threads, _current_jni_active_count); + SafepointTracing::cleanup(); } void SafepointSynchronize::disarm_safepoint() { @@ -520,10 +481,6 @@ } } // ~JavaThreadIteratorWithHandle - log_info(safepoint)("Leaving safepoint region"); - - RuntimeService::record_safepoint_end(); - // Release threads lock, so threads can be created/destroyed again. Threads_lock->unlock(); @@ -539,19 +496,11 @@ uint64_t safepoint_id = _safepoint_counter; assert(Thread::current()->is_VM_thread(), "Only VM thread can execute a safepoint"); - if (log_is_enabled(Debug, safepoint, stats)) { - end_statistics(os::javaTimeNanos()); - } - disarm_safepoint(); - RuntimeService::record_safepoint_epilog(stopped_description); - Universe::heap()->safepoint_synchronize_end(); - // record this time so VMThread can keep track how much time has elapsed - // since last safepoint. - _end_of_last_safepoint = os::javaTimeMillis(); + SafepointTracing::end(); post_safepoint_end_event(event, safepoint_id); } @@ -915,7 +864,7 @@ assert(SafepointSynchronize::is_synchronizing(), "polling encountered outside safepoint synchronization"); } - if (log_is_enabled(Debug, safepoint, stats)) { + if (log_is_enabled(Info, safepoint, stats)) { Atomic::inc(&_nof_threads_hit_polling_page); } @@ -925,7 +874,7 @@ } -void SafepointSynchronize::print_safepoint_timeout(SafepointTimeoutReason reason) { +void SafepointSynchronize::print_safepoint_timeout() { if (!timeout_error_printed) { timeout_error_printed = true; // Print out the thread info which didn't reach the safepoint for debugging @@ -937,20 +886,10 @@ ls.cr(); ls.print_cr("# SafepointSynchronize::begin: Timeout detected:"); - if (reason == _spinning_timeout) { - ls.print_cr("# SafepointSynchronize::begin: Timed out while spinning to reach a safepoint."); - } else if (reason == _blocking_timeout) { - ls.print_cr("# SafepointSynchronize::begin: Timed out while waiting for threads to stop."); - } - + ls.print_cr("# SafepointSynchronize::begin: Timed out while spinning to reach a safepoint."); ls.print_cr("# SafepointSynchronize::begin: Threads which did not reach the safepoint:"); - ThreadSafepointState *cur_state; for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur_thread = jtiwh.next(); ) { - cur_state = cur_thread->safepoint_state(); - - if (cur_thread->thread_state() != _thread_blocked && - ((reason == _spinning_timeout && cur_state->is_running()) || - (reason == _blocking_timeout))) { + if (cur_thread->safepoint_state()->is_running()) { ls.print("# "); cur_thread->print_on(&ls); ls.cr(); @@ -964,11 +903,10 @@ // ShowMessageBoxOnError. if (AbortVMOnSafepointTimeout) { fatal("Safepoint sync time longer than " INTX_FORMAT "ms detected when executing %s.", - SafepointTimeoutDelay, VMThread::vm_safepoint_description()); + SafepointTimeoutDelay, VMThread::vm_operation()->name()); } } - // ------------------------------------------------------------------------------------------------------- // Implementation of ThreadSafepointState @@ -1176,108 +1114,25 @@ } -// -// Statistics & Instrumentations -// -struct SafepointStats { - float _time_stamp; // record when the current safepoint occurs in seconds - int _vmop_type; // tyep of VM operation triggers the safepoint - int _nof_total_threads; // total number of Java threads - int _nof_initial_running_threads; // total number of initially seen running threads - int _nof_threads_wait_to_block; // total number of threads waiting for to block - bool _page_armed; // true if polling page is armed, false otherwise - int _nof_threads_hit_page_trap; // total number of threads hitting the page trap - jlong _time_to_spin; // total time in millis spent in spinning - jlong _time_to_wait_to_block; // total time in millis spent in waiting for to block - jlong _time_to_do_cleanups; // total time in millis spent in performing cleanups - jlong _time_to_sync; // total time in millis spent in getting to _synchronized - jlong _time_to_exec_vmop; // total time in millis spent in vm operation itself -}; +// ------------------------------------------------------------------------------------------------------- +// Implementation of SafepointTracing -static const int _statistics_header_count = 30; -static int _cur_stat_index = 0; -static SafepointStats safepoint_stats = {0}; // zero initialize -static SafepointStats* spstat = &safepoint_stats; +jlong SafepointTracing::_last_safepoint_begin_time_ns = 0; +jlong SafepointTracing::_last_safepoint_sync_time_ns = 0; +jlong SafepointTracing::_last_safepoint_cleanup_time_ns = 0; +jlong SafepointTracing::_last_safepoint_end_time_ns = 0; +jlong SafepointTracing::_last_app_time_ns = 0; +int SafepointTracing::_nof_threads = 0; +int SafepointTracing::_nof_running = 0; +int SafepointTracing::_page_trap = 0; +VM_Operation::VMOp_Type SafepointTracing::_current_type; +jlong SafepointTracing::_max_sync_time = 0; +jlong SafepointTracing::_max_vmop_time = 0; +uint64_t SafepointTracing::_op_count[VM_Operation::VMOp_Terminating] = {0}; -static julong _safepoint_reasons[VM_Operation::VMOp_Terminating]; -static jlong _max_sync_time = 0; -static jlong _max_vmop_time = 0; - -static jlong cleanup_end_time = 0; - -void SafepointSynchronize::begin_statistics(int nof_threads, int nof_running) { - - spstat->_time_stamp = _ts_of_current_safepoint; - - VM_Operation *op = VMThread::vm_operation(); - spstat->_vmop_type = op != NULL ? op->type() : VM_Operation::VMOp_None; - _safepoint_reasons[spstat->_vmop_type]++; - - spstat->_nof_total_threads = nof_threads; - spstat->_nof_initial_running_threads = nof_running; - - // Records the start time of spinning. The real time spent on spinning - // will be adjusted when spin is done. Same trick is applied for time - // spent on waiting for threads to block. - if (nof_running != 0) { - spstat->_time_to_spin = os::javaTimeNanos(); - } else { - spstat->_time_to_spin = 0; - } -} - -void SafepointSynchronize::update_statistics_on_spin_end() { - jlong cur_time = os::javaTimeNanos(); - - spstat->_nof_threads_wait_to_block = _waiting_to_block; - if (spstat->_nof_initial_running_threads != 0) { - spstat->_time_to_spin = cur_time - spstat->_time_to_spin; - } - - // Records the start time of waiting for to block. Updated when block is done. - if (_waiting_to_block != 0) { - spstat->_time_to_wait_to_block = cur_time; - } else { - spstat->_time_to_wait_to_block = 0; - } -} - -void SafepointSynchronize::update_statistics_on_sync_end(jlong end_time) { - - if (spstat->_nof_threads_wait_to_block != 0) { - spstat->_time_to_wait_to_block = end_time - - spstat->_time_to_wait_to_block; - } - - // Records the end time of sync which will be used to calculate the total - // vm operation time. Again, the real time spending in syncing will be deducted - // from the start of the sync time later when end_statistics is called. - spstat->_time_to_sync = end_time - _safepoint_begin_time; - if (spstat->_time_to_sync > _max_sync_time) { - _max_sync_time = spstat->_time_to_sync; - } - - spstat->_time_to_do_cleanups = end_time; -} - -void SafepointSynchronize::update_statistics_on_cleanup_end(jlong end_time) { - - // Record how long spent in cleanup tasks. - spstat->_time_to_do_cleanups = end_time - spstat->_time_to_do_cleanups; - cleanup_end_time = end_time; -} - -void SafepointSynchronize::end_statistics(jlong vmop_end_time) { - - // Update the vm operation time. - spstat->_time_to_exec_vmop = vmop_end_time - cleanup_end_time; - if (spstat->_time_to_exec_vmop > _max_vmop_time) { - _max_vmop_time = spstat->_time_to_exec_vmop; - } - - spstat->_nof_threads_hit_page_trap = _nof_threads_hit_polling_page; - - print_statistics(); +void SafepointTracing::init() { + // Application start + _last_safepoint_end_time_ns = os::javaTimeNanos(); } // Helper method to print the header. @@ -1285,66 +1140,121 @@ // The number of spaces is significant here, and should match the format // specifiers in print_statistics(). - st->print(" vmop " - "[ threads: total initially_running wait_to_block ]" - "[ time: spin block sync cleanup vmop ] "); + st->print("VM Operation " + "[ threads: total initial_running ]" + "[ time: sync cleanup vmop total ]"); - st->print_cr("page_trap_count"); + st->print_cr(" page_trap_count"); } // This prints a nice table. To get the statistics to not shift due to the logging uptime -// decorator, use the option as: -Xlog:safepoint+stats=debug:[outputfile]:none -void SafepointSynchronize::print_statistics() { - LogTarget(Debug, safepoint, stats) lt; +// decorator, use the option as: -Xlog:safepoint+stats:[outputfile]:none +void SafepointTracing::statistics_log() { + LogTarget(Info, safepoint, stats) lt; assert (lt.is_enabled(), "should only be called when printing statistics is enabled"); LogStream ls(lt); + static int _cur_stat_index = 0; + // Print header every 30 entries - if ((_cur_stat_index % _statistics_header_count) == 0) { + if ((_cur_stat_index % 30) == 0) { print_header(&ls); _cur_stat_index = 1; // wrap } else { _cur_stat_index++; } - ls.print("%8.3f: ", spstat->_time_stamp); - ls.print("%-28s [ " - INT32_FORMAT_W(8) " " INT32_FORMAT_W(17) " " INT32_FORMAT_W(13) " " + ls.print("%-28s [ " + INT32_FORMAT_W(8) " " INT32_FORMAT_W(8) " " "]", - VM_Operation::name(spstat->_vmop_type), - spstat->_nof_total_threads, - spstat->_nof_initial_running_threads, - spstat->_nof_threads_wait_to_block); - // "/ MICROUNITS " is to convert the unit from nanos to millis. + VM_Operation::name(_current_type), + _nof_threads, + _nof_running); ls.print("[ " - INT64_FORMAT_W(7) " " INT64_FORMAT_W(7) " " - INT64_FORMAT_W(7) " " INT64_FORMAT_W(7) " " - INT64_FORMAT_W(7) " ] ", - (int64_t)(spstat->_time_to_spin / MICROUNITS), - (int64_t)(spstat->_time_to_wait_to_block / MICROUNITS), - (int64_t)(spstat->_time_to_sync / MICROUNITS), - (int64_t)(spstat->_time_to_do_cleanups / MICROUNITS), - (int64_t)(spstat->_time_to_exec_vmop / MICROUNITS)); + INT64_FORMAT_W(10) " " INT64_FORMAT_W(10) " " + INT64_FORMAT_W(10) " " INT64_FORMAT_W(10) " ]", + (int64_t)(_last_safepoint_sync_time_ns - _last_safepoint_begin_time_ns), + (int64_t)(_last_safepoint_cleanup_time_ns - _last_safepoint_sync_time_ns), + (int64_t)(_last_safepoint_end_time_ns - _last_safepoint_cleanup_time_ns), + (int64_t)(_last_safepoint_end_time_ns - _last_safepoint_begin_time_ns)); - ls.print_cr(INT32_FORMAT_W(15) " ", spstat->_nof_threads_hit_page_trap); + ls.print_cr(INT32_FORMAT_W(16), _page_trap); } // This method will be called when VM exits. This tries to summarize the sampling. // Current thread may already be deleted, so don't use ResourceMark. -void SafepointSynchronize::print_stat_on_exit() { - +void SafepointTracing::statistics_exit_log() { + if (!log_is_enabled(Info, safepoint, stats)) { + return; + } for (int index = 0; index < VM_Operation::VMOp_Terminating; index++) { - if (_safepoint_reasons[index] != 0) { - log_debug(safepoint, stats)("%-28s" UINT64_FORMAT_W(10), VM_Operation::name(index), - _safepoint_reasons[index]); + if (_op_count[index] != 0) { + log_info(safepoint, stats)("%-28s" UINT64_FORMAT_W(10), VM_Operation::name(index), + _op_count[index]); } } - log_debug(safepoint, stats)("VM operations coalesced during safepoint " INT64_FORMAT, - _coalesced_vmop_count); - log_debug(safepoint, stats)("Maximum sync time " INT64_FORMAT" ms", - (int64_t)(_max_sync_time / MICROUNITS)); - log_debug(safepoint, stats)("Maximum vm operation time (except for Exit VM operation) " - INT64_FORMAT " ms", - (int64_t)(_max_vmop_time / MICROUNITS)); + log_info(safepoint, stats)("VM operations coalesced during safepoint " INT64_FORMAT, + VMThread::get_coalesced_count()); + log_info(safepoint, stats)("Maximum sync time " INT64_FORMAT" ns", + (int64_t)(_max_sync_time)); + log_info(safepoint, stats)("Maximum vm operation time (except for Exit VM operation) " + INT64_FORMAT " ns", + (int64_t)(_max_vmop_time)); } + +void SafepointTracing::begin(VM_Operation::VMOp_Type type) { + _op_count[type]++; + _current_type = type; + + // update the time stamp to begin recording safepoint time + _last_safepoint_begin_time_ns = os::javaTimeNanos(); + _last_safepoint_sync_time_ns = 0; + _last_safepoint_cleanup_time_ns = 0; + + _last_app_time_ns = _last_safepoint_begin_time_ns - _last_safepoint_end_time_ns; + _last_safepoint_end_time_ns = 0; + + RuntimeService::record_safepoint_begin(_last_app_time_ns); +} + +void SafepointTracing::synchronized(int nof_threads, int nof_running, int traps) { + _last_safepoint_sync_time_ns = os::javaTimeNanos(); + _nof_threads = nof_threads; + _nof_running = nof_running; + _page_trap = traps; + RuntimeService::record_safepoint_synchronized(_last_safepoint_sync_time_ns - _last_safepoint_begin_time_ns); +} + +void SafepointTracing::cleanup() { + _last_safepoint_cleanup_time_ns = os::javaTimeNanos(); +} + +void SafepointTracing::end() { + _last_safepoint_end_time_ns = os::javaTimeNanos(); + + if (_max_sync_time < (_last_safepoint_sync_time_ns - _last_safepoint_begin_time_ns)) { + _max_sync_time = _last_safepoint_sync_time_ns - _last_safepoint_begin_time_ns; + } + if (_max_vmop_time < (_last_safepoint_end_time_ns - _last_safepoint_sync_time_ns)) { + _max_vmop_time = _last_safepoint_end_time_ns - _last_safepoint_sync_time_ns; + } + if (log_is_enabled(Info, safepoint, stats)) { + statistics_log(); + } + + log_info(safepoint)( + "Safepoint \"%s\", " + "Time since last: " JLONG_FORMAT " ns, " + "Reaching safepoint: " JLONG_FORMAT " ns, " + "At safepoint: " JLONG_FORMAT " ns, " + "Total: " JLONG_FORMAT " ns", + VM_Operation::name(_current_type), + _last_app_time_ns, + _last_safepoint_cleanup_time_ns - _last_safepoint_begin_time_ns, + _last_safepoint_end_time_ns - _last_safepoint_cleanup_time_ns, + _last_safepoint_end_time_ns - _last_safepoint_begin_time_ns + ); + + RuntimeService::record_safepoint_end(_last_safepoint_end_time_ns - _last_safepoint_cleanup_time_ns); +}
--- a/src/hotspot/share/runtime/safepoint.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/runtime/safepoint.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "runtime/os.hpp" #include "runtime/thread.hpp" +#include "runtime/vmOperations.hpp" #include "utilities/ostream.hpp" #include "utilities/waitBarrier.hpp" @@ -77,11 +78,6 @@ friend class ThreadSafepointState; friend class HandshakeState; - enum SafepointTimeoutReason { - _spinning_timeout = 0, - _blocking_timeout = 1 - }; - // Threads might read this flag directly, without acquiring the Threads_lock: static volatile SynchronizeState _state; // Number of threads we are waiting for to block: @@ -110,7 +106,7 @@ static void print_statistics(); // For debug long safepoint - static void print_safepoint_timeout(SafepointTimeoutReason timeout_reason); + static void print_safepoint_timeout(); // Helper methods for safepoint procedure: static void arm_safepoint(); @@ -150,19 +146,9 @@ // Exception handling for page polling static void handle_polling_page_exception(JavaThread *thread); - // VM Thread interface for determining safepoint rate - static long last_non_safepoint_interval() { - return os::javaTimeMillis() - _end_of_last_safepoint; - } - static long end_of_last_safepoint() { - return _end_of_last_safepoint; - } static bool is_cleanup_needed(); static void do_cleanup_tasks(); - static void print_stat_on_exit(); - static void inc_vmop_coalesced_count() { _coalesced_vmop_count++; } - static void set_is_at_safepoint() { _state = _synchronized; } static void set_is_not_at_safepoint() { _state = _not_synchronized; } @@ -247,6 +233,48 @@ static void destroy(JavaThread *thread); }; +class SafepointTracing : public AllStatic { +private: + // Absolute + static jlong _last_safepoint_begin_time_ns; + static jlong _last_safepoint_sync_time_ns; + static jlong _last_safepoint_cleanup_time_ns; + static jlong _last_safepoint_end_time_ns; + // Relative + static jlong _last_app_time_ns; + static int _nof_threads; + static int _nof_running; + static int _page_trap; + + static VM_Operation::VMOp_Type _current_type; + static jlong _max_sync_time; + static jlong _max_vmop_time; + static uint64_t _op_count[VM_Operation::VMOp_Terminating]; + + static void statistics_log(); + +public: + static void init(); + + static void begin(VM_Operation::VMOp_Type type); + static void synchronized(int nof_threads, int nof_running, int traps); + static void cleanup(); + static void end(); + + static void statistics_exit_log(); + + static jlong time_since_last_safepoint_ms() { + return (os::javaTimeNanos() - _last_safepoint_end_time_ns) / (NANOUNITS / MILLIUNITS); + } + + static jlong end_of_last_safepoint_ms() { + return _last_safepoint_end_time_ns / (NANOUNITS / MILLIUNITS); + } + + static jlong start_of_safepoint() { + return _last_safepoint_begin_time_ns; + } +}; #endif // SHARE_RUNTIME_SAFEPOINT_HPP
--- a/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -479,7 +479,7 @@ // We don't update the rate if we've just came out of a safepoint. // delta_s is the time since last safepoint in milliseconds. - jlong delta_s = t - SafepointSynchronize::end_of_last_safepoint(); + jlong delta_s = t - SafepointTracing::end_of_last_safepoint_ms(); jlong delta_t = t - (m->prev_time() != 0 ? m->prev_time() : start_time()); // milliseconds since the last measurement // How many events were there since the last time? int event_count = m->invocation_count() + m->backedge_count(); @@ -504,7 +504,7 @@ // Check if this method has been stale from a given number of milliseconds. // See select_task(). bool TieredThresholdPolicy::is_stale(jlong t, jlong timeout, Method* m) { - jlong delta_s = t - SafepointSynchronize::end_of_last_safepoint(); + jlong delta_s = t - SafepointTracing::end_of_last_safepoint_ms(); jlong delta_t = t - m->prev_time(); if (delta_t > timeout && delta_s > timeout) { int event_count = m->invocation_count() + m->backedge_count();
--- a/src/hotspot/share/runtime/vmOperations.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/runtime/vmOperations.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -41,6 +41,7 @@ // Note: When new VM_XXX comes up, add 'XXX' to the template table. #define VM_OPS_DO(template) \ template(None) \ + template(Cleanup) \ template(ThreadStop) \ template(ThreadDump) \ template(PrintThreads) \ @@ -213,7 +214,7 @@ // Debugging virtual void print_on_error(outputStream* st) const; - const char* name() const { return _names[type()]; } + virtual const char* name() const { return _names[type()]; } static const char* name(int type) { assert(type >= 0 && type < VMOp_Terminating, "invalid VM operation type"); return _names[type]; @@ -223,6 +224,21 @@ #endif }; +class VM_None: public VM_Operation { + const char* _reason; + public: + VM_None(const char* reason) : _reason(reason) {} + const char* name() const { return _reason; } + VMOp_Type type() const { return VMOp_None; } + void doit() {}; +}; + +class VM_Cleanup: public VM_Operation { + public: + VMOp_Type type() const { return VMOp_Cleanup; } + void doit() {}; +}; + class VM_ThreadStop: public VM_Operation { private: oop _thread; // The Thread that the Throwable is thrown against
--- a/src/hotspot/share/runtime/vmThread.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/runtime/vmThread.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -48,19 +48,13 @@ #include "utilities/vmError.hpp" #include "utilities/xmlstream.hpp" -// Dummy VM operation to act as first element in our circular double-linked list -class VM_None: public VM_Operation { - VMOp_Type type() const { return VMOp_None; } - void doit() {}; -}; - VMOperationQueue::VMOperationQueue() { // The queue is a circular doubled-linked list, which always contains // one element (i.e., one element means empty). for(int i = 0; i < nof_priorities; i++) { _queue_length[i] = 0; _queue_counter = 0; - _queue[i] = new VM_None(); + _queue[i] = new VM_None("QueueHead"); _queue[i]->set_next(_queue[i]); _queue[i]->set_prev(_queue[i]); } @@ -229,14 +223,14 @@ //------------------------------------------------------------------------------------------------------------------ // Implementation of VMThread stuff -bool VMThread::_should_terminate = false; +bool VMThread::_should_terminate = false; bool VMThread::_terminated = false; Monitor* VMThread::_terminate_lock = NULL; VMThread* VMThread::_vm_thread = NULL; VM_Operation* VMThread::_cur_vm_operation = NULL; VMOperationQueue* VMThread::_vm_queue = NULL; PerfCounter* VMThread::_perf_accumulated_vm_operation_time = NULL; -const char* VMThread::_no_op_reason = NULL; +uint64_t VMThread::_coalesced_count = 0; VMOperationTimeoutTask* VMThread::_timeout_task = NULL; @@ -283,6 +277,8 @@ _vm_thread = NULL; // VM thread is gone } +static VM_None halt_op("Halt"); + void VMThread::run() { assert(this == vm_thread(), "check"); @@ -320,7 +316,7 @@ } // 4526887 let VM thread exit at Safepoint - _no_op_reason = "Halt"; + _cur_vm_operation = &halt_op; SafepointSynchronize::begin(); if (VerifyBeforeExit) { @@ -435,24 +431,25 @@ } } -bool VMThread::no_op_safepoint_needed(bool check_time) { +static VM_None safepointALot_op("SafepointALot"); +static VM_Cleanup cleanup_op; + +VM_Operation* VMThread::no_op_safepoint(bool check_time) { if (SafepointALot) { - _no_op_reason = "SafepointALot"; - return true; + return &safepointALot_op; } if (!SafepointSynchronize::is_cleanup_needed()) { - return false; + return NULL; } if (check_time) { - long interval = SafepointSynchronize::last_non_safepoint_interval(); + long interval_ms = SafepointTracing::time_since_last_safepoint_ms(); bool max_time_exceeded = GuaranteedSafepointInterval != 0 && - (interval > GuaranteedSafepointInterval); + (interval_ms > GuaranteedSafepointInterval); if (!max_time_exceeded) { - return false; + return NULL; } } - _no_op_reason = "Cleanup"; - return true; + return &cleanup_op; } void VMThread::loop() { @@ -494,7 +491,7 @@ exit(-1); } - if (timedout && VMThread::no_op_safepoint_needed(false)) { + if (timedout && (_cur_vm_operation = VMThread::no_op_safepoint(false)) != NULL) { MutexUnlockerEx mul(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag); // Force a safepoint since we have not had one for at least @@ -506,6 +503,7 @@ if (GCALotAtAllSafepoints) InterfaceSupport::check_gc_alot(); #endif SafepointSynchronize::end(); + _cur_vm_operation = NULL; } _cur_vm_operation = _vm_queue->remove_next(); @@ -555,9 +553,7 @@ _vm_queue->set_drain_list(next); evaluate_operation(_cur_vm_operation); _cur_vm_operation = next; - if (log_is_enabled(Debug, safepoint, stats)) { - SafepointSynchronize::inc_vmop_coalesced_count(); - } + _coalesced_count++; } while (_cur_vm_operation != NULL); } // There is a chance that a thread enqueued a safepoint op @@ -622,10 +618,11 @@ // // We want to make sure that we get to a safepoint regularly. // - if (VMThread::no_op_safepoint_needed(true)) { + if ((_cur_vm_operation = VMThread::no_op_safepoint(false)) != NULL) { HandleMark hm(VMThread::vm_thread()); SafepointSynchronize::begin(); SafepointSynchronize::end(); + _cur_vm_operation = NULL; } } }
--- a/src/hotspot/share/runtime/vmThread.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/runtime/vmThread.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -119,12 +119,11 @@ static bool _terminated; static Monitor * _terminate_lock; static PerfCounter* _perf_accumulated_vm_operation_time; - - static const char* _no_op_reason; + static uint64_t _coalesced_count; static VMOperationTimeoutTask* _timeout_task; - static bool no_op_safepoint_needed(bool check_time); + static VM_Operation* no_op_safepoint(bool check_time); void evaluate_operation(VM_Operation* op); @@ -155,9 +154,8 @@ // Returns the current vm operation if any. static VM_Operation* vm_operation() { return _cur_vm_operation; } - - // Returns the current vm operation name or set reason - static const char* vm_safepoint_description() { return _cur_vm_operation != NULL ? _cur_vm_operation->name() : _no_op_reason; }; + static VM_Operation::VMOp_Type vm_op_type() { return _cur_vm_operation->type(); } + static uint64_t get_coalesced_count() { return _coalesced_count; } // Returns the single instance of VMThread. static VMThread* vm_thread() { return _vm_thread; }
--- a/src/hotspot/share/services/diagnosticArgument.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/services/diagnosticArgument.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -180,7 +180,7 @@ _value = NULL; } else { _value = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal); - int n = snprintf(_value, len + 1, "%.*s", (int)len, str); + int n = os::snprintf(_value, len + 1, "%.*s", (int)len, str); assert((size_t)n <= len, "Unexpected number of characters in string"); } }
--- a/src/hotspot/share/services/runtimeService.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/services/runtimeService.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" #include "logging/log.hpp" -#include "runtime/timer.hpp" +#include "logging/logStream.hpp" #include "runtime/vm_version.hpp" #include "services/attachListener.hpp" #include "services/management.hpp" @@ -35,18 +35,12 @@ #include "utilities/macros.hpp" #if INCLUDE_MANAGEMENT -TimeStamp RuntimeService::_app_timer; -TimeStamp RuntimeService::_safepoint_timer; PerfCounter* RuntimeService::_sync_time_ticks = NULL; PerfCounter* RuntimeService::_total_safepoints = NULL; PerfCounter* RuntimeService::_safepoint_time_ticks = NULL; PerfCounter* RuntimeService::_application_time_ticks = NULL; -jlong RuntimeService::_last_safepoint_sync_time_ns = 0; -jlong RuntimeService::_last_safepoint_end_time_ns = 0; -jlong RuntimeService::_last_app_time_ns = 0; void RuntimeService::init() { - if (UsePerfData) { EXCEPTION_MARK; @@ -87,85 +81,27 @@ } } -void RuntimeService::record_safepoint_begin() { +void RuntimeService::record_safepoint_begin(jlong app_ticks) { HS_PRIVATE_SAFEPOINT_BEGIN(); - - // Print the time interval in which the app was executing - if (_app_timer.is_updated()) { - _last_app_time_ns = _app_timer.ticks_since_update(); - log_info(safepoint)("Application time: %3.7f seconds", TimeHelper::counter_to_seconds(_last_app_time_ns)); - } - - // update the time stamp to begin recording safepoint time - _last_safepoint_sync_time_ns = 0; - _last_safepoint_end_time_ns = 0; - _safepoint_timer.update(); if (UsePerfData) { _total_safepoints->inc(); - if (_app_timer.is_updated()) { - _application_time_ticks->inc(_app_timer.ticks_since_update()); - } + _application_time_ticks->inc(app_ticks); } } -void RuntimeService::record_safepoint_synchronized() { +void RuntimeService::record_safepoint_synchronized(jlong sync_ticks) { if (UsePerfData) { - _sync_time_ticks->inc(_safepoint_timer.ticks_since_update()); - } - if (log_is_enabled(Info, safepoint) || log_is_enabled(Info, safepoint, stats)) { - _last_safepoint_sync_time_ns = _safepoint_timer.ticks_since_update(); + _sync_time_ticks->inc(sync_ticks); } } -void RuntimeService::record_safepoint_end() { +void RuntimeService::record_safepoint_end(jlong safepoint_ticks) { HS_PRIVATE_SAFEPOINT_END(); - - // Logging of safepoint+stats=info needs _last_safepoint_end_time_ns to be set. - // Logging of safepoint=info needs _last_safepoint_end_time_ns for following log. - if (log_is_enabled(Info, safepoint) || log_is_enabled(Info, safepoint, stats)) { - _last_safepoint_end_time_ns = _safepoint_timer.ticks_since_update(); - log_info(safepoint)( - "Total time for which application threads were stopped: %3.7f seconds, " - "Stopping threads took: %3.7f seconds", - TimeHelper::counter_to_seconds(_last_safepoint_end_time_ns), - TimeHelper::counter_to_seconds(_last_safepoint_sync_time_ns)); - } - - // update the time stamp to begin recording app time - _app_timer.update(); if (UsePerfData) { - _safepoint_time_ticks->inc(_safepoint_timer.ticks_since_update()); + _safepoint_time_ticks->inc(safepoint_ticks); } } -void RuntimeService::record_safepoint_epilog(const char* operation_name) { - if (!log_is_enabled(Info, safepoint, stats)) { - return; - } - - log_info(safepoint, stats)( - "Safepoint \"%s\", " - "Time since last: " JLONG_FORMAT " ns; " - "Reaching safepoint: " JLONG_FORMAT " ns; " - "At safepoint: " JLONG_FORMAT " ns; " - "Total: " JLONG_FORMAT " ns", - operation_name, - _last_app_time_ns, - _last_safepoint_sync_time_ns, - _last_safepoint_end_time_ns - _last_safepoint_sync_time_ns, - _last_safepoint_end_time_ns - ); -} - -void RuntimeService::record_application_start() { - // update the time stamp to begin recording app time - _app_timer.update(); -} - -// Don't need to record application end because we currently -// exit at a safepoint and record_safepoint_begin() handles updating -// the application time counter at VM exit. - jlong RuntimeService::safepoint_sync_time_ms() { return UsePerfData ? Management::ticks_to_ms(_sync_time_ticks->get_value()) : -1;
--- a/src/hotspot/share/services/runtimeService.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/services/runtimeService.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -35,12 +35,6 @@ static PerfCounter* _safepoint_time_ticks; // Accumulated time at safepoints static PerfCounter* _application_time_ticks; // Accumulated time not at safepoints - static TimeStamp _safepoint_timer; - static TimeStamp _app_timer; - static jlong _last_safepoint_sync_time_ns; - static jlong _last_safepoint_end_time_ns; - static jlong _last_app_time_ns; - public: static void init(); @@ -50,12 +44,9 @@ static jlong application_time_ms(); // callbacks - static void record_safepoint_begin() NOT_MANAGEMENT_RETURN; - static void record_safepoint_synchronized() NOT_MANAGEMENT_RETURN; - static void record_safepoint_end() NOT_MANAGEMENT_RETURN; - static void record_safepoint_epilog(const char* operation_name) NOT_MANAGEMENT_RETURN; - static void record_application_start() NOT_MANAGEMENT_RETURN; - + static void record_safepoint_begin(jlong app_ticks) NOT_MANAGEMENT_RETURN; + static void record_safepoint_synchronized(jlong sync_ticks) NOT_MANAGEMENT_RETURN; + static void record_safepoint_end(jlong safepoint_ticks) NOT_MANAGEMENT_RETURN; }; #endif // SHARE_SERVICES_RUNTIMESERVICE_HPP
--- a/src/hotspot/share/utilities/debug.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/utilities/debug.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -643,6 +643,7 @@ tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or"); tty->print_cr(" pns($sp, $ebp, $pc) on Linux/x86 or"); tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or"); + tty->print_cr(" pns($sp, $s8, $pc) on Linux/mips or"); tty->print_cr(" pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC"); tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()"); tty->print_cr(" - in dbx do 'frame 1' before calling pns()");
--- a/src/hotspot/share/utilities/intHisto.cpp Fri Feb 22 14:51:06 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2001, 2012, 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. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "utilities/intHisto.hpp" - -IntHistogram::IntHistogram(int est, int max) : _max(max), _tot(0) { - assert(0 <= est && est <= max, "Preconditions"); - _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<int>(est, true); - guarantee(_elements != NULL, "alloc failure"); -} - -void IntHistogram::add_entry(int outcome) { - if (outcome > _max) outcome = _max; - int new_count = _elements->at_grow(outcome) + 1; - _elements->at_put(outcome, new_count); - _tot++; -} - -int IntHistogram::entries_for_outcome(int outcome) { - return _elements->at_grow(outcome); -} - -void IntHistogram::print_on(outputStream* st) const { - double tot_d = (double)_tot; - st->print_cr("Outcome # of occurrences %% of occurrences"); - st->print_cr("-----------------------------------------------"); - for (int i=0; i < _elements->length()-2; i++) { - int cnt = _elements->at(i); - if (cnt != 0) { - st->print_cr("%7d %10d %8.4f", - i, cnt, (double)cnt/tot_d); - } - } - // Does it have any max entries? - if (_elements->length()-1 == _max) { - int cnt = _elements->at(_max); - st->print_cr(">= %4d %10d %8.4f", - _max, cnt, (double)cnt/tot_d); - } - st->print_cr("-----------------------------------------------"); - st->print_cr(" All %10d %8.4f", _tot, 1.0); -}
--- a/src/hotspot/share/utilities/intHisto.hpp Fri Feb 22 14:51:06 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2001, 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. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_UTILITIES_INTHISTO_HPP -#define SHARE_UTILITIES_INTHISTO_HPP - -#include "memory/allocation.hpp" -#include "utilities/growableArray.hpp" - -// This class implements a simple histogram. - -// A histogram summarizes a series of "measurements", each of which is -// assumed (required in this implementation) to have an outcome that is a -// non-negative integer. The histogram efficiently maps measurement outcomes -// to the number of measurements had that outcome. - -// To print the results, invoke print() on your Histogram*. - -// Note: there is already an existing "Histogram" class, in file -// histogram.{hpp,cpp}, but to my mind that's not a histogram, it's a table -// mapping strings to counts. To be a histogram (IMHO) it needs to map -// numbers (in fact, integers) to number of occurrences of that number. - -// ysr: (i am not sure i agree with the above note.) i suspect we want to have a -// histogram template that will map an arbitrary type (with a defined order -// relation) to a count. - - -class IntHistogram : public CHeapObj<mtInternal> { - protected: - int _max; - int _tot; - GrowableArray<int>* _elements; - -public: - // Create a new, empty table. "est" is an estimate of the maximum outcome - // that will be added, and "max" is an outcome such that all outcomes at - // least that large will be bundled with it. - IntHistogram(int est, int max); - // Add a measurement with the given outcome to the sequence. - void add_entry(int outcome); - // Return the number of entries recorded so far with the given outcome. - int entries_for_outcome(int outcome); - // Return the total number of entries recorded so far. - int total_entries() { return _tot; } - // Return the number of entries recorded so far with the given outcome as - // a fraction of the total number recorded so far. - double fraction_for_outcome(int outcome) { - return - (double)entries_for_outcome(outcome)/ - (double)total_entries(); - } - // Print the histogram on the given output stream. - void print_on(outputStream* st) const; -}; - -#endif // SHARE_UTILITIES_INTHISTO_HPP
--- a/src/hotspot/share/utilities/ostream.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/utilities/ostream.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -559,18 +559,6 @@ fflush(_file); } -fdStream::fdStream(const char* file_name) { - _fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); - _need_close = true; -} - -fdStream::~fdStream() { - if (_fd != -1) { - if (_need_close) close(_fd); - _fd = -1; - } -} - void fdStream::write(const char* s, size_t len) { if (_fd != -1) { // Make an unused local variable to avoid warning from gcc 4.x compiler.
--- a/src/hotspot/share/utilities/ostream.hpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/utilities/ostream.hpp Thu Feb 28 22:05:33 2019 +0100 @@ -216,7 +216,6 @@ fileStream(FILE* file, bool need_close = false) { _file = file; _need_close = need_close; } ~fileStream(); bool is_open() const { return _file != NULL; } - void set_need_close(bool b) { _need_close = b;} virtual void write(const char* c, size_t len); size_t read(void *data, size_t size, size_t count) { return ::fread(data, size, count, _file); } char* readln(char *data, int count); @@ -235,13 +234,10 @@ class fdStream : public outputStream { protected: int _fd; - bool _need_close; public: - fdStream(const char* file_name); - fdStream(int fd = -1) { _fd = fd; _need_close = false; } - ~fdStream(); + fdStream(int fd = -1) : _fd(fd) { } bool is_open() const { return _fd != -1; } - void set_fd(int fd) { _fd = fd; _need_close = false; } + void set_fd(int fd) { _fd = fd; } int fd() const { return _fd; } virtual void write(const char* c, size_t len); void flush() {};
--- a/src/hotspot/share/utilities/xmlstream.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/hotspot/share/utilities/xmlstream.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -356,11 +356,11 @@ size_t kind_len; if (kind_end != NULL) { kind_len = kind_end - kind; - int n = snprintf(buffer, sizeof(buffer), "%.*s_done", (int)kind_len, kind); + int n = os::snprintf(buffer, sizeof(buffer), "%.*s_done", (int)kind_len, kind); assert((size_t)n < sizeof(buffer), "Unexpected number of characters in string"); } else { kind_len = format_len; - int n = snprintf(buffer, sizeof(buffer), "%s_done%s", kind, kind + kind_len); + int n = os::snprintf(buffer, sizeof(buffer), "%s_done%s", kind, kind + kind_len); assert((size_t)n < sizeof(buffer), "Unexpected number of characters in string"); } // Output the trailing event with the timestamp.
--- a/src/java.base/macosx/native/libjli/java_md_macosx.m Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/macosx/native/libjli/java_md_macosx.m Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -717,10 +717,17 @@ } /* - * Block current thread and continue execution in a new thread + * Signature adapter for pthread_create(). + */ +static void* ThreadJavaMain(void* args) { + return (void*)(intptr_t)JavaMain(args); +} + +/* + * Block current thread and continue execution in a new thread. */ int -ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) { +CallJavaMainInNewThread(jlong stack_size, void* args) { int rslt; pthread_t tid; pthread_attr_t attr; @@ -728,22 +735,22 @@ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); if (stack_size > 0) { - pthread_attr_setstacksize(&attr, stack_size); + pthread_attr_setstacksize(&attr, stack_size); } pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads - if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) { - void * tmp; - pthread_join(tid, &tmp); - rslt = (int)(intptr_t)tmp; + if (pthread_create(&tid, &attr, ThreadJavaMain, args) == 0) { + void* tmp; + pthread_join(tid, &tmp); + rslt = (int)(intptr_t)tmp; } else { - /* - * Continue execution in current thread if for some reason (e.g. out of - * memory/LWP) a new thread can't be created. This will likely fail - * later in continuation as JNI_CreateJavaVM needs to create quite a - * few new threads, anyway, just give it a try.. - */ - rslt = continuation(args); + /* + * Continue execution in current thread if for some reason (e.g. out of + * memory/LWP) a new thread can't be created. This will likely fail + * later in JavaMain as JNI_CreateJavaVM needs to create quite a + * few new threads, anyway, just give it a try.. + */ + rslt = JavaMain(args); } pthread_attr_destroy(&attr);
--- a/src/java.base/share/classes/java/lang/Throwable.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/lang/Throwable.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -616,7 +616,7 @@ * ... 1 more * </pre> * Note that the "... n more" notation is used on suppressed exceptions - * just at it is used on causes. Unlike causes, suppressed exceptions are + * just as it is used on causes. Unlike causes, suppressed exceptions are * indented beyond their "containing exceptions." * * <p>An exception can have both a cause and one or more suppressed
--- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java Thu Feb 28 22:05:33 2019 +0100 @@ -170,7 +170,7 @@ * * @param rank the rank of the array * @return a {@linkplain ClassDesc} describing the array type - * @throws IllegalArgumentException if the rank is less than zero or if the rank of the resulting array type is + * @throws IllegalArgumentException if the rank is less than or equal to zero or if the rank of the resulting array type is * greater than 255 * @jvms 4.4.1 The CONSTANT_Class_info Structure */
--- a/src/java.base/share/classes/java/nio/Bits.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/nio/Bits.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -172,7 +172,10 @@ } // no luck - throw new OutOfMemoryError("Direct buffer memory"); + throw new OutOfMemoryError + ("Cannot reserve " + + size + " bytes of direct buffer memory (allocated: " + + RESERVED_MEMORY.get() + ", limit: " + MAX_MEMORY +")"); } finally { if (interrupted) {
--- a/src/java.base/share/classes/java/nio/Buffer.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/nio/Buffer.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -134,8 +134,9 @@ * it already contains: It leaves the limit unchanged and sets the position * to zero. </p></li> * - * <li><p> {@link #slice} creates a subsequence of a buffer: It leaves the - * limit and the position unchanged. </p></li> + * <li><p> The {@link #slice} and {@link #slice(int,int) slice(index,length)} + * methods create a subsequence of a buffer: They leave the limit and the + * position unchanged. </p></li> * * <li><p> {@link #duplicate} creates a shallow copy of a buffer: It leaves * the limit and the position unchanged. </p></li> @@ -600,6 +601,39 @@ public abstract Buffer slice(); /** + * Creates a new buffer whose content is a shared subsequence of + * this buffer's content. + * + * <p> The content of the new buffer will start at position {@code index} + * in this buffer, and will contain {@code length} elements. Changes to + * this buffer's content will be visible in the new buffer, and vice versa; + * the two buffers' position, limit, and mark values will be independent. + * + * <p> The new buffer's position will be zero, its capacity and its limit + * will be {@code length}, its mark will be undefined. The new buffer will + * be direct if, and only if, this buffer is direct, and it will be + * read-only if, and only if, this buffer is read-only. </p> + * + * @param index + * The position in this buffer at which the content of the new + * buffer will start; must be non-negative and no larger than + * {@link #limit() limit()} + * + * @param length + * The number of elements the new buffer will contain; must be + * non-negative and no larger than {@code limit() - index} + * + * @return The new buffer + * + * @throws IndexOutOfBoundsException + * If {@code index} is negative or greater than {@code limit()}, + * {@code length} is negative, or {@code length > limit() - index} + * + * @since 13 + */ + public abstract Buffer slice(int index, int length); + + /** * Creates a new buffer that shares this buffer's content. * * <p> The content of the new buffer will be that of this buffer. Changes
--- a/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -27,9 +27,9 @@ package java.nio; +import java.util.Objects; import jdk.internal.misc.Unsafe; - class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private extends {#if[ro]?ByteBufferAs}$Type$Buffer{#if[ro]?$BO$} { @@ -85,6 +85,18 @@ return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, addr); } + @Override + public $Type$Buffer slice(int index, int length) { + Objects.checkIndex(index, limit() + 1); + Objects.checkIndex(length, limit() - index + 1); + return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, + -1, + 0, + length, + length, + byteOffset(index)); + } + public $Type$Buffer duplicate() { return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, this.markValue(),
--- a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template Thu Feb 28 22:05:33 2019 +0100 @@ -218,14 +218,17 @@ return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off); } -#if[byte] - public $Type$Buffer slice(int pos, int lim) { - assert (pos >= 0); - assert (pos <= lim); - int rem = lim - pos; - return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, pos); + @Override + public $Type$Buffer slice(int index, int length) { + Objects.checkIndex(index, limit() + 1); + Objects.checkIndex(length, limit() - index + 1); + return new Direct$Type$Buffer$RW$$BO$(this, + -1, + 0, + length, + length, + index); } -#end[byte] public $Type$Buffer duplicate() { return new Direct$Type$Buffer$RW$$BO$(this,
--- a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template Thu Feb 28 22:05:33 2019 +0100 @@ -27,6 +27,8 @@ package java.nio; +import java.util.Objects; + /** #if[rw] * A read/write Heap$Type$Buffer. @@ -38,8 +40,6 @@ #end[rw] */ -import java.util.Objects; - class Heap$Type$Buffer$RW$ extends {#if[ro]?Heap}$Type$Buffer { @@ -112,19 +112,17 @@ this.position() + offset); } -#if[byte] - $Type$Buffer slice(int pos, int lim) { - assert (pos >= 0); - assert (pos <= lim); - int rem = lim - pos; + @Override + public $Type$Buffer slice(int index, int length) { + Objects.checkIndex(index, limit() + 1); + Objects.checkIndex(length, limit() - index + 1); return new Heap$Type$Buffer$RW$(hb, -1, 0, - rem, - rem, - pos + offset); + length, + length, + index + offset); } -#end[byte] public $Type$Buffer duplicate() { return new Heap$Type$Buffer$RW$(hb, @@ -270,6 +268,25 @@ #end[rw] } +#if[char] + + public $Type$Buffer put(String src, int start, int end) { + int length = end - start; + checkBounds(start, length, src.length()); + if (isReadOnly()) + throw new ReadOnlyBufferException(); + int pos = position(); + int lim = limit(); + int rem = (pos <= lim) ? lim - pos : 0; + if (length > rem) + throw new BufferOverflowException(); + src.getChars(start, end, hb, ix(pos)); + position(pos + length); + return this; + } + +#end[char] + public $Type$Buffer compact() { #if[rw] System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
--- a/src/java.base/share/classes/java/nio/StringCharBuffer.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/nio/StringCharBuffer.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -25,6 +25,7 @@ package java.nio; +import java.util.Objects; // ## If the sequence is a string, use reflection to share its array @@ -51,6 +52,18 @@ offset + this.position()); } + @Override + public CharBuffer slice(int index, int length) { + Objects.checkIndex(index, limit() + 1); + Objects.checkIndex(length, limit() - index + 1); + return new StringCharBuffer(str, + -1, + 0, + length, + length, + offset + index); + } + private StringCharBuffer(CharSequence s, int mark, int pos,
--- a/src/java.base/share/classes/java/nio/X-Buffer.java.template Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/nio/X-Buffer.java.template Thu Feb 28 22:05:33 2019 +0100 @@ -547,6 +547,46 @@ public abstract $Type$Buffer slice(); /** + * Creates a new $type$ buffer whose content is a shared subsequence of + * this buffer's content. + * + * <p> The content of the new buffer will start at position {@code index} + * in this buffer, and will contain {@code length} elements. Changes to + * this buffer's content will be visible in the new buffer, and vice versa; + * the two buffers' position, limit, and mark values will be independent. + * + * <p> The new buffer's position will be zero, its capacity and its limit + * will be {@code length}, its mark will be undefined, and its byte order + * will be +#if[byte] + * {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN}. +#else[byte] + * identical to that of this buffer. +#end[byte] + * The new buffer will be direct if, and only if, this buffer is direct, + * and it will be read-only if, and only if, this buffer is read-only. </p> + * + * @param index + * The position in this buffer at which the content of the new + * buffer will start; must be non-negative and no larger than + * {@link #limit() limit()} + * + * @param length + * The number of elements the new buffer will contain; must be + * non-negative and no larger than {@code limit() - index} + * + * @return The new buffer + * + * @throws IndexOutOfBoundsException + * If {@code index} is negative or greater than {@code limit()}, + * {@code length} is negative, or {@code length > limit() - index} + * + * @since 13 + */ + @Override + public abstract $Type$Buffer slice(int index, int length); + + /** * Creates a new $type$ buffer that shares this buffer's content. * * <p> The content of the new buffer will be that of this buffer. Changes @@ -1950,11 +1990,9 @@ aligned_pos = aligned_lim = pos; } - return slice(aligned_pos, aligned_lim); + return slice(aligned_pos, aligned_lim - aligned_pos); } - abstract ByteBuffer slice(int pos, int lim); - // #BIN // // Binary-data access methods for short, char, int, long, float,
--- a/src/java.base/share/classes/java/security/PrivilegedAction.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/security/PrivilegedAction.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -39,7 +39,7 @@ * @see AccessController#doPrivileged(PrivilegedAction) * @see PrivilegedExceptionAction */ - +@FunctionalInterface public interface PrivilegedAction<T> { /** * Performs the computation. This method will be called by
--- a/src/java.base/share/classes/java/security/PrivilegedExceptionAction.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/security/PrivilegedExceptionAction.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -42,7 +42,7 @@ * AccessControlContext) * @see PrivilegedAction */ - +@FunctionalInterface public interface PrivilegedExceptionAction<T> { /** * Performs the computation. This method will be called by
--- a/src/java.base/share/classes/java/util/spi/ToolProvider.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/java/util/spi/ToolProvider.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -126,8 +126,9 @@ default int run(PrintStream out, PrintStream err, String... args) { Objects.requireNonNull(out); Objects.requireNonNull(err); + Objects.requireNonNull(args); for (String arg : args) { - Objects.requireNonNull(args); + Objects.requireNonNull(arg); } PrintWriter outWriter = new PrintWriter(out);
--- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -3114,7 +3114,7 @@ * @param offset field/element offset * @param mask the mask value * @return the previous value - * @since 1.9 + * @since 9 */ @ForceInline public final int getAndBitwiseAndInt(Object o, long offset, int mask) { @@ -3343,6 +3343,14 @@ } /** + * 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. */
--- a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -175,7 +175,7 @@ public FieldAccessor newFieldAccessor(Field field, boolean override) { checkInitted(); - Field root = langReflectAccess.getRoot(field); + Field root = langReflectAccess().getRoot(field); if (root != null) { // FieldAccessor will use the root unless the modifiers have // been overrridden @@ -197,7 +197,7 @@ } // use the root Method that will not cache caller class - Method root = langReflectAccess.getRoot(method); + Method root = langReflectAccess().getRoot(method); if (root != null) { method = root; } @@ -233,7 +233,7 @@ } // use the root Constructor that will not cache caller class - Constructor<?> root = langReflectAccess.getRoot(c); + Constructor<?> root = langReflectAccess().getRoot(c); if (root != null) { c = root; }
--- a/src/java.base/share/classes/sun/security/ssl/Finished.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/sun/security/ssl/Finished.java Thu Feb 28 22:05:33 2019 +0100 @@ -102,7 +102,7 @@ } if (m.remaining() != verifyDataLen) { - throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER, + throw context.conContext.fatal(Alert.DECODE_ERROR, "Inappropriate finished message: need " + verifyDataLen + " but remaining " + m.remaining() + " bytes verify_data"); } @@ -120,7 +120,7 @@ "Failed to generate verify_data", ioe); } if (!MessageDigest.isEqual(myVerifyData, verifyData)) { - throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER, + throw context.conContext.fatal(Alert.DECRYPT_ERROR, "The Finished message cannot be verified."); } }
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -916,8 +916,12 @@ /** * Try the best to use up the input records so as to close the * socket gracefully, without impact the performance too much. + * + * Note: please don't synchronize this method as the read() method + * may hold the lock. A race should be fine as this method is + * designed for cleanup only. */ - private synchronized void deplete() { + private void deplete() { if (!conContext.isInboundClosed()) { if (!(conContext.inputRecord instanceof SSLSocketInputRecord)) { return;
--- a/src/java.base/share/native/libjli/java.c Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/native/libjli/java.c Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -388,8 +388,8 @@ } while (JNI_FALSE) -int JNICALL -JavaMain(void * _args) +int +JavaMain(void* _args) { JavaMainArgs *args = (JavaMainArgs *)_args; int argc = args->argc; @@ -2348,7 +2348,7 @@ args.what = what; args.ifn = *ifn; - rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args); + rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args); /* If the caller has deemed there is an error we * simply return that, otherwise we return the value of * the callee
--- a/src/java.base/share/native/libjli/java.h Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/share/native/libjli/java.h Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -156,10 +156,9 @@ void PrintMachineDependentOptions(); /* - * Block current thread and continue execution in new thread + * Block current thread and continue execution in new thread. */ -int ContinueInNewThread0(int (JNICALL *continuation)(void *), - jlong stack_size, void * args); +int CallJavaMainInNewThread(jlong stack_size, void* args); /* sun.java.launcher.* platform properties. */ void SetJavaLauncherPlatformProps(void); @@ -224,7 +223,10 @@ jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc); jclass GetLauncherHelperClass(JNIEnv *env); -int JNICALL JavaMain(void * args); /* entry point */ +/* + * Entry point. + */ +int JavaMain(void* args); enum LaunchMode { // cf. sun.launcher.LauncherHelper LM_UNKNOWN = 0,
--- a/src/java.base/unix/native/libjli/java_md_solinux.c Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/unix/native/libjli/java_md_solinux.c Thu Feb 28 22:05:33 2019 +0100 @@ -718,10 +718,17 @@ } /* - * Block current thread and continue execution in a new thread + * Signature adapter for pthread_create() or thr_create(). + */ +static void* ThreadJavaMain(void* args) { + return (void*)(intptr_t)JavaMain(args); +} + +/* + * Block current thread and continue execution in a new thread. */ int -ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) { +CallJavaMainInNewThread(jlong stack_size, void* args) { int rslt; #ifndef __solaris__ pthread_t tid; @@ -730,35 +737,35 @@ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); if (stack_size > 0) { - pthread_attr_setstacksize(&attr, stack_size); + pthread_attr_setstacksize(&attr, stack_size); } pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads - if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) { - void * tmp; - pthread_join(tid, &tmp); - rslt = (int)(intptr_t)tmp; + if (pthread_create(&tid, &attr, ThreadJavaMain, args) == 0) { + void* tmp; + pthread_join(tid, &tmp); + rslt = (int)(intptr_t)tmp; } else { - /* - * Continue execution in current thread if for some reason (e.g. out of - * memory/LWP) a new thread can't be created. This will likely fail - * later in continuation as JNI_CreateJavaVM needs to create quite a - * few new threads, anyway, just give it a try.. - */ - rslt = continuation(args); + /* + * Continue execution in current thread if for some reason (e.g. out of + * memory/LWP) a new thread can't be created. This will likely fail + * later in JavaMain as JNI_CreateJavaVM needs to create quite a + * few new threads, anyway, just give it a try.. + */ + rslt = JavaMain(args); } pthread_attr_destroy(&attr); #else /* __solaris__ */ thread_t tid; long flags = 0; - if (thr_create(NULL, stack_size, (void *(*)(void *))continuation, args, flags, &tid) == 0) { - void * tmp; - thr_join(tid, NULL, &tmp); - rslt = (int)(intptr_t)tmp; + if (thr_create(NULL, stack_size, ThreadJavaMain, args, flags, &tid) == 0) { + void* tmp; + thr_join(tid, NULL, &tmp); + rslt = (int)(intptr_t)tmp; } else { - /* See above. Continue in current thread if thr_create() failed */ - rslt = continuation(args); + /* See above. Continue in current thread if thr_create() failed */ + rslt = JavaMain(args); } #endif /* !__solaris__ */ return rslt;
--- a/src/java.base/windows/native/libjli/java_md.c Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.base/windows/native/libjli/java_md.c Thu Feb 28 22:05:33 2019 +0100 @@ -704,10 +704,17 @@ } /* - * Block current thread and continue execution in a new thread + * Signature adapter for _beginthreadex(). + */ +static unsigned __stdcall ThreadJavaMain(void* args) { + return (unsigned)JavaMain(args); +} + +/* + * Block current thread and continue execution in a new thread. */ int -ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) { +CallJavaMainInNewThread(jlong stack_size, void* args) { int rslt = 0; unsigned thread_id; @@ -722,20 +729,20 @@ * source (os_win32.cpp) for details. */ HANDLE thread_handle = - (HANDLE)_beginthreadex(NULL, - (unsigned)stack_size, - continuation, - args, - STACK_SIZE_PARAM_IS_A_RESERVATION, - &thread_id); + (HANDLE)_beginthreadex(NULL, + (unsigned)stack_size, + ThreadJavaMain, + args, + STACK_SIZE_PARAM_IS_A_RESERVATION, + &thread_id); if (thread_handle == NULL) { - thread_handle = - (HANDLE)_beginthreadex(NULL, - (unsigned)stack_size, - continuation, - args, - 0, - &thread_id); + thread_handle = + (HANDLE)_beginthreadex(NULL, + (unsigned)stack_size, + ThreadJavaMain, + args, + 0, + &thread_id); } /* AWT preloading (AFTER main thread start) */ @@ -772,11 +779,11 @@ #endif /* ENABLE_AWT_PRELOAD */ if (thread_handle) { - WaitForSingleObject(thread_handle, INFINITE); - GetExitCodeThread(thread_handle, &rslt); - CloseHandle(thread_handle); + WaitForSingleObject(thread_handle, INFINITE); + GetExitCodeThread(thread_handle, &rslt); + CloseHandle(thread_handle); } else { - rslt = continuation(args); + rslt = JavaMain(args); } #ifdef ENABLE_AWT_PRELOAD
--- a/src/java.compiler/share/classes/javax/lang/model/element/package-info.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.compiler/share/classes/javax/lang/model/element/package-info.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -107,6 +107,7 @@ * @author Joseph D. Darcy * @author Scott Seligman * @author Peter von der Ahé + * @see javax.lang.model.util.Elements * @since 1.6 */ package javax.lang.model.element;
--- a/src/java.compiler/share/classes/javax/lang/model/type/package-info.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.compiler/share/classes/javax/lang/model/type/package-info.java Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -36,6 +36,7 @@ * @author Joseph D. Darcy * @author Scott Seligman * @author Peter von der Ahé + * @see javax.lang.model.util.Types * @since 1.6 */ package javax.lang.model.type;
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.h Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.h Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -47,6 +47,7 @@ jint preFullScreenLevel; NSRect standardFrame; BOOL isMinimizing; + BOOL keyNotificationRecd; } // An instance of either AWTWindow_Normal or AWTWindow_Panel @@ -62,6 +63,7 @@ @property (nonatomic) jint preFullScreenLevel; @property (nonatomic) NSRect standardFrame; @property (nonatomic) BOOL isMinimizing; +@property (nonatomic) BOOL keyNotificationRecd; - (id) initWithPlatformWindow:(JNFWeakJObjectWrapper *)javaPlatformWindow ownerWindow:owner
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Thu Feb 28 22:05:33 2019 +0100 @@ -186,6 +186,7 @@ @synthesize preFullScreenLevel; @synthesize standardFrame; @synthesize isMinimizing; +@synthesize keyNotificationRecd; - (void) updateMinMaxSize:(BOOL)resizable { if (resizable) { @@ -319,6 +320,7 @@ if (self.nsWindow == nil) return nil; // no hope either [self.nsWindow release]; // the property retains the object already + self.keyNotificationRecd = NO; self.isEnabled = YES; self.isMinimizing = NO; self.javaPlatformWindow = platformWindow; @@ -747,9 +749,16 @@ AWT_ASSERT_APPKIT_THREAD; [AWTToolkit eventCountPlusPlus]; #ifdef DEBUG - NSLog(@"became main: %d %@ %@", [self.nsWindow isKeyWindow], [self.nsWindow title], [self menuBarForWindow]); + NSLog(@"became main: %d %@ %@ %d", [self.nsWindow isKeyWindow], [self.nsWindow title], [self menuBarForWindow], self.keyNotificationRecd); #endif + // if for some reason, no KEY notification is received but this main window is also a key window + // then we need to execute the KEY notification functionality. + if(self.keyNotificationRecd != YES && [self.nsWindow isKeyWindow]) { + [self doWindowDidBecomeKey]; + } + self.keyNotificationRecd = NO; + if (![self.nsWindow isKeyWindow]) { [self activateWindowMenuBar]; } @@ -769,6 +778,12 @@ #ifdef DEBUG NSLog(@"became key: %d %@ %@", [self.nsWindow isMainWindow], [self.nsWindow title], [self menuBarForWindow]); #endif + [self doWindowDidBecomeKey]; + self.keyNotificationRecd = YES; +} + +- (void) doWindowDidBecomeKey { +AWT_ASSERT_APPKIT_THREAD; AWTWindow *opposite = [AWTWindow lastKeyWindow]; if (![self.nsWindow isMainWindow]) {
--- a/src/java.desktop/share/classes/javax/swing/text/html/CSS.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.desktop/share/classes/javax/swing/text/html/CSS.java Thu Feb 28 22:05:33 2019 +0100 @@ -1362,6 +1362,19 @@ } else { digits = value; } + // Some webpage passes 3 digit color code as in #fff which is + // decoded as #000FFF resulting in blue background. + // As per https://www.w3.org/TR/CSS1/#color-units, + // The three-digit RGB notation (#rgb) is converted into six-digit form + // (#rrggbb) by replicating digits, not by adding zeros. + // This makes sure that white (#ffffff) can be specified with the short notation + // (#fff) and removes any dependencies on the color depth of the display. + if (digits.length() == 3) { + final String r = digits.substring(0, 1); + final String g = digits.substring(1, 2); + final String b = digits.substring(2, 3); + digits = String.format("%s%s%s%s%s%s", r, r, g, g, b, b); + } String hstr = "0x" + digits; Color c; try {
--- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java Thu Feb 28 22:05:33 2019 +0100 @@ -1185,6 +1185,10 @@ parserState.put(keyword, Integer.valueOf(parameter)); return true; } + if (keyword.equals("cb")) { + parserState.put(keyword, Integer.valueOf(parameter)); + return true; + } { RTFAttribute attr = straightforwardAttributes.get(keyword);
--- a/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java Thu Feb 28 22:05:33 2019 +0100 @@ -403,18 +403,36 @@ list. */ class RemotePrinterChangeListener implements Runnable { - private String[] prevRemotePrinters; + private String[] prevRemotePrinters = null; RemotePrinterChangeListener() { prevRemotePrinters = getRemotePrintersNames(); } boolean doCompare(String[] str1, String[] str2) { + if (str1 == null && str2 == null) { + return false; + } else if (str1 == null || str2 == null) { + return true; + } + if (str1.length != str2.length) { return true; } else { for (int i = 0;i < str1.length;i++) { for (int j = 0;j < str2.length;j++) { + // skip if both are nulls + if (str1[i] == null && str2[j] == null) { + continue; + } + + // return true if there is a 'difference' but + // no need to access the individual string + if (str1[i] == null || str2[j] == null) { + return true; + } + + // do comparison only if they are non-nulls if (!str1[i].equals(str2[j])) { return true; } @@ -428,15 +446,19 @@ @Override public void run() { while (true) { - String[] currentRemotePrinters = getRemotePrintersNames(); - if (doCompare(prevRemotePrinters, currentRemotePrinters)) { + if (prevRemotePrinters != null && prevRemotePrinters.length > 0) { + String[] currentRemotePrinters = getRemotePrintersNames(); + if (doCompare(prevRemotePrinters, currentRemotePrinters)) { - // updated the printers data - // printers list now contains both local and network printer data - refreshServices(); + // updated the printers data + // printers list now contains both local and network printer data + refreshServices(); - // store the current data for next comparison - prevRemotePrinters = currentRemotePrinters; + // store the current data for next comparison + prevRemotePrinters = currentRemotePrinters; + } + } else { + prevRemotePrinters = getRemotePrintersNames(); } try {
--- a/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp Thu Feb 28 22:05:33 2019 +0100 @@ -249,7 +249,7 @@ if (clazz == NULL) { return NULL; } - jobjectArray nameArray; + jobjectArray nameArray = NULL; try { ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, @@ -270,13 +270,14 @@ } } - // Allocate space only for the network type printers - nameArray = env->NewObjectArray(remotePrintersCount, clazz, NULL); - if (nameArray == NULL) { - throw std::bad_alloc(); + // return remote printers only if the list contains it. + if (remotePrintersCount > 0) { + // Allocate space only for the network type printers + nameArray = env->NewObjectArray(remotePrintersCount, clazz, NULL); + if (nameArray == NULL) { + throw std::bad_alloc(); + } } - } else { - nameArray = NULL; } // Loop thro' network printers list only @@ -298,7 +299,12 @@ delete [] pPrinterEnum; delete [] pNetworkPrinterLoc; - return nameArray; + + if (nameArray != NULL) { + return nameArray; + } else { + return env->NewObjectArray(0, clazz, NULL); + } CATCH_BAD_ALLOC_RET(NULL); }
--- a/src/java.smartcardio/share/native/libj2pcsc/pcsc.c Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.smartcardio/share/native/libj2pcsc/pcsc.c Thu Feb 28 22:05:33 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -181,7 +181,7 @@ { SCARDCONTEXT context = (SCARDCONTEXT)jContext; LONG rv; - LPTSTR mszReaders = NULL; + LPSTR mszReaders = NULL; DWORD size = 0; jobjectArray result; @@ -220,7 +220,7 @@ { SCARDCONTEXT context = (SCARDCONTEXT)jContext; LONG rv; - LPCTSTR readerName; + LPCSTR readerName; SCARDHANDLE card = 0; DWORD proto = 0;
--- a/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/COPYING Fri Feb 22 14:51:06 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -Copyright (c) 1999-2003 David Corcoran <corcoran@linuxnet.com> -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. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -Changes to this license can be made only by the copyright author with -explicit written consent. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
--- a/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/pcsclite.h Fri Feb 22 14:51:06 2019 +0100 +++ b/src/java.smartcardio/unix/native/libj2pcsc/MUSCLE/pcsclite.h Thu Feb 28 22:05:33 2019 +0100 @@ -1,374 +1,306 @@ /* - * This keeps a list of defines for pcsc-lite. - * - * MUSCLE SmartCard Development ( http://www.linuxnet.com ) + * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ ) * * Copyright (C) 1999-2004 - * David Corcoran <corcoran@linuxnet.com> + * David Corcoran <corcoran@musclecard.com> + * Copyright (C) 2002-2011 * Ludovic Rousseau <ludovic.rousseau@free.fr> + * Copyright (C) 2005 + * Martin Paljak <martin@paljak.pri.ee> * - * $Id: pcsclite.h.in,v 1.47 2004/08/24 21:46:57 rousseau Exp $ +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. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/** + * @file + * @brief This keeps a list of defines for pcsc-lite. + * + * Error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx */ #ifndef __pcsclite_h__ #define __pcsclite_h__ -#ifndef __sun_jdk #include <wintypes.h> -#else -#include <sys/types.h> -#include <inttypes.h> -#ifdef BYTE -#error BYTE is already defined -#else - typedef unsigned char BYTE; -#endif /* End BYTE */ - - typedef unsigned char UCHAR; - typedef unsigned char *PUCHAR; - typedef unsigned short USHORT; - typedef unsigned long ULONG; - typedef void *LPVOID; - typedef short BOOL; - typedef unsigned long *PULONG; - typedef const void *LPCVOID; - typedef unsigned long DWORD; - typedef unsigned long *PDWORD; - typedef unsigned short WORD; - typedef long LONG; - typedef long RESPONSECODE; - typedef const char *LPCTSTR; - typedef const BYTE *LPCBYTE; - typedef BYTE *LPBYTE; - typedef DWORD *LPDWORD; - typedef char *LPTSTR; - -#endif #ifdef __cplusplus extern "C" { #endif -#ifdef WIN32 -#include <winscard.h> -#else -typedef long SCARDCONTEXT; +typedef LONG SCARDCONTEXT; /**< \p hContext returned by SCardEstablishContext() */ typedef SCARDCONTEXT *PSCARDCONTEXT; typedef SCARDCONTEXT *LPSCARDCONTEXT; -typedef long SCARDHANDLE; +typedef LONG SCARDHANDLE; /**< \p hCard returned by SCardConnect() */ typedef SCARDHANDLE *PSCARDHANDLE; typedef SCARDHANDLE *LPSCARDHANDLE; -#define MAX_ATR_SIZE 33 /* Maximum ATR size */ +#define MAX_ATR_SIZE 33 /**< Maximum ATR size */ -#ifndef __APPLE__ +/* Set structure elements aligment on bytes + * http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html */ +#ifdef __APPLE__ +#pragma pack(1) +#endif typedef struct { - const char *szReader; - void *pvUserData; - unsigned long dwCurrentState; - unsigned long dwEventState; - unsigned long cbAtr; - unsigned char rgbAtr[MAX_ATR_SIZE]; + const char *szReader; + void *pvUserData; + DWORD dwCurrentState; + DWORD dwEventState; + DWORD cbAtr; + unsigned char rgbAtr[MAX_ATR_SIZE]; } -SCARD_READERSTATE_A; +SCARD_READERSTATE, *LPSCARD_READERSTATE; -typedef struct _SCARD_IO_REQUEST +/** Protocol Control Information (PCI) */ +typedef struct { - unsigned long dwProtocol; /* Protocol identifier */ - unsigned long cbPciLength; /* Protocol Control Inf Length */ + unsigned long dwProtocol; /**< Protocol identifier */ + unsigned long cbPciLength; /**< Protocol Control Inf Length */ } SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST; -#else // __APPLE__ - -#pragma pack(1) -typedef struct -{ - const char *szReader; - void *pvUserData; - uint32_t dwCurrentState; - uint32_t dwEventState; - uint32_t cbAtr; - unsigned char rgbAtr[MAX_ATR_SIZE]; -} -SCARD_READERSTATE_A; - -typedef struct _SCARD_IO_REQUEST -{ - uint32_t dwProtocol; /* Protocol identifier */ - uint32_t cbPciLength; /* Protocol Control Inf Length */ -} -SCARD_IO_REQUEST, *PSCARD_IO_REQUEST, *LPSCARD_IO_REQUEST; -#pragma pack() - -#endif // __APPLE__ - -typedef SCARD_READERSTATE_A SCARD_READERSTATE, *PSCARD_READERSTATE_A, - *LPSCARD_READERSTATE_A; - typedef const SCARD_IO_REQUEST *LPCSCARD_IO_REQUEST; -extern SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, - g_rgSCardRawPci; +extern const SCARD_IO_REQUEST g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci; -#define SCARD_PCI_T0 (&g_rgSCardT0Pci) -#define SCARD_PCI_T1 (&g_rgSCardT1Pci) -#define SCARD_PCI_RAW (&g_rgSCardRawPci) - -#define SCARD_S_SUCCESS 0x00000000 -#define SCARD_E_CANCELLED 0x80100002 -#define SCARD_E_CANT_DISPOSE 0x8010000E -#define SCARD_E_INSUFFICIENT_BUFFER 0x80100008 -#define SCARD_E_INVALID_ATR 0x80100015 -#define SCARD_E_INVALID_HANDLE 0x80100003 -#define SCARD_E_INVALID_PARAMETER 0x80100004 -#define SCARD_E_INVALID_TARGET 0x80100005 -#define SCARD_E_INVALID_VALUE 0x80100011 -#define SCARD_E_NO_MEMORY 0x80100006 -#define SCARD_F_COMM_ERROR 0x80100013 -#define SCARD_F_INTERNAL_ERROR 0x80100001 -#define SCARD_F_UNKNOWN_ERROR 0x80100014 -#define SCARD_F_WAITED_TOO_LONG 0x80100007 -#define SCARD_E_UNKNOWN_READER 0x80100009 -#define SCARD_E_TIMEOUT 0x8010000A -#define SCARD_E_SHARING_VIOLATION 0x8010000B -#define SCARD_E_NO_SMARTCARD 0x8010000C -#define SCARD_E_UNKNOWN_CARD 0x8010000D -#define SCARD_E_PROTO_MISMATCH 0x8010000F -#define SCARD_E_NOT_READY 0x80100010 -#define SCARD_E_SYSTEM_CANCELLED 0x80100012 -#define SCARD_E_NOT_TRANSACTED 0x80100016 -#define SCARD_E_READER_UNAVAILABLE 0x80100017 - -#define SCARD_W_UNSUPPORTED_CARD 0x80100065 -#define SCARD_W_UNRESPONSIVE_CARD 0x80100066 -#define SCARD_W_UNPOWERED_CARD 0x80100067 -#define SCARD_W_RESET_CARD 0x80100068 -#define SCARD_W_REMOVED_CARD 0x80100069 - -#define SCARD_E_PCI_TOO_SMALL 0x80100019 -#define SCARD_E_READER_UNSUPPORTED 0x8010001A -#define SCARD_E_DUPLICATE_READER 0x8010001B -#define SCARD_E_CARD_UNSUPPORTED 0x8010001C -#define SCARD_E_NO_SERVICE 0x8010001D -#define SCARD_E_SERVICE_STOPPED 0x8010001E - -#define SCARD_SCOPE_USER 0x0000 /* Scope in user space */ -#define SCARD_SCOPE_TERMINAL 0x0001 /* Scope in terminal */ -#define SCARD_SCOPE_SYSTEM 0x0002 /* Scope in system */ - -#define SCARD_PROTOCOL_UNSET 0x0000 /* protocol not set */ -#define SCARD_PROTOCOL_T0 0x0001 /* T=0 active protocol. */ -#define SCARD_PROTOCOL_T1 0x0002 /* T=1 active protocol. */ -#define SCARD_PROTOCOL_RAW 0x0004 /* Raw active protocol. */ -#define SCARD_PROTOCOL_T15 0x0008 /* T=15 protocol. */ - -#define SCARD_PROTOCOL_ANY (SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1) /* IFD determines prot. */ - -#define SCARD_SHARE_EXCLUSIVE 0x0001 /* Exclusive mode only */ -#define SCARD_SHARE_SHARED 0x0002 /* Shared mode only */ -#define SCARD_SHARE_DIRECT 0x0003 /* Raw mode only */ - -#define SCARD_LEAVE_CARD 0x0000 /* Do nothing on close */ -#define SCARD_RESET_CARD 0x0001 /* Reset on close */ -#define SCARD_UNPOWER_CARD 0x0002 /* Power down on close */ -#define SCARD_EJECT_CARD 0x0003 /* Eject on close */ - -#define SCARD_UNKNOWN 0x0001 /* Unknown state */ -#define SCARD_ABSENT 0x0002 /* Card is absent */ -#define SCARD_PRESENT 0x0004 /* Card is present */ -#define SCARD_SWALLOWED 0x0008 /* Card not powered */ -#define SCARD_POWERED 0x0010 /* Card is powered */ -#define SCARD_NEGOTIABLE 0x0020 /* Ready for PTS */ -#define SCARD_SPECIFIC 0x0040 /* PTS has been set */ - -#define SCARD_STATE_UNAWARE 0x0000 /* App wants status */ -#define SCARD_STATE_IGNORE 0x0001 /* Ignore this reader */ -#define SCARD_STATE_CHANGED 0x0002 /* State has changed */ -#define SCARD_STATE_UNKNOWN 0x0004 /* Reader unknown */ -#define SCARD_STATE_UNAVAILABLE 0x0008 /* Status unavailable */ -#define SCARD_STATE_EMPTY 0x0010 /* Card removed */ -#define SCARD_STATE_PRESENT 0x0020 /* Card inserted */ -#define SCARD_STATE_ATRMATCH 0x0040 /* ATR matches card */ -#define SCARD_STATE_EXCLUSIVE 0x0080 /* Exclusive Mode */ -#define SCARD_STATE_INUSE 0x0100 /* Shared Mode */ -#define SCARD_STATE_MUTE 0x0200 /* Unresponsive card */ -#define SCARD_STATE_UNPOWERED 0x0400 /* Unpowered card */ - -/* - * Tags for requesting card and reader attributes - */ - -#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag))) - -#define SCARD_CLASS_VENDOR_INFO 1 /* Vendor information definitions */ -#define SCARD_CLASS_COMMUNICATIONS 2 /* Communication definitions */ -#define SCARD_CLASS_PROTOCOL 3 /* Protocol definitions */ -#define SCARD_CLASS_POWER_MGMT 4 /* Power Management definitions */ -#define SCARD_CLASS_SECURITY 5 /* Security Assurance definitions */ -#define SCARD_CLASS_MECHANICAL 6 /* Mechanical characteristic definitions */ -#define SCARD_CLASS_VENDOR_DEFINED 7 /* Vendor specific definitions */ -#define SCARD_CLASS_IFD_PROTOCOL 8 /* Interface Device Protocol options */ -#define SCARD_CLASS_ICC_STATE 9 /* ICC State specific definitions */ -#define SCARD_CLASS_SYSTEM 0x7fff /* System-specific definitions */ - -#define SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0100) -#define SCARD_ATTR_VENDOR_IFD_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0101) -#define SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0102) -#define SCARD_ATTR_VENDOR_IFD_SERIAL_NO SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0103) -#define SCARD_ATTR_CHANNEL_ID SCARD_ATTR_VALUE(SCARD_CLASS_COMMUNICATIONS, 0x0110) -#define SCARD_ATTR_ASYNC_PROTOCOL_TYPES SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0120) -#define SCARD_ATTR_DEFAULT_CLK SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0121) -#define SCARD_ATTR_MAX_CLK SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0122) -#define SCARD_ATTR_DEFAULT_DATA_RATE SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0123) -#define SCARD_ATTR_MAX_DATA_RATE SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0124) -#define SCARD_ATTR_MAX_IFSD SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0125) -#define SCARD_ATTR_SYNC_PROTOCOL_TYPES SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0126) -#define SCARD_ATTR_POWER_MGMT_SUPPORT SCARD_ATTR_VALUE(SCARD_CLASS_POWER_MGMT, 0x0131) -#define SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE SCARD_ATTR_VALUE(SCARD_CLASS_SECURITY, 0x0140) -#define SCARD_ATTR_USER_AUTH_INPUT_DEVICE SCARD_ATTR_VALUE(SCARD_CLASS_SECURITY, 0x0142) -#define SCARD_ATTR_CHARACTERISTICS SCARD_ATTR_VALUE(SCARD_CLASS_MECHANICAL, 0x0150) - -#define SCARD_ATTR_CURRENT_PROTOCOL_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0201) -#define SCARD_ATTR_CURRENT_CLK SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0202) -#define SCARD_ATTR_CURRENT_F SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0203) -#define SCARD_ATTR_CURRENT_D SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0204) -#define SCARD_ATTR_CURRENT_N SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0205) -#define SCARD_ATTR_CURRENT_W SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0206) -#define SCARD_ATTR_CURRENT_IFSC SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0207) -#define SCARD_ATTR_CURRENT_IFSD SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0208) -#define SCARD_ATTR_CURRENT_BWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0209) -#define SCARD_ATTR_CURRENT_CWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020a) -#define SCARD_ATTR_CURRENT_EBC_ENCODING SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020b) -#define SCARD_ATTR_EXTENDED_BWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020c) - -#define SCARD_ATTR_ICC_PRESENCE SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0300) -#define SCARD_ATTR_ICC_INTERFACE_STATUS SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0301) -#define SCARD_ATTR_CURRENT_IO_STATE SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0302) -#define SCARD_ATTR_ATR_STRING SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0303) -#define SCARD_ATTR_ICC_TYPE_PER_ATR SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0304) - -#define SCARD_ATTR_ESC_RESET SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA000) -#define SCARD_ATTR_ESC_CANCEL SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA003) -#define SCARD_ATTR_ESC_AUTHREQUEST SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA005) -#define SCARD_ATTR_MAXINPUT SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA007) - -#define SCARD_ATTR_DEVICE_UNIT SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0001) -#define SCARD_ATTR_DEVICE_IN_USE SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0002) -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME_A SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0003) -#define SCARD_ATTR_DEVICE_SYSTEM_NAME_A SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0004) -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME_W SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0005) -#define SCARD_ATTR_DEVICE_SYSTEM_NAME_W SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0006) -#define SCARD_ATTR_SUPRESS_T1_IFS_REQUEST SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0007) - -#ifdef UNICODE -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME SCARD_ATTR_DEVICE_FRIENDLY_NAME_W -#define SCARD_ATTR_DEVICE_SYSTEM_NAME SCARD_ATTR_DEVICE_SYSTEM_NAME_W -#else -#define SCARD_ATTR_DEVICE_FRIENDLY_NAME SCARD_ATTR_DEVICE_FRIENDLY_NAME_A -#define SCARD_ATTR_DEVICE_SYSTEM_NAME SCARD_ATTR_DEVICE_SYSTEM_NAME_A +/* restore default structure elements alignment */ +#ifdef __APPLE__ +#pragma pack() #endif +#define SCARD_PCI_T0 (&g_rgSCardT0Pci) /**< protocol control information (PCI) for T=0 */ +#define SCARD_PCI_T1 (&g_rgSCardT1Pci) /**< protocol control information (PCI) for T=1 */ +#define SCARD_PCI_RAW (&g_rgSCardRawPci) /**< protocol control information (PCI) for RAW protocol */ + +/** + * @defgroup ErrorCodes ErrorCodes + * @brief Error code documentation + * + * The error codes descriptions are from + * http://msdn.microsoft.com/en-us/library/aa924526.aspx + */ +/** @ingroup ErrorCodes */ +#define SCARD_S_SUCCESS ((LONG)0x00000000) /**< No error was encountered. */ +/** @ingroup ErrorCodes */ +#define SCARD_F_INTERNAL_ERROR ((LONG)0x80100001) /**< An internal consistency check failed. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_CANCELLED ((LONG)0x80100002) /**< The action was cancelled by an SCardCancel request. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_INVALID_HANDLE ((LONG)0x80100003) /**< The supplied handle was invalid. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_INVALID_PARAMETER ((LONG)0x80100004) /**< One or more of the supplied parameters could not be properly interpreted. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_INVALID_TARGET ((LONG)0x80100005) /**< Registry startup information is missing or invalid. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NO_MEMORY ((LONG)0x80100006) /**< Not enough memory available to complete this command. */ +/** @ingroup ErrorCodes */ +#define SCARD_F_WAITED_TOO_LONG ((LONG)0x80100007) /**< An internal consistency timer has expired. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_INSUFFICIENT_BUFFER ((LONG)0x80100008) /**< The data buffer to receive returned data is too small for the returned data. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_UNKNOWN_READER ((LONG)0x80100009) /**< The specified reader name is not recognized. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_TIMEOUT ((LONG)0x8010000A) /**< The user-specified timeout value has expired. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_SHARING_VIOLATION ((LONG)0x8010000B) /**< The smart card cannot be accessed because of other connections outstanding. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NO_SMARTCARD ((LONG)0x8010000C) /**< The operation requires a Smart Card, but no Smart Card is currently in the device. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_UNKNOWN_CARD ((LONG)0x8010000D) /**< The specified smart card name is not recognized. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_CANT_DISPOSE ((LONG)0x8010000E) /**< The system could not dispose of the media in the requested manner. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_PROTO_MISMATCH ((LONG)0x8010000F) /**< The requested protocols are incompatible with the protocol currently in use with the smart card. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NOT_READY ((LONG)0x80100010) /**< The reader or smart card is not ready to accept commands. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_INVALID_VALUE ((LONG)0x80100011) /**< One or more of the supplied parameters values could not be properly interpreted. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_SYSTEM_CANCELLED ((LONG)0x80100012) /**< The action was cancelled by the system, presumably to log off or shut down. */ +/** @ingroup ErrorCodes */ +#define SCARD_F_COMM_ERROR ((LONG)0x80100013) /**< An internal communications error has been detected. */ +/** @ingroup ErrorCodes */ +#define SCARD_F_UNKNOWN_ERROR ((LONG)0x80100014) /**< An internal error has been detected, but the source is unknown. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_INVALID_ATR ((LONG)0x80100015) /**< An ATR obtained from the registry is not a valid ATR string. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NOT_TRANSACTED ((LONG)0x80100016) /**< An attempt was made to end a non-existent transaction. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_READER_UNAVAILABLE ((LONG)0x80100017) /**< The specified reader is not currently available for use. */ +/** @ingroup ErrorCodes */ +#define SCARD_P_SHUTDOWN ((LONG)0x80100018) /**< The operation has been aborted to allow the server application to exit. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_PCI_TOO_SMALL ((LONG)0x80100019) /**< The PCI Receive buffer was too small. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_READER_UNSUPPORTED ((LONG)0x8010001A) /**< The reader driver does not meet minimal requirements for support. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_DUPLICATE_READER ((LONG)0x8010001B) /**< The reader driver did not produce a unique reader name. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_CARD_UNSUPPORTED ((LONG)0x8010001C) /**< The smart card does not meet minimal requirements for support. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NO_SERVICE ((LONG)0x8010001D) /**< The Smart card resource manager is not running. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_SERVICE_STOPPED ((LONG)0x8010001E) /**< The Smart card resource manager has shut down. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_UNEXPECTED ((LONG)0x8010001F) /**< An unexpected card error has occurred. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_UNSUPPORTED_FEATURE ((LONG)0x8010001F) /**< This smart card does not support the requested feature. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_ICC_INSTALLATION ((LONG)0x80100020) /**< No primary provider can be found for the smart card. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_ICC_CREATEORDER ((LONG)0x80100021) /**< The requested order of object creation is not supported. */ +/** @ingroup ErrorCodes */ +/* #define SCARD_E_UNSUPPORTED_FEATURE ((LONG)0x80100022) / **< This smart card does not support the requested feature. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_DIR_NOT_FOUND ((LONG)0x80100023) /**< The identified directory does not exist in the smart card. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_FILE_NOT_FOUND ((LONG)0x80100024) /**< The identified file does not exist in the smart card. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NO_DIR ((LONG)0x80100025) /**< The supplied path does not represent a smart card directory. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NO_FILE ((LONG)0x80100026) /**< The supplied path does not represent a smart card file. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NO_ACCESS ((LONG)0x80100027) /**< Access is denied to this file. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_WRITE_TOO_MANY ((LONG)0x80100028) /**< The smart card does not have enough memory to store the information. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_BAD_SEEK ((LONG)0x80100029) /**< There was an error trying to set the smart card file object pointer. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_INVALID_CHV ((LONG)0x8010002A) /**< The supplied PIN is incorrect. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_UNKNOWN_RES_MNG ((LONG)0x8010002B) /**< An unrecognized error code was returned from a layered component. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NO_SUCH_CERTIFICATE ((LONG)0x8010002C) /**< The requested certificate does not exist. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_CERTIFICATE_UNAVAILABLE ((LONG)0x8010002D) /**< The requested certificate could not be obtained. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NO_READERS_AVAILABLE ((LONG)0x8010002E) /**< Cannot find a smart card reader. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_COMM_DATA_LOST ((LONG)0x8010002F) /**< A communications error with the smart card has been detected. Retry the operation. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_NO_KEY_CONTAINER ((LONG)0x80100030) /**< The requested key container does not exist on the smart card. */ +/** @ingroup ErrorCodes */ +#define SCARD_E_SERVER_TOO_BUSY ((LONG)0x80100031) /**< The Smart Card Resource Manager is too busy to complete this operation. */ + +/** @ingroup ErrorCodes */ +#define SCARD_W_UNSUPPORTED_CARD ((LONG)0x80100065) /**< The reader cannot communicate with the card, due to ATR string configuration conflicts. */ +/** @ingroup ErrorCodes */ +#define SCARD_W_UNRESPONSIVE_CARD ((LONG)0x80100066) /**< The smart card is not responding to a reset. */ +/** @ingroup ErrorCodes */ +#define SCARD_W_UNPOWERED_CARD ((LONG)0x80100067) /**< Power has been removed from the smart card, so that further communication is not possible. */ +/** @ingroup ErrorCodes */ +#define SCARD_W_RESET_CARD ((LONG)0x80100068) /**< The smart card has been reset, so any shared state information is invalid. */ +/** @ingroup ErrorCodes */ +#define SCARD_W_REMOVED_CARD ((LONG)0x80100069) /**< The smart card has been removed, so further communication is not possible. */ + +/** @ingroup ErrorCodes */ +#define SCARD_W_SECURITY_VIOLATION ((LONG)0x8010006A) /**< Access was denied because of a security violation. */ +/** @ingroup ErrorCodes */ +#define SCARD_W_WRONG_CHV ((LONG)0x8010006B) /**< The card cannot be accessed because the wrong PIN was presented. */ +/** @ingroup ErrorCodes */ +#define SCARD_W_CHV_BLOCKED ((LONG)0x8010006C) /**< The card cannot be accessed because the maximum number of PIN entry attempts has been reached. */ +/** @ingroup ErrorCodes */ +#define SCARD_W_EOF ((LONG)0x8010006D) /**< The end of the smart card file has been reached. */ +/** @ingroup ErrorCodes */ +#define SCARD_W_CANCELLED_BY_USER ((LONG)0x8010006E) /**< The user pressed "Cancel" on a Smart Card Selection Dialog. */ +/** @ingroup ErrorCodes */ +#define SCARD_W_CARD_NOT_AUTHENTICATED ((LONG)0x8010006F) /**< No PIN was presented to the smart card. */ + +#define SCARD_AUTOALLOCATE (DWORD)(-1) /**< see SCardFreeMemory() */ +#define SCARD_SCOPE_USER 0x0000 /**< Scope in user space */ +#define SCARD_SCOPE_TERMINAL 0x0001 /**< Scope in terminal */ +#define SCARD_SCOPE_SYSTEM 0x0002 /**< Scope in system */ +#define SCARD_SCOPE_GLOBAL 0x0003 /**< Scope is global */ + +#define SCARD_PROTOCOL_UNDEFINED 0x0000 /**< protocol not set */ +#define SCARD_PROTOCOL_UNSET SCARD_PROTOCOL_UNDEFINED /* backward compat */ +#define SCARD_PROTOCOL_T0 0x0001 /**< T=0 active protocol. */ +#define SCARD_PROTOCOL_T1 0x0002 /**< T=1 active protocol. */ +#define SCARD_PROTOCOL_RAW 0x0004 /**< Raw active protocol. */ +#define SCARD_PROTOCOL_T15 0x0008 /**< T=15 protocol. */ + +#define SCARD_PROTOCOL_ANY (SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1) /**< IFD determines prot. */ + +#define SCARD_SHARE_EXCLUSIVE 0x0001 /**< Exclusive mode only */ +#define SCARD_SHARE_SHARED 0x0002 /**< Shared mode only */ +#define SCARD_SHARE_DIRECT 0x0003 /**< Raw mode only */ + +#define SCARD_LEAVE_CARD 0x0000 /**< Do nothing on close */ +#define SCARD_RESET_CARD 0x0001 /**< Reset on close */ +#define SCARD_UNPOWER_CARD 0x0002 /**< Power down on close */ +#define SCARD_EJECT_CARD 0x0003 /**< Eject on close */ + +#define SCARD_UNKNOWN 0x0001 /**< Unknown state */ +#define SCARD_ABSENT 0x0002 /**< Card is absent */ +#define SCARD_PRESENT 0x0004 /**< Card is present */ +#define SCARD_SWALLOWED 0x0008 /**< Card not powered */ +#define SCARD_POWERED 0x0010 /**< Card is powered */ +#define SCARD_NEGOTIABLE 0x0020 /**< Ready for PTS */ +#define SCARD_SPECIFIC 0x0040 /**< PTS has been set */ + +#define SCARD_STATE_UNAWARE 0x0000 /**< App wants status */ +#define SCARD_STATE_IGNORE 0x0001 /**< Ignore this reader */ +#define SCARD_STATE_CHANGED 0x0002 /**< State has changed */ +#define SCARD_STATE_UNKNOWN 0x0004 /**< Reader unknown */ +#define SCARD_STATE_UNAVAILABLE 0x0008 /**< Status unavailable */ +#define SCARD_STATE_EMPTY 0x0010 /**< Card removed */ +#define SCARD_STATE_PRESENT 0x0020 /**< Card inserted */ +#define SCARD_STATE_ATRMATCH 0x0040 /**< ATR matches card */ +#define SCARD_STATE_EXCLUSIVE 0x0080 /**< Exclusive Mode */ +#define SCARD_STATE_INUSE 0x0100 /**< Shared Mode */ +#define SCARD_STATE_MUTE 0x0200 /**< Unresponsive card */ +#define SCARD_STATE_UNPOWERED 0x0400 /**< Unpowered card */ + +#ifndef INFINITE +#define INFINITE 0xFFFFFFFF /**< Infinite timeout */ #endif -/* PC/SC Lite specific extensions */ -#define SCARD_W_INSERTED_CARD 0x8010006A -#define SCARD_E_UNSUPPORTED_FEATURE 0x8010001F +#define PCSCLITE_VERSION_NUMBER "1.8.24" /**< Current version */ +/** Maximum readers context (a slot is count as a reader) */ +#define PCSCLITE_MAX_READERS_CONTEXTS 16 -#define SCARD_SCOPE_GLOBAL 0x0003 /* Scope is global */ - -#define SCARD_RESET 0x0001 /* Card was reset */ -#define SCARD_INSERTED 0x0002 /* Card was inserted */ -#define SCARD_REMOVED 0x0004 /* Card was removed */ - -#define BLOCK_STATUS_RESUME 0x00FF /* Normal resume */ -#define BLOCK_STATUS_BLOCKING 0x00FA /* Function is blocking */ - -#define PCSCLITE_CONFIG_DIR "/etc" - -#ifndef USE_IPCDIR -#define PCSCLITE_IPC_DIR "/var/run" -#else -#define PCSCLITE_IPC_DIR USE_IPCDIR -#endif - -#define PCSCLITE_READER_CONFIG PCSCLITE_CONFIG_DIR "/reader.conf" -#define PCSCLITE_PUBSHM_FILE PCSCLITE_IPC_DIR "/pcscd.pub" -#define PCSCLITE_CSOCK_NAME PCSCLITE_IPC_DIR "/pcscd.comm" - -#define PCSCLITE_SVC_IDENTITY 0x01030000 /* Service ID */ - -#ifndef INFINITE -#define INFINITE 0xFFFFFFFF /* Infinite timeout */ -#endif -#define PCSCLITE_INFINITE_TIMEOUT 4320000 /* 50 day infinite t/o */ - -#define PCSCLITE_VERSION_NUMBER "1.2.9-beta7" /* Current version */ -#define PCSCLITE_CLIENT_ATTEMPTS 120 /* Attempts to reach sv */ -#define PCSCLITE_MCLIENT_ATTEMPTS 20 /* Attempts to reach sv */ -#define PCSCLITE_STATUS_POLL_RATE 400000 /* Status polling rate */ -#define PCSCLITE_MSG_KEY_LEN 16 /* App ID key length */ -#define PCSCLITE_RW_ATTEMPTS 100 /* Attempts to rd/wrt */ - -/* Maximum applications */ -#define PCSCLITE_MAX_APPLICATIONS 16 -/* Maximum contexts by application */ -#define PCSCLITE_MAX_APPLICATION_CONTEXTS 16 -/* Maximum of applications contexts that pcscd can accept */ -#define PCSCLITE_MAX_APPLICATIONS_CONTEXTS \ - PCSCLITE_MAX_APPLICATIONS * PCSCLITE_MAX_APPLICATION_CONTEXTS