OpenJDK / jdk / jdk12
changeset 6324:b624b3a4e6e8
Merge
author | lana |
---|---|
date | Mon, 23 Aug 2010 19:14:20 -0700 |
parents | dd4e40a7b259 1cdec3dff0a3 |
children | adf468d05745 |
files | jdk/test/tools/pack200/Pack200Simple.sh jdk/test/tools/pack200/SegmentLimit.java |
diffstat | 72 files changed, 11897 insertions(+), 1236 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/make/common/shared/Defs-windows.gmk Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/make/common/shared/Defs-windows.gmk Mon Aug 23 19:14:20 2010 -0700 @@ -89,7 +89,7 @@ $(shell $(CYGPATH_CMD) $1 2> $(DEV_NULL)) endef define OptFullPath -$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1"; else echo "$1"; fi) +$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1" 2> $(DEV_NULL); else echo "$1"; fi) endef else # Temporary until we upgrade to MKS 8.7, MKS pwd returns mixed mode path
--- a/jdk/make/common/shared/Defs.gmk Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/make/common/shared/Defs.gmk Mon Aug 23 19:14:20 2010 -0700 @@ -136,15 +136,20 @@ $(shell echo $1 | sed -e 's@[^0-9]*\([0-9][0-9]*\.[0-9][.0-9]*\).*@\1@' ) endef +# Return one part of the version numbers, watch out for non digits. +define VersionWord # Number Version +$(word $1,$(subst ., ,$(subst -, ,$2))) +endef + # Given a major.minor.micro version, return the major, minor, or micro number define MajorVersion -$(if $(word 1, $(subst ., ,$1)),$(word 1, $(subst ., ,$1)),0) +$(if $(call VersionWord,1,$1),$(call VersionWord,1,$1),0) endef define MinorVersion -$(if $(word 2, $(subst ., ,$1)),$(word 2, $(subst ., ,$1)),0) +$(if $(call VersionWord,2,$1),$(call VersionWord,2,$1),0) endef define MicroVersion -$(if $(word 3, $(subst ., ,$1)),$(word 3, $(subst ., ,$1)),0) +$(if $(call VersionWord,3,$1),$(call VersionWord,3,$1),0) endef # Macro that returns missing, same, newer, or older $1=version $2=required
--- a/jdk/make/jdk_generic_profile.sh Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/make/jdk_generic_profile.sh Mon Aug 23 19:14:20 2010 -0700 @@ -340,6 +340,10 @@ export PATH # Export variables required for Zero +if [ "${SHARK_BUILD}" = true ] ; then + ZERO_BUILD=true + export ZERO_BUILD +fi if [ "${ZERO_BUILD}" = true ] ; then # ZERO_LIBARCH is the name of the architecture-specific # subdirectory under $JAVA_HOME/jre/lib @@ -417,4 +421,55 @@ fi export LIBFFI_CFLAGS export LIBFFI_LIBS + + # LLVM_CFLAGS, LLVM_LDFLAGS and LLVM_LIBS tell the compiler how to + # compile and link against LLVM + if [ "${SHARK_BUILD}" = true ] ; then + if [ "${LLVM_CONFIG}" = "" ] ; then + LLVM_CONFIG=$(which llvm-config 2>/dev/null) + fi + if [ ! -x "${LLVM_CONFIG}" ] ; then + echo "ERROR: Unable to locate llvm-config" + exit 1 + fi + llvm_components="jit engine nativecodegen" + + unset LLVM_CFLAGS + for flag in $("${LLVM_CONFIG}" --cxxflags $llvm_components); do + if echo "${flag}" | grep -q '^-[ID]'; then + if [ "${flag}" != "-D_DEBUG" ] ; then + if [ "${LLVM_CFLAGS}" != "" ] ; then + LLVM_CFLAGS="${LLVM_CFLAGS} " + fi + LLVM_CFLAGS="${LLVM_CFLAGS}${flag}" + fi + fi + done + llvm_version=$("${LLVM_CONFIG}" --version | sed 's/\.//; s/svn.*//') + LLVM_CFLAGS="${LLVM_CFLAGS} -DSHARK_LLVM_VERSION=${llvm_version}" + + unset LLVM_LDFLAGS + for flag in $("${LLVM_CONFIG}" --ldflags $llvm_components); do + if echo "${flag}" | grep -q '^-L'; then + if [ "${LLVM_LDFLAGS}" != "" ] ; then + LLVM_LDFLAGS="${LLVM_LDFLAGS} " + fi + LLVM_LDFLAGS="${LLVM_LDFLAGS}${flag}" + fi + done + + unset LLVM_LIBS + for flag in $("${LLVM_CONFIG}" --libs $llvm_components); do + if echo "${flag}" | grep -q '^-l'; then + if [ "${LLVM_LIBS}" != "" ] ; then + LLVM_LIBS="${LLVM_LIBS} " + fi + LLVM_LIBS="${LLVM_LIBS}${flag}" + fi + done + + export LLVM_CFLAGS + export LLVM_LDFLAGS + export LLVM_LIBS + fi fi
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java Mon Aug 23 19:14:20 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -27,7 +27,6 @@ import java.io.*; import java.util.*; -import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.ConstantPool.*; /** @@ -96,20 +95,20 @@ return this.def.compareTo(that.def); } - static private final byte[] noBytes = {}; - static private final HashMap canonLists = new HashMap(); - static private final HashMap attributes = new HashMap(); - static private final HashMap standardDefs = new HashMap(); + private static final byte[] noBytes = {}; + private static final Map<List<Attribute>, List<Attribute>> canonLists = new HashMap<>(); + private static final Map<Layout, Attribute> attributes = new HashMap<>(); + private static final Map<Layout, Attribute> standardDefs = new HashMap<>(); // Canonicalized lists of trivial attrs (Deprecated, etc.) // are used by trimToSize, in order to reduce footprint // of some common cases. (Note that Code attributes are // always zero size.) - public static List getCanonList(List al) { + public static List getCanonList(List<Attribute> al) { synchronized (canonLists) { - List cl = (List) canonLists.get(al); + List<Attribute> cl = canonLists.get(al); if (cl == null) { - cl = new ArrayList(al.size()); + cl = new ArrayList<>(al.size()); cl.addAll(al); cl = Collections.unmodifiableList(cl); canonLists.put(al, cl); @@ -122,7 +121,7 @@ public static Attribute find(int ctype, String name, String layout) { Layout key = Layout.makeKey(ctype, name, layout); synchronized (attributes) { - Attribute a = (Attribute) attributes.get(key); + Attribute a = attributes.get(key); if (a == null) { a = new Layout(ctype, name, layout).canonicalInstance(); attributes.put(key, a); @@ -131,24 +130,29 @@ } } - public static Object keyForLookup(int ctype, String name) { + public static Layout keyForLookup(int ctype, String name) { return Layout.makeKey(ctype, name); } // Find canonical empty attribute with given ctype and name, // and with the standard layout. - public static Attribute lookup(Map defs, int ctype, String name) { - if (defs == null) defs = standardDefs; - return (Attribute) defs.get(Layout.makeKey(ctype, name)); + public static Attribute lookup(Map<Layout, Attribute> defs, int ctype, + String name) { + if (defs == null) { + defs = standardDefs; + } + return defs.get(Layout.makeKey(ctype, name)); } - public static Attribute define(Map defs, int ctype, String name, String layout) { + + public static Attribute define(Map<Layout, Attribute> defs, int ctype, + String name, String layout) { Attribute a = find(ctype, name, layout); defs.put(Layout.makeKey(ctype, name), a); return a; } static { - Map sd = standardDefs; + Map<Layout, Attribute> sd = standardDefs; define(sd, ATTR_CONTEXT_CLASS, "Signature", "RSH"); define(sd, ATTR_CONTEXT_CLASS, "Synthetic", ""); define(sd, ATTR_CONTEXT_CLASS, "Deprecated", ""); @@ -244,7 +248,7 @@ +"\n ()[] ]" ) }; - Map sd = standardDefs; + Map<Layout, Attribute> sd = standardDefs; String defaultLayout = mdLayouts[2]; String annotationsLayout = mdLayouts[1] + mdLayouts[2]; String paramsLayout = mdLayouts[0] + annotationsLayout; @@ -275,10 +279,6 @@ return null; } - public static Map getStandardDefs() { - return new HashMap(standardDefs); - } - /** Base class for any attributed object (Class, Field, Method, Code). * Flags are included because they are used to help transmit the * presence of attributes. That is, flags are a mix of modifier @@ -291,7 +291,7 @@ protected abstract Entry[] getCPMap(); protected int flags; // defined here for convenience - protected List attributes; + protected List<Attribute> attributes; public int attributeSize() { return (attributes == null) ? 0 : attributes.size(); @@ -301,16 +301,15 @@ if (attributes == null) { return; } - if (attributes.size() == 0) { + if (attributes.isEmpty()) { attributes = null; return; } if (attributes instanceof ArrayList) { - ArrayList al = (ArrayList) attributes; + ArrayList<Attribute> al = (ArrayList<Attribute>)attributes; al.trimToSize(); boolean allCanon = true; - for (Iterator i = al.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : al) { if (!a.isCanonical()) { allCanon = false; } @@ -330,9 +329,9 @@ public void addAttribute(Attribute a) { if (attributes == null) - attributes = new ArrayList(3); + attributes = new ArrayList<>(3); else if (!(attributes instanceof ArrayList)) - attributes = new ArrayList(attributes); // unfreeze it + attributes = new ArrayList<>(attributes); // unfreeze it attributes.add(a); } @@ -340,32 +339,31 @@ if (attributes == null) return null; if (!attributes.contains(a)) return null; if (!(attributes instanceof ArrayList)) - attributes = new ArrayList(attributes); // unfreeze it + attributes = new ArrayList<>(attributes); // unfreeze it attributes.remove(a); return a; } public Attribute getAttribute(int n) { - return (Attribute) attributes.get(n); + return attributes.get(n); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection<Entry> refs) { if (attributes == null) return; - for (Iterator i = attributes.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : attributes) { a.visitRefs(this, mode, refs); } } - static final List noAttributes = Arrays.asList(new Object[0]); + static final List<Attribute> noAttributes = Arrays.asList(new Attribute[0]); - public List getAttributes() { + public List<Attribute> getAttributes() { if (attributes == null) return noAttributes; return attributes; } - public void setAttributes(List attrList) { + public void setAttributes(List<Attribute> attrList) { if (attrList.isEmpty()) attributes = null; else @@ -374,8 +372,7 @@ public Attribute getAttribute(String attrName) { if (attributes == null) return null; - for (Iterator i = attributes.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : attributes) { if (a.name().equals(attrName)) return a; } @@ -384,8 +381,7 @@ public Attribute getAttribute(Layout attrDef) { if (attributes == null) return null; - for (Iterator i = attributes.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : attributes) { if (a.layout() == attrDef) return a; } @@ -457,14 +453,8 @@ public String layout() { return layout; } public Attribute canonicalInstance() { return canon; } - // Cache of name reference. - private Entry nameRef; // name, for use by visitRefs public Entry getNameRef() { - Entry nameRef = this.nameRef; - if (nameRef == null) { - this.nameRef = nameRef = ConstantPool.getUtf8Entry(name()); - } - return nameRef; + return ConstantPool.getUtf8Entry(name()); } public boolean isEmpty() { return layout == ""; } @@ -834,14 +824,14 @@ */ static //private Layout.Element[] tokenizeLayout(Layout self, int curCble, String layout) { - ArrayList col = new ArrayList(layout.length()); + ArrayList<Layout.Element> col = new ArrayList<>(layout.length()); tokenizeLayout(self, curCble, layout, col); Layout.Element[] res = new Layout.Element[col.size()]; col.toArray(res); return res; } static //private - void tokenizeLayout(Layout self, int curCble, String layout, ArrayList col) { + void tokenizeLayout(Layout self, int curCble, String layout, ArrayList<Layout.Element> col) { boolean prevBCI = false; for (int len = layout.length(), i = 0; i < len; ) { int start = i; @@ -899,7 +889,7 @@ case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']' kind = EK_UN; i = tokenizeSInt(e, layout, i); - ArrayList cases = new ArrayList(); + ArrayList<Layout.Element> cases = new ArrayList<>(); for (;;) { // Keep parsing cases until we hit the default case. if (layout.charAt(i++) != '(') @@ -1053,7 +1043,7 @@ } static //private String[] splitBodies(String layout) { - ArrayList bodies = new ArrayList(); + ArrayList<String> bodies = new ArrayList<>(); // Parse several independent layout bodies: "[foo][bar]...[baz]" for (int i = 0; i < layout.length(); i++) { if (layout.charAt(i++) != '[') @@ -1132,7 +1122,9 @@ int parseIntBefore(String layout, int dash) { int end = dash; int beg = end; - while (beg > 0 && isDigit(layout.charAt(beg-1))) --beg; + while (beg > 0 && isDigit(layout.charAt(beg-1))) { + --beg; + } if (beg == end) return Integer.parseInt("empty"); // skip backward over a sign if (beg >= 1 && layout.charAt(beg-1) == '-') --beg; @@ -1145,7 +1137,9 @@ int end = beg; int limit = layout.length(); if (end < limit && layout.charAt(end) == '-') ++end; - while (end < limit && isDigit(layout.charAt(end))) ++end; + while (end < limit && isDigit(layout.charAt(end))) { + ++end; + } if (beg == end) return Integer.parseInt("empty"); return Integer.parseInt(layout.substring(beg, end)); }
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java Mon Aug 23 19:14:20 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -25,7 +25,6 @@ package com.sun.java.util.jar.pack; -import java.io.*; import java.util.*; /** @@ -40,20 +39,13 @@ return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE); } - // Uniquification tables for factory methods: - private static final HashMap utf8Entries = new HashMap(); - private static final HashMap classEntries = new HashMap(); - private static final HashMap literalEntries = new HashMap(); - private static final HashMap signatureEntries = new HashMap(); - private static final HashMap descriptorEntries = new HashMap(); - private static final HashMap memberEntries = new HashMap(); - /** Factory for Utf8 string constants. * Used for well-known strings like "SourceFile", "<init>", etc. * Also used to back up more complex constant pool entries, like Class. */ public static synchronized Utf8Entry getUtf8Entry(String value) { - Utf8Entry e = (Utf8Entry) utf8Entries.get(value); + Map<String, Utf8Entry> utf8Entries = Utils.getUtf8Entries(); + Utf8Entry e = utf8Entries.get(value); if (e == null) { e = new Utf8Entry(value); utf8Entries.put(e.stringValue(), e); @@ -62,9 +54,10 @@ } /** Factory for Class constants. */ public static synchronized ClassEntry getClassEntry(String name) { - ClassEntry e = (ClassEntry) classEntries.get(name); + Map<String, ClassEntry> classEntries = Utils.getClassEntries(); + ClassEntry e = classEntries.get(name); if (e == null) { - e = (ClassEntry) new ClassEntry(getUtf8Entry(name)); + e = new ClassEntry(getUtf8Entry(name)); assert(name.equals(e.stringValue())); classEntries.put(e.stringValue(), e); } @@ -72,7 +65,8 @@ } /** Factory for literal constants (String, Integer, etc.). */ public static synchronized LiteralEntry getLiteralEntry(Comparable value) { - LiteralEntry e = (LiteralEntry) literalEntries.get(value); + Map<Object, LiteralEntry> literalEntries = Utils.getLiteralEntries(); + LiteralEntry e = literalEntries.get(value); if (e == null) { if (value instanceof String) e = new StringEntry(getUtf8Entry((String)value)); @@ -89,7 +83,8 @@ /** Factory for signature (type) constants. */ public static synchronized SignatureEntry getSignatureEntry(String type) { - SignatureEntry e = (SignatureEntry) signatureEntries.get(type); + Map<String, SignatureEntry> signatureEntries = Utils.getSignatureEntries(); + SignatureEntry e = signatureEntries.get(type); if (e == null) { e = new SignatureEntry(type); assert(e.stringValue().equals(type)); @@ -104,8 +99,9 @@ /** Factory for descriptor (name-and-type) constants. */ public static synchronized DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, SignatureEntry typeRef) { + Map<String, DescriptorEntry> descriptorEntries = Utils.getDescriptorEntries(); String key = DescriptorEntry.stringValueOf(nameRef, typeRef); - DescriptorEntry e = (DescriptorEntry) descriptorEntries.get(key); + DescriptorEntry e = descriptorEntries.get(key); if (e == null) { e = new DescriptorEntry(nameRef, typeRef); assert(e.stringValue().equals(key)) @@ -121,8 +117,9 @@ /** Factory for member reference constants. */ public static synchronized MemberEntry getMemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) { + Map<String, MemberEntry> memberEntries = Utils.getMemberEntries(); String key = MemberEntry.stringValueOf(tag, classRef, descRef); - MemberEntry e = (MemberEntry) memberEntries.get(key); + MemberEntry e = memberEntries.get(key); if (e == null) { e = new MemberEntry(tag, classRef, descRef); assert(e.stringValue().equals(key)) @@ -489,8 +486,9 @@ String[] parts = structureSignature(value); formRef = getUtf8Entry(parts[0]); classRefs = new ClassEntry[parts.length-1]; - for (int i = 1; i < parts.length; i++) - classRefs[i-1] = getClassEntry(parts[i]); + for (int i = 1; i < parts.length; i++) { + classRefs[i - 1] = getClassEntry(parts[i]); + } hashCode(); // force computation of valueHash } protected int computeValueHash() { @@ -527,8 +525,9 @@ String stringValueOf(Utf8Entry formRef, ClassEntry[] classRefs) { String[] parts = new String[1+classRefs.length]; parts[0] = formRef.stringValue(); - for (int i = 1; i < parts.length; i++) - parts[i] = classRefs[i-1].stringValue(); + for (int i = 1; i < parts.length; i++) { + parts[i] = classRefs[i - 1].stringValue(); + } return flattenSignature(parts).intern(); } @@ -543,19 +542,23 @@ int size = 0; for (int i = min; i < max; i++) { switch (form.charAt(i)) { - case 'D': - case 'J': - if (countDoublesTwice) size++; - break; - case '[': - // Skip rest of array info. - while (form.charAt(i) == '[') ++i; - break; - case ';': - continue; - default: - assert(0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i))); - break; + case 'D': + case 'J': + if (countDoublesTwice) { + size++; + } + break; + case '[': + // Skip rest of array info. + while (form.charAt(i) == '[') { + ++i; + } + break; + case ';': + continue; + default: + assert (0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i))); + break; } size++; } @@ -586,8 +589,9 @@ s = "/" + formRef.stringValue(); } int i; - while ((i = s.indexOf(';')) >= 0) - s = s.substring(0,i) + s.substring(i+1); + while ((i = s.indexOf(';')) >= 0) { + s = s.substring(0, i) + s.substring(i + 1); + } return s; } } @@ -732,11 +736,11 @@ clearIndex(); this.cpMap = cpMap; } - protected Index(String debugName, Collection cpMapList) { + protected Index(String debugName, Collection<Entry> cpMapList) { this(debugName); setMap(cpMapList); } - protected void setMap(Collection cpMapList) { + protected void setMap(Collection<Entry> cpMapList) { cpMap = new Entry[cpMapList.size()]; cpMapList.toArray(cpMap); setMap(cpMap); @@ -756,11 +760,13 @@ // // As a special hack, if flattenSigs, signatures are // treated as equivalent entries of cpMap. This is wrong - // fron a Collection point of view, because contains() + // from a Collection point of view, because contains() // reports true for signatures, but the iterator() // never produces them! private int findIndexOf(Entry e) { - if (indexKey == null) initializeIndex(); + if (indexKey == null) { + initializeIndex(); + } int probe = findIndexLocation(e); if (indexKey[probe] != e) { if (flattenSigs && e.tag == CONSTANT_Signature) { @@ -832,7 +838,9 @@ System.out.println("initialize Index "+debugName+" ["+size()+"]"); int hsize0 = (int)((cpMap.length + 10) * 1.5); int hsize = 1; - while (hsize < hsize0) hsize <<= 1; + while (hsize < hsize0) { + hsize <<= 1; + } indexKey = new Entry[hsize]; indexValue = new int[hsize]; for (int i = 0; i < cpMap.length; i++) { @@ -855,7 +863,7 @@ return toArray(new Entry[size()]); } public Object clone() { - return new Index(debugName, (Entry[]) cpMap.clone()); + return new Index(debugName, cpMap.clone()); } public String toString() { return "Index "+debugName+" ["+size()+"]"; @@ -901,22 +909,24 @@ public static Index[] partition(Index ix, int[] keys) { // %%% Should move this into class Index. - ArrayList parts = new ArrayList(); + ArrayList<List<Entry>> parts = new ArrayList<>(); Entry[] cpMap = ix.cpMap; assert(keys.length == cpMap.length); for (int i = 0; i < keys.length; i++) { int key = keys[i]; if (key < 0) continue; - while (key >= parts.size()) parts.add(null); - ArrayList part = (ArrayList) parts.get(key); + while (key >= parts.size()) { + parts.add(null); + } + List<Entry> part = parts.get(key); if (part == null) { - parts.set(key, part = new ArrayList()); + parts.set(key, part = new ArrayList<>()); } part.add(cpMap[i]); } Index[] indexes = new Index[parts.size()]; for (int key = 0; key < indexes.length; key++) { - ArrayList part = (ArrayList) parts.get(key); + List<Entry> part = parts.get(key); if (part == null) continue; indexes[key] = new Index(ix.debugName+"/part#"+key, part); assert(indexes[key].indexOf(part.get(0)) == 0); @@ -1048,9 +1058,10 @@ whichClasses[i] = whichClass; } perClassIndexes = partition(allMembers, whichClasses); - for (int i = 0; i < perClassIndexes.length; i++) - assert(perClassIndexes[i]==null - || perClassIndexes[i].assertIsSorted()); + for (int i = 0; i < perClassIndexes.length; i++) { + assert (perClassIndexes[i] == null || + perClassIndexes[i].assertIsSorted()); + } indexByTagAndClass[tag] = perClassIndexes; } int whichClass = allClasses.indexOf(classRef); @@ -1113,7 +1124,7 @@ * Also, discard null from cpRefs. */ public static - void completeReferencesIn(Set cpRefs, boolean flattenSigs) { + void completeReferencesIn(Set<Entry> cpRefs, boolean flattenSigs) { cpRefs.remove(null); for (ListIterator work = new ArrayList(cpRefs).listIterator(cpRefs.size());
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java Mon Aug 23 19:14:20 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,7 +25,6 @@ package com.sun.java.util.jar.pack; -import java.lang.Error; import java.io.*; import java.text.MessageFormat; import java.util.*; @@ -35,10 +34,11 @@ /** Command line interface for Pack200. */ class Driver { - private static final ResourceBundle RESOURCE= ResourceBundle.getBundle("com.sun.java.util.jar.pack.DriverResource"); + private static final ResourceBundle RESOURCE = + ResourceBundle.getBundle("com.sun.java.util.jar.pack.DriverResource"); public static void main(String[] ava) throws IOException { - ArrayList<String> av = new ArrayList<String>(Arrays.asList(ava)); + ArrayList<String> av = new ArrayList<>(Arrays.asList(ava)); boolean doPack = true; boolean doUnpack = false; @@ -61,7 +61,7 @@ } // Collect engine properties here: - HashMap<String,String> engProps = new HashMap<String,String>(); + HashMap<String,String> engProps = new HashMap<>(); engProps.put(verboseProp, System.getProperty(verboseProp)); String optionMap; @@ -75,7 +75,7 @@ } // Collect argument properties here: - HashMap<String,String> avProps = new HashMap<String,String>(); + HashMap<String,String> avProps = new HashMap<>(); try { for (;;) { String state = parseCommandOptions(av, optionMap, avProps); @@ -133,8 +133,9 @@ if (engProps.get(verboseProp) != null) fileProps.list(System.out); propIn.close(); - for (Map.Entry<Object,Object> me : fileProps.entrySet()) - engProps.put((String)me.getKey(), (String)me.getValue()); + for (Map.Entry<Object,Object> me : fileProps.entrySet()) { + engProps.put((String) me.getKey(), (String) me.getValue()); + } } else if (state == "--version") { System.out.println(MessageFormat.format(RESOURCE.getString(DriverResource.VERSION), Driver.class.getName(), "1.31, 07/05/05")); return; @@ -493,7 +494,7 @@ String resultString = null; // Convert options string into optLines dictionary. - TreeMap<String,String[]> optmap = new TreeMap<String,String[]>(); + TreeMap<String,String[]> optmap = new TreeMap<>(); loadOptmap: for (String optline : options.split("\n")) { String[] words = optline.split("\\p{Space}+"); @@ -687,7 +688,9 @@ // Report number of arguments consumed. args.subList(0, argp.nextIndex()).clear(); // Report any unconsumed partial argument. - while (pbp.hasPrevious()) args.add(0, pbp.previous()); + while (pbp.hasPrevious()) { + args.add(0, pbp.previous()); + } //System.out.println(args+" // "+properties+" -> "+resultString); return resultString; }
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java Mon Aug 23 19:14:20 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -28,13 +28,8 @@ import java.nio.*; import java.io.*; -import java.nio.channels.*; -import java.util.Date; import java.util.jar.*; import java.util.zip.*; -import java.util.*; -//import com.sun.java.util.jar.pack.Pack200; - class NativeUnpack { // Pointer to the native unpacker obj @@ -91,13 +86,13 @@ NativeUnpack(UnpackerImpl p200) { super(); _p200 = p200; - _props = p200._props; + _props = p200.props; p200._nunp = this; } // for JNI callbacks static private Object currentInstance() { - UnpackerImpl p200 = (UnpackerImpl) Utils.currentInstance.get(); + UnpackerImpl p200 = (UnpackerImpl) Utils.getTLGlobals(); return (p200 == null)? null: p200._nunp; } @@ -216,10 +211,10 @@ ++_fileCount; updateProgress(); } + presetInput = getUnusedInput(); long consumed = finish(); if (_verbose > 0) Utils.log.info("bytes consumed = "+consumed); - presetInput = getUnusedInput(); if (presetInput == null && !Utils.isPackMagic(Utils.readMagic(in))) { break;
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java Mon Aug 23 19:14:20 2010 -0700 @@ -25,9 +25,9 @@ package com.sun.java.util.jar.pack; +import com.sun.java.util.jar.pack.Attribute.Layout; import java.lang.reflect.Modifier; import java.util.*; -import java.util.zip.*; import java.util.jar.*; import java.io.*; import com.sun.java.util.jar.pack.ConstantPool.*; @@ -77,10 +77,11 @@ cp = new ConstantPool.IndexGroup(); classes.clear(); files.clear(); + BandStructure.nextSeqForDebug = 0; } int getPackageVersion() { - return (package_majver << 16) + (int)package_minver; + return (package_majver << 16) + package_minver; } // Special empty versions of Code and InnerClasses, used for markers. @@ -89,7 +90,7 @@ public static final Attribute.Layout attrSourceFileSpecial; public static final Map attrDefs; static { - HashMap ad = new HashMap(2); + HashMap<Layout, Attribute> ad = new HashMap<>(3); attrCodeEmpty = Attribute.define(ad, ATTR_CONTEXT_METHOD, "Code", "").layout(); attrInnerClassesEmpty = Attribute.define(ad, ATTR_CONTEXT_CLASS, @@ -159,9 +160,9 @@ } } - ArrayList classes = new ArrayList(); + ArrayList<Package.Class> classes = new ArrayList<>(); - public List getClasses() { + public List<Package.Class> getClasses() { return classes; } @@ -186,11 +187,11 @@ ClassEntry[] interfaces; // Class parts - ArrayList fields; - ArrayList methods; + ArrayList<Field> fields; + ArrayList<Method> methods; //ArrayList attributes; // in Attribute.Holder.this.attributes // Note that InnerClasses may be collected at the package level. - ArrayList innerClasses; + ArrayList<InnerClass> innerClasses; Class(int flags, ClassEntry thisClass, ClassEntry superClass, ClassEntry[] interfaces) { this.magic = JAVA_MAGIC; @@ -270,7 +271,7 @@ if (a != olda) { if (verbose > 2) Utils.log.fine("recoding obvious SourceFile="+obvious); - List newAttrs = new ArrayList(getAttributes()); + List<Attribute> newAttrs = new ArrayList<>(getAttributes()); int where = newAttrs.indexOf(olda); newAttrs.set(where, a); setAttributes(newAttrs); @@ -295,12 +296,12 @@ boolean hasInnerClasses() { return innerClasses != null; } - List getInnerClasses() { + List<InnerClass> getInnerClasses() { return innerClasses; } - public void setInnerClasses(Collection ics) { - innerClasses = (ics == null) ? null : new ArrayList(ics); + public void setInnerClasses(Collection<InnerClass> ics) { + innerClasses = (ics == null) ? null : new ArrayList<InnerClass>(ics); // Edit the attribute list, if necessary. Attribute a = getAttribute(attrInnerClassesEmpty); if (innerClasses != null && a == null) @@ -318,19 +319,18 @@ * The order of the resulting list is consistent * with that of Package.this.allInnerClasses. */ - public List computeGloballyImpliedICs() { - HashSet cpRefs = new HashSet(); + public List<InnerClass> computeGloballyImpliedICs() { + HashSet<Entry> cpRefs = new HashSet<>(); { // This block temporarily displaces this.innerClasses. - ArrayList innerClassesSaved = innerClasses; + ArrayList<InnerClass> innerClassesSaved = innerClasses; innerClasses = null; // ignore for the moment visitRefs(VRM_CLASSIC, cpRefs); innerClasses = innerClassesSaved; } ConstantPool.completeReferencesIn(cpRefs, true); - HashSet icRefs = new HashSet(); - for (Iterator i = cpRefs.iterator(); i.hasNext(); ) { - Entry e = (Entry) i.next(); + HashSet<Entry> icRefs = new HashSet<>(); + for (Entry e : cpRefs) { // Restrict cpRefs to InnerClasses entries only. if (!(e instanceof ClassEntry)) continue; // For every IC reference, add its outers also. @@ -345,9 +345,8 @@ // This loop is structured this way so as to accumulate // entries into impliedICs in an order which reflects // the order of allInnerClasses. - ArrayList impliedICs = new ArrayList(); - for (Iterator i = allInnerClasses.iterator(); i.hasNext(); ) { - InnerClass ic = (InnerClass) i.next(); + ArrayList<InnerClass> impliedICs = new ArrayList<>(); + for (InnerClass ic : allInnerClasses) { // This one is locally relevant if it describes // a member of the current class, or if the current // class uses it somehow. In the particular case @@ -366,10 +365,11 @@ // Helper for both minimizing and expanding. // Computes a symmetric difference. - private List computeICdiff() { - List impliedICs = computeGloballyImpliedICs(); - List actualICs = getInnerClasses(); - if (actualICs == null) actualICs = Collections.EMPTY_LIST; + private List<InnerClass> computeICdiff() { + List<InnerClass> impliedICs = computeGloballyImpliedICs(); + List<InnerClass> actualICs = getInnerClasses(); + if (actualICs == null) + actualICs = Collections.EMPTY_LIST; // Symmetric difference is calculated from I, A like this: // diff = (I+A) - (I*A) @@ -388,8 +388,8 @@ // Diff is A since I is empty. } // (I*A) is non-trivial - HashSet center = new HashSet(actualICs); - center.retainAll(new HashSet(impliedICs)); + HashSet<InnerClass> center = new HashSet<>(actualICs); + center.retainAll(new HashSet<>(impliedICs)); impliedICs.addAll(actualICs); impliedICs.removeAll(center); // Diff is now I^A = (I+A)-(I*A). @@ -407,9 +407,9 @@ * to use the globally implied ICs changed. */ void minimizeLocalICs() { - List diff = computeICdiff(); - List actualICs = innerClasses; - List localICs; // will be the diff, modulo edge cases + List<InnerClass> diff = computeICdiff(); + List<InnerClass> actualICs = innerClasses; + List<InnerClass> localICs; // will be the diff, modulo edge cases if (diff.isEmpty()) { // No diff, so transmit no attribute. localICs = null; @@ -439,12 +439,12 @@ * Otherwise, return positive if any IC tuples were added. */ int expandLocalICs() { - List localICs = innerClasses; - List actualICs; + List<InnerClass> localICs = innerClasses; + List<InnerClass> actualICs; int changed; if (localICs == null) { // Diff was empty. (Common case.) - List impliedICs = computeGloballyImpliedICs(); + List<InnerClass> impliedICs = computeGloballyImpliedICs(); if (impliedICs.isEmpty()) { actualICs = null; changed = 0; @@ -490,7 +490,7 @@ protected Entry[] getCPMap() { return cpMap; } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection<Entry> refs) { if (verbose > 2) Utils.log.fine("visitRefs "+this); // Careful: The descriptor is used by the package, // but the classfile breaks it into component refs. @@ -518,7 +518,7 @@ super(flags, descriptor); assert(!descriptor.isMethod()); if (fields == null) - fields = new ArrayList(); + fields = new ArrayList<>(); boolean added = fields.add(this); assert(added); order = fields.size(); @@ -543,7 +543,7 @@ super(flags, descriptor); assert(descriptor.isMethod()); if (methods == null) - methods = new ArrayList(); + methods = new ArrayList<>(); boolean added = methods.add(this); assert(added); } @@ -573,7 +573,7 @@ code.strip(attrName); super.strip(attrName); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection<Entry> refs) { super.visitRefs(mode, refs); if (code != null) { if (mode == VRM_CLASSIC) { @@ -614,7 +614,7 @@ super.strip(attrName); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection<Entry> refs) { if (verbose > 2) Utils.log.fine("visitRefs "+this); refs.add(thisClass); refs.add(superClass); @@ -641,7 +641,7 @@ super.visitRefs(mode, refs); } - protected void visitInnerClassRefs(int mode, Collection refs) { + protected void visitInnerClassRefs(int mode, Collection<Entry> refs) { Package.visitInnerClassRefs(innerClasses, mode, refs); } @@ -713,16 +713,15 @@ } // What non-class files are in this unit? - ArrayList files = new ArrayList(); + ArrayList<File> files = new ArrayList<>(); - public List getFiles() { + public List<File> getFiles() { return files; } - public List getClassStubs() { - ArrayList classStubs = new ArrayList(classes.size()); - for (Iterator i = classes.iterator(); i.hasNext(); ) { - Class cls = (Class) i.next(); + public List<File> getClassStubs() { + ArrayList<File> classStubs = new ArrayList<>(classes.size()); + for (Class cls : classes) { assert(cls.file.isClassStub()); classStubs.add(cls.file); } @@ -840,7 +839,7 @@ public InputStream getInputStream() { InputStream in = new ByteArrayInputStream(append.toByteArray()); if (prepend.size() == 0) return in; - ArrayList isa = new ArrayList(prepend.size()+1); + ArrayList<InputStream> isa = new ArrayList<>(prepend.size()+1); for (Iterator i = prepend.iterator(); i.hasNext(); ) { byte[] bytes = (byte[]) i.next(); isa.add(new ByteArrayInputStream(bytes)); @@ -849,7 +848,7 @@ return new SequenceInputStream(Collections.enumeration(isa)); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection<Entry> refs) { assert(name != null); refs.add(name); } @@ -877,8 +876,8 @@ } // Is there a globally declared table of inner classes? - ArrayList allInnerClasses = new ArrayList(); - HashMap allInnerClassesByThis; + ArrayList<InnerClass> allInnerClasses = new ArrayList<>(); + HashMap<ClassEntry, InnerClass> allInnerClassesByThis; public List getAllInnerClasses() { @@ -886,15 +885,14 @@ } public - void setAllInnerClasses(Collection ics) { + void setAllInnerClasses(Collection<InnerClass> ics) { assert(ics != allInnerClasses); allInnerClasses.clear(); allInnerClasses.addAll(ics); // Make an index: - allInnerClassesByThis = new HashMap(allInnerClasses.size()); - for (Iterator i = allInnerClasses.iterator(); i.hasNext(); ) { - InnerClass ic = (InnerClass) i.next(); + allInnerClassesByThis = new HashMap<>(allInnerClasses.size()); + for (InnerClass ic : allInnerClasses) { Object pic = allInnerClassesByThis.put(ic.thisClass, ic); assert(pic == null); // caller must ensure key uniqueness! } @@ -904,7 +902,7 @@ public InnerClass getGlobalInnerClass(Entry thisClass) { assert(thisClass instanceof ClassEntry); - return (InnerClass) allInnerClassesByThis.get(thisClass); + return allInnerClassesByThis.get(thisClass); } static @@ -963,7 +961,7 @@ return this.thisClass.compareTo(that.thisClass); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection<Entry> refs) { refs.add(thisClass); if (mode == VRM_CLASSIC || !predictable) { // If the name can be demangled, the package omits @@ -980,7 +978,7 @@ // Helper for building InnerClasses attributes. static private - void visitInnerClassRefs(Collection innerClasses, int mode, Collection refs) { + void visitInnerClassRefs(Collection innerClasses, int mode, Collection<Entry> refs) { if (innerClasses == null) { return; // no attribute; nothing to do } @@ -1165,9 +1163,8 @@ } } - protected void visitRefs(int mode, Collection refs) { - for (Iterator i = classes.iterator(); i.hasNext(); ) { - Class c = (Class)i.next(); + protected void visitRefs(int mode, Collection<Entry> refs) { + for ( Class c : classes) { c.visitRefs(mode, refs); } if (mode != VRM_CLASSIC) { @@ -1259,7 +1256,7 @@ } // Use this before writing the package file. - void buildGlobalConstantPool(Set requiredEntries) { + void buildGlobalConstantPool(Set<Entry> requiredEntries) { if (verbose > 1) Utils.log.fine("Checking for unused CP entries"); requiredEntries.add(getRefString("")); // uconditionally present @@ -1291,9 +1288,8 @@ // Use this before writing the class files. void ensureAllClassFiles() { - HashSet fileSet = new HashSet(files); - for (Iterator i = classes.iterator(); i.hasNext(); ) { - Class cls = (Class) i.next(); + HashSet<File> fileSet = new HashSet<>(files); + for (Class cls : classes) { // Add to the end of ths list: if (!fileSet.contains(cls.file)) files.add(cls.file);
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java Mon Aug 23 19:14:20 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,12 +25,11 @@ package com.sun.java.util.jar.pack; +import com.sun.java.util.jar.pack.Attribute.Layout; import java.util.*; import java.util.jar.*; -import java.util.zip.*; import java.io.*; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeEvent; /* @@ -41,31 +40,22 @@ */ -public class PackerImpl implements Pack200.Packer { +public class PackerImpl extends TLGlobals implements Pack200.Packer { /** * Constructs a Packer object and sets the initial state of * the packer engines. */ - public PackerImpl() { - _props = new PropMap(); - //_props.getProperty() consults defaultProps invisibly. - //_props.putAll(defaultProps); - } - - - // Private stuff. - final PropMap _props; + public PackerImpl() {} /** * Get the set of options for the pack and unpack engines. * @return A sorted association of option key strings to option values. */ - public SortedMap properties() { - return _props; + public SortedMap<String, String> properties() { + return props; } - //Driver routines /** @@ -78,21 +68,22 @@ */ public void pack(JarFile in, OutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : - TimeZone.getDefault(); + TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) + ? null + : TimeZone.getDefault(); try { Utils.currentInstance.set(this); if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { + if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) { Utils.copyJarFile(in, out); } else { (new DoPack()).run(in, out); - in.close(); } } finally { Utils.currentInstance.set(null); if (tz != null) TimeZone.setDefault(tz); + in.close(); } } @@ -112,21 +103,20 @@ */ public void pack(JarInputStream in, OutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : + TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : TimeZone.getDefault(); try { Utils.currentInstance.set(this); if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { + if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) { Utils.copyJarFile(in, out); } else { (new DoPack()).run(in, out); - in.close(); } } finally { Utils.currentInstance.set(null); if (tz != null) TimeZone.setDefault(tz); - + in.close(); } } /** @@ -134,7 +124,7 @@ * @param listener An object to be invoked when a property is changed. */ public void addPropertyChangeListener(PropertyChangeListener listener) { - _props.addListener(listener); + props.addListener(listener); } /** @@ -142,7 +132,7 @@ * @param listener The PropertyChange listener to be removed. */ public void removePropertyChangeListener(PropertyChangeListener listener) { - _props.removeListener(listener); + props.removeListener(listener); } @@ -151,11 +141,11 @@ // The packer worker. private class DoPack { - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); { - _props.setInteger(Pack200.Packer.PROGRESS, 0); - if (verbose > 0) Utils.log.info(_props.toString()); + props.setInteger(Pack200.Packer.PROGRESS, 0); + if (verbose > 0) Utils.log.info(props.toString()); } // Here's where the bits are collected before getting packed: @@ -163,7 +153,7 @@ final String unknownAttrCommand; { - String uaMode = _props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); + String uaMode = props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); if (!(Pack200.Packer.STRIP.equals(uaMode) || Pack200.Packer.PASS.equals(uaMode) || Pack200.Packer.ERROR.equals(uaMode))) { @@ -191,13 +181,12 @@ }; for (int i = 0; i < ctypes.length; i++) { String pfx = keys[i]; - Map map = _props.prefixMap(pfx); - for (Iterator j = map.keySet().iterator(); j.hasNext(); ) { - String key = (String) j.next(); + Map<String, String> map = props.prefixMap(pfx); + for (String key : map.keySet()) { assert(key.startsWith(pfx)); String name = key.substring(pfx.length()); - String layout = _props.getProperty(key); - Object lkey = Attribute.keyForLookup(ctypes[i], name); + String layout = props.getProperty(key); + Layout lkey = Attribute.keyForLookup(ctypes[i], name); if (Pack200.Packer.STRIP.equals(layout) || Pack200.Packer.PASS.equals(layout) || Pack200.Packer.ERROR.equals(layout)) { @@ -222,25 +211,25 @@ } final boolean keepFileOrder - = _props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER); + = props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER); final boolean keepClassOrder - = _props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER); + = props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER); final boolean keepModtime - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); + = Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME)); final boolean latestModtime - = Pack200.Packer.LATEST.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); + = Pack200.Packer.LATEST.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME)); final boolean keepDeflateHint - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.DEFLATE_HINT)); + = Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.DEFLATE_HINT)); { if (!keepModtime && !latestModtime) { - int modtime = _props.getTime(Pack200.Packer.MODIFICATION_TIME); + int modtime = props.getTime(Pack200.Packer.MODIFICATION_TIME); if (modtime != Constants.NO_MODTIME) { pkg.default_modtime = modtime; } } if (!keepDeflateHint) { - boolean deflate_hint = _props.getBoolean(Pack200.Packer.DEFLATE_HINT); + boolean deflate_hint = props.getBoolean(Pack200.Packer.DEFLATE_HINT); if (deflate_hint) { pkg.default_options |= Constants.AO_DEFLATE_HINT; } @@ -254,10 +243,10 @@ final long segmentLimit; { long limit; - if (_props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals("")) + if (props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals("")) limit = -1; else - limit = _props.getLong(Pack200.Packer.SEGMENT_LIMIT); + limit = props.getLong(Pack200.Packer.SEGMENT_LIMIT); limit = Math.min(Integer.MAX_VALUE, limit); limit = Math.max(-1, limit); if (limit == -1) @@ -265,10 +254,10 @@ segmentLimit = limit; } - final List passFiles; // parsed pack.pass.file options + final List<String> passFiles; // parsed pack.pass.file options { // Which class files will be passed through? - passFiles = _props.getProperties(Pack200.Packer.PASS_FILE_PFX); + passFiles = props.getProperties(Pack200.Packer.PASS_FILE_PFX); for (ListIterator i = passFiles.listIterator(); i.hasNext(); ) { String file = (String) i.next(); if (file == null) { i.remove(); continue; } @@ -283,28 +272,28 @@ { // Fill in permitted range of major/minor version numbers. int ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"min.class.majver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.majver")) != 0) pkg.min_class_majver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"min.class.minver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.minver")) != 0) pkg.min_class_minver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"max.class.majver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.majver")) != 0) pkg.max_class_majver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"max.class.minver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.minver")) != 0) pkg.max_class_minver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"package.minver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"package.minver")) != 0) pkg.package_minver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"package.majver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"package.majver")) != 0) pkg.package_majver = (short) ver; } { // Hook for testing: Forces use of special archive modes. - int opt = _props.getInteger(Utils.COM_PREFIX+"archive.options"); + int opt = props.getInteger(Utils.COM_PREFIX+"archive.options"); if (opt != 0) pkg.default_options |= opt; } - // (Done collecting options from _props.) + // (Done collecting options from props.) boolean isClassFile(String name) { if (!name.endsWith(".class")) return false; @@ -423,16 +412,18 @@ Package.File file = null; // (5078608) : discount the resource files in META-INF // from segment computation. - long inflen = (isMetaInfFile(name)) ? 0L : - inFile.getInputLength(); + long inflen = (isMetaInfFile(name)) + ? 0L + : inFile.getInputLength(); if ((segmentSize += inflen) > segmentLimit) { segmentSize -= inflen; int nextCount = -1; // don't know; it's a stream flushPartial(out, nextCount); } - if (verbose > 1) + if (verbose > 1) { Utils.log.fine("Reading " + name); + } assert(je.isDirectory() == name.endsWith("/")); @@ -450,18 +441,18 @@ } void run(JarFile in, OutputStream out) throws IOException { - List inFiles = scanJar(in); + List<InFile> inFiles = scanJar(in); if (verbose > 0) Utils.log.info("Reading " + inFiles.size() + " files..."); int numDone = 0; - for (Iterator i = inFiles.iterator(); i.hasNext(); ) { - InFile inFile = (InFile) i.next(); + for (InFile inFile : inFiles) { String name = inFile.name; // (5078608) : discount the resource files completely from segmenting - long inflen = (isMetaInfFile(name)) ? 0L : - inFile.getInputLength() ; + long inflen = (isMetaInfFile(name)) + ? 0L + : inFile.getInputLength() ; if ((segmentSize += inflen) > segmentLimit) { segmentSize -= inflen; // Estimate number of remaining segments: @@ -530,11 +521,11 @@ } void flushPartial(OutputStream out, int nextCount) throws IOException { - if (pkg.files.size() == 0 && pkg.classes.size() == 0) { + if (pkg.files.isEmpty() && pkg.classes.isEmpty()) { return; // do not flush an empty segment } flushPackage(out, Math.max(1, nextCount)); - _props.setInteger(Pack200.Packer.PROGRESS, 25); + props.setInteger(Pack200.Packer.PROGRESS, 25); // In case there will be another segment: makeNextPackage(); segmentCount += 1; @@ -543,10 +534,10 @@ } void flushAll(OutputStream out) throws IOException { - _props.setInteger(Pack200.Packer.PROGRESS, 50); + props.setInteger(Pack200.Packer.PROGRESS, 50); flushPackage(out, 0); out.flush(); - _props.setInteger(Pack200.Packer.PROGRESS, 100); + props.setInteger(Pack200.Packer.PROGRESS, 100); segmentCount += 1; segmentTotalSize += segmentSize; segmentSize = 0; @@ -582,11 +573,11 @@ pkg.trimStubs(); // Do some stripping, maybe. - if (_props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses"); // Must choose an archive version; PackageWriter does not. if (pkg.package_majver <= 0) pkg.choosePackageVersion(); @@ -606,11 +597,10 @@ } } - List scanJar(JarFile jf) throws IOException { + List<InFile> scanJar(JarFile jf) throws IOException { // Collect jar entries, preserving order. - List inFiles = new ArrayList(); - for (Enumeration e = jf.entries(); e.hasMoreElements(); ) { - JarEntry je = (JarEntry) e.nextElement(); + List<InFile> inFiles = new ArrayList<>(); + for (JarEntry je : Collections.list(jf.entries())) { InFile inFile = new InFile(jf, je); assert(je.isDirectory() == inFile.name.endsWith("/")); inFiles.add(inFile);
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java Mon Aug 23 19:14:20 2010 -0700 @@ -91,7 +91,7 @@ String.valueOf(Boolean.getBoolean(Utils.PACK_DEFAULT_TIMEZONE))); // The segment size is unlimited - props.put(Pack200.Packer.SEGMENT_LIMIT, ""); + props.put(Pack200.Packer.SEGMENT_LIMIT, "-1"); // Preserve file ordering by default. props.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.TRUE);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.java.util.jar.pack; + +import com.sun.java.util.jar.pack.ConstantPool.ClassEntry; +import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry; +import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry; +import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; +import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; +import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedMap; + +/* + * @author ksrini + */ + +/* + * This class provides a container to hold the global variables, for packer + * and unpacker instances. This is typically stashed away in a ThreadLocal, + * and the storage is destroyed upon completion. Therefore any local + * references to these members must be eliminated appropriately to prevent a + * memory leak. + */ +class TLGlobals { + // Global environment + final PropMap props; + + // Needed by ConstantPool.java + private final Map<String, Utf8Entry> utf8Entries; + private final Map<String, ClassEntry> classEntries; + private final Map<Object, LiteralEntry> literalEntries; + private final Map<String, SignatureEntry> signatureEntries; + private final Map<String, DescriptorEntry> descriptorEntries; + private final Map<String, MemberEntry> memberEntries; + + TLGlobals() { + utf8Entries = new HashMap<>(); + classEntries = new HashMap<>(); + literalEntries = new HashMap<>(); + signatureEntries = new HashMap<>(); + descriptorEntries = new HashMap<>(); + memberEntries = new HashMap<>(); + props = new PropMap(); + } + + SortedMap<Object, Object> getPropMap() { + return props; + } + + Map<String, Utf8Entry> getUtf8Entries() { + return utf8Entries; + } + + Map<String, ClassEntry> getClassEntries() { + return classEntries; + } + + Map<Object, LiteralEntry> getLiteralEntries() { + return literalEntries; + } + + Map<String, DescriptorEntry> getDescriptorEntries() { + return descriptorEntries; + } + + Map<String, SignatureEntry> getSignatureEntries() { + return signatureEntries; + } + + Map<String, MemberEntry> getMemberEntries() { + return memberEntries; + } +}
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java Mon Aug 23 19:14:20 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -30,7 +30,6 @@ import java.util.zip.*; import java.io.*; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeEvent; /* * Implementation of the Pack provider. @@ -40,7 +39,7 @@ */ -public class UnpackerImpl implements Pack200.Unpacker { +public class UnpackerImpl extends TLGlobals implements Pack200.Unpacker { /** @@ -48,7 +47,7 @@ * @param listener An object to be invoked when a property is changed. */ public void addPropertyChangeListener(PropertyChangeListener listener) { - _props.addListener(listener); + props.addListener(listener); } @@ -57,25 +56,19 @@ * @param listener The PropertyChange listener to be removed. */ public void removePropertyChangeListener(PropertyChangeListener listener) { - _props.removeListener(listener); + props.removeListener(listener); } - public UnpackerImpl() { - _props = new PropMap(); - //_props.getProperty() consults defaultProps invisibly. - //_props.putAll(defaultProps); - } + public UnpackerImpl() {} - // Private stuff. - final PropMap _props; /** * Get the set of options for the pack and unpack engines. * @return A sorted association of option key strings to option values. */ - public SortedMap properties() { - return _props; + public SortedMap<String, String> properties() { + return props; } // Back-pointer to NativeUnpacker, when active. @@ -101,19 +94,20 @@ */ public void unpack(InputStream in0, JarOutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : - TimeZone.getDefault(); + TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) + ? null + : TimeZone.getDefault(); try { Utils.currentInstance.set(this); if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); BufferedInputStream in = new BufferedInputStream(in0); if (Utils.isJarMagic(Utils.readMagic(in))) { if (verbose > 0) Utils.log.info("Copying unpacked JAR file..."); Utils.copyJarFile(new JarInputStream(in), out); - } else if (_props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { + } else if (props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { (new DoUnpack()).run(in, out); in.close(); Utils.markJarFile(out); @@ -142,36 +136,38 @@ // %%% Reconsider if native unpacker learns to memory-map the file. FileInputStream instr = new FileInputStream(in); unpack(instr, out); - if (_props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { + if (props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { in.delete(); } } private class DoUnpack { - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); { - _props.setInteger(Pack200.Unpacker.PROGRESS, 0); + props.setInteger(Pack200.Unpacker.PROGRESS, 0); } // Here's where the bits are read from disk: final Package pkg = new Package(); final boolean keepModtime - = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); + = Pack200.Packer.KEEP.equals( + props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); final boolean keepDeflateHint - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); + = Pack200.Packer.KEEP.equals( + props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); final int modtime; final boolean deflateHint; { if (!keepModtime) { - modtime = _props.getTime(Utils.UNPACK_MODIFICATION_TIME); + modtime = props.getTime(Utils.UNPACK_MODIFICATION_TIME); } else { modtime = pkg.default_modtime; } deflateHint = (keepDeflateHint) ? false : - _props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); + props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); } // Checksum apparatus. @@ -181,7 +177,7 @@ public void run(BufferedInputStream in, JarOutputStream out) throws IOException { if (verbose > 0) { - _props.list(System.out); + props.list(System.out); } for (int seg = 1; ; seg++) { unpackSegment(in, out); @@ -194,25 +190,26 @@ } private void unpackSegment(InputStream in, JarOutputStream out) throws IOException { - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); + props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); // Process the output directory or jar output. new PackageReader(pkg, in).read(); - if (_props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); - if (_props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); + if (props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); + if (props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); + props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); pkg.ensureAllClassFiles(); // Now write out the files. - HashSet classesToWrite = new HashSet(pkg.getClasses()); + HashSet<Package.Class> classesToWrite = new HashSet<>(pkg.getClasses()); for (Iterator i = pkg.getFiles().iterator(); i.hasNext(); ) { Package.File file = (Package.File) i.next(); String name = file.nameString; JarEntry je = new JarEntry(Utils.getJarEntryName(name)); boolean deflate; - deflate = (keepDeflateHint) ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || - ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) : - deflateHint; + deflate = (keepDeflateHint) + ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || + ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) + : deflateHint; boolean needCRC = !deflate; // STORE mode requires CRC @@ -250,7 +247,7 @@ Utils.log.info("Writing "+Utils.zeString((ZipEntry)je)); } assert(classesToWrite.isEmpty()); - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100"); + props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100"); pkg.reset(); // reset for the next segment, if any } }
--- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java Mon Aug 23 19:14:20 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,6 +25,13 @@ package com.sun.java.util.jar.pack; +import com.sun.java.util.jar.pack.Attribute.Layout; +import com.sun.java.util.jar.pack.ConstantPool.ClassEntry; +import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry; +import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry; +import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; +import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; +import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; import java.util.*; import java.util.jar.*; import java.util.zip.*; @@ -113,17 +120,46 @@ */ static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200"; - // Keep a TLS point to the current Packer or Unpacker. - // This makes it simpler to supply environmental options + // Keep a TLS point to the global data and environment. + // This makes it simpler to supply environmental options // to the engine code, especially the native code. - static final ThreadLocal currentInstance = new ThreadLocal(); + static final ThreadLocal<TLGlobals> currentInstance = new ThreadLocal<>(); + + // convenience methods to access the TL globals + static TLGlobals getTLGlobals() { + return currentInstance.get(); + } + + static Map<String, Utf8Entry> getUtf8Entries() { + return getTLGlobals().getUtf8Entries(); + } + + static Map<String, ClassEntry> getClassEntries() { + return getTLGlobals().getClassEntries(); + } + + static Map<Object, LiteralEntry> getLiteralEntries() { + return getTLGlobals().getLiteralEntries(); + } + + static Map<String, DescriptorEntry> getDescriptorEntries() { + return getTLGlobals().getDescriptorEntries(); + } + + static Map<String, SignatureEntry> getSignatureEntries() { + return getTLGlobals().getSignatureEntries(); + } + + static Map<String, MemberEntry> getMemberEntries() { + return getTLGlobals().getMemberEntries(); + } static PropMap currentPropMap() { Object obj = currentInstance.get(); if (obj instanceof PackerImpl) - return ((PackerImpl)obj)._props; + return ((PackerImpl)obj).props; if (obj instanceof UnpackerImpl) - return ((UnpackerImpl)obj)._props; + return ((UnpackerImpl)obj).props; return null; }
--- a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java Mon Aug 23 19:14:20 2010 -0700 @@ -813,7 +813,8 @@ try { while (true) { try { - inbuf = new byte[10]; + // type and length (at most 128 octets for long form) + inbuf = new byte[129]; offset = 0; seqlen = 0;
--- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java Mon Aug 23 19:14:20 2010 -0700 @@ -470,7 +470,7 @@ public AbstractStringBuilder append(CharSequence s, int start, int end) { if (s == null) s = "null"; - if ((start < 0) || (end < 0) || (start > end) || (end > s.length())) + if ((start < 0) || (start > end) || (end > s.length())) throw new IndexOutOfBoundsException( "start " + start + ", end " + end + ", s.length() " + s.length()); @@ -529,7 +529,8 @@ * or {@code offset+len > str.length} */ public AbstractStringBuilder append(char str[], int offset, int len) { - ensureCapacityInternal(count + len); + if (len > 0) // let arraycopy report AIOOBE for len < 0 + ensureCapacityInternal(count + len); System.arraycopy(str, offset, value, count, len); count += len; return this;
--- a/jdk/src/share/classes/java/lang/Thread.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/java/lang/Thread.java Mon Aug 23 19:14:20 2010 -0700 @@ -414,6 +414,18 @@ } /** + * Throws CloneNotSupportedException as a Thread can not be meaningfully + * cloned. Construct a new Thread instead. + * + * @throws CloneNotSupportedException + * always + */ + @Override + protected Object clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + /** * Allocates a new {@code Thread} object. This constructor has the same * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} * {@code (null, null, gname)}, where {@code gname} is a newly generated
--- a/jdk/src/share/classes/java/lang/Throwable.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/java/lang/Throwable.java Mon Aug 23 19:14:20 2010 -0700 @@ -200,7 +200,16 @@ * @serial * @since 1.7 */ - private List<Throwable> suppressedExceptions = Collections.emptyList(); + private List<Throwable> suppressedExceptions = null; + /* + * This field is lazily initialized when the first suppressed + * exception is added. + * + * OutOfMemoryError is preallocated in the VM for better OOM + * diagnosability during VM initialization. Constructor can't + * be not invoked. If a new field to be added in the future must + * be initialized to non-null, it requires a synchronized VM change. + */ /** Message for trying to suppress a null exception. */ private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception."; @@ -329,7 +338,7 @@ * cause is nonexistent or unknown. * @since 1.4 */ - public Throwable getCause() { + public synchronized Throwable getCause() { return (cause==this ? null : cause); } @@ -563,7 +572,7 @@ s.println("\tat " + traceElement); // Print suppressed exceptions, if any - for (Throwable se : suppressedExceptions) + for (Throwable se : getSuppressedExceptions()) se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu); // Print cause, if any @@ -604,7 +613,7 @@ s.println(prefix + "\t... " + framesInCommon + " more"); // Print suppressed exceptions, if any - for (Throwable se : suppressedExceptions) + for (Throwable se : getSuppressedExceptions()) se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, prefix +"\t", dejaVu); @@ -747,7 +756,9 @@ if (defensiveCopy[i] == null) throw new NullPointerException("stackTrace[" + i + "]"); - this.stackTrace = defensiveCopy; + synchronized (this) { + this.stackTrace = defensiveCopy; + } } /** @@ -772,11 +783,11 @@ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); // read in all fields - List<Throwable> suppressed = Collections.emptyList(); + List<Throwable> suppressed = null; if (suppressedExceptions != null && !suppressedExceptions.isEmpty()) { // Copy Throwables to new list suppressed = new ArrayList<Throwable>(); - for(Throwable t : suppressedExceptions) { + for (Throwable t : suppressedExceptions) { if (t == null) throw new NullPointerException(NULL_CAUSE_MESSAGE); suppressed.add(t); @@ -819,7 +830,7 @@ if (exception == this) throw new IllegalArgumentException("Self-suppression not permitted"); - if (suppressedExceptions.size() == 0) + if (suppressedExceptions == null) suppressedExceptions = new ArrayList<Throwable>(); suppressedExceptions.add(exception); } @@ -835,7 +846,10 @@ * suppressed to deliver this exception. * @since 1.7 */ - public Throwable[] getSuppressedExceptions() { - return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); + public synchronized Throwable[] getSuppressedExceptions() { + if (suppressedExceptions == null) + return EMPTY_THROWABLE_ARRAY; + else + return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); } }
--- a/jdk/src/share/classes/java/net/HttpCookie.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/java/net/HttpCookie.java Mon Aug 23 19:14:20 2010 -0700 @@ -1093,14 +1093,8 @@ return sb.toString(); } - private static SimpleDateFormat[] cDateFormats = null; - static { - cDateFormats = new SimpleDateFormat[COOKIE_DATE_FORMATS.length]; - for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) { - cDateFormats[i] = new SimpleDateFormat(COOKIE_DATE_FORMATS[i], Locale.US); - cDateFormats[i].setTimeZone(TimeZone.getTimeZone("GMT")); - } - } + static final TimeZone GMT = TimeZone.getTimeZone("GMT"); + /* * @param dateString a date string in one of the formats * defined in Netscape cookie spec @@ -1109,12 +1103,14 @@ * time and the time specified by dateString */ private long expiryDate2DeltaSeconds(String dateString) { - for (SimpleDateFormat df : cDateFormats) { + for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) { + SimpleDateFormat df = new SimpleDateFormat(COOKIE_DATE_FORMATS[i], Locale.US); + df.setTimeZone(GMT); try { Date date = df.parse(dateString); return (date.getTime() - whenCreated) / 1000; } catch (Exception e) { - + // Ignore, try the next date format } } return 0;
--- a/jdk/src/share/classes/java/net/URI.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/java/net/URI.java Mon Aug 23 19:14:20 2010 -0700 @@ -856,9 +856,7 @@ try { return new URI(str); } catch (URISyntaxException x) { - IllegalArgumentException y = new IllegalArgumentException(); - y.initCause(x); - throw y; + throw new IllegalArgumentException(x.getMessage(), x); } }
--- a/jdk/src/share/classes/java/security/KeyStore.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/java/security/KeyStore.java Mon Aug 23 19:14:20 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -131,17 +131,19 @@ * to read existing entries from the keystore, or to write new entries * into the keystore: * <pre> + * KeyStore.ProtectionParameter protParam = + * new KeyStore.PasswordProtection(password); + * * // get my private key * KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) - * ks.getEntry("privateKeyAlias", password); + * ks.getEntry("privateKeyAlias", protParam); * PrivateKey myPrivateKey = pkEntry.getPrivateKey(); * * // save my secret key * javax.crypto.SecretKey mySecretKey; * KeyStore.SecretKeyEntry skEntry = * new KeyStore.SecretKeyEntry(mySecretKey); - * ks.setEntry("secretKeyAlias", skEntry, - * new KeyStore.PasswordProtection(password)); + * ks.setEntry("secretKeyAlias", skEntry, protParam); * * // store away the keystore * java.io.FileOutputStream fos = null;
--- a/jdk/src/share/classes/java/sql/Date.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/java/sql/Date.java Mon Aug 23 19:14:20 2010 -0700 @@ -103,27 +103,46 @@ * JDBC date escape format (yyyy-mm-dd) */ public static Date valueOf(String s) { - int year; - int month; - int day; + final int YEAR_LENGTH = 4; + final int MONTH_LENGTH = 2; + final int DAY_LENGTH = 2; + final int MAX_MONTH = 12; + final int MAX_DAY = 31; int firstDash; int secondDash; + Date d = null; - if (s == null) throw new java.lang.IllegalArgumentException(); - - firstDash = s.indexOf('-'); - secondDash = s.indexOf('-', firstDash+1); - if ((firstDash > 0) & (secondDash > 0) & (secondDash < s.length()-1)) { - year = Integer.parseInt(s.substring(0, firstDash)) - 1900; - month = Integer.parseInt(s.substring(firstDash+1, secondDash)) - 1; - day = Integer.parseInt(s.substring(secondDash+1)); - } else { + if (s == null) { throw new java.lang.IllegalArgumentException(); } - return new Date(year, month, day); + firstDash = s.indexOf('-'); + secondDash = s.indexOf('-', firstDash + 1); + + if ((firstDash > 0) && (secondDash > 0) && (secondDash < s.length() - 1)) { + String yyyy = s.substring(0, firstDash); + String mm = s.substring(firstDash + 1, secondDash); + String dd = s.substring(secondDash + 1); + if (yyyy.length() == YEAR_LENGTH && mm.length() == MONTH_LENGTH && + dd.length() == DAY_LENGTH) { + int year = Integer.parseInt(yyyy); + int month = Integer.parseInt(mm); + int day = Integer.parseInt(dd); + + if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) { + d = new Date(year - 1900, month - 1, day); + } + } + } + if (d == null) { + throw new java.lang.IllegalArgumentException(); + } + + return d; + } + /** * Formats a date in the date escape format yyyy-mm-dd. * <P>
--- a/jdk/src/share/classes/sun/net/www/protocol/file/FileURLConnection.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/sun/net/www/protocol/file/FileURLConnection.java Mon Aug 23 19:14:20 2010 -0700 @@ -59,7 +59,7 @@ String filename; boolean isDirectory = false; boolean exists = false; - List files; + List<String> files; long length = -1; long lastModified = 0; @@ -81,7 +81,10 @@ filename = file.toString(); isDirectory = file.isDirectory(); if (isDirectory) { - files = (List) Arrays.asList(file.list()); + String[] fileList = file.list(); + if (fileList == null) + throw new FileNotFoundException(filename + " exists, but is not accessible"); + files = Arrays.<String>asList(fileList); } else { is = new BufferedInputStream(new FileInputStream(filename)); @@ -197,7 +200,7 @@ Collections.sort(files, Collator.getInstance()); for (int i = 0 ; i < files.size() ; i++) { - String fileName = (String)files.get(i); + String fileName = files.get(i); buf.append(fileName); buf.append("\n"); }
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Mon Aug 23 19:14:20 2010 -0700 @@ -1768,6 +1768,10 @@ // Not really necessary for a tunnel, but can't hurt requests.setIfNotSet("Accept", acceptString); + if (http.getHttpKeepAliveSet()) { + requests.setIfNotSet("Proxy-Connection", "keep-alive"); + } + setPreemptiveProxyAuthentication(requests); /* Log the CONNECT request */
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Mon Aug 23 19:14:20 2010 -0700 @@ -536,9 +536,11 @@ } } - private long read0(ByteBuffer[] bufs) throws IOException { - if (bufs == null) - throw new NullPointerException(); + public long read(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) + throw new IndexOutOfBoundsException(); synchronized (readLock) { synchronized (stateLock) { ensureOpen(); @@ -552,7 +554,7 @@ return 0; readerThread = NativeThread.current(); do { - n = IOUtil.read(fd, bufs, nd); + n = IOUtil.read(fd, dsts, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -563,15 +565,6 @@ } } - public long read(ByteBuffer[] dsts, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return read0(Util.subsequence(dsts, offset, length)); - } - public int write(ByteBuffer buf) throws IOException { if (buf == null) throw new NullPointerException(); @@ -599,9 +592,11 @@ } } - private long write0(ByteBuffer[] bufs) throws IOException { - if (bufs == null) - throw new NullPointerException(); + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) + throw new IndexOutOfBoundsException(); synchronized (writeLock) { synchronized (stateLock) { ensureOpen(); @@ -615,7 +610,7 @@ return 0; writerThread = NativeThread.current(); do { - n = IOUtil.write(fd, bufs, nd); + n = IOUtil.write(fd, srcs, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -626,15 +621,6 @@ } } - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return write0(Util.subsequence(srcs, offset, length)); - } - protected void implConfigureBlocking(boolean block) throws IOException { IOUtil.configureBlocking(fd, block); }
--- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Mon Aug 23 19:14:20 2010 -0700 @@ -143,7 +143,11 @@ } } - private long read0(ByteBuffer[] dsts) throws IOException { + public long read(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) + throw new IndexOutOfBoundsException(); ensureOpen(); if (!readable) throw new NonReadableChannelException(); @@ -156,7 +160,7 @@ if (!isOpen()) return 0; do { - n = IOUtil.read(fd, dsts, nd); + n = IOUtil.read(fd, dsts, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -167,15 +171,6 @@ } } - public long read(ByteBuffer[] dsts, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return read0(Util.subsequence(dsts, offset, length)); - } - public int write(ByteBuffer src) throws IOException { ensureOpen(); if (!writable) @@ -200,7 +195,11 @@ } } - private long write0(ByteBuffer[] srcs) throws IOException { + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) + throw new IndexOutOfBoundsException(); ensureOpen(); if (!writable) throw new NonWritableChannelException(); @@ -213,7 +212,7 @@ if (!isOpen()) return 0; do { - n = IOUtil.write(fd, srcs, nd); + n = IOUtil.write(fd, srcs, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -224,16 +223,6 @@ } } - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return write0(Util.subsequence(srcs, offset, length)); - } - - // -- Other operations -- public long position() throws IOException { @@ -440,24 +429,45 @@ } } - private long transferToTrustedChannel(long position, int icount, + // Maximum size to map when using a mapped buffer + private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L; + + private long transferToTrustedChannel(long position, long count, WritableByteChannel target) throws IOException { - if ( !((target instanceof FileChannelImpl) - || (target instanceof SelChImpl))) + boolean isSelChImpl = (target instanceof SelChImpl); + if (!((target instanceof FileChannelImpl) || isSelChImpl)) return IOStatus.UNSUPPORTED; // Trusted target: Use a mapped buffer - MappedByteBuffer dbb = null; - try { - dbb = map(MapMode.READ_ONLY, position, icount); - // ## Bug: Closing this channel will not terminate the write - return target.write(dbb); - } finally { - if (dbb != null) - unmap(dbb); + long remaining = count; + while (remaining > 0L) { + long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); + try { + MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size); + try { + // ## Bug: Closing this channel will not terminate the write + int n = target.write(dbb); + assert n >= 0; + remaining -= n; + if (isSelChImpl) { + // one attempt to write to selectable channel + break; + } + assert n > 0; + position += n; + } finally { + unmap(dbb); + } + } catch (IOException ioe) { + // Only throw exception if no bytes have been written + if (remaining == count) + throw ioe; + break; + } } + return count - remaining; } private long transferToArbitraryChannel(long position, int icount, @@ -535,20 +545,34 @@ long position, long count) throws IOException { - // Note we could loop here to accumulate more at once synchronized (src.positionLock) { - long p = src.position(); - int icount = (int)Math.min(Math.min(count, Integer.MAX_VALUE), - src.size() - p); - // ## Bug: Closing this channel will not terminate the write - MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, icount); - try { - long n = write(bb, position); - src.position(p + n); - return n; - } finally { - unmap(bb); + long pos = src.position(); + long max = Math.min(count, src.size() - pos); + + long remaining = max; + long p = pos; + while (remaining > 0L) { + long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); + // ## Bug: Closing this channel will not terminate the write + MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size); + try { + long n = write(bb, position); + assert n > 0; + p += n; + position += n; + remaining -= n; + } catch (IOException ioe) { + // Only throw exception if no bytes have been written + if (remaining == max) + throw ioe; + break; + } finally { + unmap(bb); + } } + long nwritten = max - remaining; + src.position(pos + nwritten); + return nwritten; } }
--- a/jdk/src/share/classes/sun/nio/ch/IOUtil.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java Mon Aug 23 19:14:20 2010 -0700 @@ -38,34 +38,6 @@ private IOUtil() { } // No instantiation - /* - * Returns the index of first buffer in bufs with remaining, - * or -1 if there is nothing left - */ - private static int remaining(ByteBuffer[] bufs) { - int numBufs = bufs.length; - for (int i=0; i<numBufs; i++) { - if (bufs[i].hasRemaining()) { - return i; - } - } - return -1; - } - - /* - * Returns a new ByteBuffer array with only unfinished buffers in it - */ - private static ByteBuffer[] skipBufs(ByteBuffer[] bufs, - int nextWithRemaining) - { - int newSize = bufs.length - nextWithRemaining; - ByteBuffer[] temp = new ByteBuffer[newSize]; - for (int i=0; i<newSize; i++) { - temp[i] = bufs[i + nextWithRemaining]; - } - return temp; - } - static int write(FileDescriptor fd, ByteBuffer src, long position, NativeDispatcher nd, Object lock) throws IOException @@ -93,7 +65,7 @@ } return n; } finally { - Util.releaseTemporaryDirectBuffer(bb); + Util.offerFirstTemporaryDirectBuffer(bb); } } @@ -125,88 +97,81 @@ static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) throws IOException { - int nextWithRemaining = remaining(bufs); - // if all bufs are empty we should return immediately - if (nextWithRemaining < 0) - return 0; - // If some bufs are empty we should skip them - if (nextWithRemaining > 0) - bufs = skipBufs(bufs, nextWithRemaining); + return write(fd, bufs, 0, bufs.length, nd); + } - int numBufs = bufs.length; + static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, + NativeDispatcher nd) + throws IOException + { + IOVecWrapper vec = IOVecWrapper.get(length); - // Create shadow to ensure DirectByteBuffers are used - ByteBuffer[] shadow = new ByteBuffer[numBufs]; + boolean completed = false; + int iov_len = 0; try { - for (int i=0; i<numBufs; i++) { - if (!(bufs[i] instanceof DirectBuffer)) { - int pos = bufs[i].position(); - int lim = bufs[i].limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - ByteBuffer bb = Util.getTemporaryDirectBuffer(rem); - shadow[i] = bb; - // Leave slow buffer position untouched; it will be updated - // after we see how many bytes were really written out - bb.put(bufs[i]); - bufs[i].position(pos); - bb.flip(); - } else { - shadow[i] = bufs[i]; + // Iterate over buffers to populate native iovec array. + int count = offset + length; + for (int i=offset; i<count; i++) { + ByteBuffer buf = bufs[i]; + int pos = buf.position(); + int lim = buf.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + if (rem > 0) { + vec.setBuffer(iov_len, buf, pos, rem); + + // allocate shadow buffer to ensure I/O is done with direct buffer + if (!(buf instanceof DirectBuffer)) { + ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem); + shadow.put(buf); + shadow.flip(); + vec.setShadow(iov_len, shadow); + buf.position(pos); // temporarily restore position in user buffer + buf = shadow; + pos = shadow.position(); + } + + vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos); + vec.putLen(iov_len, rem); + iov_len++; } } + if (iov_len == 0) + return 0L; - IOVecWrapper vec = null; - long bytesWritten = 0; - try { - // Create a native iovec array - vec= new IOVecWrapper(numBufs); - - // Fill in the iovec array with appropriate data - for (int i=0; i<numBufs; i++) { - ByteBuffer nextBuffer = shadow[i]; - // put in the buffer addresses - long pos = nextBuffer.position(); - long len = nextBuffer.limit() - pos; - vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos); - vec.putLen(i, len); - } - - // Invoke native call to fill the buffers - bytesWritten = nd.writev(fd, vec.address, numBufs); - } finally { - vec.free(); - } - long returnVal = bytesWritten; + long bytesWritten = nd.writev(fd, vec.address, iov_len); // Notify the buffers how many bytes were taken - for (int i=0; i<numBufs; i++) { - ByteBuffer nextBuffer = bufs[i]; - int pos = nextBuffer.position(); - int lim = nextBuffer.limit(); - assert (pos <= lim); - int len = (pos <= lim ? lim - pos : lim); - if (bytesWritten >= len) { - bytesWritten -= len; - int newPosition = pos + len; - nextBuffer.position(newPosition); - } else { // Buffers not completely filled - if (bytesWritten > 0) { - assert(pos + bytesWritten < (long)Integer.MAX_VALUE); - int newPosition = (int)(pos + bytesWritten); - nextBuffer.position(newPosition); - } - break; + long left = bytesWritten; + for (int j=0; j<iov_len; j++) { + if (left > 0) { + ByteBuffer buf = vec.getBuffer(j); + int pos = vec.getPosition(j); + int rem = vec.getRemaining(j); + int n = (left > rem) ? rem : (int)left; + buf.position(pos + n); + left -= n; } + // return shadow buffers to buffer pool + ByteBuffer shadow = vec.getShadow(j); + if (shadow != null) + Util.offerLastTemporaryDirectBuffer(shadow); + vec.clearRefs(j); } - return returnVal; + + completed = true; + return bytesWritten; + } finally { - // return any substituted buffers to cache - for (int i=0; i<numBufs; i++) { - ByteBuffer bb = shadow[i]; - if (bb != null && bb != bufs[i]) { - Util.releaseTemporaryDirectBuffer(bb); + // if an error occurred then clear refs to buffers and return any shadow + // buffers to cache + if (!completed) { + for (int j=0; j<iov_len; j++) { + ByteBuffer shadow = vec.getShadow(j); + if (shadow != null) + Util.offerLastTemporaryDirectBuffer(shadow); + vec.clearRefs(j); } } } @@ -231,7 +196,7 @@ dst.put(bb); return n; } finally { - Util.releaseTemporaryDirectBuffer(bb); + Util.offerFirstTemporaryDirectBuffer(bb); } } @@ -262,92 +227,85 @@ static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) throws IOException { - int nextWithRemaining = remaining(bufs); - // if all bufs are empty we should return immediately - if (nextWithRemaining < 0) - return 0; - // If some bufs are empty we should skip them - if (nextWithRemaining > 0) - bufs = skipBufs(bufs, nextWithRemaining); + return read(fd, bufs, 0, bufs.length, nd); + } - int numBufs = bufs.length; + static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, + NativeDispatcher nd) + throws IOException + { + IOVecWrapper vec = IOVecWrapper.get(length); - // Read into the shadow to ensure DirectByteBuffers are used - ByteBuffer[] shadow = new ByteBuffer[numBufs]; - boolean usingSlowBuffers = false; + boolean completed = false; + int iov_len = 0; try { - for (int i=0; i<numBufs; i++) { - if (bufs[i].isReadOnly()) + + // Iterate over buffers to populate native iovec array. + int count = offset + length; + for (int i=offset; i<count; i++) { + ByteBuffer buf = bufs[i]; + if (buf.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); - if (!(bufs[i] instanceof DirectBuffer)) { - shadow[i] = Util.getTemporaryDirectBuffer(bufs[i].remaining()); - usingSlowBuffers = true; - } else { - shadow[i] = bufs[i]; + int pos = buf.position(); + int lim = buf.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + if (rem > 0) { + vec.setBuffer(iov_len, buf, pos, rem); + + // allocate shadow buffer to ensure I/O is done with direct buffer + if (!(buf instanceof DirectBuffer)) { + ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem); + vec.setShadow(iov_len, shadow); + buf = shadow; + pos = shadow.position(); + } + + vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos); + vec.putLen(iov_len, rem); + iov_len++; } } + if (iov_len == 0) + return 0L; - IOVecWrapper vec = null; - long bytesRead = 0; - try { - // Create a native iovec array - vec = new IOVecWrapper(numBufs); - - // Fill in the iovec array with appropriate data - for (int i=0; i<numBufs; i++) { - ByteBuffer nextBuffer = shadow[i]; - // put in the buffer addresses - long pos = nextBuffer.position(); - long len = nextBuffer.remaining(); - vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos); - vec.putLen(i, len); - } - - // Invoke native call to fill the buffers - bytesRead = nd.readv(fd, vec.address, numBufs); - } finally { - vec.free(); - } - long returnVal = bytesRead; + long bytesRead = nd.readv(fd, vec.address, iov_len); // Notify the buffers how many bytes were read - for (int i=0; i<numBufs; i++) { - ByteBuffer nextBuffer = shadow[i]; - // Note: should this have been cached from above? - int pos = nextBuffer.position(); - int len = nextBuffer.remaining(); - if (bytesRead >= len) { - bytesRead -= len; - int newPosition = pos + len; - nextBuffer.position(newPosition); - } else { // Buffers not completely filled - if (bytesRead > 0) { - assert(pos + bytesRead < (long)Integer.MAX_VALUE); - int newPosition = (int)(pos + bytesRead); - nextBuffer.position(newPosition); + long left = bytesRead; + for (int j=0; j<iov_len; j++) { + ByteBuffer shadow = vec.getShadow(j); + if (left > 0) { + ByteBuffer buf = vec.getBuffer(j); + int rem = vec.getRemaining(j); + int n = (left > rem) ? rem : (int)left; + if (shadow == null) { + int pos = vec.getPosition(j); + buf.position(pos + n); + } else { + shadow.limit(shadow.position() + n); + buf.put(shadow); } - break; + left -= n; } + if (shadow != null) + Util.offerLastTemporaryDirectBuffer(shadow); + vec.clearRefs(j); } - // Put results from shadow into the slow buffers - if (usingSlowBuffers) { - for (int i=0; i<numBufs; i++) { - if (!(bufs[i] instanceof DirectBuffer)) { - shadow[i].flip(); - bufs[i].put(shadow[i]); - } - } - } - return returnVal; + completed = true; + return bytesRead; + } finally { - // return any substituted buffers to cache - if (usingSlowBuffers) { - for (int i=0; i<numBufs; i++) { - ByteBuffer bb = shadow[i]; - if (bb != null && bb != bufs[i]) { - Util.releaseTemporaryDirectBuffer(bb); - } + // if an error occurred then clear refs to buffers and return any shadow + // buffers to cache + if (!completed) { + for (int j=0; j<iov_len; j++) { + ByteBuffer shadow = vec.getShadow(j); + if (shadow != null) + Util.offerLastTemporaryDirectBuffer(shadow); + vec.clearRefs(j); } } }
--- a/jdk/src/share/classes/sun/nio/ch/IOVecWrapper.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/IOVecWrapper.java Mon Aug 23 19:14:20 2010 -0700 @@ -25,6 +25,7 @@ package sun.nio.ch; +import java.nio.ByteBuffer; import sun.misc.*; @@ -43,23 +44,98 @@ class IOVecWrapper { // Miscellaneous constants - static int BASE_OFFSET = 0; - static int LEN_OFFSET; - static int SIZE_IOVEC; + private static final int BASE_OFFSET = 0; + private static final int LEN_OFFSET; + private static final int SIZE_IOVEC; // The iovec array - private AllocatedNativeObject vecArray; + private final AllocatedNativeObject vecArray; + + // Number of elements in iovec array + private final int size; + + // Buffers and position/remaining corresponding to elements in iovec array + private final ByteBuffer[] buf; + private final int[] position; + private final int[] remaining; + + // Shadow buffers for cases when original buffer is substituted + private final ByteBuffer[] shadow; // Base address of this array - long address; + final long address; // Address size in bytes static int addressSize; - IOVecWrapper(int newSize) { - newSize = (newSize + 1) * SIZE_IOVEC; - vecArray = new AllocatedNativeObject(newSize, false); - address = vecArray.address(); + private static class Deallocator implements Runnable { + private final AllocatedNativeObject obj; + Deallocator(AllocatedNativeObject obj) { + this.obj = obj; + } + public void run() { + obj.free(); + } + } + + // per thread IOVecWrapper + private static final ThreadLocal<IOVecWrapper> cached = + new ThreadLocal<IOVecWrapper>(); + + private IOVecWrapper(int size) { + this.size = size; + this.buf = new ByteBuffer[size]; + this.position = new int[size]; + this.remaining = new int[size]; + this.shadow = new ByteBuffer[size]; + this.vecArray = new AllocatedNativeObject(size * SIZE_IOVEC, false); + this.address = vecArray.address(); + } + + static IOVecWrapper get(int size) { + IOVecWrapper wrapper = cached.get(); + if (wrapper != null && wrapper.size < size) { + // not big enough; eagerly release memory + wrapper.vecArray.free(); + wrapper = null; + } + if (wrapper == null) { + wrapper = new IOVecWrapper(size); + Cleaner.create(wrapper, new Deallocator(wrapper.vecArray)); + cached.set(wrapper); + } + return wrapper; + } + + void setBuffer(int i, ByteBuffer buf, int pos, int rem) { + this.buf[i] = buf; + this.position[i] = pos; + this.remaining[i] = rem; + } + + void setShadow(int i, ByteBuffer buf) { + shadow[i] = buf; + } + + ByteBuffer getBuffer(int i) { + return buf[i]; + } + + int getPosition(int i) { + return position[i]; + } + + int getRemaining(int i) { + return remaining[i]; + } + + ByteBuffer getShadow(int i) { + return shadow[i]; + } + + void clearRefs(int i) { + buf[i] = null; + shadow[i] = null; } void putBase(int i, long base) { @@ -78,10 +154,6 @@ vecArray.putLong(offset, len); } - void free() { - vecArray.free(); - } - static { addressSize = Util.unsafe().addressSize(); LEN_OFFSET = addressSize;
--- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Mon Aug 23 19:14:20 2010 -0700 @@ -385,9 +385,11 @@ } } - private long read0(ByteBuffer[] bufs) throws IOException { - if (bufs == null) - throw new NullPointerException(); + public long read(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) + throw new IndexOutOfBoundsException(); synchronized (readLock) { if (!ensureReadOpen()) return -1; @@ -401,7 +403,7 @@ } for (;;) { - n = IOUtil.read(fd, bufs, nd); + n = IOUtil.read(fd, dsts, offset, length, nd); if ((n == IOStatus.INTERRUPTED) && isOpen()) continue; return IOStatus.normalize(n); @@ -418,15 +420,6 @@ } } - public long read(ByteBuffer[] dsts, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return read0(Util.subsequence(dsts, offset, length)); - } - public int write(ByteBuffer buf) throws IOException { if (buf == null) throw new NullPointerException(); @@ -458,9 +451,11 @@ } } - public long write0(ByteBuffer[] bufs) throws IOException { - if (bufs == null) - throw new NullPointerException(); + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) + throw new IndexOutOfBoundsException(); synchronized (writeLock) { ensureWriteOpen(); long n = 0; @@ -472,7 +467,7 @@ writerThread = NativeThread.current(); } for (;;) { - n = IOUtil.write(fd, bufs, nd); + n = IOUtil.write(fd, srcs, offset, length, nd); if ((n == IOStatus.INTERRUPTED) && isOpen()) continue; return IOStatus.normalize(n); @@ -489,15 +484,6 @@ } } - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return write0(Util.subsequence(srcs, offset, length)); - } - // package-private int sendOutOfBandData(byte b) throws IOException { synchronized (writeLock) {
--- a/jdk/src/share/classes/sun/nio/ch/Util.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/Util.java Mon Aug 23 19:14:20 2010 -0700 @@ -41,67 +41,180 @@ class Util { - // -- Caches -- // The number of temp buffers in our pool - private static final int TEMP_BUF_POOL_SIZE = 3; + private static final int TEMP_BUF_POOL_SIZE = 8; - // Per-thread soft cache of the last temporary direct buffer - private static ThreadLocal<SoftReference<ByteBuffer>>[] bufferPool; + // Per-thread cache of temporary direct buffers + private static ThreadLocal<BufferCache> bufferCache = + new ThreadLocal<BufferCache>() + { + @Override + protected BufferCache initialValue() { + return new BufferCache(); + } + }; - @SuppressWarnings("unchecked") - static ThreadLocal<SoftReference<ByteBuffer>>[] createThreadLocalBufferPool() { - return new ThreadLocal[TEMP_BUF_POOL_SIZE]; - } + /** + * A simple cache of direct buffers. + */ + private static class BufferCache { + // the array of buffers + private ByteBuffer[] buffers; - static { - bufferPool = createThreadLocalBufferPool(); - for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) - bufferPool[i] = new ThreadLocal<SoftReference<ByteBuffer>>(); - } + // the number of buffers in the cache + private int count; - static ByteBuffer getTemporaryDirectBuffer(int size) { - ByteBuffer buf = null; - // Grab a buffer if available - for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) { - SoftReference<ByteBuffer> ref = bufferPool[i].get(); - if ((ref != null) && ((buf = ref.get()) != null) && - (buf.capacity() >= size)) { - buf.rewind(); - buf.limit(size); - bufferPool[i].set(null); - return buf; + // the index of the first valid buffer (undefined if count == 0) + private int start; + + private int next(int i) { + return (i + 1) % TEMP_BUF_POOL_SIZE; + } + + BufferCache() { + buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE]; + } + + /** + * Removes and returns a buffer from the cache of at least the given + * size (or null if no suitable buffer is found). + */ + ByteBuffer get(int size) { + if (count == 0) + return null; // cache is empty + + ByteBuffer[] buffers = this.buffers; + + // search for suitable buffer (often the first buffer will do) + ByteBuffer buf = buffers[start]; + if (buf.capacity() < size) { + buf = null; + int i = start; + while ((i = next(i)) != start) { + ByteBuffer bb = buffers[i]; + if (bb == null) + break; + if (bb.capacity() >= size) { + buf = bb; + break; + } + } + if (buf == null) + return null; + // move first element to here to avoid re-packing + buffers[i] = buffers[start]; + } + + // remove first element + buffers[start] = null; + start = next(start); + count--; + + // prepare the buffer and return it + buf.rewind(); + buf.limit(size); + return buf; + } + + boolean offerFirst(ByteBuffer buf) { + if (count >= TEMP_BUF_POOL_SIZE) { + return false; + } else { + start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE; + buffers[start] = buf; + count++; + return true; } } - // Make a new one - return ByteBuffer.allocateDirect(size); - } - - static void releaseTemporaryDirectBuffer(ByteBuffer buf) { - if (buf == null) - return; - // Put it in an empty slot if such exists - for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) { - SoftReference<ByteBuffer> ref = bufferPool[i].get(); - if ((ref == null) || (ref.get() == null)) { - bufferPool[i].set(new SoftReference<ByteBuffer>(buf)); - return; - } - } - // Otherwise replace a smaller one in the cache if such exists - for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) { - SoftReference<ByteBuffer> ref = bufferPool[i].get(); - ByteBuffer inCacheBuf = ref.get(); - if ((inCacheBuf == null) || (buf.capacity() > inCacheBuf.capacity())) { - bufferPool[i].set(new SoftReference<ByteBuffer>(buf)); - return; + boolean offerLast(ByteBuffer buf) { + if (count >= TEMP_BUF_POOL_SIZE) { + return false; + } else { + int next = (start + count) % TEMP_BUF_POOL_SIZE; + buffers[next] = buf; + count++; + return true; } } - // release memory - ((DirectBuffer)buf).cleaner().clean(); + boolean isEmpty() { + return count == 0; + } + + ByteBuffer removeFirst() { + assert count > 0; + ByteBuffer buf = buffers[start]; + buffers[start] = null; + start = next(start); + count--; + return buf; + } + } + + /** + * Returns a temporary buffer of at least the given size + */ + static ByteBuffer getTemporaryDirectBuffer(int size) { + BufferCache cache = bufferCache.get(); + ByteBuffer buf = cache.get(size); + if (buf != null) { + return buf; + } else { + // No suitable buffer in the cache so we need to allocate a new + // one. To avoid the cache growing then we remove the first + // buffer from the cache and free it. + if (!cache.isEmpty()) { + buf = cache.removeFirst(); + free(buf); + } + return ByteBuffer.allocateDirect(size); + } + } + + /** + * Releases a temporary buffer by returning to the cache or freeing it. + */ + static void releaseTemporaryDirectBuffer(ByteBuffer buf) { + offerFirstTemporaryDirectBuffer(buf); + } + + /** + * Releases a temporary buffer by returning to the cache or freeing it. If + * returning to the cache then insert it at the start so that it is + * likely to be returned by a subsequent call to getTemporaryDirectBuffer. + */ + static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { + assert buf != null; + BufferCache cache = bufferCache.get(); + if (!cache.offerFirst(buf)) { + // cache is full + free(buf); + } + } + + /** + * Releases a temporary buffer by returning to the cache or freeing it. If + * returning to the cache then insert it at the end. This makes it + * suitable for scatter/gather operations where the buffers are returned to + * cache in same order that they were obtained. + */ + static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { + assert buf != null; + BufferCache cache = bufferCache.get(); + if (!cache.offerLast(buf)) { + // cache is full + free(buf); + } + } + + /** + * Frees the memory for the given direct buffer + */ + private static void free(ByteBuffer buf) { + ((DirectBuffer)buf).cleaner().clean(); } private static class SelectorWrapper {
--- a/jdk/src/share/lib/security/java.security-solaris Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/lib/security/java.security-solaris Mon Aug 23 19:14:20 2010 -0700 @@ -260,3 +260,30 @@ # Example, # ocsp.responderCertSerialNumber=2A:FF:00 +# +# Policy for failed Kerberos KDC lookups: +# +# When a KDC is unavailable (network error, service failure, etc), it is +# put inside a blacklist and accessed less often for future requests. The +# value (case-insensitive) for this policy can be: +# +# tryLast +# KDCs in the blacklist are always tried after those not on the list. +# +# tryLess[:max_retries,timeout] +# KDCs in the blacklist are still tried by their order in the configuration, +# but with smaller max_retries and timeout values. max_retries and timeout +# are optional numerical parameters (default 1 and 5000, which means once +# and 5 seconds). Please notes that if any of the values defined here is +# more than what is defined in krb5.conf, it will be ignored. +# +# Whenever a KDC is detected as available, it is removed from the blacklist. +# The blacklist is reset when krb5.conf is reloaded. You can add +# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is +# reloaded whenever a JAAS authentication is attempted. +# +# Example, +# krb5.kdc.bad.policy = tryLast +# krb5.kdc.bad.policy = tryLess:2,2000 +krb5.kdc.bad.policy = tryLast +
--- a/jdk/src/share/lib/security/java.security-windows Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/lib/security/java.security-windows Mon Aug 23 19:14:20 2010 -0700 @@ -260,3 +260,30 @@ # Example, # ocsp.responderCertSerialNumber=2A:FF:00 +# +# Policy for failed Kerberos KDC lookups: +# +# When a KDC is unavailable (network error, service failure, etc), it is +# put inside a blacklist and accessed less often for future requests. The +# value (case-insensitive) for this policy can be: +# +# tryLast +# KDCs in the blacklist are always tried after those not on the list. +# +# tryLess[:max_retries,timeout] +# KDCs in the blacklist are still tried by their order in the configuration, +# but with smaller max_retries and timeout values. max_retries and timeout +# are optional numerical parameters (default 1 and 5000, which means once +# and 5 seconds). Please notes that if any of the values defined here is +# more than what is defined in krb5.conf, it will be ignored. +# +# Whenever a KDC is detected as available, it is removed from the blacklist. +# The blacklist is reset when krb5.conf is reloaded. You can add +# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is +# reloaded whenever a JAAS authentication is attempted. +# +# Example, +# krb5.kdc.bad.policy = tryLast +# krb5.kdc.bad.policy = tryLess:2,2000 +krb5.kdc.bad.policy = tryLast +
--- a/jdk/src/share/native/common/check_code.c Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/share/native/common/check_code.c Mon Aug 23 19:14:20 2010 -0700 @@ -2730,7 +2730,10 @@ operand); const char *result_signature; check_and_push(context, signature, VM_STRING_UTF); - result_signature = strchr(signature, JVM_SIGNATURE_ENDFUNC) + 1; + result_signature = strchr(signature, JVM_SIGNATURE_ENDFUNC); + if (result_signature++ == NULL) { + CCerror(context, "Illegal signature %s", signature); + } if (result_signature[0] == JVM_SIGNATURE_VOID) { stack_results = ""; } else { @@ -3654,14 +3657,13 @@ const char **signature_p, fullinfo_type *full_info_p) { const char *p = *signature_p; - fullinfo_type full_info = MAKE_FULLINFO(0, 0, 0); + fullinfo_type full_info = MAKE_FULLINFO(ITEM_Bogus, 0, 0); char result; int array_depth = 0; for (;;) { switch(*p++) { default: - full_info = MAKE_FULLINFO(ITEM_Bogus, 0, 0); result = 0; break; @@ -3714,7 +3716,14 @@ char buffer_space[256]; char *buffer = buffer_space; char *finish = strchr(p, JVM_SIGNATURE_ENDCLASS); - int length = finish - p; + int length; + if (finish == NULL) { + /* Signature must have ';' after the class name. + * If it does not, return 0 and ITEM_Bogus in full_info. */ + result = 0; + break; + } + length = finish - p; if (length + 1 > (int)sizeof(buffer_space)) { buffer = malloc(length + 1); check_and_push(context, buffer, VM_MALLOC_BLK);
--- a/jdk/src/solaris/classes/java/io/UnixFileSystem.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/solaris/classes/java/io/UnixFileSystem.java Mon Aug 23 19:14:20 2010 -0700 @@ -187,7 +187,6 @@ } } } - assert canonicalize0(path).equals(res) || path.startsWith(javaHome); return res; } }
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java Mon Aug 23 19:14:20 2010 -0700 @@ -1141,6 +1141,13 @@ } result = result.resolve(element); } + + // check file exists (without following links) + try { + UnixFileAttributes.get(result, false); + } catch (UnixException x) { + x.rethrowAsIOException(result); + } return result; }
--- a/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c Mon Aug 23 19:14:20 2010 -0700 @@ -1052,30 +1052,38 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env, jobject this) { jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); - int fd; - - int t = 1; + int fd, t = 1; +#ifdef AF_INET6 + int domain = ipv6_available() ? AF_INET6 : AF_INET; +#else + int domain = AF_INET; +#endif if (IS_NULL(fdObj)) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); return; - } else { -#ifdef AF_INET6 - if (ipv6_available()) { - fd = JVM_Socket(AF_INET6, SOCK_DGRAM, 0); - } else -#endif /* AF_INET6 */ - { - fd = JVM_Socket(AF_INET, SOCK_DGRAM, 0); - } } - if (fd == JVM_IO_ERR) { + + if ((fd = JVM_Socket(domain, SOCK_DGRAM, 0)) == JVM_IO_ERR) { NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; } +#ifdef AF_INET6 + /* Disable IPV6_V6ONLY to ensure dual-socket support */ + if (domain == AF_INET6) { + int arg = 0; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, + sizeof(int)) < 0) { + NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6"); + close(fd); + return; + } + } +#endif /* AF_INET6 */ + setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int)); #ifdef __linux__ @@ -1088,7 +1096,7 @@ * On Linux for IPv6 sockets we must set the hop limit * to 1 to be compatible with default ttl of 1 for IPv4 sockets. */ - if (ipv6_available()) { + if (domain == AF_INET6) { int ttl = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl, sizeof(ttl));
--- a/jdk/src/solaris/native/java/net/PlainSocketImpl.c Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/solaris/native/java/net/PlainSocketImpl.c Mon Aug 23 19:14:20 2010 -0700 @@ -181,6 +181,12 @@ jboolean stream) { jobject fdObj, ssObj; int fd; + int type = (stream ? SOCK_STREAM : SOCK_DGRAM); +#ifdef AF_INET6 + int domain = ipv6_available() ? AF_INET6 : AF_INET; +#else + int domain = AF_INET; +#endif if (socketExceptionCls == NULL) { jclass c = (*env)->FindClass(env, "java/net/SocketException"); @@ -194,25 +200,29 @@ (*env)->ThrowNew(env, socketExceptionCls, "null fd object"); return; } -#ifdef AF_INET6 - if (ipv6_available()) { - fd = JVM_Socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); - } else -#endif /* AF_INET6 */ - { - fd = JVM_Socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); - } - if (fd == JVM_IO_ERR) { + + if ((fd = JVM_Socket(domain, type, 0)) == JVM_IO_ERR) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. */ NET_ThrowNew(env, errno, "can't create socket"); return; - } else { - (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); } +#ifdef AF_INET6 + /* Disable IPV6_V6ONLY to ensure dual-socket support */ + if (domain == AF_INET6) { + int arg = 0; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, + sizeof(int)) < 0) { + NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6"); + close(fd); + return; + } + } +#endif /* AF_INET6 */ + /* * If this is a server socket then enable SO_REUSEADDR * automatically and set to non blocking. @@ -221,9 +231,15 @@ if (ssObj != NULL) { int arg = 1; SET_NONBLOCKING(fd); - JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, - sizeof(arg)); + if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, + sizeof(arg)) < 0) { + NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR"); + close(fd); + return; + } } + + (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); } /*
--- a/jdk/src/solaris/native/sun/nio/ch/Net.c Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/solaris/native/sun/nio/ch/Net.c Mon Aug 23 19:14:20 2010 -0700 @@ -170,6 +170,22 @@ if (fd < 0) { return handleSocketError(env, errno); } + +#ifdef AF_INET6 + /* Disable IPV6_V6ONLY to ensure dual-socket support */ + if (domain == AF_INET6) { + int arg = 0; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, + sizeof(int)) < 0) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "sun.nio.ch.Net.setIntOption"); + close(fd); + return -1; + } + } +#endif + if (reuse) { int arg = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
--- a/jdk/src/windows/classes/java/io/Win32FileSystem.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/src/windows/classes/java/io/Win32FileSystem.java Mon Aug 23 19:14:20 2010 -0700 @@ -424,7 +424,6 @@ } } } - assert canonicalize0(path).equalsIgnoreCase(res); return res; } }
--- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh Mon Aug 23 19:14:20 2010 -0700 @@ -55,7 +55,7 @@ Linux ) FS="/" ;; - Windows* ) + Windows* | CYGWIN* ) FS="\\" ;; esac
--- a/jdk/test/java/net/URI/Test.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/test/java/net/URI/Test.java Mon Aug 23 19:14:20 2010 -0700 @@ -1536,6 +1536,7 @@ serial(); urls(); npes(); + bugs(); } @@ -1572,6 +1573,19 @@ } + // miscellaneous bugs/rfes that don't fit in with the test framework + + static void bugs() { + // 6339649 - include detail message from nested exception + try { + URI uri = URI.create("http://nowhere.net/should not be permitted"); + } catch (IllegalArgumentException e) { + if ("".equals(e.getMessage()) || e.getMessage() == null) { + throw new RuntimeException ("No detail message"); + } + } + } + public static void main(String[] args) throws Exception { switch (args.length) {
--- a/jdk/test/java/nio/file/Path/Misc.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/test/java/nio/file/Path/Misc.java Mon Aug 23 19:14:20 2010 -0700 @@ -261,6 +261,21 @@ assertTrue(file.toRealPath(true).isSameFile(file.toRealPath(false))); /** + * Test: toRealPath should fail if file does not exist + */ + Path doesNotExist = dir.resolve("DoesNotExist"); + try { + doesNotExist.toRealPath(true); + throw new RuntimeException("IOException expected"); + } catch (IOException expected) { + } + try { + doesNotExist.toRealPath(false); + throw new RuntimeException("IOException expected"); + } catch (IOException expected) { + } + + /** * Test: toRealPath(true) should resolve links */ if (supportsLinks) {
--- a/jdk/test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh Mon Aug 23 19:14:20 2010 -0700 @@ -23,6 +23,7 @@ # # @test +# @ignore until 6543856 is fixed # @bug 4990825 # @summary attach to external but local JVM processes # @library ../../testlibrary
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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. + */ + +import java.net.URL; +import java.net.URLConnection; +import java.io.IOException; + +public class DirPermissionDenied { + public static void main(String[] args) throws Exception { + URL url = new URL("file:" + args[0]); + + try { + URLConnection uc = url.openConnection(); + uc.connect(); + } catch (IOException e) { + // OK + } catch (Exception e) { + throw new RuntimeException("Failed " + e); + } + + try { + URLConnection uc = url.openConnection(); + uc.getInputStream(); + } catch (IOException e) { + // OK + } catch (Exception e) { + throw new RuntimeException("Failed " + e); + } + + try { + URLConnection uc = url.openConnection(); + uc.getContentLengthLong(); + } catch (IOException e) { + // OK + } catch (Exception e) { + throw new RuntimeException("Failed " + e); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.sh Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,41 @@ +# +# Copyright (c) 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. +# + +# +# @test +# @bug 6977851 +# @summary NPE from FileURLConnection.connect +# @build DirPermissionDenied +# @run shell DirPermissionDenied.sh + +TESTDIR="${TESTCLASSES}/DirPermissionDeniedDirectory" +echo ${TESTDIR} + +rm -rf ${TESTDIR} +mkdir -p ${TESTDIR} +chmod 333 ${TESTDIR} + +$TESTJAVA/bin/java -classpath $TESTCLASSES DirPermissionDenied ${TESTDIR} +result=$? +rm -rf ${TESTDIR} +exit $result
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/krb5/BadKdcDefaultValue.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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. + */ +/* + * @test + * @bug 6976536 + * @summary Solaris JREs do not have the krb5.kdc.bad.policy configured by default. + * @run main/othervm BadKdcDefaultValue + */ + +import java.security.Security; + +public class BadKdcDefaultValue { + public static void main(String[] args) throws Exception { + if (!"tryLast".equalsIgnoreCase( + Security.getProperty("krb5.kdc.bad.policy"))) { + throw new Exception("Default value not correct"); + } + } +} +
--- a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java Mon Aug 23 19:14:20 2010 -0700 @@ -23,7 +23,7 @@ /* * @test - * @bug 6226610 + * @bug 6226610 6973030 * @run main/othervm B6226610 * @summary HTTP tunnel connections send user headers to proxy */ @@ -36,45 +36,23 @@ import java.io.*; import java.net.*; -import javax.net.ssl.*; -import javax.net.ServerSocketFactory; -import sun.net.www.*; -import java.util.Enumeration; +import sun.net.www.MessageHeader; public class B6226610 { static HeaderCheckerProxyTunnelServer proxy; - // it seems there's no proxy ever if a url points to 'localhost', - // even if proxy related properties are set. so we need to bind - // our simple http proxy and http server to a non-loopback address - static InetAddress firstNonLoAddress = null; + public static void main(String[] args) throws Exception + { + proxy = new HeaderCheckerProxyTunnelServer(); + proxy.start(); - public static void main(String[] args) - { - try { - proxy = new HeaderCheckerProxyTunnelServer(); - proxy.start(); - } catch (Exception e) { - System.out.println("Cannot create proxy: " + e); - } - - try { - firstNonLoAddress = getNonLoAddress(); - - if (firstNonLoAddress == null) { - System.out.println("The test needs at least one non-loopback address to run. Quit now."); - System.exit(0); - } - } catch (Exception e) { - e.printStackTrace(); - } - - System.setProperty( "https.proxyHost", firstNonLoAddress.getHostAddress()); - System.setProperty( "https.proxyPort", (new Integer(proxy.getLocalPort())).toString() ); + String hostname = InetAddress.getLocalHost().getHostName(); try { - URL u = new URL("https://" + firstNonLoAddress.getHostAddress()); - java.net.URLConnection c = u.openConnection(); + URL u = new URL("https://" + hostname + "/"); + System.out.println("Connecting to " + u); + InetSocketAddress proxyAddr = new InetSocketAddress(hostname, proxy.getLocalPort()); + java.net.URLConnection c = u.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddr)); /* I want this header to go to the destination server only, protected * by SSL @@ -89,33 +67,15 @@ } else System.out.println(e); - + } finally { + if (proxy != null) proxy.shutdown(); } if (HeaderCheckerProxyTunnelServer.failed) - throw new RuntimeException("Test failed: Proxy should not receive user defined headers for tunneled requests"); + throw new RuntimeException("Test failed; see output"); } - - public static InetAddress getNonLoAddress() throws Exception { - NetworkInterface loNIC = NetworkInterface.getByInetAddress(InetAddress.getByName("localhost")); - Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces(); - while (nics.hasMoreElements()) { - NetworkInterface nic = nics.nextElement(); - if (!nic.getName().equalsIgnoreCase(loNIC.getName())) { - Enumeration<InetAddress> addrs = nic.getInetAddresses(); - while (addrs.hasMoreElements()) { - InetAddress addr = addrs.nextElement(); - if (!addr.isLoopbackAddress()) - return addr; - } - } - } - return null; - } - } - class HeaderCheckerProxyTunnelServer extends Thread { public static boolean failed = false; @@ -139,6 +99,10 @@ } } + void shutdown() { + try { ss.close(); } catch (IOException e) {} + } + public void run() { try { @@ -178,6 +142,15 @@ retrieveConnectInfo(statusLine); if (mheader.findValue("X-TestHeader") != null) { + System.out.println("Proxy should not receive user defined headers for tunneled requests"); + failed = true; + } + + // 6973030 + String value; + if ((value = mheader.findValue("Proxy-Connection")) == null || + !value.equals("keep-alive")) { + System.out.println("Proxy-Connection:keep-alive not being sent"); failed = true; }
--- a/jdk/test/tools/jar/JarEntryTime.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/test/tools/jar/JarEntryTime.java Mon Aug 23 19:14:20 2010 -0700 @@ -23,7 +23,7 @@ /** * @test - * @bug 4225317 + * @bug 4225317 6969651 * @summary Check extracted files have date as per those in the .jar file */ @@ -68,17 +68,9 @@ } public static void realMain(String[] args) throws Throwable { - final long now = System.currentTimeMillis(); - final long earlier = now - (60L * 60L * 6L * 1000L); - final long yesterday = now - (60L * 60L * 24L * 1000L); - - // ZipEntry's mod date has 2 seconds precision: give extra time to - // allow for e.g. rounding/truncation and networked/samba drives. - final long PRECISION = 10000L; File dirOuter = new File("outer"); File dirInner = new File(dirOuter, "inner"); - File jarFile = new File("JarEntryTime.jar"); // Remove any leftovers from prior run @@ -99,6 +91,17 @@ PrintWriter pw = new PrintWriter(fileInner); pw.println("hello, world"); pw.close(); + + // Get the "now" from the "last-modified-time" of the last file we + // just created, instead of the "System.currentTimeMillis()", to + // workaround the possible "time difference" due to nfs. + final long now = fileInner.lastModified(); + final long earlier = now - (60L * 60L * 6L * 1000L); + final long yesterday = now - (60L * 60L * 24L * 1000L); + // ZipEntry's mod date has 2 seconds precision: give extra time to + // allow for e.g. rounding/truncation and networked/samba drives. + final long PRECISION = 10000L; + dirOuter.setLastModified(now); dirInner.setLastModified(yesterday); fileInner.setLastModified(earlier);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/CommandLineTests.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2007, 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. + */ + +/* + * @test CommandLineTests.sh + * @bug 6521334 6965836 6965836 + * @compile -XDignore.symbol.file CommandLineTests.java Pack200Test.java + * @run main/timeout=1200 CommandLineTests + * @summary An ad hoc test to verify the behavior of pack200/unpack200 CLIs, + * and a simulation of pack/unpacking in the install repo. + * @author ksrini + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +/* + * We try a potpouri of things ie. we have pack.conf to setup some + * options as well as a couple of command line options. We also test + * the packing and unpacking mechanism using the Java APIs. This also + * simulates pack200 the install workspace, noting that this is a simulation + * and can only test jars that are guaranteed to be available, also the + * configuration may not be in sync with the installer workspace. + */ + +public class CommandLineTests { + private static final File CWD = new File("."); + private static final File EXP_SDK = new File(CWD, "exp-sdk-image"); + private static final File EXP_SDK_LIB_DIR = new File(EXP_SDK, "lib"); + private static final File EXP_SDK_BIN_DIR = new File(EXP_SDK, "bin"); + private static final File EXP_JRE_DIR = new File(EXP_SDK, "jre"); + private static final File EXP_JRE_LIB_DIR = new File(EXP_JRE_DIR, "lib"); + private static final File RtJar = new File(EXP_JRE_LIB_DIR, "rt.jar"); + private static final File CharsetsJar = new File(EXP_JRE_LIB_DIR, "charsets.jar"); + private static final File JsseJar = new File(EXP_JRE_LIB_DIR, "jsse.jar"); + private static final File ToolsJar = new File(EXP_SDK_LIB_DIR, "tools.jar"); + private static final File javaCmd; + private static final File javacCmd; + private static final File ConfigFile = new File("pack.conf"); + private static final List<File> jarList; + + static { + javaCmd = Utils.IsWindows + ? new File(EXP_SDK_BIN_DIR, "java.exe") + : new File(EXP_SDK_BIN_DIR, "java"); + + javacCmd = Utils.IsWindows + ? new File(EXP_SDK_BIN_DIR, "javac.exe") + : new File(EXP_SDK_BIN_DIR, "javac"); + + jarList = new ArrayList<File>(); + jarList.add(RtJar); + jarList.add(CharsetsJar); + jarList.add(JsseJar); + jarList.add(ToolsJar); + } + + // init test area with a copy of the sdk + static void init() throws IOException { + Utils.recursiveCopy(Utils.JavaSDK, EXP_SDK); + creatConfigFile(); + } + + // Hopefully, this should be kept in sync with what the installer does. + static void creatConfigFile() throws IOException { + FileOutputStream fos = null; + PrintStream ps = null; + try { + fos = new FileOutputStream(ConfigFile); + ps = new PrintStream(fos); + ps.println("com.sun.java.util.jar.pack.debug.verbose=0"); + ps.println("pack.modification.time=keep"); + ps.println("pack.keep.class.order=true"); + ps.println("pack.deflate.hint=false"); + // Fail the build, if new or unknown attributes are introduced. + ps.println("pack.unknown.attribute=error"); + ps.println("pack.segment.limit=-1"); + // BugId: 6328502, These files will be passed-through as-is. + ps.println("pack.pass.file.0=java/lang/Error.class"); + ps.println("pack.pass.file.1=java/lang/LinkageError.class"); + ps.println("pack.pass.file.2=java/lang/Object.class"); + ps.println("pack.pass.file.3=java/lang/Throwable.class"); + ps.println("pack.pass.file.4=java/lang/VerifyError.class"); + ps.println("pack.pass.file.5=com/sun/demo/jvmti/hprof/Tracker.class"); + } finally { + Utils.close(ps); + Utils.close(fos); + } + } + + static void runPack200(boolean jre) throws IOException { + List<String> cmdsList = new ArrayList<String>(); + for (File f : jarList) { + if (jre && f.getName().equals("tools.jar")) { + continue; // need not worry about tools.jar for JRE + } + // make a backup copy for re-use + File bakFile = new File(f.getName() + ".bak"); + if (!bakFile.exists()) { // backup + Utils.copyFile(f.getAbsoluteFile(), bakFile.getAbsoluteFile()); + } else { // restore + Utils.copyFile(bakFile.getAbsoluteFile(), f.getAbsoluteFile()); + } + cmdsList.clear(); + cmdsList.add(Utils.getPack200Cmd()); + cmdsList.add("-J-esa"); + cmdsList.add("-J-ea"); + cmdsList.add(Utils.Is64Bit ? "-J-Xmx1g" : "-J-Xmx512m"); + cmdsList.add("--repack"); + cmdsList.add("--config-file=" + ConfigFile.getAbsolutePath()); + if (jre) { + cmdsList.add("--strip-debug"); + } + // NOTE: commented until 6965836 is fixed + // cmdsList.add("--code-attribute=StackMapTable=strip"); + cmdsList.add(f.getAbsolutePath()); + Utils.runExec(cmdsList); + } + } + + static void testJRE() throws IOException { + runPack200(true); + // the speciment JRE + List<String> cmdsList = new ArrayList<String>(); + cmdsList.add(javaCmd.getAbsolutePath()); + cmdsList.add("-verify"); + cmdsList.add("-version"); + Utils.runExec(cmdsList); + } + + static void testJDK() throws IOException { + runPack200(false); + // test the specimen JDK + List<String> cmdsList = new ArrayList<String>(); + cmdsList.add(javaCmd.getAbsolutePath()); + cmdsList.add("-verify"); + cmdsList.add("-version"); + Utils.runExec(cmdsList); + + // invoke javac to test the tools.jar + cmdsList.clear(); + cmdsList.add(javacCmd.getAbsolutePath()); + cmdsList.add("-J-verify"); + cmdsList.add("-help"); + Utils.runExec(cmdsList); + } + public static void main(String... args) { + try { + init(); + testJRE(); + testJDK(); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/Pack200Props.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * @bug 6575373 6969063 + * @summary verify default properties of the packer/unpacker and segment limit + * @compile -XDignore.symbol.file Utils.java Pack200Props.java + * @run main Pack200Props + * @author ksrini + */ + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.jar.Pack200; +import java.util.jar.Pack200.Packer; + +/* + * Run this against a large jar file, by default the packer should generate only + * one segment, parse the output of the packer to verify if this is indeed true. + */ + +public class Pack200Props { + + public static void main(String... args) { + verifyDefaults(); + File out = new File("test" + Utils.PACK_FILE_EXT); + out.delete(); + verifySegmentLimit(out); + } + + static void verifySegmentLimit(File outFile) { + File sdkHome = Utils.JavaSDK; + File testJar = new File(new File(sdkHome, "lib"), "tools.jar"); + + System.out.println("using pack200: " + Utils.getPack200Cmd()); + + List<String> cmdsList = new ArrayList<>(); + cmdsList.add(Utils.getPack200Cmd()); + cmdsList.add("--effort=1"); + cmdsList.add("--verbose"); + cmdsList.add("--no-gzip"); + cmdsList.add(outFile.getName()); + cmdsList.add(testJar.getAbsolutePath()); + List<String> outList = Utils.runExec(cmdsList); + + int count = 0; + for (String line : outList) { + System.out.println(line); + if (line.matches(".*Transmitted.*files of.*input bytes in a segment of.*bytes")) { + count++; + } + } + if (count == 0) { + throw new RuntimeException("no segments or no output ????"); + } else if (count > 1) { + throw new RuntimeException("multiple segments detected, expected 1"); + } + } + + private static void verifyDefaults() { + Map<String, String> expectedDefaults = new HashMap<>(); + Packer p = Pack200.newPacker(); + expectedDefaults.put("com.sun.java.util.jar.pack.default.timezone", + p.FALSE); + expectedDefaults.put("com.sun.java.util.jar.pack.disable.native", + p.FALSE); + expectedDefaults.put("com.sun.java.util.jar.pack.verbose", "0"); + expectedDefaults.put(p.CLASS_ATTRIBUTE_PFX + "CompilationID", "RUH"); + expectedDefaults.put(p.CLASS_ATTRIBUTE_PFX + "SourceID", "RUH"); + expectedDefaults.put(p.CODE_ATTRIBUTE_PFX + "CharacterRangeTable", + "NH[PHPOHIIH]"); + expectedDefaults.put(p.CODE_ATTRIBUTE_PFX + "CoverageTable", + "NH[PHHII]"); + expectedDefaults.put(p.DEFLATE_HINT, p.KEEP); + expectedDefaults.put(p.EFFORT, "5"); + expectedDefaults.put(p.KEEP_FILE_ORDER, p.TRUE); + expectedDefaults.put(p.MODIFICATION_TIME, p.KEEP); + expectedDefaults.put(p.SEGMENT_LIMIT, "-1"); + expectedDefaults.put(p.UNKNOWN_ATTRIBUTE, p.PASS); + + Map<String, String> props = p.properties(); + int errors = 0; + for (String key : expectedDefaults.keySet()) { + String def = expectedDefaults.get(key); + String x = props.get(key); + if (x == null) { + System.out.println("Error: key not found:" + key); + errors++; + } else { + if (!def.equals(x)) { + System.out.println("Error: key " + key + + "\n value expected: " + def + + "\n value obtained: " + x); + errors++; + } + } + } + if (errors > 0) { + throw new RuntimeException(errors + + " error(s) encountered in default properties verification"); + } + } +} +
--- a/jdk/test/tools/pack200/Pack200Simple.sh Mon Aug 23 19:13:15 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,197 +0,0 @@ -# -# Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# - -# @test Pack200Simple.sh -# @bug 6521334 -# @build Pack200Test -# @run shell/timeout=1200 Pack200Simple.sh -# @summary An ad hoc test to verify class-file format. -# @author Kumar Srinivasan - -# The goal of this test is to assist javac or other developers -# who modify class file formats, to quickly test those modifications -# without having to build the install workspace. However it must -# be noted that building the install workspace is the only know -# way to prevent build breakages. - -# Pack200 developers could use this as a basic smoke-test, however -# please note, there are other more elaborate and thorough tests for -# this very purpose. - -# We try a potpouri of things ie. we have pack.conf to setup some -# options as well as a couple of command line options. We also test -# the packing and unpacking mechanism using the Java APIs. - -# print error and exit with a message -errorOut() { - if [ "x$1" = "x" ]; then - printf "Error: Unknown error\n" - else - printf "Error: %s\n" "$1" - fi - - exit 1 -} - -# Verify directory context variables are set -if [ "${TESTJAVA}" = "" ]; then - errorOut "TESTJAVA not set. Test cannot execute. Failed." -fi - -if [ "${TESTSRC}" = "" ]; then - errorOut "TESTSRC not set. Test cannot execute. Failed." -fi - - -if [ "${TESTCLASSES}" = "" ]; then - errorOut "TESTCLASSES not set. Test cannot execute. Failed." -fi - -# The common java utils we need -PACK200=${TESTJAVA}/bin/pack200 -UNPACK200=${TESTJAVA}/bin/unpack200 -JAR=${TESTJAVA}/bin/jar - -# For Windows and Linux needs the heap to be set, for others ergonomics -# will do the rest. It is important to use ea, which can expose class -# format errors much earlier than later. - -OS=`uname -s` - - -case "$OS" in - Windows*|CYGWIN* ) - PackOptions="-J-Xmx512m -J-ea" - break - ;; - - Linux ) - PackOptions="-J-Xmx512m -J-ea" - break - ;; - - * ) - PackOptions="-J-ea" - ;; -esac - -# Creates a packfile of choice expects 1 argument the filename -createConfigFile() { - # optimize for speed - printf "pack.effort=1\n" > $1 - # we DO want to know about new attributes - printf "pack.unknown.attribute=error\n" >> $1 - # optimize for speed - printf "pack.deflate.hint=false\n" >> $1 - # keep the ordering for easy compare - printf "pack.keep.class.order=true\n" >> $1 -} - - -# Tests a given jar, expects 1 argument the fully qualified -# name to a test jar, it writes all output to the current -# directory which is a scratch area. -testAJar() { - PackConf="pack.conf" - createConfigFile $PackConf - - # Try some command line options - CLIPackOptions="$PackOptions -v --no-gzip --segment-limit=10000 --config-file=$PackConf" - - jfName=`basename $1` - - ${PACK200} $CLIPackOptions ${jfName}.pack $1 > ${jfName}.pack.log 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName packing failed" - fi - - # We want to test unpack200, therefore we dont use -r with pack - ${UNPACK200} -v ${jfName}.pack $jfName > ${jfName}.unpack.log 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName unpacking failed" - fi - - # A quick crc compare test to ensure a well formed zip - # archive, this is a critical unpack200 behaviour. - - unzip -t $jfName > ${jfName}.unzip.log 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName unzip -t test failed" - fi - - # The PACK200 signature should be at the top of the log - # this tag is critical for deployment related tools. - - head -5 ${jfName}.unzip.log | grep PACK200 > /dev/null 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName PACK200 signature missing" - fi - - - # we know the size fields don't match, strip 'em out, its - # extremely important to ensure that the date stamps match up. - # Don't EVER sort the output we are checking for correct ordering. - - ${JAR} -tvf $1 | sed -e 's/^ *[0-9]* //g'> ${jfName}.ref.txt - ${JAR} -tvf $jfName | sed -e 's/^ *[0-9]* //g'> ${jfName}.cmp.txt - - diff ${jfName}.ref.txt ${jfName}.cmp.txt > ${jfName}.diff.log 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName files missing" - fi -} - -# These JARs are the largest and also the most likely specimens to -# expose class format issues and stress the packer as well. - -JLIST="${TESTJAVA}/lib/tools.jar ${TESTJAVA}/jre/lib/rt.jar" - - -# Test the Command Line Interfaces (CLI). -mkdir cliTestDir -_pwd=`pwd` -cd cliTestDir - -for jarfile in $JLIST ; do - if [ -f $jarfile ]; then - testAJar $jarfile - else - errorOut "Error: '$jarFile' does not exist\nTest requires a j2sdk-image\n" - fi -done -cd $_pwd - -# Test the Java APIs. -mkdir apiTestDir -_pwd=`pwd` -cd apiTestDir - -# Strip out the -J prefixes. -JavaPackOptions=`printf %s "$PackOptions" | sed -e 's/-J//g'` - -# Test the Java APIs now. -$TESTJAVA/bin/java $JavaPackOptions -cp $TESTCLASSES Pack200Test $JLIST || exit 1 - -cd $_pwd - -exit 0
--- a/jdk/test/tools/pack200/Pack200Test.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/test/tools/pack200/Pack200Test.java Mon Aug 23 19:14:20 2010 -0700 @@ -24,111 +24,97 @@ import java.util.*; import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; import java.util.jar.*; -import java.util.zip.*; -/* - * Pack200Test.java - * - * @author ksrini - */ + /* + * @test + * @bug 6521334 6712743 + * @summary check for memory leaks, test general packer/unpacker functionality\ + * using native and java unpackers + * @compile -XDignore.symbol.file Utils.java Pack200Test.java + * @run main/othervm/timeout=1200 -Xmx512m Pack200Test + * @author ksrini + */ /** - * These tests are very rudimentary smoke tests to ensure that the packing - * unpacking process works on a select set of JARs. + * Tests the packing/unpacking via the APIs. */ public class Pack200Test { private static ArrayList <File> jarList = new ArrayList<File>(); - static final String PACKEXT = ".pack"; + static final MemoryMXBean mmxbean = ManagementFactory.getMemoryMXBean(); + static final long m0 = getUsedMemory(); + static final int LEAK_TOLERANCE = 20000; // OS and GC related variations. /** Creates a new instance of Pack200Test */ private Pack200Test() {} - private static void doPackUnpack() { - for (File in : jarList) { - Pack200.Packer packer = Pack200.newPacker(); - Map<String, String> p = packer.properties(); - // Take the time optimization vs. space - p.put(packer.EFFORT, "1"); // CAUTION: do not use 0. - // Make the memory consumption as effective as possible - p.put(packer.SEGMENT_LIMIT,"10000"); - // throw an error if an attribute is unrecognized - p.put(packer.UNKNOWN_ATTRIBUTE, packer.ERROR); - // ignore all JAR deflation requests to save time - p.put(packer.DEFLATE_HINT, packer.FALSE); - // save the file ordering of the original JAR - p.put(packer.KEEP_FILE_ORDER, packer.TRUE); + static long getUsedMemory() { + mmxbean.gc(); + mmxbean.gc(); + mmxbean.gc(); + return mmxbean.getHeapMemoryUsage().getUsed()/1024; + } - try { - JarFile jarFile = new JarFile(in); - - // Write out to a jtreg scratch area - FileOutputStream fos = new FileOutputStream(in.getName() + PACKEXT); - - System.out.print("Packing [" + in.toString() + "]..."); - // Call the packer - packer.pack(jarFile, fos); - jarFile.close(); - fos.close(); - - System.out.print("Unpacking..."); - File f = new File(in.getName() + PACKEXT); - - // Write out to current directory, jtreg will setup a scratch area - JarOutputStream jostream = new JarOutputStream(new FileOutputStream(in.getName())); - - // Unpack the files - Pack200.Unpacker unpacker = Pack200.newUnpacker(); - // Call the unpacker - unpacker.unpack(f, jostream); - // Must explicitly close the output. - jostream.close(); - System.out.print("Testing..."); - // Ok we have unpacked the file, lets test it. - doTest(in); - System.out.println("Done."); - } catch (Exception e) { - System.out.println("ERROR: " + e.getMessage()); - System.exit(1); - } + private static void leakCheck() throws Exception { + long diff = getUsedMemory() - m0; + System.out.println(" Info: memory diff = " + diff + "K"); + if ( diff > LEAK_TOLERANCE) { + throw new Exception("memory leak detected " + diff); } } - private static ArrayList <String> getZipFileEntryNames(ZipFile z) { - ArrayList <String> out = new ArrayList<String>(); - for (ZipEntry ze : Collections.list(z.entries())) { - out.add(ze.getName()); - } - return out; - } + private static void doPackUnpack() { + for (File in : jarList) { + JarOutputStream javaUnpackerStream = null; + JarOutputStream nativeUnpackerStream = null; + JarFile jarFile = null; + try { + jarFile = new JarFile(in); - private static void doTest(File in) throws Exception { - // make sure all the files in the original jar exists in the other - ArrayList <String> refList = getZipFileEntryNames(new ZipFile(in)); - ArrayList <String> cmpList = getZipFileEntryNames(new ZipFile(in.getName())); + // Write out to a jtreg scratch area + File packFile = new File(in.getName() + Utils.PACK_FILE_EXT); - System.out.print(refList.size() + "/" + cmpList.size() + " entries..."); + System.out.println("Packing [" + in.toString() + "]"); + // Call the packer + Utils.pack(jarFile, packFile); + jarFile.close(); + leakCheck(); - if (refList.size() != cmpList.size()) { - throw new Exception("Missing: files ?, entries don't match"); - } + System.out.println(" Unpacking using java unpacker"); + File javaUnpackedJar = new File("java-" + in.getName()); + // Write out to current directory, jtreg will setup a scratch area + javaUnpackerStream = new JarOutputStream( + new FileOutputStream(javaUnpackedJar)); + Utils.unpackj(packFile, javaUnpackerStream); + javaUnpackerStream.close(); + System.out.println(" Testing...java unpacker"); + leakCheck(); + // Ok we have unpacked the file, lets test it. + Utils.doCompareVerify(in.getAbsoluteFile(), javaUnpackedJar); - for (String ename: refList) { - if (!cmpList.contains(ename)) { - throw new Exception("Does not contain : " + ename); - } - } - } - - private static void doSanity(String[] args) { - for (String s: args) { - File f = new File(s); - if (f.exists()) { - jarList.add(f); - } else { - System.out.println("Warning: The JAR file " + f.toString() + " does not exist,"); - System.out.println(" this test requires a JDK image, this file will be skipped."); + System.out.println(" Unpacking using native unpacker"); + // Write out to current directory + File nativeUnpackedJar = new File("native-" + in.getName()); + nativeUnpackerStream = new JarOutputStream( + new FileOutputStream(nativeUnpackedJar)); + Utils.unpackn(packFile, nativeUnpackerStream); + nativeUnpackerStream.close(); + System.out.println(" Testing...native unpacker"); + leakCheck(); + // the unpackers (native and java) should produce identical bits + // so we use use bit wise compare, the verification compare is + // very expensive wrt. time. + Utils.doCompareBitWise(javaUnpackedJar, nativeUnpackedJar); + System.out.println("Done."); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + Utils.close(nativeUnpackerStream); + Utils.close(javaUnpackerStream); + Utils.close((Closeable) jarFile); } } } @@ -137,11 +123,12 @@ * @param args the command line arguments */ public static void main(String[] args) { - if (args.length < 1) { - System.out.println("Usage: jar1 jar2 jar3 ....."); - System.exit(1); - } - doSanity(args); + // select the jars carefully, adding more jars will increase the + // testing time, especially for jprt. + jarList.add(Utils.locateJar("tools.jar")); + jarList.add(Utils.locateJar("rt.jar")); + jarList.add(Utils.locateJar("golden.jar")); + System.out.println(jarList); doPackUnpack(); } }
--- a/jdk/test/tools/pack200/PackageVersionTest.java Mon Aug 23 19:13:15 2010 -0700 +++ b/jdk/test/tools/pack200/PackageVersionTest.java Mon Aug 23 19:14:20 2010 -0700 @@ -22,13 +22,14 @@ * questions. */ -/** - * @test - * @bug 6712743 - * @summary verify package versioning - * @compile -XDignore.symbol.file PackageVersionTest.java - * @run main PackageVersionTest - */ +/* + * @test + * @bug 6712743 + * @summary verify package versions + * @compile -XDignore.symbol.file Utils.java PackageVersionTest.java + * @run main PackageVersionTest + * @author ksrini + */ import java.io.ByteArrayOutputStream; import java.io.Closeable; @@ -74,14 +75,6 @@ JAVA5_PACKAGE_MINOR_VERSION); } - static void close(Closeable c) { - if (c == null) { - return; - } - try { - c.close(); - } catch (IOException ignore) {} - } static void createClassFile(String name) { createJavaFile(name); @@ -93,7 +86,7 @@ name.substring(name.length() - 1), name + ".java" }; - compileJava(javacCmds); + Utils.compiler(javacCmds); } static void createJavaFile(String name) { @@ -108,22 +101,8 @@ } catch (IOException ioe) { throw new RuntimeException("creation of test file failed"); } finally { - close(ps); - close(fos); - } - } - - static void compileJava(String... javacCmds) { - if (com.sun.tools.javac.Main.compile(javacCmds) != 0) { - throw new RuntimeException("compilation failed"); - } - } - - static void makeJar(String... jargs) { - sun.tools.jar.Main jarTool = - new sun.tools.jar.Main(System.out, System.err, "jartool"); - if (!jarTool.run(jargs)) { - throw new RuntimeException("jar command failed"); + Utils.close(ps); + Utils.close(fos); } } @@ -136,7 +115,7 @@ jarFileName.getName(), filename }; - makeJar(jargs); + Utils.jar(jargs); JarFile jfin = null; try { @@ -163,7 +142,7 @@ } catch (IOException ioe) { throw new RuntimeException(ioe.getMessage()); } finally { - close(jfin); + Utils.close((Closeable) jfin); } } }
--- a/jdk/test/tools/pack200/SegmentLimit.java Mon Aug 23 19:13:15 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/** - * @test - * @bug 6575373 - * @summary verify default segment limit - * @compile SegmentLimit.java - * @run main SegmentLimit - */ - -import java.io.BufferedReader; -import java.io.Closeable; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintStream; - -/* - * Run this against a large jar file, by default the packer should generate only - * one segment, parse the output of the packer to verify if this is indeed true. - */ - -public class SegmentLimit { - - private static final File javaHome = new File(System.getProperty("java.home")); - - public static void main(String... args) { - if (!javaHome.getName().endsWith("jre")) { - throw new RuntimeException("Error: requires an SDK to run"); - } - - File out = new File("test" + Pack200Test.PACKEXT); - out.delete(); - runPack200(out); - } - - static void close(Closeable c) { - if (c == null) { - return; - } - try { - c.close(); - } catch (IOException ignore) {} - } - - static void runPack200(File outFile) { - File binDir = new File(javaHome, "bin"); - File pack200Exe = System.getProperty("os.name").startsWith("Windows") - ? new File(binDir, "pack200.exe") - : new File(binDir, "pack200"); - File sdkHome = javaHome.getParentFile(); - File testJar = new File(new File(sdkHome, "lib"), "tools.jar"); - - System.out.println("using pack200: " + pack200Exe.getAbsolutePath()); - - String[] cmds = { pack200Exe.getAbsolutePath(), - "--effort=1", - "--verbose", - "--no-gzip", - outFile.getName(), - testJar.getAbsolutePath() - }; - InputStream is = null; - BufferedReader br = null; - InputStreamReader ir = null; - - FileOutputStream fos = null; - PrintStream ps = null; - - try { - ProcessBuilder pb = new ProcessBuilder(cmds); - pb.redirectErrorStream(true); - Process p = pb.start(); - is = p.getInputStream(); - ir = new InputStreamReader(is); - br = new BufferedReader(ir); - - File logFile = new File("pack200.log"); - fos = new FileOutputStream(logFile); - ps = new PrintStream(fos); - - String line = br.readLine(); - int count = 0; - while (line != null) { - line = line.trim(); - if (line.matches(".*Transmitted.*files of.*input bytes in a segment of.*bytes")) { - count++; - } - ps.println(line); - line=br.readLine(); - } - p.waitFor(); - if (p.exitValue() != 0) { - throw new RuntimeException("pack200 failed"); - } - p.destroy(); - if (count > 1) { - throw new Error("test fails: check for multiple segments(" + - count + ") in: " + logFile.getAbsolutePath()); - } - } catch (IOException ex) { - throw new RuntimeException(ex.getMessage()); - } catch (InterruptedException ignore){ - } finally { - close(is); - close(ps); - close(fos); - } - } -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/TimeStamp.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 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. + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.TimeZone; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; + +/* + * @test + * @bug 6966740 + * @summary verify identical timestamps, unpacked in any timezone + * @compile -XDignore.symbol.file Utils.java TimeStamp.java + * @run main/othervm TimeStamp + * @author ksrini + */ + +/** + * First we pack the file in some time zone say India, then we unpack the file + * in the current time zone, and ensure the timestamp recorded in the unpacked + * jar are the same. + */ +public class TimeStamp { + static final TimeZone tz = TimeZone.getDefault(); + + + public static void main(String... args) throws IOException { + + // make a local copy of our test file + File srcFile = Utils.locateJar("golden.jar"); + File goldenFile = new File("golden.jar"); + Utils.copyFile(srcFile, goldenFile.getAbsoluteFile()); + + JarFile goldenJarFile = new JarFile(goldenFile); + File packFile = new File("golden.pack"); + + // set the test timezone and pack the file + TimeZone.setDefault(TimeZone.getTimeZone("IST")); + Utils.pack(goldenJarFile, packFile); + TimeZone.setDefault(tz); // reset the timezone + + // unpack in the test timezone + File istFile = new File("golden.jar.java.IST"); + unpackJava(packFile, istFile); + verifyJar(goldenFile, istFile); + istFile.delete(); + + // unpack in some other timezone + File pstFile = new File("golden.jar.java.PST"); + unpackJava(packFile, pstFile); + verifyJar(goldenFile, pstFile); + pstFile.delete(); + + // repeat the test for unpack200 tool. + istFile = new File("golden.jar.native.IST"); + unpackNative(packFile, istFile); + verifyJar(goldenFile, istFile); + istFile.delete(); + + pstFile = new File("golden.jar.native.PST"); + unpackNative(packFile, pstFile); + verifyJar(goldenFile, pstFile); + pstFile.delete(); + } + + static void unpackNative(File packFile, File outFile) { + String name = outFile.getName(); + String tzname = name.substring(name.lastIndexOf(".") + 1); + HashMap<String, String> env = new HashMap<>(); + switch(tzname) { + case "PST": + env.put("TZ", "US/Pacific"); + break; + case "IST": + env.put("TZ", "Asia/Calcutta"); + break; + default: + throw new RuntimeException("not implemented: " + tzname); + } + List<String> cmdsList = new ArrayList<>(); + cmdsList.add(Utils.getUnpack200Cmd()); + cmdsList.add(packFile.getName()); + cmdsList.add(outFile.getName()); + Utils.runExec(cmdsList, env); + } + + static void unpackJava(File packFile, File outFile) throws IOException { + String name = outFile.getName(); + String tzname = name.substring(name.lastIndexOf(".") + 1); + JarOutputStream jos = null; + try { + TimeZone.setDefault(TimeZone.getTimeZone(tzname)); + jos = new JarOutputStream(new FileOutputStream(outFile)); + System.out.println("Using timezone: " + TimeZone.getDefault()); + Utils.unpackj(packFile, jos); + } finally { + Utils.close(jos); + TimeZone.setDefault(tz); // always reset + } + } + + static void verifyJar(File f1, File f2) throws IOException { + int errors = 0; + JarFile jf1 = null; + JarFile jf2 = null; + try { + jf1 = new JarFile(f1); + jf2 = new JarFile(f2); + System.out.println("Verifying: " + f1 + " and " + f2); + for (JarEntry je1 : Collections.list(jf1.entries())) { + JarEntry je2 = jf2.getJarEntry(je1.getName()); + if (je1.getTime() != je2.getTime()) { + System.out.println("Error:"); + System.out.println(" expected:" + jf1.getName() + ":" + + je1.getName() + ":" + je1.getTime()); + System.out.println(" obtained:" + jf2.getName() + ":" + + je2.getName() + ":" + je2.getTime()); + errors++; + } + } + } finally { + Utils.close(jf1); + Utils.close(jf2); + } + if (errors > 0) { + throw new RuntimeException("FAIL:" + errors + " error(s) encounted"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/UnpackerMemoryTest.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test + * @bug 6531345 + * @summary check for unpacker memory leaks + * @compile -XDignore.symbol.file Utils.java UnpackerMemoryTest.java + * @run main/othervm/timeout=1200 -Xmx32m UnpackerMemoryTest + * @author ksrini + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.io.IOException; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; + +public class UnpackerMemoryTest { + + private static void createPackFile(File packFile) throws IOException { + File tFile = new File("test.dat"); + FileOutputStream fos = null; + PrintStream ps = null; + String jarFileName = Utils.baseName(packFile, Utils.PACK_FILE_EXT) + + Utils.JAR_FILE_EXT; + JarFile jarFile = null; + try { + fos = new FileOutputStream(tFile); + ps = new PrintStream(fos); + ps.println("A quick brown fox"); + Utils.jar("cvf", jarFileName, tFile.getName()); + jarFile = new JarFile(jarFileName); + Utils.pack(jarFile, packFile); + } finally { + Utils.close(ps); + tFile.delete(); + Utils.close(jarFile); + } + } + + public static void main(String[] args) throws Exception { + String name = "foo"; + File packFile = new File(name + Utils.PACK_FILE_EXT); + createPackFile(packFile); + if (!packFile.exists()) { + throw new RuntimeException(packFile + " not found"); + } + File jarOut = new File(name + ".out"); + for (int i = 0; i < 2000; i++) { + JarOutputStream jarOS = null; + FileOutputStream fos = null; + try { + fos = new FileOutputStream(jarOut); + jarOS = new JarOutputStream(fos); + System.out.println("Unpacking[" + i + "]" + packFile); + Utils.unpackn(packFile, jarOS); + } finally { + Utils.close(jarOS); + Utils.close(fos); + } + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/Utils.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2007, 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. + */ + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Pack200; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * + * @author ksrini + */ + +/* + * This class contains all the commonly used utilities used by various tests + * in this directory. + */ +class Utils { + static final String JavaHome = System.getProperty("test.java", + System.getProperty("java.home")); + static final boolean IsWindows = + System.getProperty("os.name").startsWith("Windows"); + static final boolean Is64Bit = + System.getProperty("sun.arch.data.model", "32").equals("64"); + static final File JavaSDK = new File(JavaHome).getParentFile(); + + static final String PACK_FILE_EXT = ".pack"; + static final String JAVA_FILE_EXT = ".java"; + static final String CLASS_FILE_EXT = ".class"; + static final String JAR_FILE_EXT = ".jar"; + + static final File TEST_SRC_DIR = new File(System.getProperty("test.src")); + static final String VERIFIER_DIR_NAME = "pack200-verifier"; + static final File VerifierJar = new File(VERIFIER_DIR_NAME + JAR_FILE_EXT); + + private Utils() {} // all static + + static { + if (!JavaHome.endsWith("jre")) { + throw new RuntimeException("Error: requires an SDK to run"); + } + } + + private static void init() throws IOException { + if (VerifierJar.exists()) { + return; + } + File srcDir = new File(TEST_SRC_DIR, VERIFIER_DIR_NAME); + List<File> javaFileList = findFiles(srcDir, createFilter(JAVA_FILE_EXT)); + File tmpFile = File.createTempFile("javac", ".tmp"); + File classesDir = new File("xclasses"); + classesDir.mkdirs(); + FileOutputStream fos = null; + PrintStream ps = null; + try { + fos = new FileOutputStream(tmpFile); + ps = new PrintStream(fos); + for (File f : javaFileList) { + ps.println(f.getAbsolutePath()); + } + } finally { + close(ps); + close(fos); + } + + compiler("-d", + "xclasses", + "@" + tmpFile.getAbsolutePath()); + + jar("cvfe", + VerifierJar.getName(), + "sun.tools.pack.verify.Main", + "-C", + "xclasses", + "."); + } + + static void dirlist(File dir) { + File[] files = dir.listFiles(); + System.out.println("--listing " + dir.getAbsolutePath() + "---"); + for (File f : files) { + StringBuffer sb = new StringBuffer(); + sb.append(f.isDirectory() ? "d " : "- "); + sb.append(f.getName()); + System.out.println(sb); + } + } + static void doCompareVerify(File reference, File specimen) throws IOException { + init(); + List<String> cmds = new ArrayList<String>(); + cmds.add(getJavaCmd()); + cmds.add("-jar"); + cmds.add(VerifierJar.getName()); + cmds.add(reference.getAbsolutePath()); + cmds.add(specimen.getAbsolutePath()); + cmds.add("-O"); + runExec(cmds); + } + + static void doCompareBitWise(File reference, File specimen) + throws IOException { + init(); + List<String> cmds = new ArrayList<String>(); + cmds.add(getJavaCmd()); + cmds.add("-jar"); + cmds.add(VerifierJar.getName()); + cmds.add(reference.getName()); + cmds.add(specimen.getName()); + cmds.add("-O"); + cmds.add("-b"); + runExec(cmds); + } + + static FileFilter createFilter(final String extension) { + return new FileFilter() { + @Override + public boolean accept(File pathname) { + String name = pathname.getName(); + if (name.endsWith(extension)) { + return true; + } + return false; + } + }; + } + + static final FileFilter DIR_FILTER = new FileFilter() { + public boolean accept(File pathname) { + if (pathname.isDirectory()) { + return true; + } + return false; + } + }; + + static final FileFilter FILE_FILTER = new FileFilter() { + public boolean accept(File pathname) { + if (pathname.isFile()) { + return true; + } + return false; + } + }; + + private static void setFileAttributes(File src, File dst) throws IOException { + dst.setExecutable(src.canExecute()); + dst.setReadable(src.canRead()); + dst.setWritable(src.canWrite()); + dst.setLastModified(src.lastModified()); + } + + static void copyFile(File src, File dst) throws IOException { + if (src.isDirectory()) { + dst.mkdirs(); + setFileAttributes(src, dst); + return; + } else { + File baseDirFile = dst.getParentFile(); + if (!baseDirFile.exists()) { + baseDirFile.mkdirs(); + } + } + FileInputStream in = null; + FileOutputStream out = null; + FileChannel srcChannel = null; + FileChannel dstChannel = null; + try { + in = new FileInputStream(src); + out = new FileOutputStream(dst); + srcChannel = in.getChannel(); + dstChannel = out.getChannel(); + + long retval = srcChannel.transferTo(0, src.length(), dstChannel); + if (src.length() != dst.length()) { + throw new IOException("file copy failed for " + src); + } + } finally { + close(srcChannel); + close(dstChannel); + close(in); + close(out); + } + setFileAttributes(src, dst); + } + + static String baseName(File file, String extension) { + return baseName(file.getAbsolutePath(), extension); + } + + static String baseName(String name, String extension) { + int cut = name.length() - extension.length(); + return name.lastIndexOf(extension) == cut + ? name.substring(0, cut) + : name; + + } + + /* + * Suppose a path is provided which consists of a full path + * this method returns the sub path for a full path ex: /foo/bar/baz/foobar.z + * and the base path is /foo/bar it will will return baz/foobar.z. + */ + private static String getEntryPath(String basePath, String fullPath) { + if (!fullPath.startsWith(basePath)) { + return null; + } + return fullPath.substring(basePath.length()); + } + + static String getEntryPath(File basePathFile, File fullPathFile) { + return getEntryPath(basePathFile.toString(), fullPathFile.toString()); + } + + public static void recursiveCopy(File src, File dest) throws IOException { + if (!src.exists() || !src.canRead()) { + throw new IOException("file not found or readable: " + src); + } + if (dest.exists() && !dest.isDirectory() && !dest.canWrite()) { + throw new IOException("file not found or writeable: " + dest); + } + if (!dest.exists()) { + dest.mkdirs(); + } + List<File> a = directoryList(src); + for (File f : a) { + copyFile(f, new File(dest, getEntryPath(src, f))); + } + } + + static List<File> directoryList(File dirname) { + List<File> dirList = new ArrayList<File>(); + return directoryList(dirname, dirList, null); + } + + private static List<File> directoryList(File dirname, List<File> dirList, + File[] dirs) { + dirList.addAll(Arrays.asList(dirname.listFiles(FILE_FILTER))); + dirs = dirname.listFiles(DIR_FILTER); + for (File f : dirs) { + if (f.isDirectory() && !f.equals(dirname)) { + dirList.add(f); + directoryList(f, dirList, dirs); + } + } + return dirList; + } + + static void recursiveDelete(File dir) throws IOException { + if (dir.isFile()) { + dir.delete(); + } else if (dir.isDirectory()) { + File[] entries = dir.listFiles(); + for (int i = 0; i < entries.length; i++) { + if (entries[i].isDirectory()) { + recursiveDelete(entries[i]); + } + entries[i].delete(); + } + dir.delete(); + } + } + + static List<File> findFiles(File startDir, FileFilter filter) + throws IOException { + List<File> list = new ArrayList<File>(); + findFiles0(startDir, list, filter); + return list; + } + /* + * finds files in the start directory using the the filter, appends + * the files to the dirList. + */ + private static void findFiles0(File startDir, List<File> list, + FileFilter filter) throws IOException { + File[] foundFiles = startDir.listFiles(filter); + list.addAll(Arrays.asList(foundFiles)); + File[] dirs = startDir.listFiles(DIR_FILTER); + for (File dir : dirs) { + findFiles0(dir, list, filter); + } + } + + static void close(Closeable c) { + if (c == null) { + return; + } + try { + c.close(); + } catch (IOException ignore) { + } + } + + static void compiler(String... javacCmds) { + if (com.sun.tools.javac.Main.compile(javacCmds) != 0) { + throw new RuntimeException("compilation failed"); + } + } + + static void jar(String... jargs) { + sun.tools.jar.Main jarTool = + new sun.tools.jar.Main(System.out, System.err, "jartool"); + if (!jarTool.run(jargs)) { + throw new RuntimeException("jar command failed"); + } + } + + // given a jar file foo.jar will write to foo.pack + static void pack(JarFile jarFile, File packFile) throws IOException { + Pack200.Packer packer = Pack200.newPacker(); + Map<String, String> p = packer.properties(); + // Take the time optimization vs. space + p.put(packer.EFFORT, "1"); // CAUTION: do not use 0. + // Make the memory consumption as effective as possible + p.put(packer.SEGMENT_LIMIT, "10000"); + // ignore all JAR deflation requests to save time + p.put(packer.DEFLATE_HINT, packer.FALSE); + // save the file ordering of the original JAR + p.put(packer.KEEP_FILE_ORDER, packer.TRUE); + FileOutputStream fos = null; + try { + // Write out to a jtreg scratch area + fos = new FileOutputStream(packFile); + // Call the packer + packer.pack(jarFile, fos); + } finally { + close(fos); + } + } + + // uses java unpacker, slow but useful to discover issues with the packer + static void unpackj(File inFile, JarOutputStream jarStream) + throws IOException { + unpack0(inFile, jarStream, true); + + } + + // uses native unpacker using the java APIs + static void unpackn(File inFile, JarOutputStream jarStream) + throws IOException { + unpack0(inFile, jarStream, false); + } + + // given a packed file, create the jar file in the current directory. + private static void unpack0(File inFile, JarOutputStream jarStream, + boolean useJavaUnpack) throws IOException { + // Unpack the files + Pack200.Unpacker unpacker = Pack200.newUnpacker(); + Map<String, String> props = unpacker.properties(); + if (useJavaUnpack) { + props.put("com.sun.java.util.jar.pack.disable.native", "true"); + } + // Call the unpacker + unpacker.unpack(inFile, jarStream); + } + + static byte[] getBuffer(ZipFile zf, ZipEntry ze) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte buf[] = new byte[8192]; + InputStream is = null; + try { + is = zf.getInputStream(ze); + int n = is.read(buf); + while (n > 0) { + baos.write(buf, 0, n); + n = is.read(buf); + } + return baos.toByteArray(); + } finally { + close(is); + } + } + + static ArrayList<String> getZipFileEntryNames(ZipFile z) { + ArrayList<String> out = new ArrayList<String>(); + for (ZipEntry ze : Collections.list(z.entries())) { + out.add(ze.getName()); + } + return out; + } + static List<String> runExec(List<String> cmdsList) { + return runExec(cmdsList, null); + } + static List<String> runExec(List<String> cmdsList, Map<String, String> penv) { + ArrayList<String> alist = new ArrayList<String>(); + ProcessBuilder pb = + new ProcessBuilder(cmdsList); + Map<String, String> env = pb.environment(); + if (penv != null && !penv.isEmpty()) { + env.putAll(penv); + } + pb.directory(new File(".")); + dirlist(new File(".")); + for (String x : cmdsList) { + System.out.print(x + " "); + } + System.out.println(""); + int retval = 0; + Process p = null; + InputStreamReader ir = null; + BufferedReader rd = null; + InputStream is = null; + try { + pb.redirectErrorStream(true); + p = pb.start(); + is = p.getInputStream(); + ir = new InputStreamReader(is); + rd = new BufferedReader(ir, 8192); + + String in = rd.readLine(); + while (in != null) { + alist.add(in); + System.out.println(in); + in = rd.readLine(); + } + retval = p.waitFor(); + if (retval != 0) { + throw new RuntimeException("process failed with non-zero exit"); + } + } catch (Exception ex) { + throw new RuntimeException(ex.getMessage()); + } finally { + close(rd); + close(ir); + close(is); + if (p != null) { + p.destroy(); + } + } + return alist; + } + + static String getUnpack200Cmd() { + return getAjavaCmd("unpack200"); + } + + static String getPack200Cmd() { + return getAjavaCmd("pack200"); + } + + static String getJavaCmd() { + return getAjavaCmd("java"); + } + + static String getAjavaCmd(String cmdStr) { + File binDir = new File(JavaHome, "bin"); + File unpack200File = IsWindows + ? new File(binDir, cmdStr + ".exe") + : new File(binDir, cmdStr); + + String cmd = unpack200File.getAbsolutePath(); + if (!unpack200File.canExecute()) { + throw new RuntimeException("please check" + + cmd + " exists and is executable"); + } + return cmd; + } + + private static List<File> locaterCache = null; + // search the source dir and jdk dir for requested file and returns + // the first location it finds. + static File locateJar(String name) { + try { + if (locaterCache == null) { + locaterCache = new ArrayList<File>(); + locaterCache.addAll(findFiles(TEST_SRC_DIR, createFilter(JAR_FILE_EXT))); + locaterCache.addAll(findFiles(JavaSDK, createFilter(JAR_FILE_EXT))); + } + for (File f : locaterCache) { + if (f.getName().equals(name)) { + return f; + } + } + throw new IOException("file not found: " + name); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/data/README Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,45 @@ +The files contained in the golden.jar have been harvested from many +different sources, some are hand-crafted invalid class files (odds directory), +or from random JDK builds. + +Generally these files serve to ensure the integrity of the packer and unpacker +by, + 1. maximizing the test coverage. + 2. exercising all the Bands in the pack200 specification. + 2. testing the behavior of the packer with invalid classes. + 3. testing the archive integrity, ordering and description (date, sizes, + CRC etc.) + +Build: +To rebuild this JAR follow these steps: + 1. unzip the golden.jar to some directory lets call it "example" + 2. now we can add any directories with files into example. + 2. run the script BUILDME.sh as + % sh BUILDME.sh example + +Note: the BUILDME.sh is known to work on all Unix platforms as well as Windows + using Cygwin. + +The above will create two JAR files in the current directory, +example.jar and example-cls.jar, now the example.jar can be used as the +golden.jar. + +To ensure the JAR has been built correctly use jar -tvf and compare the +results of the old jar and the newly built one, note that the compressed sizes +may differ, however the timestamps etc. should be consistent. + +Test: + Basic: + % pack200 --repack test.jar golden.jar + + Advanced: + Create a pack.conf as follows: + % cat pack.conf + com.sun.java.util.jar.pack.dump.bands=true + + % pack200 --no-gzip --config-file=pack.conf \ + --verbose golden.jar.pack golden.jar + + This command will dump the Bands in a unique directory BD_XXXXXX, + one can inspect the directory to ensure all of the bands are being + generated. Familiarity of the Pack200 specification is suggested. \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/make/build.xml Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,59 @@ +<project name="PackageVerify" default="dist" basedir=".."> + <!-- Requires ant 1.6.1+ and JDK 1.6+--> + + <!-- set global properties for this build --> + <property name="src" value="${basedir}/src"/> + <property name="build" value="${basedir}/build"/> + <property name="dist" value="${basedir}/dist"/> + <property name="make" value="${basedir}/make"/> + <property name="classes" value="${build}/classes"/> + <property name="api" value="${build}/api"/> + + <target name="init"> + <!-- Create the time stamp --> + <tstamp/> + <!-- Create the build directory structure used by compile --> + <mkdir dir="${build}"/> + <mkdir dir="${dist}"/> + <mkdir dir="${classes}"/> + <mkdir dir="${api}"/> + </target> + + <target name="compile" depends="init"> + <!-- Compile the java code from ${src} into ${build} --> + <javac + source="1.6" + srcdir="${src}" + destdir="${build}/classes" + verbose="no" + debug="on" + /> + </target> + + <target name="doc" depends="init, compile"> + <javadoc + source="1.6" + sourcepath="${src}" + destdir="${api}" + /> + </target> + <target name="dist" depends="compile, doc"> + <!-- Put everything in jar file --> + <jar destfile="${dist}/pack200-verifier.jar"> + <manifest> + <attribute name="Main-Class" value="sun.tools.pack.verify.Main"/> + </manifest> + <fileset dir="${classes}"/> + </jar> + <zip destfile="dist/pack200-verifier-doc.zip"> + <fileset dir="${api}"/> + </zip> + </target> + + <target name="clean"> + <!-- Delete the ${build} and ${dist} directory trees --> + <delete dir="${build}"/> + <delete dir="${dist}"/> + </target> + +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 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. + */ +package sun.tools.pack.verify; + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import xmlkit.*; + +public class ClassCompare { + + /* + * @author ksrini + */ + private static XMLKit.Element getXMLelement(InputStream is, + boolean ignoreUnkAttrs, + List<String> ignoreElements) throws IOException { + + ClassReader cr = new ClassReader(); + cr.keepOrder = false; + XMLKit.Element e = cr.readFrom(is); + + if (ignoreElements != null) { + XMLKit.Filter filter = XMLKit.elementFilter(ignoreElements); + e.removeAllInTree(filter); + } + + if (ignoreUnkAttrs == true) { + // This removes any unknown attributes + e.removeAllInTree(XMLKit.elementFilter("Attribute")); + } + return e; + } + + private static String getXMLPrettyString(XMLKit.Element e) throws IOException { + StringWriter out = new StringWriter(); + e.writePrettyTo(out); + return out.toString(); + } + + private static boolean compareClass0(JarFile jf1, JarFile jf2, + JarEntry je, boolean ignoreUnkAttrs, + List<String> ignoreElements) + throws IOException { + + InputStream is1 = jf1.getInputStream(je); + InputStream is2 = jf2.getInputStream(je); + + // First we try to compare the bits if they are the same + boolean bCompare = JarFileCompare.compareStreams(is1, is2); + + // If they are the same there is nothing more to do. + if (bCompare) { + Globals.println("+++" + je.getName() + "+++\t" + + "b/b:PASS"); + return bCompare; + } + is1.close(); + is2.close(); + + is1 = jf1.getInputStream(je); + is2 = jf2.getInputStream(je); + + + XMLKit.Element e1 = getXMLelement(is1, ignoreUnkAttrs, ignoreElements); + XMLKit.Element e2 = getXMLelement(is2, ignoreUnkAttrs, ignoreElements); + + Globals.print("+++" + je.getName() + "+++\t" + + e1.size() + "/" + e1.size() + ":"); + + boolean result = true; + + if (e1.equals(e2)) { + Globals.println("PASS"); + } else { + Globals.println("FAIL"); + Globals.log("Strings differs"); + Globals.log(getXMLPrettyString(e1)); + Globals.log("----------"); + Globals.log(getXMLPrettyString(e2)); + result = false; + } + return result; + } + + /* + * Given two Class Paths could be jars the first being a reference + * will execute a series of comparisons on the classname specified + * The className could be null in which case it will iterate through + * all the classes, otherwise it will compare one class and exit. + */ + public static boolean compareClass(String jar1, String jar2, + String className, boolean ignoreUnkAttrs, + List<String> ignoreElements) + throws IOException { + + Globals.println("Unknown attributes ignored:" + ignoreUnkAttrs); + if (ignoreElements != null) { + Globals.println(ignoreElements.toString()); + } + + JarFile jf1 = new JarFile(jar1); + JarFile jf2 = new JarFile(jar2); + + boolean result = true; + + if (className == null) { + for (JarEntry je1 : Collections.list((Enumeration<JarEntry>) jf1.entries())) { + if (je1.getName().endsWith(".class")) { + JarEntry je2 = jf2.getJarEntry(je1.getName()); + boolean pf = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements); + if (result == true) { + result = pf; + } + } + } + } else { + JarEntry je1 = jf1.getJarEntry(className); + result = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements); + } + if (result == false) { + throw new RuntimeException("Class structural comparison failure"); + } + return result; + } + + public static boolean compareClass(String jar1, String jar2, + String className) throws IOException { + + Stack<String> s = new Stack(); + if (Globals.ignoreDebugAttributes()) { + s = new Stack(); + s.push("LocalVariable"); + s.push("LocalVariableType"); + s.push("LineNumber"); + s.push("SourceFile"); + } + return compareClass(jar1, jar2, className, Globals.ignoreUnknownAttributes(), s); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,310 @@ +/* + * Copyright (c) 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. + */ + +/* + * A collection of useful global utilities commonly used. + */ +package sun.tools.pack.verify; + +import java.io.*; +import java.util.*; + +/* + * @author ksrini + */ + +class Globals { + + private static int errors = 0; + private static PrintWriter _pw = null; + private static String _logFileName = null; + private static final String DEFAULT_LOG_FILE = "verifier.log"; + private static boolean _verbose = true; + private static boolean _ignoreJarDirectories = false; + private static boolean _checkJarClassOrdering = true; + private static boolean _bitWiseClassCompare = false; + // Ignore Deprecated, SourceFile and Synthetic + private static boolean _ignoreCompileAttributes = false; + // Ignore Debug Attributes LocalVariableTable, LocalVariableType,LineNumberTable + private static boolean _ignoreDebugAttributes = false; + private static boolean _ignoreUnknownAttributes = false; + private static boolean _validateClass = true; + private static Globals _instance = null; + + static Globals getInstance() { + if (_instance == null) { + _instance = new Globals(); + _verbose = (System.getProperty("sun.tools.pack.verify.verbose") == null) + ? false : true; + _ignoreJarDirectories = (System.getProperty("ignoreJarDirectories") == null) + ? false : true; + } + return _instance; + } + + static boolean ignoreCompileAttributes() { + return _ignoreCompileAttributes; + } + + static boolean ignoreDebugAttributes() { + return _ignoreDebugAttributes; + } + + static boolean ignoreUnknownAttributes() { + return _ignoreUnknownAttributes; + } + + static boolean ignoreJarDirectories() { + return _ignoreJarDirectories; + } + + static boolean validateClass() { + return _validateClass; + } + + static void setCheckJarClassOrdering(boolean flag) { + _checkJarClassOrdering = flag; + } + + static boolean checkJarClassOrdering() { + return _checkJarClassOrdering; + } + + static boolean bitWiseClassCompare() { + return _bitWiseClassCompare; + } + + static boolean setBitWiseClassCompare(boolean flag) { + return _bitWiseClassCompare = flag; + } + + public static boolean setIgnoreCompileAttributes(boolean flag) { + return _ignoreCompileAttributes = flag; + } + + static boolean setIgnoreDebugAttributes(boolean flag) { + return _ignoreDebugAttributes = flag; + } + + static boolean setIgnoreUnknownAttributes(boolean flag) { + return _ignoreUnknownAttributes = flag; + } + + static boolean setValidateClass(boolean flag) { + return _validateClass = flag; + } + + static int getErrors() { + return errors; + } + + static void trace(String s) { + if (_verbose) { + println(s); + } + } + + static void print(String s) { + _pw.print(s); + } + + static void println(String s) { + _pw.println(s); + } + + static void log(String s) { + errors++; + _pw.println("ERROR:" + s); + } + + static void lognoln(String s) { + errors++; + _pw.print(s); + } + + private static PrintWriter openFile(String fileName) { + //Lets create the directory if it does not exist. + File f = new File(fileName); + File baseDir = f.getParentFile(); + if (baseDir != null && baseDir.exists() == false) { + baseDir.mkdirs(); + } + try { + return new PrintWriter(new FileWriter(f), true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void closeFile() { + _pw.flush(); + _pw.close(); + } + + static void printPropsToLog() { + println("Log started " + new Date(System.currentTimeMillis())); + print(System.getProperty("java.vm.version")); + println("\t" + System.getProperty("java.vm.name")); + + println("System properties"); + println("\tjava.home=" + System.getProperty("java.home")); + println("\tjava.class.version=" + System.getProperty("java.class.version")); + println("\tjava.class.path=" + System.getProperty("java.class.path")); + println("\tjava.ext.dirs=" + System.getProperty("java.ext.dirs")); + println("\tos.name=" + System.getProperty("os.name")); + println("\tos.arch=" + System.getProperty("os.arch")); + println("\tos.version=" + System.getProperty("os.version")); + println("\tuser.name=" + System.getProperty("user.name")); + println("\tuser.home=" + System.getProperty("user.home")); + println("\tuser.dir=" + System.getProperty("user.dir")); + println("\tLocale.getDefault=" + Locale.getDefault()); + println("System properties end"); + } + + static void openLog(String s) { + _logFileName = (s != null) ? s : "." + File.separator + DEFAULT_LOG_FILE; + _logFileName = (new File(_logFileName).isDirectory()) + ? _logFileName + File.separator + DEFAULT_LOG_FILE : _logFileName; + _pw = openFile(_logFileName); + printPropsToLog(); + } + + static void closeLog() { + closeFile(); + } + + static String getLogFileName() { + return _logFileName; + } + + static void diffCharData(String s1, String s2) { + boolean diff = false; + char[] c1 = s1.toCharArray(); + char[] c2 = s2.toCharArray(); + if (c1.length != c2.length) { + diff = true; + Globals.log("Length differs: " + (c1.length - c2.length)); + } + // Take the smaller of the two arrays to prevent Array...Exception + int minlen = (c1.length < c2.length) ? c1.length : c2.length; + for (int i = 0; i < c1.length; i++) { + if (c1[i] != c2[i]) { + diff = true; + Globals.lognoln("\t idx[" + i + "] 0x" + Integer.toHexString(c1[i]) + "<>" + "0x" + Integer.toHexString(c2[i])); + Globals.log(" -> " + c1[i] + "<>" + c2[i]); + } + } + } + + static void diffByteData(String s1, String s2) { + boolean diff = false; + byte[] b1 = s1.getBytes(); + byte[] b2 = s2.getBytes(); + + if (b1.length != b2.length) { + diff = true; + //(+) b1 is greater, (-) b2 is greater + Globals.log("Length differs diff: " + (b1.length - b2.length)); + } + // Take the smaller of the two array to prevent Array...Exception + int minlen = (b1.length < b2.length) ? b1.length : b2.length; + for (int i = 0; i < b1.length; i++) { + if (b1[i] != b2[i]) { + diff = true; + Globals.log("\t" + "idx[" + i + "] 0x" + Integer.toHexString(b1[i]) + "<>" + "0x" + Integer.toHexString(b2[i])); + } + } + } + + static void dumpToHex(String s) { + try { + dumpToHex(s.getBytes("UTF-8")); + } catch (UnsupportedEncodingException uce) { + throw new RuntimeException(uce); + } + } + + static void dumpToHex(byte[] buffer) { + int linecount = 0; + byte[] b = new byte[16]; + for (int i = 0; i < buffer.length; i += 16) { + if (buffer.length - i > 16) { + System.arraycopy(buffer, i, b, 0, 16); + print16Bytes(b, linecount); + linecount += 16; + } else { + System.arraycopy(buffer, i, b, 0, buffer.length - i); + for (int n = buffer.length - (i + 1); n < 16; n++) { + b[n] = 0; + } + print16Bytes(b, linecount); + linecount += 16; + } + } + Globals.log("-----------------------------------------------------------------"); + } + + static void print16Bytes(byte[] buffer, int linecount) { + final int MAX = 4; + Globals.lognoln(paddedHexString(linecount, 4) + " "); + + for (int i = 0; i < buffer.length; i += 2) { + int iOut = pack2Bytes2Int(buffer[i], buffer[i + 1]); + Globals.lognoln(paddedHexString(iOut, 4) + " "); + } + + Globals.lognoln("| "); + + StringBuilder sb = new StringBuilder(new String(buffer)); + + for (int i = 0; i < buffer.length; i++) { + if (Character.isISOControl(sb.charAt(i))) { + sb.setCharAt(i, '.'); + } + } + Globals.log(sb.toString()); + } + + static int pack2Bytes2Int(byte b1, byte b2) { + int out = 0x0; + out += b1; + out <<= 8; + out &= 0x0000ffff; + out |= 0x000000ff & b2; + return out; + } + + static String paddedHexString(int n, int max) { + char[] c = Integer.toHexString(n).toCharArray(); + char[] out = new char[max]; + + for (int i = 0; i < max; i++) { + out[i] = '0'; + } + int offset = (max - c.length < 0) ? 0 : max - c.length; + for (int i = 0; i < c.length; i++) { + out[offset + i] = c[i]; + } + return new String(out); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 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. + */ +package sun.tools.pack.verify; + +import java.io.*; +import java.util.*; +import java.util.jar.*; + +class JarFileCompare { + /* + * @author ksrini + */ + + private static VerifyTreeSet getVerifyTreeSet(String jarPath) { + VerifyTreeSet vts = new VerifyTreeSet(); + try { + JarFile j = new JarFile(jarPath); + for (JarEntry je : Collections.list((Enumeration<JarEntry>) j.entries())) { + if (!je.isDirectory()) { // totally ignore directories + vts.add(je.getName()); + } + } + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + return vts; + } + + private static LinkedList getListOfClasses(String jarPath) { + LinkedList l = new LinkedList(); + try { + JarFile j = new JarFile(jarPath); + for (JarEntry je : Collections.list((Enumeration<JarEntry>) j.entries())) { + if (!je.isDirectory() && je.getName().endsWith(".class")) { + l.add(je.getName()); + } + } + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + return l; + } + + private static void jarDirectoryCompare(String jarPath1, String jarPath2) { + VerifyTreeSet vts1 = getVerifyTreeSet(jarPath1); + VerifyTreeSet vts2 = getVerifyTreeSet(jarPath2); + + TreeSet diff1 = vts1.diff(vts2); + if (diff1.size() > 0) { + Globals.log("Left has the following entries that right does not have"); + Globals.log(diff1.toString()); + } + TreeSet diff2 = vts2.diff(vts1); + if (diff2.size() > 0) { + Globals.log("Right has the following entries that left does not have"); + Globals.log(diff2.toString()); + } + if (Globals.checkJarClassOrdering()) { + boolean error = false; + Globals.println("Checking Class Ordering"); + LinkedList l1 = getListOfClasses(jarPath1); + LinkedList l2 = getListOfClasses(jarPath2); + if (l1.size() != l2.size()) { + error = true; + Globals.log("The number of classes differs"); + Globals.log("\t" + l1.size() + "<>" + l2.size()); + } + for (int i = 0; i < l1.size(); i++) { + String s1 = (String) l1.get(i); + String s2 = (String) l2.get(i); + if (s1.compareTo(s2) != 0) { + error = true; + Globals.log("Ordering differs at[" + i + "] = " + s1); + Globals.log("\t" + s2); + } + } + } + } + + /* + * Returns true if the two Streams are bit identical, and false if they + * are not, no further diagnostics + */ + static boolean compareStreams(InputStream is1, InputStream is2) { + + BufferedInputStream bis1 = new BufferedInputStream(is1, 8192); + BufferedInputStream bis2 = new BufferedInputStream(is2, 8192); + try { + int i1, i2; + int count = 0; + while ((i1 = bis1.read()) == (i2 = bis2.read())) { + count++; + if (i1 < 0) { + // System.out.println("bytes read " + count); + return true; // got all the way to EOF + } + } + return false; // reads returned dif + + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + + private static void checkEntry(JarFile jf1, JarFile jf2, JarEntry je) throws IOException { + InputStream is1 = jf1.getInputStream(je); + InputStream is2 = jf2.getInputStream(je); + if (is1 != null && is2 != null) { + if (!compareStreams(jf1.getInputStream(je), jf2.getInputStream(je))) { + Globals.println("+++" + je.getName() + "+++"); + Globals.log("Error: File:" + je.getName() + + " differs, use a diff util for further diagnostics"); + } + } else { + Globals.println("+++" + je.getName() + "+++"); + Globals.log("Error: File:" + je.getName() + " not found in " + jf2.getName()); + } + } + + /* + * Given two jar files we compare and see if the jarfiles have all the + * entries. The property ignoreJarDirectories is set to true by default + * which means that Directory entries in a jar may be ignore. + */ + static void jarCompare(String jarPath1, String jarPath2) { + jarDirectoryCompare(jarPath1, jarPath2); + + try { + JarFile jf1 = new JarFile(jarPath1); + JarFile jf2 = new JarFile(jarPath2); + + int nclasses = 0; + int nentries = 0; + int entries_checked = 0; + int classes_checked = 0; + + for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf1.entries())) { + if (!je.isDirectory() && !je.getName().endsWith(".class")) { + nentries++; + } else if (je.getName().endsWith(".class")) { + nclasses++; + } + } + + for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf1.entries())) { + if (je.isDirectory()) { + continue; // Ignore directories + } + if (!je.getName().endsWith(".class")) { + entries_checked++; + if (je.getName().compareTo("META-INF/MANIFEST.MF") == 0) { + Manifest mf1 = new Manifest(jf1.getInputStream(je)); + Manifest mf2 = new Manifest(jf2.getInputStream(je)); + if (!mf1.equals(mf2)) { + Globals.log("Error: Manifests differ"); + Globals.log("Manifest1"); + Globals.log(mf1.getMainAttributes().entrySet().toString()); + Globals.log("Manifest2"); + Globals.log(mf2.getMainAttributes().entrySet().toString()); + } + } else { + checkEntry(jf1, jf2, je); + } + } else if (Globals.bitWiseClassCompare() == true) { + checkEntry(jf1, jf2, je); + classes_checked++; + } + } + if (Globals.bitWiseClassCompare()) { + Globals.println("Class entries checked (byte wise)/Total Class entries = " + + classes_checked + "/" + nclasses); + } + Globals.println("Non-class entries checked/Total non-class entries = " + + entries_checked + "/" + nentries); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 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. + */ +// The Main Entry point +package sun.tools.pack.verify; + +import java.io.*; + +/** + * This class provides a convenient entry point to the pack200 verifier. This + * compares two classes, either in path or in an archive. + * @see xmlkit.XMLKit + * @author ksrini + */ +public class Main { + + private static void syntax() { + System.out.println("Usage: "); + System.out.println("\tREFERENCE_CLASSPATH COMPARED_CLASSPATH [Options]"); + System.out.println("\tOptions:"); + System.out.println("\t\t-O check jar ordering"); + System.out.println("\t\t-C ignore compile attributes (Deprecated, SourceFile, Synthetic, )"); + System.out.println("\t\t-D ignore debug attributes (LocalVariable, LineNumber)"); + System.out.println("\t\t-u ignore unknown attributes"); + System.out.println("\t\t-V turn off class validation"); + System.out.println("\t\t-c CLASS, compare CLASS only"); + System.out.println("\t\t-b Compares all entries bitwise only"); + System.out.println("\t\t-l Directory or Log File Name"); + } + + /** + * main entry point to the class file comparator, which compares semantically + * class files in a classpath or an archive. + * @param args String array as described below + * @throws RuntimeException + * <pre> + * Usage: + * ReferenceClasspath SpecimenClaspath [Options] + * Options: + * -O check jar ordering + * -C do not compare compile attributes (Deprecated, SourceFile, Synthetic) + * -D do not compare debug attribute (LocalVariableTable, LineNumberTable) + * -u ignore unknown attributes + * -V turn off class validation + * -c class, compare a single class + * -b compares all entries bitwise (fastest) + * -l directory or log file name + * </pre> + */ + public static void main(String args[]) { + Globals.getInstance(); + if (args == null || args.length < 2) { + syntax(); + System.exit(1); + } + String refJarFileName = null; + String cmpJarFileName = null; + String specificClass = null; + String logDirFileName = null; + + for (int i = 0; i < args.length; i++) { + if (i == 0) { + refJarFileName = args[0]; + continue; + } + if (i == 1) { + cmpJarFileName = args[1]; + continue; + } + + if (args[i].startsWith("-O")) { + Globals.setCheckJarClassOrdering(true); + } + + if (args[i].startsWith("-b")) { + Globals.setBitWiseClassCompare(true); + } + + if (args[i].startsWith("-C")) { + Globals.setIgnoreCompileAttributes(true); + } + + if (args[i].startsWith("-D")) { + Globals.setIgnoreDebugAttributes(true); + } + + if (args[i].startsWith("-V")) { + Globals.setValidateClass(false); + } + + if (args[i].startsWith("-c")) { + i++; + specificClass = args[i].trim(); + } + + if (args[i].startsWith("-u")) { + i++; + Globals.setIgnoreUnknownAttributes(true); + } + + if (args[i].startsWith("-l")) { + i++; + logDirFileName = args[i].trim(); + } + } + + Globals.openLog(logDirFileName); + + File refJarFile = new File(refJarFileName); + File cmpJarFile = new File(cmpJarFileName); + + String f1 = refJarFile.getAbsoluteFile().toString(); + String f2 = cmpJarFile.getAbsoluteFile().toString(); + + System.out.println("LogFile:" + Globals.getLogFileName()); + System.out.println("Reference JAR:" + f1); + System.out.println("Compared JAR:" + f2); + + Globals.println("LogFile:" + Globals.getLogFileName()); + Globals.println("Reference JAR:" + f1); + Globals.println("Compared JAR:" + f2); + + Globals.println("Ignore Compile Attributes:" + Globals.ignoreCompileAttributes()); + Globals.println("Ignore Debug Attributes:" + Globals.ignoreDebugAttributes()); + Globals.println("Ignore Unknown Attributes:" + Globals.ignoreUnknownAttributes()); + Globals.println("Class ordering check:" + Globals.checkJarClassOrdering()); + Globals.println("Class validation check:" + Globals.validateClass()); + Globals.println("Bit-wise compare:" + Globals.bitWiseClassCompare()); + Globals.println("ClassName:" + ((specificClass == null) ? "ALL" : specificClass)); + + if (specificClass == null && Globals.bitWiseClassCompare() == true) { + JarFileCompare.jarCompare(refJarFileName, cmpJarFileName); + } else { + try { + ClassCompare.compareClass(refJarFileName, cmpJarFileName, specificClass); + } catch (Exception e) { + Globals.log("Exception " + e); + throw new RuntimeException(e); + } + } + + if (Globals.getErrors() > 0) { + System.out.println("FAIL"); + Globals.println("FAIL"); + System.exit(Globals.getErrors()); + } + + System.out.println("PASS"); + Globals.println("PASS"); + System.exit(Globals.getErrors()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/VerifyTreeSet.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 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. + */ + +package sun.tools.pack.verify; + +import java.util.*; +/* + * @author ksrini + */ + +class VerifyTreeSet<K> extends java.util.TreeSet { + + VerifyTreeSet() { + super(); + } + + public VerifyTreeSet(Comparator c) { + super(c); + } + + public TreeSet<K> diff(TreeSet in) { + TreeSet<K> delta = (TreeSet<K>) this.clone(); + delta.removeAll(in); + return delta; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,1003 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- + +import java.util.*; +import java.util.jar.*; +import java.lang.reflect.*; +import java.io.*; +import xmlkit.XMLKit.Element; + +/* + * @author jrose + */ +public class ClassReader extends ClassSyntax { + + private static final CommandLineParser CLP = new CommandLineParser("" + + "-source: +> = \n" + + "-dest: +> = \n" + + "-encoding: +> = \n" + + "-jcov $ \n -nojcov !-jcov \n" + + "-verbose $ \n -noverbose !-verbose \n" + + "-pretty $ \n -nopretty !-pretty \n" + + "-keepPath $ \n -nokeepPath !-keepPath \n" + + "-keepCP $ \n -nokeepCP !-keepCP \n" + + "-keepBytes $ \n -nokeepBytes !-keepBytes \n" + + "-parseBytes $ \n -noparseBytes !-parseBytes \n" + + "-resolveRefs $ \n -noresolveRefs !-resolveRefs \n" + + "-keepOrder $ \n -nokeepOrder !-keepOrder \n" + + "-keepSizes $ \n -nokeepSizes !-keepSizes \n" + + "-continue $ \n -nocontinue !-continue \n" + + "-attrDef & \n" + + "-@ >-@ . \n" + + "- +? \n" + + "\n"); + + public static void main(String[] ava) throws IOException { + ArrayList<String> av = new ArrayList<String>(Arrays.asList(ava)); + HashMap<String, String> props = new HashMap<String, String>(); + props.put("-encoding:", "UTF8"); // default + props.put("-keepOrder", null); // CLI default + props.put("-pretty", "1"); // CLI default + props.put("-continue", "1"); // CLI default + CLP.parse(av, props); + //System.out.println(props+" ++ "+av); + File source = asFile(props.get("-source:")); + File dest = asFile(props.get("-dest:")); + String encoding = props.get("-encoding:"); + boolean contError = props.containsKey("-continue"); + ClassReader options = new ClassReader(); + options.copyOptionsFrom(props); + /* + if (dest == null && av.size() > 1) { + dest = File.createTempFile("TestOut", ".dir", new File(".")); + dest.delete(); + if (!dest.mkdir()) + throw new RuntimeException("Cannot create "+dest); + System.out.println("Writing results to "+dest); + } + */ + if (av.isEmpty()) { + av.add("doit"); //to enter this loop + } + boolean readList = false; + for (String a : av) { + if (readList) { + readList = false; + InputStream fin; + if (a.equals("-")) { + fin = System.in; + } else { + fin = new FileInputStream(a); + } + + BufferedReader files = makeReader(fin, encoding); + for (String file; (file = files.readLine()) != null;) { + doFile(file, source, dest, options, encoding, contError); + } + if (fin != System.in) { + fin.close(); + } + } else if (a.equals("-@")) { + readList = true; + } else if (a.startsWith("-")) { + throw new RuntimeException("Bad flag argument: " + a); + } else if (source.getName().endsWith(".jar")) { + doJar(a, source, dest, options, encoding, contError); + } else { + doFile(a, source, dest, options, encoding, contError); + } + } + } + + private static File asFile(String str) { + return (str == null) ? null : new File(str); + } + + private static void doFile(String a, + File source, File dest, + ClassReader options, String encoding, + boolean contError) throws IOException { + if (!contError) { + doFile(a, source, dest, options, encoding); + } else { + try { + doFile(a, source, dest, options, encoding); + } catch (Exception ee) { + System.out.println("Error processing " + source + ": " + ee); + } + } + } + + private static void doJar(String a, File source, File dest, ClassReader options, + String encoding, Boolean contError) throws IOException { + try { + JarFile jf = new JarFile(source); + for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf.entries())) { + String name = je.getName(); + if (!name.endsWith(".class")) { + continue; + } + doStream(name, jf.getInputStream(je), dest, options, encoding); + } + } catch (IOException ioe) { + if (contError) { + System.out.println("Error processing " + source + ": " + ioe); + } else { + throw ioe; + } + } + } + + private static void doStream(String a, InputStream in, File dest, + ClassReader options, String encoding) throws IOException { + + File f = new File(a); + ClassReader cr = new ClassReader(options); + Element e = cr.readFrom(in); + + OutputStream out; + if (dest == null) { + //System.out.println(e.prettyString()); + out = System.out; + } else { + File outf = new File(dest, f.isAbsolute() ? f.getName() : f.getPath()); + String outName = outf.getName(); + File outSubdir = outf.getParentFile(); + outSubdir.mkdirs(); + int extPos = outName.lastIndexOf('.'); + if (extPos > 0) { + outf = new File(outSubdir, outName.substring(0, extPos) + ".xml"); + } + out = new FileOutputStream(outf); + } + + Writer outw = makeWriter(out, encoding); + if (options.pretty || !options.keepOrder) { + e.writePrettyTo(outw); + } else { + e.writeTo(outw); + } + if (out == System.out) { + outw.write("\n"); + outw.flush(); + } else { + outw.close(); + } + } + + private static void doFile(String a, + File source, File dest, + ClassReader options, String encoding) throws IOException { + File inf = new File(source, a); + if (dest != null && options.verbose) { + System.out.println("Reading " + inf); + } + + BufferedInputStream in = new BufferedInputStream(new FileInputStream(inf)); + + doStream(a, in, dest, options, encoding); + + } + + public static BufferedReader makeReader(InputStream in, String encoding) throws IOException { + // encoding in DEFAULT, '', UTF8, 8BIT, , or any valid encoding name + if (encoding.equals("8BIT")) { + encoding = EIGHT_BIT_CHAR_ENCODING; + } + if (encoding.equals("UTF8")) { + encoding = UTF8_ENCODING; + } + if (encoding.equals("DEFAULT")) { + encoding = null; + } + if (encoding.equals("-")) { + encoding = null; + } + Reader inw; + in = new BufferedInputStream(in); // add buffering + if (encoding == null) { + inw = new InputStreamReader(in); + } else { + inw = new InputStreamReader(in, encoding); + } + return new BufferedReader(inw); // add buffering + } + + public static Writer makeWriter(OutputStream out, String encoding) throws IOException { + // encoding in DEFAULT, '', UTF8, 8BIT, , or any valid encoding name + if (encoding.equals("8BIT")) { + encoding = EIGHT_BIT_CHAR_ENCODING; + } + if (encoding.equals("UTF8")) { + encoding = UTF8_ENCODING; + } + if (encoding.equals("DEFAULT")) { + encoding = null; + } + if (encoding.equals("-")) { + encoding = null; + } + Writer outw; + if (encoding == null) { + outw = new OutputStreamWriter(out); + } else { + outw = new OutputStreamWriter(out, encoding); + } + return new BufferedWriter(outw); // add buffering + } + + public Element result() { + return cfile; + } + protected InputStream in; + protected ByteArrayOutputStream buf = new ByteArrayOutputStream(1024); + protected byte cpTag[]; + protected String cpName[]; + protected String[] callables; // varies + public static final String REF_PREFIX = "#"; + // input options + public boolean pretty = false; + public boolean verbose = false; + public boolean keepPath = false; + public boolean keepCP = false; + public boolean keepBytes = false; + public boolean parseBytes = true; + public boolean resolveRefs = true; + public boolean keepOrder = true; + public boolean keepSizes = false; + + public ClassReader() { + super.cfile = new Element("ClassFile"); + } + + public ClassReader(ClassReader options) { + this(); + copyOptionsFrom(options); + } + + public void copyOptionsFrom(ClassReader options) { + pretty = options.pretty; + verbose = options.verbose; + keepPath = options.keepPath; + keepCP = options.keepCP; + keepBytes = options.keepBytes; + parseBytes = options.parseBytes; + resolveRefs = options.resolveRefs; + keepSizes = options.keepSizes; + keepOrder = options.keepOrder; + attrTypes = options.attrTypes; + } + + public void copyOptionsFrom(Map<String, String> options) { + if (options.containsKey("-pretty")) { + pretty = (options.get("-pretty") != null); + } + if (options.containsKey("-verbose")) { + verbose = (options.get("-verbose") != null); + } + if (options.containsKey("-keepPath")) { + keepPath = (options.get("-keepPath") != null); + } + if (options.containsKey("-keepCP")) { + keepCP = (options.get("-keepCP") != null); + } + if (options.containsKey("-keepBytes")) { + keepBytes = (options.get("-keepBytes") != null); + } + if (options.containsKey("-parseBytes")) { + parseBytes = (options.get("-parseBytes") != null); + } + if (options.containsKey("-resolveRefs")) { + resolveRefs = (options.get("-resolveRefs") != null); + } + if (options.containsKey("-keepSizes")) { + keepSizes = (options.get("-keepSizes") != null); + } + if (options.containsKey("-keepOrder")) { + keepOrder = (options.get("-keepOrder") != null); + } + if (options.containsKey("-attrDef")) { + addAttrTypes(options.get("-attrDef").split(" ")); + } + if (options.get("-jcov") != null) { + addJcovAttrTypes(); + } + } + + public Element readFrom(InputStream in) throws IOException { + this.in = in; + // read the file header + int magic = u4(); + if (magic != 0xCAFEBABE) { + throw new RuntimeException("bad magic number " + Integer.toHexString(magic)); + } + cfile.setAttr("magic", "" + magic); + int minver = u2(); + int majver = u2(); + cfile.setAttr("minver", "" + minver); + cfile.setAttr("majver", "" + majver); + readCP(); + readClass(); + return result(); + } + + public Element readFrom(File file) throws IOException { + InputStream in = null; + try { + in = new FileInputStream(file); + Element e = readFrom(new BufferedInputStream(in)); + if (keepPath) { + e.setAttr("path", file.toString()); + } + return e; + } finally { + if (in != null) { + in.close(); + } + } + } + + private void readClass() throws IOException { + klass = new Element("Class"); + cfile.add(klass); + int flags = u2(); + String thisk = cpRef(); + String superk = cpRef(); + klass.setAttr("name", thisk); + boolean flagsSync = ((flags & Modifier.SYNCHRONIZED) != 0); + flags &= ~Modifier.SYNCHRONIZED; + String flagString = flagString(flags, klass); + if (!flagsSync) { + if (flagString.length() > 0) { + flagString += " "; + } + flagString += "!synchronized"; + } + klass.setAttr("flags", flagString); + klass.setAttr("super", superk); + for (int len = u2(), i = 0; i < len; i++) { + String interk = cpRef(); + klass.add(new Element("Interface", "name", interk)); + } + Element fields = readMembers("Field"); + klass.addAll(fields); + Element methods = readMembers("Method"); + if (!keepOrder) { + methods.sort(); + } + klass.addAll(methods); + readAttributesFor(klass); + klass.trimToSize(); + if (keepSizes) { + attachTo(cfile, formatAttrSizes()); + } + if (paddingSize != 0) { + cfile.setAttr("padding", "" + paddingSize); + } + } + + private Element readMembers(String kind) throws IOException { + int len = u2(); + Element members = new Element(len); + for (int i = 0; i < len; i++) { + Element member = new Element(kind); + int flags = u2(); + String name = cpRef(); + String type = cpRef(); + member.setAttr("name", name); + member.setAttr("type", type); + member.setAttr("flags", flagString(flags, member)); + readAttributesFor(member); + member.trimToSize(); + members.add(member); + } + return members; + } + + protected String flagString(int flags, Element holder) { + // Superset of Modifier.toString. + int kind = 0; + if (holder.getName() == "Field") { + kind = 1; + } + if (holder.getName() == "Method") { + kind = 2; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0; flags != 0; i++, flags >>>= 1) { + if ((flags & 1) != 0) { + if (sb.length() > 0) { + sb.append(' '); + } + if (i < modifierNames.length) { + String[] names = modifierNames[i]; + String name = (kind < names.length) ? names[kind] : null; + for (String name2 : names) { + if (name != null) { + break; + } + name = name2; + } + sb.append(name); + } else { + sb.append("#").append(1 << i); + } + } + } + return sb.toString(); + } + + private void readAttributesFor(Element x) throws IOException { + Element prevCurrent; + Element y = new Element(); + if (x.getName() == "Code") { + prevCurrent = currentCode; + currentCode = x; + } else { + prevCurrent = currentMember; + currentMember = x; + } + for (int len = u2(), i = 0; i < len; i++) { + int ref = u2(); + String uname = cpName(ref).intern(); + String refName = uname; + if (!resolveRefs) { + refName = (REF_PREFIX + ref).intern(); + } + String qname = (x.getName() + "." + uname).intern(); + String wname = ("*." + uname).intern(); + String type = attrTypes.get(qname); + if (type == null || "".equals(type)) { + type = attrTypes.get(wname); + } + if ("".equals(type)) { + type = null; + } + int size = u4(); + int[] countVar = attrSizes.get(qname); + if (countVar == null) { + attrSizes.put(qname, countVar = new int[2]); + } + countVar[0] += 1; + countVar[1] += size; + buf.reset(); + for (int j = 0; j < size; j++) { + buf.write(u1()); + } + if (type == null && size == 0) { + y.add(new Element(uname)); // <Bridge>, etc. + } else if (type == null) { + //System.out.println("Warning: No attribute type description: "+qname); + // write cdata attribute + Element a = new Element("Attribute", + new String[]{"Name", refName}, + buf.toString(EIGHT_BIT_CHAR_ENCODING)); + a.addContent(getCPDigest()); + y.add(a); + } else if (type.equals("")) { + // ignore this attribute... + } else { + InputStream in0 = in; + int fileSize0 = fileSize; + ByteArrayInputStream in1 = new ByteArrayInputStream(buf.toByteArray()); + boolean ok = false; + try { + in = in1; + // parse according to type desc. + Element aval; + if (type.equals("<Code>...")) { + // delve into Code attribute + aval = readCode(); + } else if (type.equals("<Frame>...")) { + // delve into StackMap attribute + aval = readStackMap(false); + } else if (type.equals("<FrameX>...")) { + // delve into StackMap attribute + aval = readStackMap(true); + } else if (type.startsWith("[")) { + aval = readAttributeCallables(type); + } else { + aval = readAttribute(type); + } + //System.out.println("attachTo 1 "+y+" <- "+aval); + attachTo(y, aval); + if (false + && in1.available() != 0) { + throw new RuntimeException("extra bytes in " + qname + " :" + in1.available()); + } + ok = true; + } finally { + in = in0; + fileSize = fileSize0; + if (!ok) { + System.out.println("*** Failed to read " + type); + } + } + } + } + if (x.getName() == "Code") { + currentCode = prevCurrent; + } else { + currentMember = prevCurrent; + } + if (!keepOrder) { + y.sort(); + y.sortAttrs(); + } + //System.out.println("attachTo 2 "+x+" <- "+y); + attachTo(x, y); + } + private int fileSize = 0; + private int paddingSize = 0; + private HashMap<String, int[]> attrSizes = new HashMap<String, int[]>(); + + private Element formatAttrSizes() { + Element e = new Element("Sizes"); + e.setAttr("fileSize", "" + fileSize); + for (Map.Entry<String, int[]> ie : attrSizes.entrySet()) { + int[] countVar = ie.getValue(); + e.add(new Element("AttrSize", + "name", ie.getKey().toString(), + "count", "" + countVar[0], + "size", "" + countVar[1])); + } + return e; + } + + private void attachTo(Element x, Object aval0) { + if (aval0 == null) { + return; + } + //System.out.println("attachTo "+x+" : "+aval0); + if (!(aval0 instanceof Element)) { + x.add(aval0); + return; + } + Element aval = (Element) aval0; + if (!aval.isAnonymous()) { + x.add(aval); + return; + } + for (int imax = aval.attrSize(), i = 0; i < imax; i++) { + //%% + attachAttrTo(x, aval.getAttrName(i), aval.getAttr(i)); + } + x.addAll(aval); + } + + private void attachAttrTo(Element x, String aname, String aval) { + //System.out.println("attachAttrTo "+x+" : "+aname+"="+aval); + String aval0 = x.getAttr(aname); + if (aval0 != null) { + aval = aval0 + " " + aval; + } + x.setAttr(aname, aval); + } + + private Element readAttributeCallables(String type) throws IOException { + assert (callables == null); + callables = getBodies(type); + Element res = readAttribute(callables[0]); + callables = null; + return res; + } + + private Element readAttribute(String type) throws IOException { + //System.out.println("readAttribute "+type); + Element aval = new Element(); + String nextAttrName = null; + for (int len = type.length(), next, i = 0; i < len; i = next) { + String value; + switch (type.charAt(i)) { + case '<': + assert (nextAttrName == null); + next = type.indexOf('>', ++i); + String form = type.substring(i, next++); + if (form.indexOf('=') < 0) { + // elem_placement = '<' elemname '>' + assert (aval.attrSize() == 0); + assert (aval.isAnonymous()); + aval.setName(form.intern()); + } else { + // attr_placement = '<' attrname '=' (value)? '>' + int eqPos = form.indexOf('='); + nextAttrName = form.substring(0, eqPos).intern(); + if (eqPos != form.length() - 1) { + value = form.substring(eqPos + 1); + attachAttrTo(aval, nextAttrName, value); + nextAttrName = null; + } + // ...else subsequent type parsing will find the attr value + // and add it as "nextAttrName". + } + continue; + case '(': + next = type.indexOf(')', ++i); + int callee = Integer.parseInt(type.substring(i, next++)); + attachTo(aval, readAttribute(callables[callee])); + continue; + case 'N': // replication = 'N' int '[' type ... ']' + { + int count = getInt(type.charAt(i + 1), false); + assert (count >= 0); + next = i + 2; + String type1 = getBody(type, next); + next += type1.length() + 2; // skip body and brackets + for (int j = 0; j < count; j++) { + attachTo(aval, readAttribute(type1)); + } + } + continue; + case 'T': // union = 'T' any_int union_case* '(' ')' '[' body ']' + int tagValue; + if (type.charAt(++i) == 'S') { + tagValue = getInt(type.charAt(++i), true); + } else { + tagValue = getInt(type.charAt(i), false); + } + attachAttrTo(aval, "tag", "" + tagValue); // always named "tag" + ++i; // skip the int type char + // union_case = '(' uc_tag (',' uc_tag)* ')' '[' body ']' + // uc_tag = ('-')? digit+ + for (boolean foundCase = false;; i = next) { + assert (type.charAt(i) == '('); + next = type.indexOf(')', ++i); + assert (next >= i); + if (type.charAt(next - 1) == '\\' + && type.charAt(next - 2) != '\\') // Skip an escaped paren. + { + next = type.indexOf(')', next + 1); + } + String caseStr = type.substring(i, next++); + String type1 = getBody(type, next); + next += type1.length() + 2; // skip body and brackets + boolean lastCase = (caseStr.length() == 0); + if (!foundCase + && (lastCase || matchTag(tagValue, caseStr))) { + foundCase = true; + // Execute this body. + attachTo(aval, readAttribute(type1)); + } + if (lastCase) { + break; + } + } + continue; + case 'B': + case 'H': + case 'I': // int = oneof "BHI" + next = i + 1; + value = "" + getInt(type.charAt(i), false); + break; + case 'K': + assert ("IJFDLQ".indexOf(type.charAt(i + 1)) >= 0); + assert (type.charAt(i + 2) == 'H'); // only H works for now + next = i + 3; + value = cpRef(); + break; + case 'R': + assert ("CSDFMIU?".indexOf(type.charAt(i + 1)) >= 0); + assert (type.charAt(i + 2) == 'H'); // only H works for now + next = i + 3; + value = cpRef(); + break; + case 'P': // bci = 'P' int + next = i + 2; + value = "" + getInt(type.charAt(i + 1), false); + break; + case 'S': // signed_int = 'S' int + next = i + 2; + value = "" + getInt(type.charAt(i + 1), true); + break; + case 'F': + next = i + 2; + value = flagString(getInt(type.charAt(i + 1), false), currentMember); + break; + default: + throw new RuntimeException("bad attr format '" + type.charAt(i) + "': " + type); + } + // store the value + if (nextAttrName != null) { + attachAttrTo(aval, nextAttrName, value); + nextAttrName = null; + } else { + attachTo(aval, value); + } + } + //System.out.println("readAttribute => "+aval); + assert (nextAttrName == null); + return aval; + } + + private int getInt(char ch, boolean signed) throws IOException { + if (signed) { + switch (ch) { + case 'B': + return (byte) u1(); + case 'H': + return (short) u2(); + case 'I': + return (int) u4(); + } + } else { + switch (ch) { + case 'B': + return u1(); + case 'H': + return u2(); + case 'I': + return u4(); + } + } + assert ("BHIJ".indexOf(ch) >= 0); + return 0; + } + + private Element readCode() throws IOException { + int stack = u2(); + int local = u2(); + int length = u4(); + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; i++) { + sb.append((char) u1()); + } + String bytecodes = sb.toString(); + Element e = new Element("Code", + "stack", "" + stack, + "local", "" + local); + Element bytes = new Element("Bytes", (String[]) null, bytecodes); + if (keepBytes) { + e.add(bytes); + } + if (parseBytes) { + e.add(parseByteCodes(bytecodes)); + } + for (int len = u2(), i = 0; i < len; i++) { + int start = u2(); + int end = u2(); + int catsh = u2(); + String clasz = cpRef(); + e.add(new Element("Handler", + "start", "" + start, + "end", "" + end, + "catch", "" + catsh, + "class", clasz)); + } + readAttributesFor(e); + e.trimToSize(); + return e; + } + + private Element parseByteCodes(String bytecodes) { + Element e = InstructionSyntax.parse(bytecodes); + for (Element ins : e.elements()) { + Number ref = ins.getAttrNumber("ref"); + if (ref != null && resolveRefs) { + int id = ref.intValue(); + String val = cpName(id); + if (ins.getName().startsWith("ldc")) { + // Yuck: Arb. string cannot be an XML attribute. + ins.add(val); + val = ""; + byte tag = (id >= 0 && id < cpTag.length) ? cpTag[id] : 0; + if (tag != 0) { + ins.setAttrLong("tag", tag); + } + } + if (ins.getName() == "invokeinterface" + && computeInterfaceNum(val) == ins.getAttrLong("num")) { + ins.setAttr("num", null); // garbage bytes + } + ins.setAttr("ref", null); + ins.setAttr("val", val); + } + } + return e; + } + + private Element readStackMap(boolean hasXOption) throws IOException { + Element result = new Element(); + Element bytes = currentCode.findElement("Bytes"); + assert (bytes != null && bytes.size() == 1); + int byteLength = ((String) bytes.get(0)).length(); + boolean uoffsetIsU4 = (byteLength >= (1 << 16)); + boolean ulocalvarIsU4 = currentCode.getAttrLong("local") >= (1 << 16); + boolean ustackIsU4 = currentCode.getAttrLong("stack") >= (1 << 16); + if (hasXOption || uoffsetIsU4 || ulocalvarIsU4 || ustackIsU4) { + Element flags = new Element("StackMapFlags"); + if (hasXOption) { + flags.setAttr("hasXOption", "true"); + } + if (uoffsetIsU4) { + flags.setAttr("uoffsetIsU4", "true"); + } + if (ulocalvarIsU4) { + flags.setAttr("ulocalvarIsU4", "true"); + } + if (ustackIsU4) { + flags.setAttr("ustackIsU4", "true"); + } + currentCode.add(flags); + } + int frame_count = (uoffsetIsU4 ? u4() : u2()); + for (int i = 0; i < frame_count; i++) { + int bci = (uoffsetIsU4 ? u4() : u2()); + int flags = (hasXOption ? u1() : 0); + Element frame = new Element("Frame"); + result.add(frame); + if (flags != 0) { + frame.setAttr("flags", "" + flags); + } + frame.setAttr("bci", "" + bci); + // Scan local and stack types in this frame: + final int LOCALS = 0, STACK = 1; + for (int j = LOCALS; j <= STACK; j++) { + int typeSize; + if (j == LOCALS) { + typeSize = (ulocalvarIsU4 ? u4() : u2()); + } else { // STACK + typeSize = (ustackIsU4 ? u4() : u2()); + } + Element types = new Element(j == LOCALS ? "Local" : "Stack"); + for (int k = 0; k < typeSize; k++) { + int tag = u1(); + Element type = new Element(itemTagName(tag)); + types.add(type); + switch (tag) { + case ITEM_Object: + type.setAttr("class", cpRef()); + break; + case ITEM_Uninitialized: + case ITEM_ReturnAddress: + type.setAttr("bci", "" + (uoffsetIsU4 ? u4() : u2())); + break; + } + } + if (types.size() > 0) { + frame.add(types); + } + } + } + return result; + } + + private void readCP() throws IOException { + int cpLen = u2(); + cpTag = new byte[cpLen]; + cpName = new String[cpLen]; + int cpTem[][] = new int[cpLen][]; + for (int i = 1; i < cpLen; i++) { + cpTag[i] = (byte) u1(); + switch (cpTag[i]) { + case CONSTANT_Utf8: + buf.reset(); + for (int len = u2(), j = 0; j < len; j++) { + buf.write(u1()); + } + cpName[i] = buf.toString(UTF8_ENCODING); + break; + case CONSTANT_Integer: + cpName[i] = String.valueOf((int) u4()); + break; + case CONSTANT_Float: + cpName[i] = String.valueOf(Float.intBitsToFloat(u4())); + break; + case CONSTANT_Long: + cpName[i] = String.valueOf(u8()); + i += 1; + break; + case CONSTANT_Double: + cpName[i] = String.valueOf(Double.longBitsToDouble(u8())); + i += 1; + break; + case CONSTANT_Class: + case CONSTANT_String: + cpTem[i] = new int[]{u2()}; + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_NameAndType: + cpTem[i] = new int[]{u2(), u2()}; + break; + } + } + for (int i = 1; i < cpLen; i++) { + switch (cpTag[i]) { + case CONSTANT_Class: + case CONSTANT_String: + cpName[i] = cpName[cpTem[i][0]]; + break; + case CONSTANT_NameAndType: + cpName[i] = cpName[cpTem[i][0]] + " " + cpName[cpTem[i][1]]; + break; + } + } + // do fieldref et al after nameandtype are all resolved + for (int i = 1; i < cpLen; i++) { + switch (cpTag[i]) { + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + cpName[i] = cpName[cpTem[i][0]] + " " + cpName[cpTem[i][1]]; + break; + } + } + cpool = new Element("ConstantPool", cpName.length); + for (int i = 0; i < cpName.length; i++) { + if (cpName[i] == null) { + continue; + } + cpool.add(new Element(cpTagName(cpTag[i]), + new String[]{"id", "" + i}, + cpName[i])); + } + if (keepCP) { + cfile.add(cpool); + } + } + + private String cpRef() throws IOException { + int ref = u2(); + if (resolveRefs) { + return cpName(ref); + } else { + return REF_PREFIX + ref; + } + } + + private String cpName(int id) { + if (id >= 0 && id < cpName.length) { + return cpName[id]; + } else { + return "[CP#" + Integer.toHexString(id) + "]"; + } + } + + private long u8() throws IOException { + return ((long) u4() << 32) + (((long) u4() << 32) >>> 32); + } + + private int u4() throws IOException { + return (u2() << 16) + u2(); + } + + private int u2() throws IOException { + return (u1() << 8) + u1(); + } + + private int u1() throws IOException { + int x = in.read(); + if (x < 0) { + paddingSize++; + return 0; // error recovery + } + fileSize++; + assert (x == (x & 0xFF)); + return x; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,518 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- +import xmlkit.XMLKit.*; + +import java.util.*; +import java.security.MessageDigest; +import java.nio.ByteBuffer; +import xmlkit.XMLKit.Element; +/* + * @author jrose + */ +public abstract class ClassSyntax { + + public interface GetCPIndex { + + int getCPIndex(int tag, String name); // cp finder + } + public static final int CONSTANT_Utf8 = 1, + CONSTANT_Integer = 3, + CONSTANT_Float = 4, + CONSTANT_Long = 5, + CONSTANT_Double = 6, + CONSTANT_Class = 7, + CONSTANT_String = 8, + CONSTANT_Fieldref = 9, + CONSTANT_Methodref = 10, + CONSTANT_InterfaceMethodref = 11, + CONSTANT_NameAndType = 12; + private static final String[] cpTagName = { + /* 0: */null, + /* 1: */ "Utf8", + /* 2: */ null, + /* 3: */ "Integer", + /* 4: */ "Float", + /* 5: */ "Long", + /* 6: */ "Double", + /* 7: */ "Class", + /* 8: */ "String", + /* 9: */ "Fieldref", + /* 10: */ "Methodref", + /* 11: */ "InterfaceMethodref", + /* 12: */ "NameAndType", + null + }; + private static final Set<String> cpTagNames; + + static { + Set<String> set = new HashSet<String>(Arrays.asList(cpTagName)); + set.remove(null); + cpTagNames = Collections.unmodifiableSet(set); + } + public static final int ITEM_Top = 0, // replicates by [1..4,1..4] + ITEM_Integer = 1, // (ditto) + ITEM_Float = 2, + ITEM_Double = 3, + ITEM_Long = 4, + ITEM_Null = 5, + ITEM_UninitializedThis = 6, + ITEM_Object = 7, + ITEM_Uninitialized = 8, + ITEM_ReturnAddress = 9, + ITEM_LIMIT = 10; + private static final String[] itemTagName = { + "Top", + "Integer", + "Float", + "Double", + "Long", + "Null", + "UninitializedThis", + "Object", + "Uninitialized", + "ReturnAddress",}; + private static final Set<String> itemTagNames; + + static { + Set<String> set = new HashSet<String>(Arrays.asList(itemTagName)); + set.remove(null); + itemTagNames = Collections.unmodifiableSet(set); + } + protected static final HashMap<String, String> attrTypesBacking; + protected static final Map<String, String> attrTypesInit; + + static { + HashMap<String, String> at = new HashMap<String, String>(); + + //at.put("*.Deprecated", "<deprecated=true>"); + //at.put("*.Synthetic", "<synthetic=true>"); + ////at.put("Field.ConstantValue", "<constantValue=>KQH"); + //at.put("Class.SourceFile", "<sourceFile=>RUH"); + at.put("Method.Bridge", "<Bridge>"); + at.put("Method.Varargs", "<Varargs>"); + at.put("Class.Enum", "<Enum>"); + at.put("*.Signature", "<Signature>RSH"); + //at.put("*.Deprecated", "<Deprecated>"); + //at.put("*.Synthetic", "<Synthetic>"); + at.put("Field.ConstantValue", "<ConstantValue>KQH"); + at.put("Class.SourceFile", "<SourceFile>RUH"); + at.put("Class.InnerClasses", "NH[<InnerClass><class=>RCH<outer=>RCH<name=>RUH<flags=>FH]"); + at.put("Code.LineNumberTable", "NH[<LineNumber><bci=>PH<line=>H]"); + at.put("Code.LocalVariableTable", "NH[<LocalVariable><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]"); + at.put("Code.LocalVariableTypeTable", "NH[<LocalVariableType><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]"); + at.put("Method.Exceptions", "NH[<Exception><name=>RCH]"); + at.put("Method.Code", "<Code>..."); + at.put("Code.StackMapTable", "<Frame>..."); + //at.put("Code.StkMapX", "<FrameX>..."); + if (true) { + at.put("Code.StackMapTable", + "[NH[<Frame>(1)]]" + + "[TB" + + "(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79" + + ",80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95" + + ",96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111" + + ",112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127" + + ")[<SameLocals1StackItemFrame>(4)]" + + "(247)[<SameLocals1StackItemExtended>H(4)]" + + "(248)[<Chop3>H]" + + "(249)[<Chop2>H]" + + "(250)[<Chop1>H]" + + "(251)[<SameFrameExtended>H]" + + "(252)[<Append1>H(4)]" + + "(253)[<Append2>H(4)(4)]" + + "(254)[<Append3>H(4)(4)(4)]" + + "(255)[<FullFrame>H(2)(3)]" + + "()[<SameFrame>]]" + + "[NH[<Local>(4)]]" + + "[NH[<Stack>(4)]]" + + "[TB" + + ("(0)[<Top>]" + + "(1)[<ItemInteger>](2)[<ItemFloat>](3)[<ItemDouble>](4)[<ItemLong>]" + + "(5)[<ItemNull>](6)[<ItemUninitializedThis>]" + + "(7)[<ItemObject><class=>RCH]" + + "(8)[<ItemUninitialized><bci=>PH]" + + "()[<ItemUnknown>]]")); + } + + at.put("Class.EnclosingMethod", "<EnclosingMethod><class=>RCH<desc=>RDH");//RDNH + + // Layouts of metadata attrs: + String vpf = "[<RuntimeVisibleAnnotation>"; + String ipf = "[<RuntimeInvisibleAnnotation>"; + String apf = "[<Annotation>"; + String mdanno2 = "" + + "<type=>RSHNH[<Member><name=>RUH(3)]]" + + ("[TB" + + "(\\B,\\C,\\I,\\S,\\Z)[<value=>KIH]" + + "(\\D)[<value=>KDH]" + + "(\\F)[<value=>KFH]" + + "(\\J)[<value=>KJH]" + + "(\\c)[<class=>RSH]" + + "(\\e)[<type=>RSH<name=>RUH]" + + "(\\s)[<String>RUH]" + + "(\\@)[(2)]" + + "(\\[)[NH[<Element>(3)]]" + + "()[]" + + "]"); + String visanno = "[NH[(2)]][(1)]" + vpf + mdanno2; + String invanno = "[NH[(2)]][(1)]" + ipf + mdanno2; + String vparamanno = "" + + "[NB[<RuntimeVisibleParameterAnnotation>(1)]][NH[(2)]]" + + apf + mdanno2; + String iparamanno = "" + + "[NB[<RuntimeInvisibleParameterAnnotation>(1)]][NH[(2)]]" + + apf + mdanno2; + String mdannodef = "[<AnnotationDefault>(3)][(1)]" + apf + mdanno2; + String[] mdplaces = {"Class", "Field", "Method"}; + for (String place : mdplaces) { + at.put(place + ".RuntimeVisibleAnnotations", visanno); + at.put(place + ".RuntimeInvisibleAnnotations", invanno); + } + at.put("Method.RuntimeVisibleParameterAnnotations", vparamanno); + at.put("Method.RuntimeInvisibleParameterAnnotations", iparamanno); + at.put("Method.AnnotationDefault", mdannodef); + + attrTypesBacking = at; + attrTypesInit = Collections.unmodifiableMap(at); + } + + ; + private static final String[] jcovAttrTypes = { + "Code.CoverageTable=NH[<Coverage><bci=>PH<type=>H<line=>I<pos=>I]", + "Code.CharacterRangeTable=NH[<CharacterRange><bci=>PH<endbci=>POH<from=>I<to=>I<flag=>H]", + "Class.SourceID=<SourceID><id=>RUH", + "Class.CompilationID=<CompilationID><id=>RUH" + }; + protected static final String[][] modifierNames = { + {"public"}, + {"private"}, + {"protected"}, + {"static"}, + {"final"}, + {"synchronized"}, + {null, "volatile", "bridge"}, + {null, "transient", "varargs"}, + {null, null, "native"}, + {"interface"}, + {"abstract"}, + {"strictfp"}, + {"synthetic"}, + {"annotation"}, + {"enum"},}; + protected static final String EIGHT_BIT_CHAR_ENCODING = "ISO8859_1"; + protected static final String UTF8_ENCODING = "UTF8"; + // What XML tags are used by this syntax, apart from attributes? + protected static final Set<String> nonAttrTags; + + static { + HashSet<String> tagSet = new HashSet<String>(); + Collections.addAll(tagSet, new String[]{ + "ConstantPool",// the CP + "Class", // the class + "Interface", // implemented interfaces + "Method", // methods + "Field", // fields + "Handler", // exception handler pseudo-attribute + "Attribute", // unparsed attribute + "Bytes", // bytecodes + "Instructions" // bytecodes, parsed + }); + nonAttrTags = Collections.unmodifiableSet(tagSet); + } + + // Accessors. + public static Set<String> nonAttrTags() { + return nonAttrTags; + } + + public static String cpTagName(int t) { + t &= 0xFF; + String ts = null; + if (t < cpTagName.length) { + ts = cpTagName[t]; + } + if (ts != null) { + return ts; + } + return ("UnknownTag" + (int) t).intern(); + } + + public static int cpTagValue(String name) { + for (int t = 0; t < cpTagName.length; t++) { + if (name.equals(cpTagName[t])) { + return t; + } + } + return 0; + } + + public static String itemTagName(int t) { + t &= 0xFF; + String ts = null; + if (t < itemTagName.length) { + ts = itemTagName[t]; + } + if (ts != null) { + return ts; + } + return ("UnknownItem" + (int) t).intern(); + } + + public static int itemTagValue(String name) { + for (int t = 0; t < itemTagName.length; t++) { + if (name.equals(itemTagName[t])) { + return t; + } + } + return -1; + } + + public void addJcovAttrTypes() { + addAttrTypes(jcovAttrTypes); + } + // Public methods for declaring attribute types. + protected Map<String, String> attrTypes = attrTypesInit; + + public void addAttrType(String opt) { + int eqpos = opt.indexOf('='); + addAttrType(opt.substring(0, eqpos), opt.substring(eqpos + 1)); + } + + public void addAttrTypes(String[] opts) { + for (String opt : opts) { + addAttrType(opt); + } + } + + private void checkAttr(String attr) { + if (!attr.startsWith("Class.") + && !attr.startsWith("Field.") + && !attr.startsWith("Method.") + && !attr.startsWith("Code.") + && !attr.startsWith("*.")) { + throw new IllegalArgumentException("attr name must start with 'Class.', etc."); + } + String uattr = attr.substring(attr.indexOf('.') + 1); + if (nonAttrTags.contains(uattr)) { + throw new IllegalArgumentException("attr name must not be one of " + nonAttrTags); + } + } + + private void checkAttrs(Map<String, String> at) { + for (String attr : at.keySet()) { + checkAttr(attr); + } + } + + private void modAttrs() { + if (attrTypes == attrTypesInit) { + // Make modifiable. + attrTypes = new HashMap<String, String>(attrTypesBacking); + } + } + + public void addAttrType(String attr, String fmt) { + checkAttr(attr); + modAttrs(); + attrTypes.put(attr, fmt); + } + + public void addAttrTypes(Map<String, String> at) { + checkAttrs(at); + modAttrs(); + attrTypes.putAll(at); + } + + public Map<String, String> getAttrTypes() { + if (attrTypes == attrTypesInit) { + return attrTypes; + } + return Collections.unmodifiableMap(attrTypes); + } + + public void setAttrTypes(Map<String, String> at) { + checkAttrs(at); + modAttrs(); + attrTypes.keySet().retainAll(at.keySet()); + attrTypes.putAll(at); + } + + // attr format helpers + protected static boolean matchTag(int tagValue, String caseStr) { + //System.out.println("matchTag "+tagValue+" in "+caseStr); + for (int pos = 0, max = caseStr.length(), comma; + pos < max; + pos = comma + 1) { + int caseValue; + if (caseStr.charAt(pos) == '\\') { + caseValue = caseStr.charAt(pos + 1); + comma = pos + 2; + assert (comma == max || caseStr.charAt(comma) == ','); + } else { + comma = caseStr.indexOf(',', pos); + if (comma < 0) { + comma = max; + } + caseValue = Integer.parseInt(caseStr.substring(pos, comma)); + } + if (tagValue == caseValue) { + return true; + } + } + return false; + } + + protected static String[] getBodies(String type) { + ArrayList<String> bodies = new ArrayList<String>(); + for (int i = 0; i < type.length();) { + String body = getBody(type, i); + bodies.add(body); + i += body.length() + 2; // skip body and brackets + } + return bodies.toArray(new String[bodies.size()]); + } + + protected static String getBody(String type, int i) { + assert (type.charAt(i) == '['); + int next = ++i; // skip bracket + for (int depth = 1; depth > 0; next++) { + switch (type.charAt(next)) { + case '[': + depth++; + break; + case ']': + depth--; + break; + case '(': + next = type.indexOf(')', next); + break; + case '<': + next = type.indexOf('>', next); + break; + } + assert (next > 0); + } + --next; // get before bracket + assert (type.charAt(next) == ']'); + return type.substring(i, next); + } + + public Element makeCPDigest(int length) { + MessageDigest md; + try { + md = MessageDigest.getInstance("MD5"); + } catch (java.security.NoSuchAlgorithmException ee) { + throw new Error(ee); + } + int items = 0; + for (Element e : cpool.elements()) { + if (items == length) { + break; + } + if (cpTagNames.contains(e.getName())) { + items += 1; + md.update((byte) cpTagValue(e.getName())); + try { + md.update(e.getText().toString().getBytes(UTF8_ENCODING)); + } catch (java.io.UnsupportedEncodingException ee) { + throw new Error(ee); + } + } + } + ByteBuffer bb = ByteBuffer.wrap(md.digest()); + String l0 = Long.toHexString(bb.getLong(0)); + String l1 = Long.toHexString(bb.getLong(8)); + while (l0.length() < 16) { + l0 = "0" + l0; + } + while (l1.length() < 16) { + l1 = "0" + l1; + } + return new Element("Digest", + "length", "" + items, + "bytes", l0 + l1); + } + + public Element getCPDigest(int length) { + if (length == -1) { + length = cpool.countAll(XMLKit.elementFilter(cpTagNames)); + } + for (Element md : cpool.findAllElements("Digest").elements()) { + if (md.getAttrLong("length") == length) { + return md; + } + } + Element md = makeCPDigest(length); + cpool.add(md); + return md; + } + + public Element getCPDigest() { + return getCPDigest(-1); + } + + public boolean checkCPDigest(Element md) { + return md.equals(getCPDigest((int) md.getAttrLong("length"))); + } + + public static int computeInterfaceNum(String intMethRef) { + intMethRef = intMethRef.substring(1 + intMethRef.lastIndexOf(' ')); + if (!intMethRef.startsWith("(")) { + return -1; + } + int signum = 1; // start with one for "this" + scanSig: + for (int i = 1; i < intMethRef.length(); i++) { + char ch = intMethRef.charAt(i); + signum++; + switch (ch) { + case ')': + --signum; + break scanSig; + case 'L': + i = intMethRef.indexOf(';', i); + break; + case '[': + while (ch == '[') { + ch = intMethRef.charAt(++i); + } + if (ch == 'L') { + i = intMethRef.indexOf(';', i); + } + break; + } + } + int num = (signum << 8) | 0; + //System.out.println("computeInterfaceNum "+intMethRef+" => "+num); + return num; + } + // Protected state for representing the class file. + protected Element cfile; // <ClassFile ...> + protected Element cpool; // <ConstantPool ...> + protected Element klass; // <Class ...> + protected Element currentMember; // varies during scans + protected Element currentCode; // varies during scans +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,818 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- + +import java.util.*; +import java.lang.reflect.*; +import java.io.*; +import xmlkit.XMLKit.Element; +/* + * @author jrose + */ +public class ClassWriter extends ClassSyntax implements ClassSyntax.GetCPIndex { + + private static final CommandLineParser CLP = new CommandLineParser("" + + "-source: +> = \n" + + "-dest: +> = \n" + + "-encoding: +> = \n" + + "-parseBytes $ \n" + + "- *? \n" + + "\n"); + + public static void main(String[] ava) throws IOException { + ArrayList<String> av = new ArrayList<String>(Arrays.asList(ava)); + HashMap<String, String> props = new HashMap<String, String>(); + props.put("-encoding:", "UTF8"); // default + CLP.parse(av, props); + File source = asFile(props.get("-source:")); + File dest = asFile(props.get("-dest:")); + String encoding = props.get("-encoding:"); + boolean parseBytes = props.containsKey("-parseBytes"); + boolean destMade = false; + + for (String a : av) { + File f; + File inf = new File(source, a); + System.out.println("Reading " + inf); + Element e; + if (inf.getName().endsWith(".class")) { + ClassReader cr = new ClassReader(); + cr.parseBytes = parseBytes; + e = cr.readFrom(inf); + f = new File(a); + } else if (inf.getName().endsWith(".xml")) { + InputStream in = new FileInputStream(inf); + Reader inw = ClassReader.makeReader(in, encoding); + e = XMLKit.readFrom(inw); + e.findAllInTree(XMLKit.and(XMLKit.elementFilter(nonAttrTags()), + XMLKit.methodFilter(Element.method("trimText")))); + //System.out.println(e); + inw.close(); + f = new File(a.substring(0, a.length() - ".xml".length()) + ".class"); + } else { + System.out.println("Warning: unknown input " + a); + continue; + } + // Now write it: + if (!destMade) { + destMade = true; + if (dest == null) { + dest = File.createTempFile("TestOut", ".dir", new File(".")); + dest.delete(); + System.out.println("Writing results to " + dest); + } + if (!(dest.isDirectory() || dest.mkdir())) { + throw new RuntimeException("Cannot create " + dest); + } + } + File outf = new File(dest, f.isAbsolute() ? f.getName() : f.getPath()); + outf.getParentFile().mkdirs(); + new ClassWriter(e).writeTo(outf); + } + } + + private static File asFile(String str) { + return (str == null) ? null : new File(str); + } + + public void writeTo(File file) throws IOException { + OutputStream out = null; + try { + out = new BufferedOutputStream(new FileOutputStream(file)); + writeTo(out); + } finally { + if (out != null) { + out.close(); + } + } + } + protected String[] callables; // varies + protected int cpoolSize = 0; + protected HashMap<String, String> attrTypesByTag; + protected OutputStream out; + protected HashMap<String, int[]> cpMap = new HashMap<String, int[]>(); + protected ArrayList<ByteArrayOutputStream> attrBufs = new ArrayList<ByteArrayOutputStream>(); + + private void setupAttrTypes() { + attrTypesByTag = new HashMap<String, String>(); + for (String key : attrTypes.keySet()) { + String pfx = key.substring(0, key.indexOf('.') + 1); + String val = attrTypes.get(key); + int pos = val.indexOf('<'); + if (pos >= 0) { + String tag = val.substring(pos + 1, val.indexOf('>', pos)); + attrTypesByTag.put(pfx + tag, key); + } + } + //System.out.println("attrTypesByTag: "+attrTypesByTag); + } + + protected ByteArrayOutputStream getAttrBuf() { + int nab = attrBufs.size(); + if (nab == 0) { + return new ByteArrayOutputStream(1024); + } + ByteArrayOutputStream ab = attrBufs.get(nab - 1); + attrBufs.remove(nab - 1); + return ab; + } + + protected void putAttrBuf(ByteArrayOutputStream ab) { + ab.reset(); + attrBufs.add(ab); + } + + public ClassWriter(Element root) { + this(root, null); + } + + public ClassWriter(Element root, ClassSyntax cr) { + if (cr != null) { + attrTypes = cr.attrTypes; + } + setupAttrTypes(); + if (root.getName() == "ClassFile") { + cfile = root; + cpool = root.findElement("ConstantPool"); + klass = root.findElement("Class"); + } else if (root.getName() == "Class") { + cfile = new Element("ClassFile", + new String[]{ + "magic", String.valueOf(0xCAFEBABE), + "minver", "0", "majver", "46",}); + cpool = new Element("ConstantPool"); + klass = root; + } else { + throw new IllegalArgumentException("bad element type " + root.getName()); + } + if (cpool == null) { + cpool = new Element("ConstantPool"); + } + + int cpLen = 1 + cpool.size(); + for (Element c : cpool.elements()) { + int id = (int) c.getAttrLong("id"); + int tag = cpTagValue(c.getName()); + setCPIndex(tag, c.getText().toString(), id); + switch (tag) { + case CONSTANT_Long: + case CONSTANT_Double: + cpLen += 1; + } + } + cpoolSize = cpLen; + } + + public int findCPIndex(int tag, String name) { + if (name == null) { + return 0; + } + int[] ids = cpMap.get(name.toString()); + return (ids == null) ? 0 : ids[tag]; + } + + public int getCPIndex(int tag, String name) { + //System.out.println("getCPIndex "+cpTagName(tag)+" "+name); + if (name == null) { + return 0; + } + int id = findCPIndex(tag, name); + if (id == 0) { + id = cpoolSize; + cpoolSize += 1; + setCPIndex(tag, name, id); + cpool.add(new Element(cpTagName(tag), + new String[]{"id", "" + id}, + new Object[]{name})); + int pos; + switch (tag) { + case CONSTANT_Long: + case CONSTANT_Double: + cpoolSize += 1; + break; + case CONSTANT_Class: + case CONSTANT_String: + getCPIndex(CONSTANT_Utf8, name); + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + pos = name.indexOf(' '); + getCPIndex(CONSTANT_Class, name.substring(0, pos)); + getCPIndex(CONSTANT_NameAndType, name.substring(pos + 1)); + break; + case CONSTANT_NameAndType: + pos = name.indexOf(' '); + getCPIndex(CONSTANT_Utf8, name.substring(0, pos)); + getCPIndex(CONSTANT_Utf8, name.substring(pos + 1)); + break; + } + } + return id; + } + + public void setCPIndex(int tag, String name, int id) { + //System.out.println("setCPIndex id="+id+" tag="+tag+" name="+name); + int[] ids = cpMap.get(name); + if (ids == null) { + cpMap.put(name, ids = new int[13]); + } + if (ids[tag] != 0 && ids[tag] != id) { + System.out.println("Warning: Duplicate CP entries for " + ids[tag] + " and " + id); + } + //assert(ids[tag] == 0 || ids[tag] == id); + ids[tag] = id; + } + + public int parseFlags(String flagString) { + int flags = 0; + int i = -1; + for (String[] names : modifierNames) { + ++i; + for (String name : names) { + if (name == null) { + continue; + } + int pos = flagString.indexOf(name); + if (pos >= 0) { + flags |= (1 << i); + } + } + } + return flags; + } + + public void writeTo(OutputStream realOut) throws IOException { + OutputStream headOut = realOut; + ByteArrayOutputStream tailOut = new ByteArrayOutputStream(); + + // write the body of the class file first + this.out = tailOut; + writeClass(); + + // write the file header last + this.out = headOut; + u4((int) cfile.getAttrLong("magic")); + u2((int) cfile.getAttrLong("minver")); + u2((int) cfile.getAttrLong("majver")); + writeCP(); + + // recopy the file tail + this.out = null; + tailOut.writeTo(realOut); + } + + void writeClass() throws IOException { + int flags = parseFlags(klass.getAttr("flags")); + flags ^= Modifier.SYNCHRONIZED; + u2(flags); + cpRef(CONSTANT_Class, klass.getAttr("name")); + cpRef(CONSTANT_Class, klass.getAttr("super")); + Element interfaces = klass.findAllElements("Interface"); + u2(interfaces.size()); + for (Element e : interfaces.elements()) { + cpRef(CONSTANT_Class, e.getAttr("name")); + } + for (int isMethod = 0; isMethod <= 1; isMethod++) { + Element members = klass.findAllElements(isMethod != 0 ? "Method" : "Field"); + u2(members.size()); + for (Element m : members.elements()) { + writeMember(m, isMethod != 0); + } + } + writeAttributesFor(klass); + } + + private void writeMember(Element member, boolean isMethod) throws IOException { + //System.out.println("writeMember "+member); + u2(parseFlags(member.getAttr("flags"))); + cpRef(CONSTANT_Utf8, member.getAttr("name")); + cpRef(CONSTANT_Utf8, member.getAttr("type")); + writeAttributesFor(member); + } + + protected void writeAttributesFor(Element x) throws IOException { + LinkedHashSet<String> attrNames = new LinkedHashSet<String>(); + for (Element e : x.elements()) { + attrNames.add(e.getName()); // uniquifying + } + attrNames.removeAll(nonAttrTags()); + u2(attrNames.size()); + if (attrNames.isEmpty()) { + return; + } + Element prevCurrent; + if (x.getName() == "Code") { + prevCurrent = currentCode; + currentCode = x; + } else { + prevCurrent = currentMember; + currentMember = x; + } + OutputStream realOut = this.out; + for (String utag : attrNames) { + String qtag = x.getName() + "." + utag; + String wtag = "*." + utag; + String key = attrTypesByTag.get(qtag); + if (key == null) { + key = attrTypesByTag.get(wtag); + } + String type = attrTypes.get(key); + //System.out.println("tag "+qtag+" => key "+key+"; type "+type); + Element attrs = x.findAllElements(utag); + ByteArrayOutputStream attrBuf = getAttrBuf(); + if (type == null) { + if (attrs.size() != 1 || !attrs.get(0).equals(new Element(utag))) { + System.out.println("Warning: No attribute type description: " + qtag); + } + key = wtag; + } else { + try { + this.out = attrBuf; + // unparse according to type desc. + if (type.equals("<Code>...")) { + writeCode((Element) attrs.get(0)); // assume only 1 + } else if (type.equals("<Frame>...")) { + writeStackMap(attrs, false); + } else if (type.equals("<FrameX>...")) { + writeStackMap(attrs, true); + } else if (type.startsWith("[")) { + writeAttributeRecursive(attrs, type); + } else { + writeAttribute(attrs, type); + } + } finally { + //System.out.println("Attr Bytes = \""+attrBuf.toString(EIGHT_BIT_CHAR_ENCODING).replace('"', (char)('"'|0x80))+"\""); + this.out = realOut; + } + } + cpRef(CONSTANT_Utf8, key.substring(key.indexOf('.') + 1)); + u4(attrBuf.size()); + attrBuf.writeTo(out); + putAttrBuf(attrBuf); + } + if (x.getName() == "Code") { + currentCode = prevCurrent; + } else { + currentMember = prevCurrent; + } + } + + private void writeAttributeRecursive(Element aval, String type) throws IOException { + assert (callables == null); + callables = getBodies(type); + writeAttribute(aval, callables[0]); + callables = null; + } + + private void writeAttribute(Element aval, String type) throws IOException { + //System.out.println("writeAttribute "+aval+" using "+type); + String nextAttrName = null; + boolean afterElemHead = false; + for (int len = type.length(), next, i = 0; i < len; i = next) { + int value; + char intKind; + int tag; + int sigChar; + String attrValue; + switch (type.charAt(i)) { + case '<': + assert (nextAttrName == null); + next = type.indexOf('>', i); + String form = type.substring(i + 1, next++); + if (form.indexOf('=') < 0) { + // elem_placement = '<' elemname '>' + if (aval.isAnonymous()) { + assert (aval.size() == 1); + aval = (Element) aval.get(0); + } + assert (aval.getName().equals(form)) : aval + " // " + form; + afterElemHead = true; + } else { + // attr_placement = '(' attrname '=' (value)? ')' + int eqPos = form.indexOf('='); + assert (eqPos >= 0); + nextAttrName = form.substring(0, eqPos).intern(); + if (eqPos != form.length() - 1) { + // value is implicit, not placed in file + nextAttrName = null; + } + afterElemHead = false; + } + continue; + case '(': + next = type.indexOf(')', ++i); + int callee = Integer.parseInt(type.substring(i, next++)); + writeAttribute(aval, callables[callee]); + continue; + case 'N': // replication = 'N' int '[' type ... ']' + { + assert (nextAttrName == null); + afterElemHead = false; + char countType = type.charAt(i + 1); + next = i + 2; + String type1 = getBody(type, next); + Element elems = aval; + if (type1.startsWith("<")) { + // Select only matching members of aval. + String elemName = type1.substring(1, type1.indexOf('>')); + elems = aval.findAllElements(elemName); + } + putInt(elems.size(), countType); + next += type1.length() + 2; // skip body and brackets + for (Element elem : elems.elements()) { + writeAttribute(elem, type1); + } + } + continue; + case 'T': // union = 'T' any_int union_case* '(' ')' '[' body ']' + // write the value + value = (int) aval.getAttrLong("tag"); + assert (aval.getAttr("tag") != null) : aval; + intKind = type.charAt(++i); + if (intKind == 'S') { + intKind = type.charAt(++i); + } + putInt(value, intKind); + nextAttrName = null; + afterElemHead = false; + ++i; // skip the int type char + // union_case = '(' ('-')? digit+ ')' '[' body ']' + for (boolean foundCase = false;;) { + assert (type.charAt(i) == '('); + next = type.indexOf(')', ++i); + assert (next >= i); + String caseStr = type.substring(i, next++); + String type1 = getBody(type, next); + next += type1.length() + 2; // skip body and brackets + boolean lastCase = (caseStr.length() == 0); + if (!foundCase + && (lastCase || matchTag(value, caseStr))) { + foundCase = true; + // Execute this body. + writeAttribute(aval, type1); + } + if (lastCase) { + break; + } + } + continue; + case 'B': + case 'H': + case 'I': // int = oneof "BHI" + value = (int) aval.getAttrLong(nextAttrName); + intKind = type.charAt(i); + next = i + 1; + break; + case 'K': + sigChar = type.charAt(i + 1); + if (sigChar == 'Q') { + assert (currentMember.getName() == "Field"); + assert (aval.getName() == "ConstantValue"); + String sig = currentMember.getAttr("type"); + sigChar = sig.charAt(0); + switch (sigChar) { + case 'Z': + case 'B': + case 'C': + case 'S': + sigChar = 'I'; + break; + } + } + switch (sigChar) { + case 'I': + tag = CONSTANT_Integer; + break; + case 'J': + tag = CONSTANT_Long; + break; + case 'F': + tag = CONSTANT_Float; + break; + case 'D': + tag = CONSTANT_Double; + break; + case 'L': + tag = CONSTANT_String; + break; + default: + assert (false); + tag = 0; + } + assert (type.charAt(i + 2) == 'H'); // only H works for now + next = i + 3; + assert (afterElemHead || nextAttrName != null); + //System.out.println("get attr "+nextAttrName+" in "+aval); + if (nextAttrName != null) { + attrValue = aval.getAttr(nextAttrName); + assert (attrValue != null); + } else { + assert (aval.isText()) : aval; + attrValue = aval.getText().toString(); + } + value = getCPIndex(tag, attrValue); + intKind = 'H'; //type.charAt(i+2); + break; + case 'R': + sigChar = type.charAt(i + 1); + switch (sigChar) { + case 'C': + tag = CONSTANT_Class; + break; + case 'S': + tag = CONSTANT_Utf8; + break; + case 'D': + tag = CONSTANT_Class; + break; + case 'F': + tag = CONSTANT_Fieldref; + break; + case 'M': + tag = CONSTANT_Methodref; + break; + case 'I': + tag = CONSTANT_InterfaceMethodref; + break; + case 'U': + tag = CONSTANT_Utf8; + break; + //case 'Q': tag = CONSTANT_Class; break; + default: + assert (false); + tag = 0; + } + assert (type.charAt(i + 2) == 'H'); // only H works for now + next = i + 3; + assert (afterElemHead || nextAttrName != null); + //System.out.println("get attr "+nextAttrName+" in "+aval); + if (nextAttrName != null) { + attrValue = aval.getAttr(nextAttrName); + } else if (aval.hasText()) { + attrValue = aval.getText().toString(); + } else { + attrValue = null; + } + value = getCPIndex(tag, attrValue); + intKind = 'H'; //type.charAt(i+2); + break; + case 'P': // bci = 'P' int + case 'S': // signed_int = 'S' int + next = i + 2; + value = (int) aval.getAttrLong(nextAttrName); + intKind = type.charAt(i + 1); + break; + case 'F': + next = i + 2; + value = parseFlags(aval.getAttr(nextAttrName)); + intKind = type.charAt(i + 1); + break; + default: + throw new RuntimeException("bad attr format '" + type.charAt(i) + "': " + type); + } + // write the value + putInt(value, intKind); + nextAttrName = null; + afterElemHead = false; + } + assert (nextAttrName == null); + } + + private void putInt(int x, char ch) throws IOException { + switch (ch) { + case 'B': + u1(x); + break; + case 'H': + u2(x); + break; + case 'I': + u4(x); + break; + } + assert ("BHI".indexOf(ch) >= 0); + } + + private void writeCode(Element code) throws IOException { + //System.out.println("writeCode "+code); + //Element m = new Element(currentMember); m.remove(code); + //System.out.println(" in "+m); + int stack = (int) code.getAttrLong("stack"); + int local = (int) code.getAttrLong("local"); + Element bytes = code.findElement("Bytes"); + Element insns = code.findElement("Instructions"); + String bytecodes; + if (insns == null) { + bytecodes = bytes.getText().toString(); + } else { + bytecodes = InstructionSyntax.assemble(insns, this); + // Cache the assembled bytecodes: + bytes = new Element("Bytes", (String[]) null, bytecodes); + code.add(0, bytes); + } + u2(stack); + u2(local); + int length = bytecodes.length(); + u4(length); + for (int i = 0; i < length; i++) { + u1((byte) bytecodes.charAt(i)); + } + Element handlers = code.findAllElements("Handler"); + u2(handlers.size()); + for (Element handler : handlers.elements()) { + int start = (int) handler.getAttrLong("start"); + int end = (int) handler.getAttrLong("end"); + int catsh = (int) handler.getAttrLong("catch"); + u2(start); + u2(end); + u2(catsh); + cpRef(CONSTANT_Class, handler.getAttr("class")); + } + writeAttributesFor(code); + } + + protected void writeStackMap(Element attrs, boolean hasXOption) throws IOException { + Element bytes = currentCode.findElement("Bytes"); + assert (bytes != null && bytes.size() == 1); + int byteLength = ((String) bytes.get(0)).length(); + boolean uoffsetIsU4 = (byteLength >= (1 << 16)); + boolean ulocalvarIsU4 = currentCode.getAttrLong("local") >= (1 << 16); + boolean ustackIsU4 = currentCode.getAttrLong("stack") >= (1 << 16); + if (uoffsetIsU4) { + u4(attrs.size()); + } else { + u2(attrs.size()); + } + for (Element frame : attrs.elements()) { + int bci = (int) frame.getAttrLong("bci"); + if (uoffsetIsU4) { + u4(bci); + } else { + u2(bci); + } + if (hasXOption) { + u1((int) frame.getAttrLong("flags")); + } + // Scan local and stack types in this frame: + final int LOCALS = 0, STACK = 1; + for (int j = LOCALS; j <= STACK; j++) { + Element types = frame.findElement(j == LOCALS ? "Local" : "Stack"); + int typeSize = (types == null) ? 0 : types.size(); + if (j == LOCALS) { + if (ulocalvarIsU4) { + u4(typeSize); + } else { + u2(typeSize); + } + } else { // STACK + if (ustackIsU4) { + u4(typeSize); + } else { + u2(typeSize); + } + } + if (types == null) { + continue; + } + for (Element type : types.elements()) { + int tag = itemTagValue(type.getName()); + u1(tag); + switch (tag) { + case ITEM_Object: + cpRef(CONSTANT_Class, type.getAttr("class")); + break; + case ITEM_Uninitialized: + case ITEM_ReturnAddress: { + int offset = (int) type.getAttrLong("bci"); + if (uoffsetIsU4) { + u4(offset); + } else { + u2(offset); + } + } + break; + } + } + } + } + } + + public void writeCP() throws IOException { + int cpLen = cpoolSize; + u2(cpLen); + ByteArrayOutputStream buf = getAttrBuf(); + for (Element c : cpool.elements()) { + if (!c.isText()) { + System.out.println("## !isText " + c); + } + int id = (int) c.getAttrLong("id"); + int tag = cpTagValue(c.getName()); + String name = c.getText().toString(); + int pos; + u1(tag); + switch (tag) { + case CONSTANT_Utf8: { + int done = 0; + buf.reset(); + int nameLen = name.length(); + while (done < nameLen) { + int next = name.indexOf((char) 0, done); + if (next < 0) { + next = nameLen; + } + if (done < next) { + buf.write(name.substring(done, next).getBytes(UTF8_ENCODING)); + } + if (next < nameLen) { + buf.write(0300); + buf.write(0200); + next++; + } + done = next; + } + u2(buf.size()); + buf.writeTo(out); + } + break; + case CONSTANT_Integer: + u4(Integer.parseInt(name)); + break; + case CONSTANT_Float: + u4(Float.floatToIntBits(Float.parseFloat(name))); + break; + case CONSTANT_Long: + u8(Long.parseLong(name)); + //i += 1; // no need: extra cp slot is implicit + break; + case CONSTANT_Double: + u8(Double.doubleToLongBits(Double.parseDouble(name))); + //i += 1; // no need: extra cp slot is implicit + break; + case CONSTANT_Class: + case CONSTANT_String: + u2(getCPIndex(CONSTANT_Utf8, name)); + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + pos = name.indexOf(' '); + u2(getCPIndex(CONSTANT_Class, name.substring(0, pos))); + u2(getCPIndex(CONSTANT_NameAndType, name.substring(pos + 1))); + break; + case CONSTANT_NameAndType: + pos = name.indexOf(' '); + u2(getCPIndex(CONSTANT_Utf8, name.substring(0, pos))); + u2(getCPIndex(CONSTANT_Utf8, name.substring(pos + 1))); + break; + } + } + putAttrBuf(buf); + } + + public void cpRef(int tag, String name) throws IOException { + u2(getCPIndex(tag, name)); + } + + public void u8(long x) throws IOException { + u4((int) (x >>> 32)); + u4((int) (x >>> 0)); + } + + public void u4(int x) throws IOException { + u2(x >>> 16); + u2(x >>> 0); + } + + public void u2(int x) throws IOException { + u1(x >>> 8); + u1(x >>> 0); + } + + public void u1(int x) throws IOException { + out.write(x & 0xFF); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/CommandLineParser.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,284 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- + +import java.util.*; +/* + * @author jrose + */ +public class CommandLineParser { + + public CommandLineParser(String optionString) { + setOptionMap(optionString); + } + TreeMap<String, String[]> optionMap; + + public void setOptionMap(String options) { + // Convert options string into optLines dictionary. + TreeMap<String, String[]> optmap = new TreeMap<String, String[]>(); + loadOptmap: + for (String optline : options.split("\n")) { + String[] words = optline.split("\\p{Space}+"); + if (words.length == 0) { + continue loadOptmap; + } + String opt = words[0]; + words[0] = ""; // initial word is not a spec + if (opt.length() == 0 && words.length >= 1) { + opt = words[1]; // initial "word" is empty due to leading ' ' + words[1] = ""; + } + if (opt.length() == 0) { + continue loadOptmap; + } + String[] prevWords = optmap.put(opt, words); + if (prevWords != null) { + throw new RuntimeException("duplicate option: " + + optline.trim()); + } + } + optionMap = optmap; + } + + public String getOptionMap() { + TreeMap<String, String[]> optmap = optionMap; + StringBuffer sb = new StringBuffer(); + for (String opt : optmap.keySet()) { + sb.append(opt); + for (String spec : optmap.get(opt)) { + sb.append(' ').append(spec); + } + sb.append('\n'); + } + return sb.toString(); + } + + /** + * Remove a set of command-line options from args, + * storing them in the properties map in a canonicalized form. + */ + public String parse(List<String> args, Map<String, String> properties) { + //System.out.println(args+" // "+properties); + + String resultString = null; + TreeMap<String, String[]> optmap = optionMap; + + // State machine for parsing a command line. + ListIterator<String> argp = args.listIterator(); + ListIterator<String> pbp = new ArrayList<String>().listIterator(); + doArgs: + for (;;) { + // One trip through this loop per argument. + // Multiple trips per option only if several options per argument. + String arg; + if (pbp.hasPrevious()) { + arg = pbp.previous(); + pbp.remove(); + } else if (argp.hasNext()) { + arg = argp.next(); + } else { + // No more arguments at all. + break doArgs; + } + tryOpt: + for (int optlen = arg.length();; optlen--) { + // One time through this loop for each matching arg prefix. + String opt; + // Match some prefix of the argument to a key in optmap. + findOpt: + for (;;) { + opt = arg.substring(0, optlen); + if (optmap.containsKey(opt)) { + break findOpt; + } + if (optlen == 0) { + break tryOpt; + } + // Decide on a smaller prefix to search for. + SortedMap<String, String[]> pfxmap = optmap.headMap(opt); + // pfxmap.lastKey is no shorter than any prefix in optmap. + int len = pfxmap.isEmpty() ? 0 : pfxmap.lastKey().length(); + optlen = Math.min(len, optlen - 1); + opt = arg.substring(0, optlen); + // (Note: We could cut opt down to its common prefix with + // pfxmap.lastKey, but that wouldn't save many cycles.) + } + opt = opt.intern(); + assert (arg.startsWith(opt)); + assert (opt.length() == optlen); + String val = arg.substring(optlen); // arg == opt+val + + // Execute the option processing specs for this opt. + // If no actions are taken, then look for a shorter prefix. + boolean didAction = false; + boolean isError = false; + + int pbpMark = pbp.nextIndex(); // in case of backtracking + String[] specs = optmap.get(opt); + eachSpec: + for (String spec : specs) { + if (spec.length() == 0) { + continue eachSpec; + } + if (spec.startsWith("#")) { + break eachSpec; + } + int sidx = 0; + char specop = spec.charAt(sidx++); + + // Deal with '+'/'*' prefixes (spec conditions). + boolean ok; + switch (specop) { + case '+': + // + means we want an non-empty val suffix. + ok = (val.length() != 0); + specop = spec.charAt(sidx++); + break; + case '*': + // * means we accept empty or non-empty + ok = true; + specop = spec.charAt(sidx++); + break; + default: + // No condition prefix means we require an exact + // match, as indicated by an empty val suffix. + ok = (val.length() == 0); + break; + } + if (!ok) { + continue eachSpec; + } + + String specarg = spec.substring(sidx); + switch (specop) { + case '.': // terminate the option sequence + resultString = (specarg.length() != 0) ? specarg.intern() : opt; + break doArgs; + case '?': // abort the option sequence + resultString = (specarg.length() != 0) ? specarg.intern() : arg; + isError = true; + break eachSpec; + case '@': // change the effective opt name + opt = specarg.intern(); + break; + case '>': // shift remaining arg val to next arg + pbp.add(specarg + val); // push a new argument + val = ""; + break; + case '!': // negation option + String negopt = (specarg.length() != 0) ? specarg.intern() : opt; + properties.remove(negopt); + properties.put(negopt, null); // leave placeholder + didAction = true; + break; + case '$': // normal "boolean" option + String boolval; + if (specarg.length() != 0) { + // If there is a given spec token, store it. + boolval = specarg; + } else { + String old = properties.get(opt); + if (old == null || old.length() == 0) { + boolval = "1"; + } else { + // Increment any previous value as a numeral. + boolval = "" + (1 + Integer.parseInt(old)); + } + } + properties.put(opt, boolval); + didAction = true; + break; + case '=': // "string" option + case '&': // "collection" option + // Read an option. + boolean append = (specop == '&'); + String strval; + if (pbp.hasPrevious()) { + strval = pbp.previous(); + pbp.remove(); + } else if (argp.hasNext()) { + strval = argp.next(); + } else { + resultString = arg + " ?"; + isError = true; + break eachSpec; + } + if (append) { + String old = properties.get(opt); + if (old != null) { + // Append new val to old with embedded delim. + String delim = specarg; + if (delim.length() == 0) { + delim = " "; + } + strval = old + specarg + strval; + } + } + properties.put(opt, strval); + didAction = true; + break; + default: + throw new RuntimeException("bad spec for " + + opt + ": " + spec); + } + } + + // Done processing specs. + if (didAction && !isError) { + continue doArgs; + } + + // The specs should have done something, but did not. + while (pbp.nextIndex() > pbpMark) { + // Remove anything pushed during these specs. + pbp.previous(); + pbp.remove(); + } + + if (isError) { + throw new IllegalArgumentException(resultString); + } + + if (optlen == 0) { + // We cannot try a shorter matching option. + break tryOpt; + } + } + + // If we come here, there was no matching option. + // So, push back the argument, and return to caller. + pbp.add(arg); + break doArgs; + } + // Report number of arguments consumed. + args.subList(0, argp.nextIndex()).clear(); + // Report any unconsumed partial argument. + while (pbp.hasPrevious()) { + args.add(0, pbp.previous()); + } + //System.out.println(args+" // "+properties+" -> "+resultString); + return resultString; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,464 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- + +import xmlkit.XMLKit.Element; +import java.util.HashMap; +/* + * @author jrose + */ +abstract class InstructionAssembler extends InstructionSyntax { + + InstructionAssembler() { + } + + public static String assemble(Element instructions, String pcAttrName, + ClassSyntax.GetCPIndex getCPI) { + int insCount = instructions.size(); + Element[] insElems = new Element[insCount]; + int[] elemToIndexMap; + int[] insLocs; + byte[] ops = new byte[insCount]; + int[] operands = new int[insCount]; + boolean[] isWide = new boolean[insCount]; + int[] branches; + int[] branchInsLocs; + HashMap<String, String> labels = new HashMap<String, String>(); + + final int WIDE = 0xc4; + final int GOTO = 0xa7; + final int GOTO_W = 0xc8; + final int GOTO_LEN = 3; + final int GOTO_W_LEN = 5; + assert ("wide".equals(bcNames[WIDE])); + assert ("goto".equals(bcNames[GOTO])); + assert ("goto_w".equals(bcNames[GOTO_W])); + assert (bcFormats[GOTO].length() == GOTO_LEN); + assert (bcFormats[GOTO_W].length() == GOTO_W_LEN); + + // Unpack instructions into temp. arrays, and find branches and labels. + { + elemToIndexMap = (pcAttrName != null) ? new int[insCount] : null; + int[] buffer = operands; + int id = 0; + int branchCount = 0; + for (int i = 0; i < insCount; i++) { + Element ins = (Element) instructions.get(i); + if (elemToIndexMap != null) { + elemToIndexMap[i] = (ins.getAttr(pcAttrName) != null ? id : -1); + } + String lab = ins.getAttr("pc"); + if (lab != null) { + labels.put(lab, String.valueOf(id)); + } + int op = opCode(ins.getName()); + if (op < 0) { + assert (ins.getAttr(pcAttrName) != null + || ins.getName().equals("label")); + continue; // delete PC holder element + } + if (op == WIDE) { //0xc4 + isWide[id] = true; // force wide format + continue; + } + if (bcFormats[op].indexOf('o') >= 0) { + buffer[branchCount++] = id; + } + if (bcFormats[op] == bcWideFormats[op]) { + isWide[id] = false; + } + insElems[id] = ins; + ops[id] = (byte) op; + id++; + } + insCount = id; // maybe we deleted some wide prefixes, etc. + branches = new int[branchCount + 1]; + System.arraycopy(buffer, 0, branches, 0, branchCount); + branches[branchCount] = -1; // sentinel + } + + // Compute instruction sizes. These sizes are final, + // except for branch instructions, which may need lengthening. + // Some instructions (ldc, bipush, iload, iinc) are automagically widened. + insLocs = new int[insCount + 1]; + int loc = 0; + for (int bn = 0, id = 0; id < insCount; id++) { + insLocs[id] = loc; + Element ins = insElems[id]; + int op = ops[id] & 0xFF; + String format = opFormat(op, isWide[id]); + // Make sure operands fit within the given format. + for (int j = 1, jlimit = format.length(); j < jlimit; j++) { + char fc = format.charAt(j); + int x = 0; + switch (fc) { + case 'l': + x = (int) ins.getAttrLong("loc"); + assert (x >= 0); + if (x > 0xFF && !isWide[id]) { + isWide[id] = true; + format = opFormat(op, isWide[id]); + } + assert (x <= 0xFFFF); + break; + case 'k': + char fc2 = format.charAt(Math.min(j + 1, format.length() - 1)); + x = getCPIndex(ins, fc2, getCPI); + if (x > 0xFF && j == jlimit - 1) { + assert (op == 0x12); //ldc + ops[id] = (byte) (op = 0x13); //ldc_w + format = opFormat(op); + } + assert (x <= 0xFFFF); + j++; // skip type-of-constant marker + break; + case 'x': + x = (int) ins.getAttrLong("num"); + assert (x >= 0 && x <= ((j == jlimit - 1) ? 0xFF : 0xFFFF)); + break; + case 's': + x = (int) ins.getAttrLong("num"); + if (x != (byte) x && j == jlimit - 1) { + switch (op) { + case 0x10: //bipush + ops[id] = (byte) (op = 0x11); //sipush + break; + case 0x84: //iinc + isWide[id] = true; + format = opFormat(op, isWide[id]); + break; + default: + assert (false); // cannot lengthen + } + } + // unsign the value now, to make later steps clearer + if (j == jlimit - 1) { + assert (x == (byte) x); + x = x & 0xFF; + } else { + assert (x == (short) x); + x = x & 0xFFFF; + } + break; + case 'o': + assert (branches[bn] == id); + bn++; + // make local copies of the branches, and fix up labels + insElems[id] = ins = new Element(ins); + String newLab = labels.get(ins.getAttr("lab")); + assert (newLab != null); + ins.setAttr("lab", newLab); + int prevCas = 0; + int k = 0; + for (Element cas : ins.elements()) { + assert (cas.getName().equals("Case")); + ins.set(k++, cas = new Element(cas)); + newLab = labels.get(cas.getAttr("lab")); + assert (newLab != null); + cas.setAttr("lab", newLab); + int thisCas = (int) cas.getAttrLong("num"); + assert (op == 0xab + || op == 0xaa && (k == 0 || thisCas == prevCas + 1)); + prevCas = thisCas; + } + break; + case 't': + // switch table is represented as Switch.Case sub-elements + break; + default: + assert (false); + } + operands[id] = x; // record operand (last if there are 2) + // skip redundant chars + while (j + 1 < jlimit && format.charAt(j + 1) == fc) { + ++j; + } + } + + switch (op) { + case 0xaa: //tableswitch + loc = switchBase(loc); + loc += 4 * (3 + ins.size()); + break; + case 0xab: //lookupswitch + loc = switchBase(loc); + loc += 4 * (2 + 2 * ins.size()); + break; + default: + if (isWide[id]) { + loc++; // 'wide' opcode prefix + } + loc += format.length(); + break; + } + } + insLocs[insCount] = loc; + + // compute branch offsets, and see if any branches need expansion + for (int maxTries = 9, tries = 0;; ++tries) { + boolean overflowing = false; + boolean[] branchExpansions = null; + for (int bn = 0; bn < branches.length - 1; bn++) { + int id = branches[bn]; + Element ins = insElems[id]; + int insSize = insLocs[id + 1] - insLocs[id]; + int origin = insLocs[id]; + int target = insLocs[(int) ins.getAttrLong("lab")]; + int offset = target - origin; + operands[id] = offset; + //System.out.println("branch id="+id+" len="+insSize+" to="+target+" offset="+offset); + assert (insSize == GOTO_LEN || insSize == GOTO_W_LEN || ins.getName().indexOf("switch") > 0); + boolean thisOverflow = (insSize == GOTO_LEN && (offset != (short) offset)); + if (thisOverflow && !overflowing) { + overflowing = true; + branchExpansions = new boolean[branches.length]; + } + if (thisOverflow || tries == maxTries - 1) { + // lengthen the branch + assert (!(thisOverflow && isWide[id])); + isWide[id] = true; + branchExpansions[bn] = true; + } + } + if (!overflowing) { + break; // done, usually on first try + } + assert (tries <= maxTries); + + // Walk over all instructions, expanding branches and updating locations. + int fixup = 0; + for (int bn = 0, id = 0; id < insCount; id++) { + insLocs[id] += fixup; + if (branches[bn] == id) { + int op = ops[id] & 0xFF; + int wop; + boolean invert; + if (branchExpansions[bn]) { + switch (op) { + case GOTO: //0xa7 + wop = GOTO_W; //0xc8 + invert = false; + break; + case 0xa8: //jsr + wop = 0xc9; //jsr_w + invert = false; + break; + default: + wop = invertBranchOp(op); + invert = true; + break; + } + assert (op != wop); + ops[id] = (byte) wop; + isWide[id] = invert; + if (invert) { + fixup += GOTO_W_LEN; //branch around a wide goto + } else { + fixup += (GOTO_W_LEN - GOTO_LEN); + } + // done expanding: ops and isWide reflect the decision + } + bn++; + } + } + insLocs[insCount] += fixup; + } + // we know the layout now + + // notify the caller of offsets, if requested + if (elemToIndexMap != null) { + for (int i = 0; i < elemToIndexMap.length; i++) { + int id = elemToIndexMap[i]; + if (id >= 0) { + Element ins = (Element) instructions.get(i); + ins.setAttr(pcAttrName, "" + insLocs[id]); + } + } + elemToIndexMap = null; // release the pointer + } + + // output the bytes + StringBuffer sbuf = new StringBuffer(insLocs[insCount]); + for (int bn = 0, id = 0; id < insCount; id++) { + //System.out.println("output id="+id+" loc="+insLocs[id]+" len="+(insLocs[id+1]-insLocs[id])+" #sbuf="+sbuf.length()); + assert (sbuf.length() == insLocs[id]); + Element ins; + int pc = insLocs[id]; + int nextpc = insLocs[id + 1]; + int op = ops[id] & 0xFF; + int opnd = operands[id]; + String format; + if (branches[bn] == id) { + bn++; + sbuf.append((char) op); + if (isWide[id]) { + // emit <ifop lab=1f> <goto_w target> <label pc=1f> + int target = pc + opnd; + putInt(sbuf, nextpc - pc, -2); + assert (sbuf.length() == pc + GOTO_LEN); + sbuf.append((char) GOTO_W); + putInt(sbuf, target - (pc + GOTO_LEN), 4); + } else if (op == 0xaa || //tableswitch + op == 0xab) { //lookupswitch + ins = insElems[id]; + for (int pad = switchBase(pc) - (pc + 1); pad > 0; pad--) { + sbuf.append((char) 0); + } + assert (pc + opnd == insLocs[(int) ins.getAttrLong("lab")]); + putInt(sbuf, opnd, 4); // default label + if (op == 0xaa) { //tableswitch + Element cas0 = (Element) ins.get(0); + int lowCase = (int) cas0.getAttrLong("num"); + Element casN = (Element) ins.get(ins.size() - 1); + int highCase = (int) casN.getAttrLong("num"); + assert (highCase - lowCase + 1 == ins.size()); + putInt(sbuf, lowCase, 4); + putInt(sbuf, highCase, 4); + int caseForAssert = lowCase; + for (Element cas : ins.elements()) { + int target = insLocs[(int) cas.getAttrLong("lab")]; + assert (cas.getAttrLong("num") == caseForAssert++); + putInt(sbuf, target - pc, 4); + } + } else { //lookupswitch + int caseCount = ins.size(); + putInt(sbuf, caseCount, 4); + for (Element cas : ins.elements()) { + int target = insLocs[(int) cas.getAttrLong("lab")]; + putInt(sbuf, (int) cas.getAttrLong("num"), 4); + putInt(sbuf, target - pc, 4); + } + } + assert (nextpc == sbuf.length()); + } else { + putInt(sbuf, opnd, -(nextpc - (pc + 1))); + } + } else if (nextpc == pc + 1) { + // a single-byte instruction + sbuf.append((char) op); + } else { + // picky stuff + boolean wide = isWide[id]; + if (wide) { + sbuf.append((char) WIDE); + pc++; + } + sbuf.append((char) op); + int opnd1; + int opnd2 = opnd; + switch (op) { + case 0x84: //iinc + ins = insElems[id]; + opnd1 = (int) ins.getAttrLong("loc"); + if (isWide[id]) { + putInt(sbuf, opnd1, 2); + putInt(sbuf, opnd2, 2); + } else { + putInt(sbuf, opnd1, 1); + putInt(sbuf, opnd2, 1); + } + break; + case 0xc5: //multianewarray + ins = insElems[id]; + opnd1 = getCPIndex(ins, 'c', getCPI); + putInt(sbuf, opnd1, 2); + putInt(sbuf, opnd2, 1); + break; + case 0xb9: //invokeinterface + ins = insElems[id]; + opnd1 = getCPIndex(ins, 'n', getCPI); + putInt(sbuf, opnd1, 2); + opnd2 = (int) ins.getAttrLong("num"); + if (opnd2 == 0) { + opnd2 = ClassSyntax.computeInterfaceNum(ins.getAttr("val")); + } + putInt(sbuf, opnd2, 2); + break; + default: + // put the single operand and be done + putInt(sbuf, opnd, nextpc - (pc + 1)); + break; + } + } + } + assert (sbuf.length() == insLocs[insCount]); + + return sbuf.toString(); + } + + static int getCPIndex(Element ins, char ctype, + ClassSyntax.GetCPIndex getCPI) { + int x = (int) ins.getAttrLong("ref"); + if (x == 0 && getCPI != null) { + String val = ins.getAttr("val"); + if (val == null || val.equals("")) { + val = ins.getText().toString(); + } + byte tag; + switch (ctype) { + case 'k': + tag = (byte) ins.getAttrLong("tag"); + break; + case 'c': + tag = ClassSyntax.CONSTANT_Class; + break; + case 'f': + tag = ClassSyntax.CONSTANT_Fieldref; + break; + case 'm': + tag = ClassSyntax.CONSTANT_Methodref; + break; + case 'n': + tag = ClassSyntax.CONSTANT_InterfaceMethodref; + break; + default: + throw new Error("bad ctype " + ctype + " in " + ins); + } + x = getCPI.getCPIndex(tag, val); + //System.out.println("getCPIndex "+ins+" => "+tag+"/"+val+" => "+x); + } else { + assert (x > 0); + } + return x; + } + + static void putInt(StringBuffer sbuf, int x, int len) { + //System.out.println("putInt x="+x+" len="+len); + boolean isSigned = false; + if (len < 0) { + len = -len; + isSigned = true; + } + assert (len == 1 || len == 2 || len == 4); + int insig = ((4 - len) * 8); // how many insignificant bits? + int sx = x << insig; + ; + assert (x == (isSigned ? (sx >> insig) : (sx >>> insig))); + for (int i = 0; i < len; i++) { + sbuf.append((char) (sx >>> 24)); + sx <<= 8; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionSyntax.java Mon Aug 23 19:14:20 2010 -0700 @@ -0,0 +1,483 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- + +import xmlkit.XMLKit.Element; +import java.util.HashMap; +import java.util.Map; +/* + * @author jrose + */ +public abstract class InstructionSyntax { + + InstructionSyntax() { + } + static final String[] bcNames; + static final String[] bcFormats; + static final String[] bcWideFormats; + static final HashMap<String, Integer> bcCodes; + static final HashMap<String, Element> abbrevs; + static final HashMap<Element, String> rabbrevs; + + static { + TokenList tl = new TokenList( + " nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3" + + " iconst_4 iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2" + + " dconst_0 dconst_1 bipush/s sipush/ss ldc/k ldc_w/kk ldc2_w/kk" + + " iload/wl lload/wl fload/wl dload/wl aload/wl iload_0 iload_1" + + " iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1" + + " fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1" + + " aload_2 aload_3 iaload laload faload daload aaload baload caload" + + " saload istore/wl lstore/wl fstore/wl dstore/wl astore/wl" + + " istore_0 istore_1 istore_2 istore_3 lstore_0 lstore_1 lstore_2"