From d090606f367fc4683046c18443c669ff60a69193 Mon Sep 17 00:00:00 2001 From: James Melvin Date: Mon, 16 Apr 2012 18:09:53 -0400 Subject: [PATCH 01/20] 7130404: [macosx] "os.arch" value should be "x86_64" for compatibility with Apple JDK6 On Mac OS X, align system property "os.arch" with Apple legacy JDKs. Also, improve os.name string matching by using .contains() method instead of .startsWith(). This fix spans multiple repositories. Reviewed-by: dcubed, phh, ohair, katleman --- jdk/make/common/Defs-macosx.gmk | 12 ++++++------ jdk/make/common/shared/Platform.gmk | 4 ++-- .../java/net/AbstractPlainDatagramSocketImpl.java | 4 ++-- jdk/src/share/classes/java/nio/Bits.java | 4 ++-- .../share/classes/java/util/prefs/Preferences.java | 4 ++-- jdk/src/share/classes/sun/awt/OSInfo.java | 4 ++-- jdk/src/share/classes/sun/font/FontUtilities.java | 4 ++-- .../share/classes/sun/launcher/LauncherHelper.java | 4 ++-- .../classes/sun/nio/cs/ext/ExtendedCharsets.java | 4 ++-- jdk/src/share/classes/sun/print/PSPrinterJob.java | 4 ++-- .../sun/security/jgss/wrapper/SunNativeProvider.java | 4 ++-- jdk/src/share/classes/sun/security/krb5/Config.java | 4 ++-- .../share/classes/sun/security/krb5/Credentials.java | 6 +++--- .../sun/security/provider/ByteArrayAccess.java | 5 +++-- .../nio/ch/DefaultAsynchronousChannelProvider.java | 4 ++-- .../sun/nio/fs/DefaultFileSystemProvider.java | 4 ++-- .../classes/sun/print/UnixPrintServiceLookup.java | 4 ++-- jdk/test/demo/jvmti/DemoRun.java | 4 ++-- jdk/test/java/io/File/GetXSpace.java | 4 ++-- jdk/test/java/lang/ProcessBuilder/Basic.java | 4 ++-- jdk/test/java/lang/ProcessBuilder/Zombies.java | 4 ++-- jdk/test/java/lang/invoke/InvokeGenericTest.java | 4 ++-- .../OperatingSystemMXBean/GetSystemLoadAverage.java | 6 +++--- jdk/test/java/nio/channels/FileChannel/Size.java | 4 ++-- jdk/test/java/nio/channels/FileChannel/Transfer.java | 4 ++-- jdk/test/java/nio/file/FileSystem/Basic.java | 4 ++-- jdk/test/sun/nio/ch/SelProvider.java | 4 ++-- jdk/test/tools/launcher/TestHelper.java | 2 +- 28 files changed, 62 insertions(+), 61 deletions(-) diff --git a/jdk/make/common/Defs-macosx.gmk b/jdk/make/common/Defs-macosx.gmk index 53871ac1d5f..b3349db2711 100644 --- a/jdk/make/common/Defs-macosx.gmk +++ b/jdk/make/common/Defs-macosx.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -111,10 +111,10 @@ CC_OPT = $(CC_OPT/$(OPTIMIZATION_LEVEL)) # For all platforms, do not omit the frame pointer register usage. # We need this frame pointer to make it easy to walk the stacks. -# This should be the default on X86, but ia64 and amd64 may not have this -# as the default. -CFLAGS_REQUIRED_amd64 += -m64 -fno-omit-frame-pointer -D_LITTLE_ENDIAN -LDFLAGS_COMMON_amd64 += -m64 +# This should be the default on X86, but ia64, and x86_64 +# may not have this as the default. +CFLAGS_REQUIRED_x86_64 += -m64 -fno-omit-frame-pointer -D_LITTLE_ENDIAN +LDFLAGS_COMMON_x86_64 += -m64 CFLAGS_REQUIRED_i586 += -m32 -fno-omit-frame-pointer -D_LITTLE_ENDIAN LDFLAGS_COMMON_i586 += -m32 CFLAGS_REQUIRED_ia64 += -m64 -fno-omit-frame-pointer -D_LITTLE_ENDIAN @@ -168,7 +168,7 @@ PIC_CODE_LARGE = -fPIC PIC_CODE_SMALL = -fpic GLOBAL_KPIC = $(PIC_CODE_LARGE) CFLAGS_COMMON += $(GLOBAL_KPIC) $(GCC_WARNINGS) -ifeq ($(ARCH), amd64) +ifeq ($(ARCH), x86_64) CFLAGS_COMMON += -pipe endif diff --git a/jdk/make/common/shared/Platform.gmk b/jdk/make/common/shared/Platform.gmk index 618fa0bec46..49e6cbda78e 100644 --- a/jdk/make/common/shared/Platform.gmk +++ b/jdk/make/common/shared/Platform.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -264,7 +264,7 @@ ifeq ($(PLATFORM), macosx) echo sparc \ ;; \ x86_64) \ - echo amd64 \ + echo x86_64 \ ;; \ universal) \ echo universal \ diff --git a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java index 71e329a84e0..3b9f531c08d 100644 --- a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java +++ b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl /** * flag set if the native connect() call not to be used */ - private final static boolean connectDisabled = os.startsWith("Mac OS"); + private final static boolean connectDisabled = os.contains("OS X"); /** * Load net library into runtime. diff --git a/jdk/src/share/classes/java/nio/Bits.java b/jdk/src/share/classes/java/nio/Bits.java index 5f1eabe7336..11f2b6d0083 100644 --- a/jdk/src/share/classes/java/nio/Bits.java +++ b/jdk/src/share/classes/java/nio/Bits.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -609,7 +609,7 @@ class Bits { // package-private String arch = AccessController.doPrivileged( new sun.security.action.GetPropertyAction("os.arch")); unaligned = arch.equals("i386") || arch.equals("x86") - || arch.equals("amd64"); + || arch.equals("amd64") || arch.equals("x86_64"); unalignedKnown = true; return unaligned; } diff --git a/jdk/src/share/classes/java/util/prefs/Preferences.java b/jdk/src/share/classes/java/util/prefs/Preferences.java index 391439cbfa1..781b95ae446 100644 --- a/jdk/src/share/classes/java/util/prefs/Preferences.java +++ b/jdk/src/share/classes/java/util/prefs/Preferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -293,7 +293,7 @@ public abstract class Preferences { String platformFactory; if (osName.startsWith("Windows")) { platformFactory = "java.util.prefs.WindowsPreferencesFactory"; - } else if (osName.startsWith("Mac OS X")) { + } else if (osName.contains("OS X")) { platformFactory = "java.util.prefs.MacOSXPreferencesFactory"; } else { platformFactory = "java.util.prefs.FileSystemPreferencesFactory"; diff --git a/jdk/src/share/classes/sun/awt/OSInfo.java b/jdk/src/share/classes/sun/awt/OSInfo.java index 58dd6cc1fd0..4a515a1734c 100644 --- a/jdk/src/share/classes/sun/awt/OSInfo.java +++ b/jdk/src/share/classes/sun/awt/OSInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ public class OSInfo { return SOLARIS; } - if (osName.startsWith("Mac OS X")) { + if (osName.contains("OS X")) { return MACOSX; } diff --git a/jdk/src/share/classes/sun/font/FontUtilities.java b/jdk/src/share/classes/sun/font/FontUtilities.java index fd1adcc9c98..2284c11714a 100644 --- a/jdk/src/share/classes/sun/font/FontUtilities.java +++ b/jdk/src/share/classes/sun/font/FontUtilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,7 +78,7 @@ public final class FontUtilities { isLinux = osName.startsWith("Linux"); - isMacOSX = osName.startsWith("Mac OS X"); // TODO: MacOSX + isMacOSX = osName.contains("OS X"); // TODO: MacOSX String t2kStr = System.getProperty("sun.java2d.font.scaler"); if (t2kStr != null) { diff --git a/jdk/src/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/share/classes/sun/launcher/LauncherHelper.java index 233704c3b01..06c64f8ed50 100644 --- a/jdk/src/share/classes/sun/launcher/LauncherHelper.java +++ b/jdk/src/share/classes/sun/launcher/LauncherHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -381,7 +381,7 @@ public enum LauncherHelper { PrintStream ostream = (printToStderr) ? System.err : System.out; ostream.println(getLocalizedMessage("java.launcher.X.usage", File.pathSeparator)); - if (System.getProperty("os.name").startsWith("Mac OS")) { + if (System.getProperty("os.name").contains("OS X")) { ostream.println(getLocalizedMessage("java.launcher.X.macosx.usage", File.pathSeparator)); } diff --git a/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java b/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java index ebf55b206ce..299db8fd7c4 100644 --- a/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java +++ b/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1280,7 +1280,7 @@ public class ExtendedCharsets String osName = AccessController.doPrivileged( new GetPropertyAction("os.name")); if ("SunOS".equals(osName) || "Linux".equals(osName) - || osName.startsWith("Mac OS")) { + || osName.contains("OS X")) { charset("x-COMPOUND_TEXT", "COMPOUND_TEXT", new String[] { "COMPOUND_TEXT", // JDK historical diff --git a/jdk/src/share/classes/sun/print/PSPrinterJob.java b/jdk/src/share/classes/sun/print/PSPrinterJob.java index 49584f2f8a2..99f88f356c4 100644 --- a/jdk/src/share/classes/sun/print/PSPrinterJob.java +++ b/jdk/src/share/classes/sun/print/PSPrinterJob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1567,7 +1567,7 @@ public class PSPrinterJob extends RasterPrinterJob { } String osname = System.getProperty("os.name"); - if (osname.equals("Linux") || osname.startsWith("Mac OS X")) { + if (osname.equals("Linux") || osname.contains("OS X")) { execCmd = new String[ncomps]; execCmd[n++] = "/usr/bin/lpr"; if ((pFlags & PRINTER) != 0) { diff --git a/jdk/src/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java b/jdk/src/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java index a6280121420..1c869ade651 100644 --- a/jdk/src/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java +++ b/jdk/src/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,7 +90,7 @@ public final class SunNativeProvider extends Provider { "libgssapi_krb5.so", "libgssapi_krb5.so.2", }; - } else if (osname.startsWith("Mac OS X")) { + } else if (osname.contains("OS X")) { gssLibs = new String[]{ "/usr/lib/sasl2/libgssapiv2.2.so", }; diff --git a/jdk/src/share/classes/sun/security/krb5/Config.java b/jdk/src/share/classes/sun/security/krb5/Config.java index 8c0cc628029..61a3c7c129f 100644 --- a/jdk/src/share/classes/sun/security/krb5/Config.java +++ b/jdk/src/share/classes/sun/security/krb5/Config.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -737,7 +737,7 @@ public class Config { } } else if (osname.startsWith("SunOS")) { name = "/etc/krb5/krb5.conf"; - } else if (osname.startsWith("Mac")) { + } else if (osname.contains("OS X")) { if (isMacosLionOrBetter()) return ""; name = findMacosConfigFile(); } else { diff --git a/jdk/src/share/classes/sun/security/krb5/Credentials.java b/jdk/src/share/classes/sun/security/krb5/Credentials.java index 3414e2f6e72..1451910c5cf 100644 --- a/jdk/src/share/classes/sun/security/krb5/Credentials.java +++ b/jdk/src/share/classes/sun/security/krb5/Credentials.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -289,7 +289,7 @@ public class Credentials { String os = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("os.name")); if (os.toUpperCase(Locale.ENGLISH).startsWith("WINDOWS") || - os.toUpperCase(Locale.ENGLISH).startsWith("MAC")) { + os.toUpperCase(Locale.ENGLISH).contains("OS X")) { Credentials creds = acquireDefaultCreds(); if (creds == null) { if (DEBUG) { @@ -478,7 +478,7 @@ public class Credentials { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction () { public Void run() { - if (System.getProperty("os.name").startsWith("Mac")) { + if (System.getProperty("os.name").contains("OS X")) { System.loadLibrary("osxkrb5"); } else { System.loadLibrary("w2k_lsa_auth"); diff --git a/jdk/src/share/classes/sun/security/provider/ByteArrayAccess.java b/jdk/src/share/classes/sun/security/provider/ByteArrayAccess.java index 5b6f8bfaa93..1c7641372ab 100644 --- a/jdk/src/share/classes/sun/security/provider/ByteArrayAccess.java +++ b/jdk/src/share/classes/sun/security/provider/ByteArrayAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,8 @@ final class ByteArrayAccess { private static boolean unaligned() { String arch = java.security.AccessController.doPrivileged (new sun.security.action.GetPropertyAction("os.arch", "")); - return arch.equals("i386") || arch.equals("x86") || arch.equals("amd64"); + return arch.equals("i386") || arch.equals("x86") || arch.equals("amd64") + || arch.equals("x86_64"); } /** diff --git a/jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java index 9767c7ced9a..3efecaacac9 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java +++ b/jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ public class DefaultAsynchronousChannelProvider { return new SolarisAsynchronousChannelProvider(); if (osname.equals("Linux")) return new LinuxAsynchronousChannelProvider(); - if (osname.startsWith("Mac OS")) + if (osname.contains("OS X")) return new BsdAsynchronousChannelProvider(); throw new InternalError("platform not recognized"); } diff --git a/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java index 2605e1d6d44..9f8d479831e 100644 --- a/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java +++ b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,7 @@ public class DefaultFileSystemProvider { return createProvider("sun.nio.fs.SolarisFileSystemProvider"); if (osname.equals("Linux")) return createProvider("sun.nio.fs.LinuxFileSystemProvider"); - if (osname.equals("Darwin") || osname.startsWith("Mac OS X")) + if (osname.equals("Darwin") || osname.contains("OS X")) return createProvider("sun.nio.fs.BsdFileSystemProvider"); throw new AssertionError("Platform not recognized"); } diff --git a/jdk/src/solaris/classes/sun/print/UnixPrintServiceLookup.java b/jdk/src/solaris/classes/sun/print/UnixPrintServiceLookup.java index c1de9bc1849..7f402865d2b 100644 --- a/jdk/src/solaris/classes/sun/print/UnixPrintServiceLookup.java +++ b/jdk/src/solaris/classes/sun/print/UnixPrintServiceLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,7 +120,7 @@ public class UnixPrintServiceLookup extends PrintServiceLookup static boolean isBSD() { return (osname.equals("Linux") || - osname.startsWith("Mac OS X")); + osname.contains("OS X")); } static final int UNINITIALIZED = -1; diff --git a/jdk/test/demo/jvmti/DemoRun.java b/jdk/test/demo/jvmti/DemoRun.java index 9038507df90..9a0ec96f20f 100644 --- a/jdk/test/demo/jvmti/DemoRun.java +++ b/jdk/test/demo/jvmti/DemoRun.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,7 @@ public class DemoRun { String os_name = System.getProperty("os.name"); String libprefix = os_name.contains("Windows")?"":"lib"; String libsuffix = os_name.contains("Windows")?".dll": - os_name.startsWith("Mac OS")?".dylib":".so"; + os_name.contains("OS X")?".dylib":".so"; boolean d64 = ( os_name.contains("Solaris") || os_name.contains("SunOS") ) && ( os_arch.equals("sparcv9") || diff --git a/jdk/test/java/io/File/GetXSpace.java b/jdk/test/java/io/File/GetXSpace.java index 9276ef5a55c..e9aed50bbed 100644 --- a/jdk/test/java/io/File/GetXSpace.java +++ b/jdk/test/java/io/File/GetXSpace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ public class GetXSpace { private static final String dfFormat; static { if (name.equals("SunOS") || name.equals("Linux") - || name.startsWith("Mac OS")) { + || name.contains("OS X")) { // FileSystem Total Used Available Use% MountedOn dfFormat = "([^\\s]+)\\s+(\\d+)\\s+\\d+\\s+(\\d+)\\s+\\d+%\\s+([^\\s]+)"; } else if (name.startsWith("Windows")) { diff --git a/jdk/test/java/lang/ProcessBuilder/Basic.java b/jdk/test/java/lang/ProcessBuilder/Basic.java index 4397c2ce8ff..b3aa3087495 100644 --- a/jdk/test/java/lang/ProcessBuilder/Basic.java +++ b/jdk/test/java/lang/ProcessBuilder/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -597,7 +597,7 @@ public class Basic { static class MacOSX { public static boolean is() { return is; } private static final String osName = System.getProperty("os.name"); - private static final boolean is = osName.startsWith("Mac OS"); + private static final boolean is = osName.contains("OS X"); } static class True { diff --git a/jdk/test/java/lang/ProcessBuilder/Zombies.java b/jdk/test/java/lang/ProcessBuilder/Zombies.java index 210d831667a..f8c3b627dd8 100644 --- a/jdk/test/java/lang/ProcessBuilder/Zombies.java +++ b/jdk/test/java/lang/ProcessBuilder/Zombies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ public class Zombies { static final String os = System.getProperty("os.name"); - static final String TrueCommand = os.startsWith("Mac OS")? + static final String TrueCommand = os.contains("OS X")? "/usr/bin/true" : "/bin/true"; public static void main(String[] args) throws Throwable { diff --git a/jdk/test/java/lang/invoke/InvokeGenericTest.java b/jdk/test/java/lang/invoke/InvokeGenericTest.java index b95a5d34f8a..b54ec5ec472 100644 --- a/jdk/test/java/lang/invoke/InvokeGenericTest.java +++ b/jdk/test/java/lang/invoke/InvokeGenericTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ public class InvokeGenericTest { String name = properties.getProperty("java.vm.name"); String arch = properties.getProperty("os.arch"); if ((arch.equals("amd64") || arch.equals("i386") || arch.equals("x86") || - arch.equals("sparc") || arch.equals("sparcv9")) && + arch.equals("x86_64") || arch.equals("sparc") || arch.equals("sparcv9")) && (name.contains("Client") || name.contains("Server")) ) { platformOK = true; diff --git a/jdk/test/java/lang/management/OperatingSystemMXBean/GetSystemLoadAverage.java b/jdk/test/java/lang/management/OperatingSystemMXBean/GetSystemLoadAverage.java index 882c9b32124..6018befc589 100644 --- a/jdk/test/java/lang/management/OperatingSystemMXBean/GetSystemLoadAverage.java +++ b/jdk/test/java/lang/management/OperatingSystemMXBean/GetSystemLoadAverage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,7 @@ public class GetSystemLoadAverage { } private static String LOAD_AVERAGE_TEXT - = System.getProperty("os.name").startsWith("Mac OS") + = System.getProperty("os.name").contains("OS X") ? "load averages:" : "load average:"; @@ -99,7 +99,7 @@ public class GetSystemLoadAverage { System.out.println("Load average returned from uptime = " + output); System.out.println("getSystemLoadAverage() returned " + loadavg); - String[] lavg = System.getProperty("os.name").startsWith("Mac OS") + String[] lavg = System.getProperty("os.name").contains("OS X") ? output.split(" ") : output.split(","); double expected = Double.parseDouble(lavg[0]); diff --git a/jdk/test/java/nio/channels/FileChannel/Size.java b/jdk/test/java/nio/channels/FileChannel/Size.java index ffa0720b9fd..d17ed6b70f4 100644 --- a/jdk/test/java/nio/channels/FileChannel/Size.java +++ b/jdk/test/java/nio/channels/FileChannel/Size.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ public class Size { // Windows and Linux can't handle the really large file sizes for a truncate // or a positional write required by the test for 4563125 String osName = System.getProperty("os.name"); - if (osName.startsWith("SunOS") || osName.startsWith("Mac OS")) { + if (osName.startsWith("SunOS") || osName.contains("OS X")) { blah = File.createTempFile("blah", null); long testSize = ((long)Integer.MAX_VALUE) * 2; initTestFile(blah, 10); diff --git a/jdk/test/java/nio/channels/FileChannel/Transfer.java b/jdk/test/java/nio/channels/FileChannel/Transfer.java index 0e18f54d726..e9524be7b5f 100644 --- a/jdk/test/java/nio/channels/FileChannel/Transfer.java +++ b/jdk/test/java/nio/channels/FileChannel/Transfer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -228,7 +228,7 @@ public class Transfer { // Windows and Linux can't handle the really large file sizes for a // truncate or a positional write required by the test for 4563125 String osName = System.getProperty("os.name"); - if (!(osName.startsWith("SunOS") || osName.startsWith("Mac OS"))) + if (!(osName.startsWith("SunOS") || osName.contains("OS X"))) return; File source = File.createTempFile("blah", null); source.deleteOnExit(); diff --git a/jdk/test/java/nio/file/FileSystem/Basic.java b/jdk/test/java/nio/file/FileSystem/Basic.java index a2ff3bf3587..89903611b4f 100644 --- a/jdk/test/java/nio/file/FileSystem/Basic.java +++ b/jdk/test/java/nio/file/FileSystem/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ public class Basic { checkSupported(fs, "posix", "unix", "owner", "acl", "user"); if (os.equals("Linux")) checkSupported(fs, "posix", "unix", "owner", "dos", "user"); - if (os.startsWith("Mac OS")) + if (os.contains("OS X")) checkSupported(fs, "posix", "unix", "owner"); if (os.equals("Windows")) checkSupported(fs, "owner", "dos", "acl", "user"); diff --git a/jdk/test/sun/nio/ch/SelProvider.java b/jdk/test/sun/nio/ch/SelProvider.java index cae745f5b78..d0682b6f288 100644 --- a/jdk/test/sun/nio/ch/SelProvider.java +++ b/jdk/test/sun/nio/ch/SelProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2012 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ public class SelProvider { expected = "sun.nio.ch.DevPollSelectorProvider"; } else if ("Linux".equals(osname)) { expected = "sun.nio.ch.EPollSelectorProvider"; - } else if (osname.startsWith("Mac OS")) { + } else if (osname.contains("OS X")) { expected = "sun.nio.ch.KQueueSelectorProvider"; } else return; diff --git a/jdk/test/tools/launcher/TestHelper.java b/jdk/test/tools/launcher/TestHelper.java index 445efcec3a6..e0e50c92466 100644 --- a/jdk/test/tools/launcher/TestHelper.java +++ b/jdk/test/tools/launcher/TestHelper.java @@ -66,7 +66,7 @@ public class TestHelper { static final boolean isWindows = System.getProperty("os.name", "unknown").startsWith("Windows"); static final boolean isMacOSX = - System.getProperty("os.name", "unknown").startsWith("Mac"); + System.getProperty("os.name", "unknown").contains("OS X"); static final boolean is64Bit = System.getProperty("sun.arch.data.model").equals("64"); static final boolean is32Bit = From 5befb6f577d7f2127534e74d89308ea1ab4db938 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Thu, 19 Apr 2012 14:05:07 +0100 Subject: [PATCH 02/20] 7162262: (fs) Typo in java.nio.file.Path class description Reviewed-by: alanb --- jdk/src/share/classes/java/nio/file/Path.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/nio/file/Path.java b/jdk/src/share/classes/java/nio/file/Path.java index 92cd1f9661e..afe07a387d6 100644 --- a/jdk/src/share/classes/java/nio/file/Path.java +++ b/jdk/src/share/classes/java/nio/file/Path.java @@ -54,7 +54,7 @@ import java.util.Iterator; * resolveSibling} methods to combine paths. The {@link #relativize relativize} * method that can be used to construct a relative path between two paths. * Paths can be {@link #compareTo compared}, and tested against each other using - * the {@link #startsWith startsWith} and {@link #endsWith endWith} methods. + * the {@link #startsWith startsWith} and {@link #endsWith endsWith} methods. * *

This interface extends {@link Watchable} interface so that a directory * located by a path can be {@link #register registered} with a {@link From a7c87287046d7a11d7b79d9339d60a7f35a0280e Mon Sep 17 00:00:00 2001 From: Vinnie Ryan Date: Thu, 19 Apr 2012 16:58:34 +0100 Subject: [PATCH 03/20] 7162823: Modify the list of excluded tests (ProblemList Reviewed-by: alanb --- jdk/test/ProblemList.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 1980d033038..79c53f580db 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -286,13 +286,13 @@ com/sun/org/apache/xml/internal/security/transforms/ClassLoaderTest.java generic # Failing on Solaris i586, 3/9/2010, not a -samevm issue (jdk_security3) sun/security/pkcs11/Secmod/AddPrivateKey.java solaris-i586 -sun/security/pkcs11/ec/ReadCertificates.java solaris-i586 -sun/security/pkcs11/ec/ReadPKCS12.java solaris-i586 +sun/security/pkcs11/ec/ReadCertificates.java generic-all +sun/security/pkcs11/ec/ReadPKCS12.java generic-all sun/security/pkcs11/ec/TestCurves.java solaris-i586 sun/security/pkcs11/ec/TestECDSA.java solaris-i586 #sun/security/pkcs11/ec/TestECGenSpec.java solaris-i586 #sun/security/pkcs11/ec/TestKeyFactory.java solaris-i586 -sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java solaris-i586 +sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java generic-all # Fails on Fedora 9/Ubuntu 10.04 64bit, PKCS11Exception: CKR_DEVICE_ERROR sun/security/pkcs11/KeyAgreement/TestDH.java generic-all From 4f6ca7513e4ccd7347e7f52a237962028cd5252d Mon Sep 17 00:00:00 2001 From: Kurchi Subhra Hazra Date: Thu, 19 Apr 2012 13:26:06 -0700 Subject: [PATCH 04/20] 7162385: TEST_BUG: sun/net/www/protocol/jar/B4957695.java failing again Enable finding "foo1.jar" Reviewed-by: chegar --- jdk/test/sun/net/www/protocol/jar/B4957695.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/test/sun/net/www/protocol/jar/B4957695.java b/jdk/test/sun/net/www/protocol/jar/B4957695.java index 0d25825f0cc..3ab0f0c7562 100644 --- a/jdk/test/sun/net/www/protocol/jar/B4957695.java +++ b/jdk/test/sun/net/www/protocol/jar/B4957695.java @@ -62,7 +62,8 @@ public class B4957695 { readOneRequest(s.getInputStream()); try (OutputStreamWriter ow = new OutputStreamWriter((s.getOutputStream()))) { - FileInputStream fin = new FileInputStream("foo1.jar"); + FileInputStream fin = new FileInputStream(new File( + System.getProperty("test.src", "."), "foo1.jar")); int length = fin.available(); byte[] b = new byte[length-10]; fin.read(b, 0, length-10); From 0590a1ea49c8a872ae070c88ec901234dfab224c Mon Sep 17 00:00:00 2001 From: Kurchi Subhra Hazra Date: Thu, 19 Apr 2012 18:11:28 -0700 Subject: [PATCH 05/20] 7158636: InterfaceAddress.getBroadcast() returns invalid broadcast address on WLAN Update Windows native code to infer WLAN interface type in Windows Vista and later Reviewed-by: chegar, alanb --- .../native/java/net/NetworkInterface.c | 22 ++++++++++++------- .../native/java/net/NetworkInterface.h | 5 +++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/jdk/src/windows/native/java/net/NetworkInterface.c b/jdk/src/windows/native/java/net/NetworkInterface.c index d6b04886975..8dbeb925029 100644 --- a/jdk/src/windows/native/java/net/NetworkInterface.c +++ b/jdk/src/windows/native/java/net/NetworkInterface.c @@ -178,7 +178,7 @@ int enumInterfaces(JNIEnv *env, netif **netifPP) int count; netif *netifP; DWORD i; - int lo=0, eth=0, tr=0, fddi=0, ppp=0, sl=0, net=0; + int lo=0, eth=0, tr=0, fddi=0, ppp=0, sl=0, wlan=0, net=0; /* * Ask the IP Helper library to enumerate the adapters @@ -218,15 +218,15 @@ int enumInterfaces(JNIEnv *env, netif **netifPP) */ switch (ifrowP->dwType) { case MIB_IF_TYPE_ETHERNET: - sprintf(dev_name, "eth%d", eth++); + _snprintf_s(dev_name, 8, _TRUNCATE, "eth%d", eth++); break; case MIB_IF_TYPE_TOKENRING: - sprintf(dev_name, "tr%d", tr++); + _snprintf_s(dev_name, 8, _TRUNCATE, "tr%d", tr++); break; case MIB_IF_TYPE_FDDI: - sprintf(dev_name, "fddi%d", fddi++); + _snprintf_s(dev_name, 8, _TRUNCATE, "fddi%d", fddi++); break; case MIB_IF_TYPE_LOOPBACK: @@ -234,20 +234,24 @@ int enumInterfaces(JNIEnv *env, netif **netifPP) if (lo > 0) { continue; } - strcpy(dev_name, "lo"); + strncpy_s(dev_name, 8, "lo", _TRUNCATE); lo++; break; case MIB_IF_TYPE_PPP: - sprintf(dev_name, "ppp%d", ppp++); + _snprintf_s(dev_name, 8, _TRUNCATE, "ppp%d", ppp++); break; case MIB_IF_TYPE_SLIP: - sprintf(dev_name, "sl%d", sl++); + _snprintf_s(dev_name, 8, _TRUNCATE, "sl%d", sl++); + break; + + case IF_TYPE_IEEE80211: + _snprintf_s(dev_name, 8, _TRUNCATE, "wlan%d", wlan++); break; default: - sprintf(dev_name, "net%d", net++); + _snprintf_s(dev_name, 8, _TRUNCATE, "net%d", net++); } /* @@ -382,6 +386,7 @@ int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP) case MIB_IF_TYPE_TOKENRING: case MIB_IF_TYPE_FDDI: case MIB_IF_TYPE_LOOPBACK: + case IF_TYPE_IEEE80211: /** * Contrary to what it seems to indicate, dwBCastAddr doesn't * contain the broadcast address but 0 or 1 depending on whether @@ -928,6 +933,7 @@ JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0 case MIB_IF_TYPE_ETHERNET: case MIB_IF_TYPE_TOKENRING: case MIB_IF_TYPE_FDDI: + case IF_TYPE_IEEE80211: len = ifRowP->dwPhysAddrLen; ret = (*env)->NewByteArray(env, len); if (!IS_NULL(ret)) { diff --git a/jdk/src/windows/native/java/net/NetworkInterface.h b/jdk/src/windows/native/java/net/NetworkInterface.h index 262e15a0db0..2f977fd624b 100644 --- a/jdk/src/windows/native/java/net/NetworkInterface.h +++ b/jdk/src/windows/native/java/net/NetworkInterface.h @@ -89,4 +89,9 @@ extern jfieldID ni_ibmaskID; /* InterfaceAddress.maskLength */ int enumInterfaces(JNIEnv *env, netif **netifPP); +// Windows Visa (and later) only..... +#ifndef IF_TYPE_IEEE80211 +#define IF_TYPE_IEEE80211 71 +#endif + #endif From c354b234a4f6980320b773859b4187921bd8fa9c Mon Sep 17 00:00:00 2001 From: Sean Chou Date: Fri, 20 Apr 2012 16:11:28 +0800 Subject: [PATCH 06/20] 7159982: ZipFile uses static for error message when malformed zip file encountered Reviewed-by: alanb, dholmes --- jdk/src/share/native/java/util/zip/ZipFile.c | 1 + jdk/src/share/native/java/util/zip/zip_util.c | 31 ++++++++++++------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/jdk/src/share/native/java/util/zip/ZipFile.c b/jdk/src/share/native/java/util/zip/ZipFile.c index 99d6d229f89..281dbc628fa 100644 --- a/jdk/src/share/native/java/util/zip/ZipFile.c +++ b/jdk/src/share/native/java/util/zip/ZipFile.c @@ -117,6 +117,7 @@ Java_java_util_zip_ZipFile_open(JNIEnv *env, jclass cls, jstring name, result = ptr_to_jlong(zip); } else if (msg != 0) { ThrowZipException(env, msg); + free(msg); } else if (errno == ENOMEM) { JNU_ThrowOutOfMemoryError(env, 0); } else { diff --git a/jdk/src/share/native/java/util/zip/zip_util.c b/jdk/src/share/native/java/util/zip/zip_util.c index 991ed5c0123..9bffd3461e5 100644 --- a/jdk/src/share/native/java/util/zip/zip_util.c +++ b/jdk/src/share/native/java/util/zip/zip_util.c @@ -726,7 +726,7 @@ readCEN(jzfile *zip, jint knownTotal) * Opens a zip file with the specified mode. Returns the jzfile object * or NULL if an error occurred. If a zip error occurred then *pmsg will * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be - * set to NULL. + * set to NULL. Caller is responsible to free the error message. */ jzfile * ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified) @@ -751,12 +751,12 @@ ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified) * Returns the jzfile corresponding to the given file name from the cache of * zip files, or NULL if the file is not in the cache. If the name is longer * than PATH_MAX or a zip error occurred then *pmsg will be set to the error - * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. + * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller + * is responsible to free the error message. */ jzfile * ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified) { - static char errbuf[256]; char buf[PATH_MAX]; jzfile *zip; @@ -771,7 +771,7 @@ ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified) if (strlen(name) >= PATH_MAX) { if (pmsg) { - *pmsg = "zip file name too long"; + *pmsg = strdup("zip file name too long"); } return NULL; } @@ -796,7 +796,8 @@ ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified) * Reads data from the given file descriptor to create a jzfile, puts the * jzfile in a cache, and returns that jzfile. Returns NULL in case of error. * If a zip error occurs, then *pmsg will be set to the error message text if - * pmsg != 0. Otherwise, *pmsg will be set to NULL. + * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to + * free the error message. */ jzfile * @@ -809,7 +810,7 @@ jzfile * ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, jboolean usemmap) { - static char errbuf[256]; + char errbuf[256]; jlong len; jzfile *zip; @@ -825,7 +826,7 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, if (zfd == -1) { if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) - *pmsg = errbuf; + *pmsg = strdup(errbuf); freeZip(zip); return NULL; } @@ -834,11 +835,11 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, if (len <= 0) { if (len == 0) { /* zip file is empty */ if (pmsg) { - *pmsg = "zip file is empty"; + *pmsg = strdup("zip file is empty"); } } else { /* error */ if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) - *pmsg = errbuf; + *pmsg = strdup(errbuf); } ZFILE_Close(zfd); freeZip(zip); @@ -850,7 +851,8 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, /* An error occurred while trying to read the zip file */ if (pmsg != 0) { /* Set the zip error message */ - *pmsg = zip->msg; + if (zip->msg != NULL) + *pmsg = strdup(zip->msg); } freeZip(zip); return NULL; @@ -867,12 +869,17 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, * Opens a zip file for reading. Returns the jzfile object or NULL * if an error occurred. If a zip error occurred then *msg will be * set to the error message text if msg != 0. Otherwise, *msg will be - * set to NULL. + * set to NULL. Caller doesn't need to free the error message. */ jzfile * JNICALL ZIP_Open(const char *name, char **pmsg) { - return ZIP_Open_Generic(name, pmsg, O_RDONLY, 0); + jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0); + if (file == NULL && pmsg != NULL && *pmsg != NULL) { + free(*pmsg); + *pmsg = "Zip file open error"; + } + return file; } /* From b0c273a9b8b56c432c64a16eb2d3f38c58c7df7a Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Sun, 22 Apr 2012 06:54:38 -0700 Subject: [PATCH 07/20] 6981776: Pack200 must support -target 7 bytecodes Pack200 implementation of JSR-200 updated for JSR-292 changes Co-authored-by: John Rose Reviewed-by: jrose, ksrini --- .../com/sun/java/util/jar/pack/Attribute.java | 46 +- .../sun/java/util/jar/pack/BandStructure.java | 67 +- .../sun/java/util/jar/pack/ClassReader.java | 129 +- .../sun/java/util/jar/pack/ClassWriter.java | 49 +- .../sun/java/util/jar/pack/ConstantPool.java | 512 ++++- .../com/sun/java/util/jar/pack/Constants.java | 49 +- .../sun/java/util/jar/pack/Instruction.java | 18 +- .../com/sun/java/util/jar/pack/Package.java | 57 +- .../sun/java/util/jar/pack/PackageReader.java | 180 +- .../sun/java/util/jar/pack/PackageWriter.java | 158 +- .../com/sun/java/util/jar/pack/TLGlobals.java | 30 +- .../com/sun/java/util/jar/pack/Utils.java | 43 +- .../com/sun/java/util/jar/pack/bands.cpp | 33 +- .../native/com/sun/java/util/jar/pack/bands.h | 24 +- .../com/sun/java/util/jar/pack/constants.h | 130 +- .../com/sun/java/util/jar/pack/defines.h | 5 +- .../com/sun/java/util/jar/pack/unpack.cpp | 606 ++++-- .../com/sun/java/util/jar/pack/unpack.h | 41 +- jdk/test/tools/pack200/AttributeTests.java | 36 +- .../tools/pack200/PackageVersionTest.java | 10 +- jdk/test/tools/pack200/Utils.java | 14 +- jdk/test/tools/pack200/dyn.jar | Bin 1963 -> 0 bytes .../pack200/pack200-verifier/data/README | 21 +- .../pack200/pack200-verifier/data/golden.jar | Bin 418156 -> 423427 bytes .../pack200/pack200-verifier/make/build.xml | 6 +- .../src/xmlkit/ClassReader.java | 1866 +++++++++++------ .../src/xmlkit/ClassSyntax.java | 518 ----- .../src/xmlkit/ClassWriter.java | 818 -------- .../src/xmlkit/InstructionAssembler.java | 464 ---- .../src/xmlkit/InstructionSyntax.java | 483 ----- 30 files changed, 2928 insertions(+), 3485 deletions(-) delete mode 100644 jdk/test/tools/pack200/dyn.jar delete mode 100644 jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java delete mode 100644 jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java delete mode 100644 jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java delete mode 100644 jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionSyntax.java diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java index 164870e4a82..5cf2456bdf1 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -166,6 +166,7 @@ class Attribute implements Comparable { define(sd, ATTR_CONTEXT_CLASS, "SourceFile", "RUH"); define(sd, ATTR_CONTEXT_CLASS, "EnclosingMethod", "RCHRDNH"); define(sd, ATTR_CONTEXT_CLASS, "InnerClasses", "NH[RCHRCNHRUNHFH]"); + define(sd, ATTR_CONTEXT_CLASS, "BootstrapMethods", "NH[RMHNH[KLH]]"); define(sd, ATTR_CONTEXT_FIELD, "Signature", "RSH"); define(sd, ATTR_CONTEXT_FIELD, "Synthetic", ""); @@ -203,6 +204,8 @@ class Attribute implements Comparable { // Their layout specs. are given here for completeness. // The Code spec is incomplete, in that it does not distinguish // bytecode bytes or locate CP references. + // The BootstrapMethods attribute is also special-cased + // elsewhere as an appendix to the local constant pool. } // Metadata. @@ -822,9 +825,9 @@ class Attribute implements Comparable { reference_type: ( constant_ref | schema_ref | utf8_ref | untyped_ref ) constant_ref: - ( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' ) + ( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' | 'KM' | 'KT' | 'KL' ) schema_ref: - ( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' ) + ( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' | 'RY' | 'RB' | 'RN' ) utf8_ref: 'RU' untyped_ref: @@ -1012,7 +1015,12 @@ class Attribute implements Comparable { case 'F': e.refKind = CONSTANT_Float; break; case 'D': e.refKind = CONSTANT_Double; break; case 'S': e.refKind = CONSTANT_String; break; - case 'Q': e.refKind = CONSTANT_Literal; break; + case 'Q': e.refKind = CONSTANT_FieldSpecific; break; + + // new in 1.7: + case 'M': e.refKind = CONSTANT_MethodHandle; break; + case 'T': e.refKind = CONSTANT_MethodType; break; + case 'L': e.refKind = CONSTANT_LoadableValue; break; default: { i = -i; continue; } // fail } break; @@ -1029,6 +1037,11 @@ class Attribute implements Comparable { case 'U': e.refKind = CONSTANT_Utf8; break; //utf8_ref case 'Q': e.refKind = CONSTANT_All; break; //untyped_ref + // new in 1.7: + case 'Y': e.refKind = CONSTANT_InvokeDynamic; break; + case 'B': e.refKind = CONSTANT_BootstrapMethod; break; + case 'N': e.refKind = CONSTANT_AnyMember; break; + default: { i = -i; continue; } // fail } break; @@ -1279,10 +1292,12 @@ class Attribute implements Comparable { // Cf. ClassReader.readSignatureRef. String typeName = globalRef.stringValue(); globalRef = ConstantPool.getSignatureEntry(typeName); - } else if (e.refKind == CONSTANT_Literal) { + } else if (e.refKind == CONSTANT_FieldSpecific) { assert(globalRef.getTag() >= CONSTANT_Integer); - assert(globalRef.getTag() <= CONSTANT_String); - } else if (e.refKind != CONSTANT_All) { + assert(globalRef.getTag() <= CONSTANT_String || + globalRef.getTag() >= CONSTANT_MethodHandle); + assert(globalRef.getTag() <= CONSTANT_MethodType); + } else if (e.refKind < CONSTANT_GroupFirst) { assert(e.refKind == globalRef.getTag()); } } @@ -1462,27 +1477,29 @@ class Attribute implements Comparable { "NH[PHPOHIIH]", // CharacterRangeTable "NH[PHHII]", // CoverageTable "NH[RCHRCNHRUNHFH]", // InnerClasses + "NH[RMHNH[KLH]]", // BootstrapMethods "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]", // Code "=AnnotationDefault", // Like metadata, but with a compact tag set: "[NH[(1)]]" - +"[NH[(2)]]" - +"[RSHNH[RUH(3)]]" - +"[TB(0,1,3)[KIH](2)[KDH](5)[KFH](4)[KJH](7)[RSH](8)[RSHRUH](9)[RUH](10)[(2)](6)[NH[(3)]]()[]]", + +"[NH[(1)]]" + +"[RSHNH[RUH(1)]]" + +"[TB(0,1,3)[KIH](2)[KDH](5)[KFH](4)[KJH](7)[RSH](8)[RSHRUH](9)[RUH](10)[(-1)](6)[NH[(0)]]()[]]", "" }; ap = 0; } + Utils.currentInstance.set(new PackerImpl()); final int[][] counts = new int[2][3]; // int bci ref final Entry[] cpMap = new Entry[maxVal+1]; for (int i = 0; i < cpMap.length; i++) { if (i == 0) continue; // 0 => null cpMap[i] = ConstantPool.getLiteralEntry(new Integer(i)); } - Class cls = new Package().new Class(""); + Package.Class cls = new Package().new Class(""); cls.cpMap = cpMap; class TestValueStream extends ValueStream { - Random rand = new Random(0); + java.util.Random rand = new java.util.Random(0); ArrayList history = new ArrayList(); int ckidx = 0; int maxVal; @@ -1570,8 +1587,7 @@ class Attribute implements Comparable { String layout = av[i]; if (layout.startsWith("=")) { String name = layout.substring(1); - for (Iterator j = standardDefs.values().iterator(); j.hasNext(); ) { - Attribute a = (Attribute) j.next(); + for (Attribute a : standardDefs.values()) { if (a.name().equals(name)) { layout = a.layout().layout(); break; @@ -1604,7 +1620,7 @@ class Attribute implements Comparable { if (verbose) { System.out.print(" parse: {"); } - self.parse(0, cls, bytes, 0, bytes.length, tts); + self.parse(cls, bytes, 0, bytes.length, tts); if (verbose) { System.out.println("}"); } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java index 8d472b9bdd4..a63491b9a34 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1372,17 +1372,17 @@ class BandStructure { protected long archiveSize1; // size reported in archive_header protected int archiveNextCount; // reported in archive_header - static final int AH_LENGTH_0 = 3; //minver, majver, options - static final int AH_ARCHIVE_SIZE_HI = 0; - static final int AH_ARCHIVE_SIZE_LO = 1; - static final int AH_LENGTH_S = 2; //optional size hi/lo - static final int AH_LENGTH = 26; // mentioned in spec + static final int AH_LENGTH_0 = 3; // archive_header_0 = {minver, majver, options} + static final int AH_LENGTH_MIN = 15; // observed in spec {header_0[3], cp_counts[8], class_counts[4]} + // Length contributions from optional archive size fields: + static final int AH_LENGTH_S = 2; // archive_header_S = optional {size_hi, size_lo} + static final int AH_ARCHIVE_SIZE_HI = 0; // offset in archive_header_S + static final int AH_ARCHIVE_SIZE_LO = 1; // offset in archive_header_S // Length contributions from optional header fields: - static final int AH_FILE_HEADER_LEN = 5; // sizehi/lo/next/modtime/files - static final int AH_SPECIAL_FORMAT_LEN = 2; // layouts/band-headers - static final int AH_CP_NUMBER_LEN = 4; // int/float/long/double - static final int AH_LENGTH_MIN = AH_LENGTH - -(AH_SPECIAL_FORMAT_LEN+AH_FILE_HEADER_LEN+AH_CP_NUMBER_LEN); + static final int AH_FILE_HEADER_LEN = 5; // file_counts = {{size_hi, size_lo}, next, modtime, files} + static final int AH_SPECIAL_FORMAT_LEN = 2; // special_counts = {layouts, band_headers} + static final int AH_CP_NUMBER_LEN = 4; // cp_number_counts = {int, float, long, double} + static final int AH_CP_EXTRA_LEN = 4; // cp_attr_counts = {MH, MT, InDy, BSM} // Common structure of attribute band groups: static final int AB_FLAGS_HI = 0; @@ -1446,6 +1446,14 @@ class BandStructure { CPRefBand cp_Method_desc = cp_bands.newCPRefBand("cp_Method_desc", UDELTA5, CONSTANT_NameandType); CPRefBand cp_Imethod_class = cp_bands.newCPRefBand("cp_Imethod_class", CONSTANT_Class); CPRefBand cp_Imethod_desc = cp_bands.newCPRefBand("cp_Imethod_desc", UDELTA5, CONSTANT_NameandType); + IntBand cp_MethodHandle_refkind = cp_bands.newIntBand("cp_MethodHandle_refkind", DELTA5); + CPRefBand cp_MethodHandle_member = cp_bands.newCPRefBand("cp_MethodHandle_member", UDELTA5, CONSTANT_AnyMember); + CPRefBand cp_MethodType = cp_bands.newCPRefBand("cp_MethodType", UDELTA5, CONSTANT_Signature); + CPRefBand cp_BootstrapMethod_ref = cp_bands.newCPRefBand("cp_BootstrapMethod_ref", DELTA5, CONSTANT_MethodHandle); + IntBand cp_BootstrapMethod_arg_count = cp_bands.newIntBand("cp_BootstrapMethod_arg_count", UDELTA5); + CPRefBand cp_BootstrapMethod_arg = cp_bands.newCPRefBand("cp_BootstrapMethod_arg", DELTA5, CONSTANT_LoadableValue); + CPRefBand cp_InvokeDynamic_spec = cp_bands.newCPRefBand("cp_InvokeDynamic_spec", DELTA5, CONSTANT_BootstrapMethod); + CPRefBand cp_InvokeDynamic_desc = cp_bands.newCPRefBand("cp_InvokeDynamic_desc", UDELTA5, CONSTANT_NameandType); // bands for carrying attribute definitions: MultiBand attr_definition_bands = all_bands.newMultiBand("(attr_definition_bands)", UNSIGNED5); @@ -1481,7 +1489,7 @@ class BandStructure { IntBand field_attr_calls = field_attr_bands.newIntBand("field_attr_calls"); // bands for predefined field attributes - CPRefBand field_ConstantValue_KQ = field_attr_bands.newCPRefBand("field_ConstantValue_KQ", CONSTANT_Literal); + CPRefBand field_ConstantValue_KQ = field_attr_bands.newCPRefBand("field_ConstantValue_KQ", CONSTANT_FieldSpecific); CPRefBand field_Signature_RS = field_attr_bands.newCPRefBand("field_Signature_RS", CONSTANT_Signature); MultiBand field_metadata_bands = field_attr_bands.newMultiBand("(field_metadata_bands)", UNSIGNED5); @@ -1585,12 +1593,14 @@ class BandStructure { CPRefBand bc_longref = bc_bands.newCPRefBand("bc_longref", DELTA5, CONSTANT_Long); CPRefBand bc_doubleref = bc_bands.newCPRefBand("bc_doubleref", DELTA5, CONSTANT_Double); CPRefBand bc_stringref = bc_bands.newCPRefBand("bc_stringref", DELTA5, CONSTANT_String); + CPRefBand bc_loadablevalueref = bc_bands.newCPRefBand("bc_loadablevalueref", DELTA5, CONSTANT_LoadableValue); // nulls produced by bc_classref are taken to mean the current class CPRefBand bc_classref = bc_bands.newCPRefBand("bc_classref", UNSIGNED5, CONSTANT_Class, NULL_IS_OK); // new, *anew*, c*cast, i*of, ldc CPRefBand bc_fieldref = bc_bands.newCPRefBand("bc_fieldref", DELTA5, CONSTANT_Fieldref); // get*, put* CPRefBand bc_methodref = bc_bands.newCPRefBand("bc_methodref", CONSTANT_Methodref); // invoke[vs]* CPRefBand bc_imethodref = bc_bands.newCPRefBand("bc_imethodref", DELTA5, CONSTANT_InterfaceMethodref); // invokeinterface + CPRefBand bc_indyref = bc_bands.newCPRefBand("bc_indyref", DELTA5, CONSTANT_InvokeDynamic); // invokedynamic // _self_linker_op family CPRefBand bc_thisfield = bc_bands.newCPRefBand("bc_thisfield", CONSTANT_None); // any field within cur. class @@ -1633,7 +1643,7 @@ class BandStructure { protected void setBandIndex(CPRefBand b, byte which) { Object[] need = { b, Byte.valueOf(which) }; - if (which == CONSTANT_Literal) { + if (which == CONSTANT_FieldSpecific) { // I.e., attribute layouts KQ (no null) or KQN (null ok). allKQBands.add(b); } else if (needPredefIndex != null) { @@ -1856,12 +1866,20 @@ class BandStructure { attrClassFileVersionMask = (1< 0) Utils.log.fine("Legacy package version"); // Revoke definition of pre-1.6 attribute type. undefineAttribute(CODE_ATTR_StackMapTable, ATTR_CONTEXT_CODE); } + if (getPackageMajver() < JAVA7_PACKAGE_MAJOR_VERSION) { + if (testBit(archiveOptions, AO_HAVE_CP_EXTRAS)) + // this bit was reserved for future use in previous versions + throw new IOException("Format bits for Java 7 must be zero in previous releases"); + } + if (testBit(archiveOptions, AO_UNUSED_MBZ)) { + throw new IOException("High archive option bits are reserved and must be zero: "+Integer.toHexString(archiveOptions)); + } } protected void initAttrIndexLimit() { @@ -2323,7 +2341,9 @@ class BandStructure { return bc_methodref; case CONSTANT_InterfaceMethodref: return bc_imethodref; - case CONSTANT_Literal: + case CONSTANT_InvokeDynamic: + return bc_indyref; + case CONSTANT_LoadableValue: switch (bc) { case _ildc: case _ildc_w: return bc_intref; @@ -2333,10 +2353,12 @@ class BandStructure { return bc_longref; case _dldc2_w: return bc_doubleref; - case _aldc: case _aldc_w: + case _sldc: case _sldc_w: return bc_stringref; case _cldc: case _cldc_w: return bc_classref; + case _qldc: case _qldc_w: + return bc_loadablevalueref; } break; } @@ -2623,15 +2645,23 @@ class BandStructure { } static void printArrayTo(PrintStream ps, Entry[] cpMap, int start, int end) { + printArrayTo(ps, cpMap, start, end, false); + } + static void printArrayTo(PrintStream ps, Entry[] cpMap, int start, int end, boolean showTags) { StringBuffer buf = new StringBuffer(); int len = end-start; for (int i = 0; i < len; i++) { - String s = cpMap[start+i].stringValue(); + Entry e = cpMap[start+i]; + ps.print(start+i); ps.print("="); + if (showTags) { ps.print(e.tag); ps.print(":"); } + String s = e.stringValue(); buf.setLength(0); for (int j = 0; j < s.length(); j++) { char ch = s.charAt(j); if (!(ch < ' ' || ch > '~' || ch == '\\')) { buf.append(ch); + } else if (ch == '\\') { + buf.append("\\\\"); } else if (ch == '\n') { buf.append("\\n"); } else if (ch == '\t') { @@ -2639,7 +2669,8 @@ class BandStructure { } else if (ch == '\r') { buf.append("\\r"); } else { - buf.append("\\x"+Integer.toHexString(ch)); + String str = "000"+Integer.toHexString(ch); + buf.append("\\u"+str.substring(str.length()-4)); } } ps.println(buf); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java index ce29f1f3a19..545faab9127 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,9 @@ 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.Entry; import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; +import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; +import com.sun.java.util.jar.pack.ConstantPool.MethodHandleEntry; +import com.sun.java.util.jar.pack.ConstantPool.BootstrapMethodEntry; import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.Package.InnerClass; @@ -37,6 +40,7 @@ import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Map; import static com.sun.java.util.jar.pack.Constants.*; @@ -114,6 +118,7 @@ class ClassReader { private Entry readRef(byte tag) throws IOException { Entry e = readRef(); assert(e != null); + assert(!(e instanceof UnresolvedEntry)); assert(e.tagMatches(tag)); return e; } @@ -151,6 +156,7 @@ class ClassReader { readMembers(false); // fields readMembers(true); // methods readAttributes(ATTR_CONTEXT_CLASS, cls); + fixUnresolvedEntries(); cls.finishReading(); assert(0 >= in.read(new byte[1])); ok = true; @@ -236,6 +242,7 @@ class ClassReader { // just read the refs; do not attempt to resolve while reading case CONSTANT_Class: case CONSTANT_String: + case CONSTANT_MethodType: fixups[fptr++] = i; fixups[fptr++] = tag; fixups[fptr++] = in.readUnsignedShort(); @@ -250,6 +257,18 @@ class ClassReader { fixups[fptr++] = in.readUnsignedShort(); fixups[fptr++] = in.readUnsignedShort(); break; + case CONSTANT_InvokeDynamic: + fixups[fptr++] = i; + fixups[fptr++] = tag; + fixups[fptr++] = -1 ^ in.readUnsignedShort(); // not a ref + fixups[fptr++] = in.readUnsignedShort(); + break; + case CONSTANT_MethodHandle: + fixups[fptr++] = i; + fixups[fptr++] = tag; + fixups[fptr++] = -1 ^ in.readUnsignedByte(); + fixups[fptr++] = in.readUnsignedShort(); + break; default: throw new ClassFormatException("Bad constant pool tag " + tag + " in File: " + cls.file.nameString + @@ -270,7 +289,7 @@ class ClassReader { int ref2 = fixups[fi++]; if (verbose > 3) Utils.log.fine(" cp["+cpi+"] = "+ConstantPool.tagName(tag)+"{"+ref+","+ref2+"}"); - if (cpMap[ref] == null || ref2 >= 0 && cpMap[ref2] == null) { + if (ref >= 0 && cpMap[ref] == null || ref2 >= 0 && cpMap[ref2] == null) { // Defer. fixups[fptr++] = cpi; fixups[fptr++] = tag; @@ -297,6 +316,19 @@ class ClassReader { Utf8Entry mtype = (Utf8Entry) cpMap[ref2]; cpMap[cpi] = ConstantPool.getDescriptorEntry(mname, mtype); break; + case CONSTANT_MethodType: + cpMap[cpi] = ConstantPool.getMethodTypeEntry((Utf8Entry) cpMap[ref]); + break; + case CONSTANT_MethodHandle: + byte refKind = (byte)(-1 ^ ref); + MemberEntry memRef = (MemberEntry) cpMap[ref2]; + cpMap[cpi] = ConstantPool.getMethodHandleEntry(refKind, memRef); + break; + case CONSTANT_InvokeDynamic: + DescriptorEntry idescr = (DescriptorEntry) cpMap[ref2]; + cpMap[cpi] = new UnresolvedEntry((byte)tag, (-1 ^ ref), idescr); + // Note that ref must be resolved later, using the BootstrapMethods attribute. + break; default: assert(false); } @@ -307,6 +339,50 @@ class ClassReader { cls.cpMap = cpMap; } + private /*non-static*/ + class UnresolvedEntry extends Entry { + final Object[] refsOrIndexes; + UnresolvedEntry(byte tag, Object... refsOrIndexes) { + super(tag); + this.refsOrIndexes = refsOrIndexes; + ClassReader.this.haveUnresolvedEntry = true; + } + Entry resolve() { + Class cls = ClassReader.this.cls; + Entry res; + switch (tag) { + case CONSTANT_InvokeDynamic: + BootstrapMethodEntry iboots = cls.bootstrapMethods.get((Integer) refsOrIndexes[0]); + DescriptorEntry idescr = (DescriptorEntry) refsOrIndexes[1]; + res = ConstantPool.getInvokeDynamicEntry(iboots, idescr); + break; + default: + throw new AssertionError(); + } + return res; + } + private void unresolved() { throw new RuntimeException("unresolved entry has no string"); } + public int compareTo(Object x) { unresolved(); return 0; } + public boolean equals(Object x) { unresolved(); return false; } + protected int computeValueHash() { unresolved(); return 0; } + public String stringValue() { unresolved(); return toString(); } + public String toString() { return "(unresolved "+ConstantPool.tagName(tag)+")"; } + } + + boolean haveUnresolvedEntry; + private void fixUnresolvedEntries() { + if (!haveUnresolvedEntry) return; + Entry[] cpMap = cls.getCPMap(); + for (int i = 0; i < cpMap.length; i++) { + Entry e = cpMap[i]; + if (e instanceof UnresolvedEntry) { + cpMap[i] = e = ((UnresolvedEntry)e).resolve(); + assert(!(e instanceof UnresolvedEntry)); + } + } + haveUnresolvedEntry = false; + } + void readHeader() throws IOException { cls.flags = readUnsignedShort(); cls.thisClass = readClassRef(); @@ -416,25 +492,31 @@ class ClassReader { unknownAttrCommand); } } - if (a.layout() == Package.attrCodeEmpty || - a.layout() == Package.attrInnerClassesEmpty) { + long pos0 = inPos; // in case we want to check it + if (a.layout() == Package.attrCodeEmpty) { // These are hardwired. - long pos0 = inPos; - if ("Code".equals(a.name())) { - Class.Method m = (Class.Method) h; - m.code = new Code(m); - try { - readCode(m.code); - } catch (Instruction.FormatException iie) { - String message = iie.getMessage() + " in " + h; - throw new ClassReader.ClassFormatException(message, iie); - } - } else { - assert(h == cls); - readInnerClasses(cls); + Class.Method m = (Class.Method) h; + m.code = new Code(m); + try { + readCode(m.code); + } catch (Instruction.FormatException iie) { + String message = iie.getMessage() + " in " + h; + throw new ClassReader.ClassFormatException(message, iie); } assert(length == inPos - pos0); // Keep empty attribute a... + } else if (a.layout() == Package.attrBootstrapMethodsEmpty) { + assert(h == cls); + readBootstrapMethods(cls); + assert(length == inPos - pos0); + // Delete the attribute; it is logically part of the constant pool. + continue; + } else if (a.layout() == Package.attrInnerClassesEmpty) { + // These are hardwired also. + assert(h == cls); + readInnerClasses(cls); + assert(length == inPos - pos0); + // Keep empty attribute a... } else if (length > 0) { byte[] bytes = new byte[length]; in.readFully(bytes); @@ -467,6 +549,19 @@ class ClassReader { readAttributes(ATTR_CONTEXT_CODE, code); } + void readBootstrapMethods(Class cls) throws IOException { + BootstrapMethodEntry[] bsms = new BootstrapMethodEntry[readUnsignedShort()]; + for (int i = 0; i < bsms.length; i++) { + MethodHandleEntry bsmRef = (MethodHandleEntry) readRef(CONSTANT_MethodHandle); + Entry[] argRefs = new Entry[readUnsignedShort()]; + for (int j = 0; j < argRefs.length; j++) { + argRefs[j] = readRef(); + } + bsms[i] = ConstantPool.getBootstrapMethodEntry(bsmRef, argRefs); + } + cls.setBootstrapMethods(Arrays.asList(bsms)); + } + void readInnerClasses(Class cls) throws IOException { int nc = readUnsignedShort(); ArrayList ics = new ArrayList<>(nc); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassWriter.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassWriter.java index 37424d1e65c..dacae44b4d3 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassWriter.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ package com.sun.java.util.jar.pack; import com.sun.java.util.jar.pack.ConstantPool.Entry; import com.sun.java.util.jar.pack.ConstantPool.Index; import com.sun.java.util.jar.pack.ConstantPool.NumberEntry; +import com.sun.java.util.jar.pack.ConstantPool.MethodHandleEntry; +import com.sun.java.util.jar.pack.ConstantPool.BootstrapMethodEntry; import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.Package.InnerClass; import java.io.BufferedOutputStream; @@ -49,6 +51,7 @@ class ClassWriter { Class cls; DataOutputStream out; Index cpIndex; + Index bsmIndex; ClassWriter(Class cls, OutputStream out) throws IOException { this.pkg = cls.getPackage(); @@ -57,6 +60,10 @@ class ClassWriter { this.out = new DataOutputStream(new BufferedOutputStream(out)); this.cpIndex = ConstantPool.makeIndex(cls.toString(), cls.getCPMap()); this.cpIndex.flattenSigs = true; + if (cls.hasBootstrapMethods()) { + this.bsmIndex = ConstantPool.makeIndex(cpIndex.debugName+".BootstrapMethods", + cls.getBootstrapMethodMap()); + } if (verbose > 1) Utils.log.fine("local CP="+(verbose > 2 ? cpIndex.dumpString() : cpIndex.toString())); } @@ -71,6 +78,11 @@ class ClassWriter { /** Write a 2-byte int representing a CP entry, using the local cpIndex. */ private void writeRef(Entry e) throws IOException { + writeRef(e, cpIndex); + } + + /** Write a 2-byte int representing a CP entry, using the given cpIndex. */ + private void writeRef(Entry e, Index cpIndex) throws IOException { int i = (e == null) ? 0 : cpIndex.indexOf(e); writeShort(i); } @@ -117,8 +129,7 @@ class ClassWriter { out.write(tag); switch (tag) { case CONSTANT_Signature: - assert(false); // should not reach here - break; + throw new AssertionError("CP should have Signatures remapped to Utf8"); case CONSTANT_Utf8: out.writeUTF(e.stringValue()); break; @@ -138,8 +149,14 @@ class ClassWriter { break; case CONSTANT_Class: case CONSTANT_String: + case CONSTANT_MethodType: writeRef(e.getRef(0)); break; + case CONSTANT_MethodHandle: + MethodHandleEntry mhe = (MethodHandleEntry) e; + out.writeByte(mhe.refKind); + writeRef(mhe.getRef(0)); + break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: @@ -147,6 +164,12 @@ class ClassWriter { writeRef(e.getRef(0)); writeRef(e.getRef(1)); break; + case CONSTANT_InvokeDynamic: + writeRef(e.getRef(0), bsmIndex); + writeRef(e.getRef(1)); + break; + case CONSTANT_BootstrapMethod: + throw new AssertionError("CP should have BootstrapMethods moved to side-table"); default: throw new IOException("Bad constant pool tag "+tag); } @@ -198,6 +221,7 @@ class ClassWriter { a.finishRefs(cpIndex); writeRef(a.getNameRef()); if (a.layout() == Package.attrCodeEmpty || + a.layout() == Package.attrBootstrapMethodsEmpty || a.layout() == Package.attrInnerClassesEmpty) { // These are hardwired. DataOutputStream savedOut = out; @@ -207,9 +231,14 @@ class ClassWriter { if ("Code".equals(a.name())) { Class.Method m = (Class.Method) h; writeCode(m.code); - } else { + } else if ("BootstrapMethods".equals(a.name())) { + assert(h == cls); + writeBootstrapMethods(cls); + } else if ("InnerClasses".equals(a.name())) { assert(h == cls); writeInnerClasses(cls); + } else { + throw new AssertionError(); } out = savedOut; if (verbose > 2) @@ -242,6 +271,18 @@ class ClassWriter { writeAttributes(ATTR_CONTEXT_CODE, code); } + void writeBootstrapMethods(Class cls) throws IOException { + List bsms = cls.getBootstrapMethods(); + writeShort(bsms.size()); + for (BootstrapMethodEntry e : bsms) { + writeRef(e.bsmRef); + writeShort(e.argRefs.length); + for (Entry argRef : e.argRefs) { + writeRef(argRef); + } + } + } + void writeInnerClasses(Class cls) throws IOException { List ics = cls.getInnerClasses(); writeShort(ics.size()); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java index acade5b7a3d..be4da54d247 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ class ConstantPool { * Also used to back up more complex constant pool entries, like Class. */ public static synchronized Utf8Entry getUtf8Entry(String value) { - Map utf8Entries = Utils.getUtf8Entries(); + Map utf8Entries = Utils.getTLGlobals().getUtf8Entries(); Utf8Entry e = utf8Entries.get(value); if (e == null) { e = new Utf8Entry(value); @@ -61,8 +61,8 @@ class ConstantPool { return e; } /** Factory for Class constants. */ - public static synchronized ClassEntry getClassEntry(String name) { - Map classEntries = Utils.getClassEntries(); + public static ClassEntry getClassEntry(String name) { + Map classEntries = Utils.getTLGlobals().getClassEntries(); ClassEntry e = classEntries.get(name); if (e == null) { e = new ClassEntry(getUtf8Entry(name)); @@ -72,8 +72,8 @@ class ConstantPool { return e; } /** Factory for literal constants (String, Integer, etc.). */ - public static synchronized LiteralEntry getLiteralEntry(Comparable value) { - Map literalEntries = Utils.getLiteralEntries(); + public static LiteralEntry getLiteralEntry(Comparable value) { + Map literalEntries = Utils.getTLGlobals().getLiteralEntries(); LiteralEntry e = literalEntries.get(value); if (e == null) { if (value instanceof String) @@ -85,13 +85,13 @@ class ConstantPool { return e; } /** Factory for literal constants (String, Integer, etc.). */ - public static synchronized StringEntry getStringEntry(String value) { + public static StringEntry getStringEntry(String value) { return (StringEntry) getLiteralEntry(value); } /** Factory for signature (type) constants. */ - public static synchronized SignatureEntry getSignatureEntry(String type) { - Map signatureEntries = Utils.getSignatureEntries(); + public static SignatureEntry getSignatureEntry(String type) { + Map signatureEntries = Utils.getTLGlobals().getSignatureEntries(); SignatureEntry e = signatureEntries.get(type); if (e == null) { e = new SignatureEntry(type); @@ -106,8 +106,8 @@ class ConstantPool { } /** Factory for descriptor (name-and-type) constants. */ - public static synchronized DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, SignatureEntry typeRef) { - Map descriptorEntries = Utils.getDescriptorEntries(); + public static DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, SignatureEntry typeRef) { + Map descriptorEntries = Utils.getTLGlobals().getDescriptorEntries(); String key = DescriptorEntry.stringValueOf(nameRef, typeRef); DescriptorEntry e = descriptorEntries.get(key); if (e == null) { @@ -124,8 +124,8 @@ class ConstantPool { } /** Factory for member reference constants. */ - public static synchronized MemberEntry getMemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) { - Map memberEntries = Utils.getMemberEntries(); + public static MemberEntry getMemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) { + Map memberEntries = Utils.getTLGlobals().getMemberEntries(); String key = MemberEntry.stringValueOf(tag, classRef, descRef); MemberEntry e = memberEntries.get(key); if (e == null) { @@ -137,6 +137,61 @@ class ConstantPool { return e; } + /** Factory for MethodHandle constants. */ + public static MethodHandleEntry getMethodHandleEntry(byte refKind, MemberEntry memRef) { + Map methodHandleEntries = Utils.getTLGlobals().getMethodHandleEntries(); + String key = MethodHandleEntry.stringValueOf(refKind, memRef); + MethodHandleEntry e = methodHandleEntries.get(key); + if (e == null) { + e = new MethodHandleEntry(refKind, memRef); + assert(e.stringValue().equals(key)); + methodHandleEntries.put(key, e); + } + return e; + } + + /** Factory for MethodType constants. */ + public static MethodTypeEntry getMethodTypeEntry(SignatureEntry sigRef) { + Map methodTypeEntries = Utils.getTLGlobals().getMethodTypeEntries(); + String key = sigRef.stringValue(); + MethodTypeEntry e = methodTypeEntries.get(key); + if (e == null) { + e = new MethodTypeEntry(sigRef); + assert(e.stringValue().equals(key)); + methodTypeEntries.put(key, e); + } + return e; + } + public static MethodTypeEntry getMethodTypeEntry(Utf8Entry typeRef) { + return getMethodTypeEntry(getSignatureEntry(typeRef.stringValue())); + } + + /** Factory for InvokeDynamic constants. */ + public static InvokeDynamicEntry getInvokeDynamicEntry(BootstrapMethodEntry bssRef, DescriptorEntry descRef) { + Map invokeDynamicEntries = Utils.getTLGlobals().getInvokeDynamicEntries(); + String key = InvokeDynamicEntry.stringValueOf(bssRef, descRef); + InvokeDynamicEntry e = invokeDynamicEntries.get(key); + if (e == null) { + e = new InvokeDynamicEntry(bssRef, descRef); + assert(e.stringValue().equals(key)); + invokeDynamicEntries.put(key, e); + } + return e; + } + + /** Factory for BootstrapMethod pseudo-constants. */ + public static BootstrapMethodEntry getBootstrapMethodEntry(MethodHandleEntry bsmRef, Entry[] argRefs) { + Map bootstrapMethodEntries = Utils.getTLGlobals().getBootstrapMethodEntries(); + String key = BootstrapMethodEntry.stringValueOf(bsmRef, argRefs); + BootstrapMethodEntry e = bootstrapMethodEntries.get(key); + if (e == null) { + e = new BootstrapMethodEntry(bsmRef, argRefs); + assert(e.stringValue().equals(key)); + bootstrapMethodEntries.put(key, e); + } + return e; + } + /** Entries in the constant pool. */ public static abstract @@ -251,6 +306,10 @@ class ConstantPool { throw new RuntimeException("bad literal value "+value); } + static boolean isRefKind(byte refKind) { + return (REF_getField <= refKind && refKind <= REF_invokeInterface); + } + public static abstract class LiteralEntry extends Entry { protected LiteralEntry(byte tag) { @@ -404,7 +463,7 @@ class ConstantPool { } static String stringValueOf(Entry nameRef, Entry typeRef) { - return typeRef.stringValue()+","+nameRef.stringValue(); + return qualifiedStringValue(typeRef, nameRef); } public String prettyString() { @@ -420,6 +479,15 @@ class ConstantPool { } } + static String qualifiedStringValue(Entry e1, Entry e2) { + return qualifiedStringValue(e1.stringValue(), e2.stringValue()); + } + static String qualifiedStringValue(String s1, String s234) { + // Qualification by dot must decompose uniquely. Second string might already be qualified. + assert(s1.indexOf(".") < 0); + return s1+"."+s234; + } + public static class MemberEntry extends Entry { final ClassEntry classRef; @@ -453,8 +521,12 @@ class ConstantPool { int x = superCompareTo(o); if (x == 0) { MemberEntry that = (MemberEntry)o; + if (Utils.SORT_MEMBERS_DESCR_MAJOR) + // descRef is transmitted as UDELTA5; sort it first? + x = this.descRef.compareTo(that.descRef); // Primary key is classRef. - x = this.classRef.compareTo(that.classRef); + if (x == 0) + x = this.classRef.compareTo(that.classRef); if (x == 0) x = this.descRef.compareTo(that.descRef); } @@ -473,7 +545,7 @@ class ConstantPool { case CONSTANT_InterfaceMethodref: pfx = "IMethod:"; break; default: pfx = tag+"???"; break; } - return pfx+classRef.stringValue()+","+descRef.stringValue(); + return pfx+qualifiedStringValue(classRef, descRef); } public boolean isMethod() { @@ -581,13 +653,26 @@ class ConstantPool { } public byte getLiteralTag() { switch (formRef.stringValue().charAt(0)) { - case 'L': return CONSTANT_String; case 'I': return CONSTANT_Integer; case 'J': return CONSTANT_Long; case 'F': return CONSTANT_Float; case 'D': return CONSTANT_Double; case 'B': case 'S': case 'C': case 'Z': return CONSTANT_Integer; + case 'L': + /* + switch (classRefs[0].stringValue()) { + case "java/lang/String": + return CONSTANT_String; + case "java/lang/invoke/MethodHandle": + return CONSTANT_MethodHandle; + case "java/lang/invoke/MethodType": + return CONSTANT_MethodType; + default: // java/lang/Object, etc. + return CONSTANT_LoadableValue; + } + */ + return CONSTANT_String; // JDK 7 ConstantValue limited to String } assert(false); return CONSTANT_None; @@ -724,6 +809,218 @@ class ConstantPool { return parts; } + /** @since JDK 7, JSR 292 */ + public static + class MethodHandleEntry extends Entry { + final int refKind; + final MemberEntry memRef; + public Entry getRef(int i) { return i == 0 ? memRef : null; } + + protected int computeValueHash() { + int hc2 = refKind; + return (memRef.hashCode() + (hc2 << 8)) ^ hc2; + } + + MethodHandleEntry(byte refKind, MemberEntry memRef) { + super(CONSTANT_MethodHandle); + assert(isRefKind(refKind)); + this.refKind = refKind; + this.memRef = memRef; + hashCode(); // force computation of valueHash + } + public boolean equals(Object o) { + if (o == null || o.getClass() != MethodHandleEntry.class) { + return false; + } + MethodHandleEntry that = (MethodHandleEntry)o; + return this.refKind == that.refKind + && this.memRef.eq(that.memRef); + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + MethodHandleEntry that = (MethodHandleEntry)o; + if (Utils.SORT_HANDLES_KIND_MAJOR) + // Primary key could be refKind. + x = this.refKind - that.refKind; + // Primary key is memRef, which is transmitted as UDELTA5. + if (x == 0) + x = this.memRef.compareTo(that.memRef); + if (x == 0) + x = this.refKind - that.refKind; + } + return x; + } + public static String stringValueOf(int refKind, MemberEntry memRef) { + return refKindName(refKind)+":"+memRef.stringValue(); + } + public String stringValue() { + return stringValueOf(refKind, memRef); + } + } + + /** @since JDK 7, JSR 292 */ + public static + class MethodTypeEntry extends Entry { + final SignatureEntry typeRef; + public Entry getRef(int i) { return i == 0 ? typeRef : null; } + + protected int computeValueHash() { + return typeRef.hashCode() + tag; + } + + MethodTypeEntry(SignatureEntry typeRef) { + super(CONSTANT_MethodType); + this.typeRef = typeRef; + hashCode(); // force computation of valueHash + } + public boolean equals(Object o) { + if (o == null || o.getClass() != MethodTypeEntry.class) { + return false; + } + MethodTypeEntry that = (MethodTypeEntry)o; + return this.typeRef.eq(that.typeRef); + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + MethodTypeEntry that = (MethodTypeEntry)o; + x = this.typeRef.compareTo(that.typeRef); + } + return x; + } + public String stringValue() { + return typeRef.stringValue(); + } + } + + /** @since JDK 7, JSR 292 */ + public static + class InvokeDynamicEntry extends Entry { + final BootstrapMethodEntry bssRef; + final DescriptorEntry descRef; + public Entry getRef(int i) { + if (i == 0) return bssRef; + if (i == 1) return descRef; + return null; + } + protected int computeValueHash() { + int hc2 = descRef.hashCode(); + return (bssRef.hashCode() + (hc2 << 8)) ^ hc2; + } + + InvokeDynamicEntry(BootstrapMethodEntry bssRef, DescriptorEntry descRef) { + super(CONSTANT_InvokeDynamic); + this.bssRef = bssRef; + this.descRef = descRef; + hashCode(); // force computation of valueHash + } + public boolean equals(Object o) { + if (o == null || o.getClass() != InvokeDynamicEntry.class) { + return false; + } + InvokeDynamicEntry that = (InvokeDynamicEntry)o; + return this.bssRef.eq(that.bssRef) + && this.descRef.eq(that.descRef); + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + InvokeDynamicEntry that = (InvokeDynamicEntry)o; + if (Utils.SORT_INDY_BSS_MAJOR) + // Primary key could be bsmRef. + x = this.bssRef.compareTo(that.bssRef); + // Primary key is descriptor, which is transmitted as UDELTA5. + if (x == 0) + x = this.descRef.compareTo(that.descRef); + if (x == 0) + x = this.bssRef.compareTo(that.bssRef); + } + return x; + } + public String stringValue() { + return stringValueOf(bssRef, descRef); + } + static + String stringValueOf(BootstrapMethodEntry bssRef, DescriptorEntry descRef) { + return "Indy:"+bssRef.stringValue()+"."+descRef.stringValue(); + } + } + + /** @since JDK 7, JSR 292 */ + public static + class BootstrapMethodEntry extends Entry { + final MethodHandleEntry bsmRef; + final Entry[] argRefs; + public Entry getRef(int i) { + if (i == 0) return bsmRef; + if (i-1 < argRefs.length) return argRefs[i-1]; + return null; + } + protected int computeValueHash() { + int hc2 = bsmRef.hashCode(); + return (Arrays.hashCode(argRefs) + (hc2 << 8)) ^ hc2; + } + + BootstrapMethodEntry(MethodHandleEntry bsmRef, Entry[] argRefs) { + super(CONSTANT_BootstrapMethod); + this.bsmRef = bsmRef; + this.argRefs = argRefs.clone(); + hashCode(); // force computation of valueHash + } + public boolean equals(Object o) { + if (o == null || o.getClass() != BootstrapMethodEntry.class) { + return false; + } + BootstrapMethodEntry that = (BootstrapMethodEntry)o; + return this.bsmRef.eq(that.bsmRef) + && Arrays.equals(this.argRefs, that.argRefs); + } + public int compareTo(Object o) { + int x = superCompareTo(o); + if (x == 0) { + BootstrapMethodEntry that = (BootstrapMethodEntry)o; + if (Utils.SORT_BSS_BSM_MAJOR) + // Primary key is bsmRef. + x = this.bsmRef.compareTo(that.bsmRef); + // Primary key is args array length, which is transmitted as UDELTA5. + if (x == 0) + x = compareArgArrays(this.argRefs, that.argRefs); + if (x == 0) + x = this.bsmRef.compareTo(that.bsmRef); + } + return x; + } + public String stringValue() { + return stringValueOf(bsmRef, argRefs); + } + static + String stringValueOf(MethodHandleEntry bsmRef, Entry[] argRefs) { + StringBuffer sb = new StringBuffer(bsmRef.stringValue()); + // Arguments are formatted as "" instead of "[foo,bar,baz]". + // This ensures there will be no confusion if "[,]" appear inside of names. + char nextSep = '<'; + boolean didOne = false; + for (Entry argRef : argRefs) { + sb.append(nextSep).append(argRef.stringValue()); + nextSep = ';'; + } + if (nextSep == '<') sb.append(nextSep); + sb.append('>'); + return sb.toString(); + } + static + int compareArgArrays(Entry[] a1, Entry[] a2) { + int x = a1.length - a2.length; + if (x != 0) return x; + for (int i = 0; i < a1.length; i++) { + x = a1[i].compareTo(a2[i]); + if (x != 0) break; + } + return x; + } + } + // Handy constants: protected static final Entry[] noRefs = {}; protected static final ClassEntry[] noClassRefs = {}; @@ -964,35 +1261,51 @@ class ConstantPool { /** Coherent group of constant pool indexes. */ public static class IndexGroup { - private Index indexUntyped; private Index[] indexByTag = new Index[CONSTANT_Limit]; + private Index[] indexByTagGroup; private int[] untypedFirstIndexByTag; - private int totalSize; + private int totalSizeQQ; private Index[][] indexByTagAndClass; /** Index of all CP entries of all types, in definition order. */ - public Index getUntypedIndex() { - if (indexUntyped == null) { + private Index makeTagGroupIndex(byte tagGroupTag, byte[] tagsInGroup) { + if (indexByTagGroup == null) + indexByTagGroup = new Index[CONSTANT_GroupLimit - CONSTANT_GroupFirst]; + int which = tagGroupTag - CONSTANT_GroupFirst; + assert(indexByTagGroup[which] == null); + int fillp = 0; + Entry[] cpMap = null; + for (int pass = 1; pass <= 2; pass++) { untypedIndexOf(null); // warm up untypedFirstIndexByTag - Entry[] cpMap = new Entry[totalSize]; - for (int tag = 0; tag < indexByTag.length; tag++) { + for (byte tag : tagsInGroup) { Index ix = indexByTag[tag]; if (ix == null) continue; int ixLen = ix.cpMap.length; if (ixLen == 0) continue; - int fillp = untypedFirstIndexByTag[tag]; - assert(cpMap[fillp] == null); - assert(cpMap[fillp+ixLen-1] == null); - System.arraycopy(ix.cpMap, 0, cpMap, fillp, ixLen); + assert(tagGroupTag == CONSTANT_All + ? fillp == untypedFirstIndexByTag[tag] + : fillp < untypedFirstIndexByTag[tag]); + if (cpMap != null) { + assert(cpMap[fillp] == null); + assert(cpMap[fillp+ixLen-1] == null); + System.arraycopy(ix.cpMap, 0, cpMap, fillp, ixLen); + } + fillp += ixLen; + } + if (cpMap == null) { + assert(pass == 1); + // get ready for pass 2 + cpMap = new Entry[fillp]; + fillp = 0; } - indexUntyped = new Index("untyped", cpMap); } - return indexUntyped; + indexByTagGroup[which] = new Index(tagName(tagGroupTag), cpMap); + return indexByTagGroup[which]; } public int untypedIndexOf(Entry e) { if (untypedFirstIndexByTag == null) { - untypedFirstIndexByTag = new int[CONSTANT_Limit]; + untypedFirstIndexByTag = new int[CONSTANT_Limit+1]; int fillp = 0; for (int i = 0; i < TAGS_IN_ORDER.length; i++) { byte tag = TAGS_IN_ORDER[i]; @@ -1002,7 +1315,7 @@ class ConstantPool { untypedFirstIndexByTag[tag] = fillp; fillp += ixLen; } - totalSize = fillp; + untypedFirstIndexByTag[CONSTANT_Limit] = fillp; } if (e == null) return -1; int tag = e.tag; @@ -1028,16 +1341,15 @@ class ConstantPool { indexByTag[tag] = ix; // decache indexes derived from this one: untypedFirstIndexByTag = null; - indexUntyped = null; + indexByTagGroup = null; if (indexByTagAndClass != null) indexByTagAndClass[tag] = null; } /** Index of all CP entries of a given tag. */ public Index getIndexByTag(byte tag) { - if (tag == CONSTANT_All) { - return getUntypedIndex(); - } + if (tag >= CONSTANT_GroupFirst) + return getIndexByTagGroup(tag); Index ix = indexByTag[tag]; if (ix == null) { // Make an empty one by default. @@ -1047,6 +1359,26 @@ class ConstantPool { return ix; } + private Index getIndexByTagGroup(byte tag) { + // pool groups: + if (indexByTagGroup != null) { + Index ix = indexByTagGroup[tag - CONSTANT_GroupFirst]; + if (ix != null) return ix; + } + switch (tag) { + case CONSTANT_All: + return makeTagGroupIndex(CONSTANT_All, TAGS_IN_ORDER); + case CONSTANT_LoadableValue: + return makeTagGroupIndex(CONSTANT_LoadableValue, LOADABLE_VALUE_TAGS); + case CONSTANT_AnyMember: + return makeTagGroupIndex(CONSTANT_AnyMember, ANY_MEMBER_TAGS); + case CONSTANT_FieldSpecific: + // This one does not have any fixed index, since it is context-specific. + return null; + } + throw new AssertionError("bad tag group "+tag); + } + /** Index of all CP entries of a given tag and class. */ public Index getMemberIndex(byte tag, ClassEntry classRef) { if (indexByTagAndClass == null) @@ -1107,16 +1439,14 @@ class ConstantPool { } public boolean haveNumbers() { - for (byte tag = CONSTANT_Integer; tag <= CONSTANT_Double; tag++) { - switch (tag) { - case CONSTANT_Integer: - case CONSTANT_Float: - case CONSTANT_Long: - case CONSTANT_Double: - break; - default: - assert(false); - } + for (byte tag : NUMBER_TAGS) { + if (getIndexByTag(tag).size() > 0) return true; + } + return false; + } + + public boolean haveExtraTags() { + for (byte tag : EXTRA_TAGS) { if (getIndexByTag(tag).size() > 0) return true; } return false; @@ -1129,8 +1459,13 @@ class ConstantPool { * by their equivalent Utf8s. * Also, discard null from cpRefs. */ + public static void completeReferencesIn(Set cpRefs, boolean flattenSigs) { + completeReferencesIn(cpRefs, flattenSigs, null); + } + public static - void completeReferencesIn(Set cpRefs, boolean flattenSigs) { + void completeReferencesIn(Set cpRefs, boolean flattenSigs, + Listbsms) { cpRefs.remove(null); for (ListIterator work = new ArrayList<>(cpRefs).listIterator(cpRefs.size()); @@ -1146,6 +1481,14 @@ class ConstantPool { cpRefs.add(ue); e = ue; // do not descend into the sig } + if (bsms != null && e.tag == CONSTANT_BootstrapMethod) { + BootstrapMethodEntry bsm = (BootstrapMethodEntry)e; + cpRefs.remove(bsm); + // move it away to the side table where it belongs + if (!bsms.contains(bsm)) + bsms.add(bsm); + // fall through to recursively add refs for this entry + } // Recursively add the refs of e to cpRefs: for (int i = 0; ; i++) { Entry re = e.getRef(i); @@ -1174,15 +1517,37 @@ class ConstantPool { case CONSTANT_Methodref: return "Methodref"; case CONSTANT_InterfaceMethodref: return "InterfaceMethodref"; case CONSTANT_NameandType: return "NameandType"; + case CONSTANT_MethodHandle: return "MethodHandle"; + case CONSTANT_MethodType: return "MethodType"; + case CONSTANT_InvokeDynamic: return "InvokeDynamic"; // pseudo-tags: - case CONSTANT_All: return "*All"; - case CONSTANT_None: return "*None"; + case CONSTANT_All: return "**All"; + case CONSTANT_None: return "**None"; + case CONSTANT_LoadableValue: return "**LoadableValue"; + case CONSTANT_AnyMember: return "**AnyMember"; + case CONSTANT_FieldSpecific: return "*FieldSpecific"; case CONSTANT_Signature: return "*Signature"; + case CONSTANT_BootstrapMethod: return "*BootstrapMethod"; } return "tag#"+tag; } + public static String refKindName(int refKind) { + switch (refKind) { + case REF_getField: return "getField"; + case REF_getStatic: return "getStatic"; + case REF_putField: return "putField"; + case REF_putStatic: return "putStatic"; + case REF_invokeVirtual: return "invokeVirtual"; + case REF_invokeStatic: return "invokeStatic"; + case REF_invokeSpecial: return "invokeSpecial"; + case REF_newInvokeSpecial: return "newInvokeSpecial"; + case REF_invokeInterface: return "invokeInterface"; + } + return "refKind#"+refKind; + } + // archive constant pool definition order static final byte TAGS_IN_ORDER[] = { CONSTANT_Utf8, @@ -1190,13 +1555,19 @@ class ConstantPool { CONSTANT_Float, CONSTANT_Long, CONSTANT_Double, - CONSTANT_String, + CONSTANT_String, // note that String=8 precedes Class=7 CONSTANT_Class, CONSTANT_Signature, CONSTANT_NameandType, // cp_Descr CONSTANT_Fieldref, // cp_Field CONSTANT_Methodref, // cp_Method - CONSTANT_InterfaceMethodref // cp_Imethod + CONSTANT_InterfaceMethodref, // cp_Imethod + + // Constants defined in JDK 7 and later: + CONSTANT_MethodHandle, + CONSTANT_MethodType, + CONSTANT_BootstrapMethod, // pseudo-tag, really stored in a class attribute + CONSTANT_InvokeDynamic }; static final byte TAG_ORDER[]; static { @@ -1211,4 +1582,45 @@ class ConstantPool { System.out.println("};"); */ } + static final byte[] NUMBER_TAGS = { + CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, CONSTANT_Double + }; + static final byte[] EXTRA_TAGS = { + CONSTANT_MethodHandle, CONSTANT_MethodType, + CONSTANT_BootstrapMethod, // pseudo-tag + CONSTANT_InvokeDynamic + }; + static final byte[] LOADABLE_VALUE_TAGS = { // for CONSTANT_LoadableValue + CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, CONSTANT_Double, + CONSTANT_String, CONSTANT_Class, + CONSTANT_MethodHandle, CONSTANT_MethodType + }; + static final byte[] ANY_MEMBER_TAGS = { // for CONSTANT_AnyMember + CONSTANT_Fieldref, CONSTANT_Methodref, CONSTANT_InterfaceMethodref + }; + static final byte[] FIELD_SPECIFIC_TAGS = { // for CONSTANT_FieldSpecific + CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, CONSTANT_Double, + CONSTANT_String + }; + static { + assert( + verifyTagOrder(TAGS_IN_ORDER) && + verifyTagOrder(NUMBER_TAGS) && + verifyTagOrder(EXTRA_TAGS) && + verifyTagOrder(LOADABLE_VALUE_TAGS) && + verifyTagOrder(ANY_MEMBER_TAGS) && + verifyTagOrder(FIELD_SPECIFIC_TAGS) + ); + } + private static boolean verifyTagOrder(byte[] tags) { + int prev = -1; + for (byte tag : tags) { + int next = TAG_ORDER[tag]; + assert(next > 0) : "tag not found: "+tag; + assert(TAGS_IN_ORDER[next-1] == tag) : "tag repeated: "+tag+" => "+next+" => "+TAGS_IN_ORDER[next-1]; + assert(prev < next) : "tags not in order: "+Arrays.toString(tags)+" at "+tag; + prev = next; + } + return true; + } } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java index 8dc6560d148..c7fa00e0f18 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,9 @@ class Constants { public final static int JAVA6_PACKAGE_MAJOR_VERSION = 160; public final static int JAVA6_PACKAGE_MINOR_VERSION = 1; + public final static int JAVA7_PACKAGE_MAJOR_VERSION = 170; + public final static int JAVA7_PACKAGE_MINOR_VERSION = 1; + public final static int CONSTANT_POOL_INDEX_LIMIT = 0x10000; public final static int CONSTANT_POOL_NARROW_LIMIT = 0x00100; @@ -82,14 +85,36 @@ class Constants { public final static byte CONSTANT_Methodref = 10; public final static byte CONSTANT_InterfaceMethodref = 11; public final static byte CONSTANT_NameandType = 12; + public final static byte CONSTANT_unused13 = 13; + public final static byte CONSTANT_unused14 = 14; + public final static byte CONSTANT_MethodHandle = 15; + public final static byte CONSTANT_MethodType = 16; + public final static byte CONSTANT_unused17 = 17; // unused + public final static byte CONSTANT_InvokeDynamic = 18; // pseudo-constants: public final static byte CONSTANT_None = 0; - public final static byte CONSTANT_Signature = 13; - public final static byte CONSTANT_Limit = 14; + public final static byte CONSTANT_Signature = CONSTANT_unused13; + public final static byte CONSTANT_BootstrapMethod = CONSTANT_unused17; // used only in InvokeDynamic constants + public final static byte CONSTANT_Limit = 19; - public final static byte CONSTANT_All = 19; // combined global map - public final static byte CONSTANT_Literal = 20; // used only for ldc fields + public final static byte CONSTANT_All = 50; // combined global map + public final static byte CONSTANT_LoadableValue = 51; // used for 'KL' and qldc operands + public final static byte CONSTANT_AnyMember = 52; // union of refs to field or (interface) method + public final static byte CONSTANT_FieldSpecific = 53; // used only for 'KQ' ConstantValue attrs + public final static byte CONSTANT_GroupFirst = CONSTANT_All; + public final static byte CONSTANT_GroupLimit = CONSTANT_FieldSpecific+1; + + // CONSTANT_MethodHandle reference kinds + public final static byte REF_getField = 1; + public final static byte REF_getStatic = 2; + public final static byte REF_putField = 3; + public final static byte REF_putStatic = 4; + public final static byte REF_invokeVirtual = 5; + public final static byte REF_invokeStatic = 6; + public final static byte REF_invokeSpecial = 7; + public final static byte REF_newInvokeSpecial = 8; + public final static byte REF_invokeInterface = 9; // pseudo-access bits public final static int ACC_IC_LONG_FORM = (1<<16); //for ic_flags @@ -133,7 +158,7 @@ class Constants { public static final int AO_HAVE_SPECIAL_FORMATS = 1<<0; public static final int AO_HAVE_CP_NUMBERS = 1<<1; public static final int AO_HAVE_ALL_CODE_FLAGS = 1<<2; - public static final int AO_3_UNUSED_MBZ = 1<<3; + public static final int AO_HAVE_CP_EXTRAS = 1<<3; public static final int AO_HAVE_FILE_HEADERS = 1<<4; public static final int AO_DEFLATE_HINT = 1<<5; public static final int AO_HAVE_FILE_MODTIME = 1<<6; @@ -143,6 +168,7 @@ class Constants { public static final int AO_HAVE_FIELD_FLAGS_HI = 1<<10; public static final int AO_HAVE_METHOD_FLAGS_HI = 1<<11; public static final int AO_HAVE_CODE_FLAGS_HI = 1<<12; + public static final int AO_UNUSED_MBZ = (-1)<<13; // option bits reserved for future use public static final int LG_AO_HAVE_XXX_FLAGS_HI = 9; @@ -357,7 +383,7 @@ class Constants { _invokespecial = 183, // 0xb7 _invokestatic = 184, // 0xb8 _invokeinterface = 185, // 0xb9 - _xxxunusedxxx = 186, // 0xba + _invokedynamic = 186, // 0xba _new = 187, // 0xbb _newarray = 188, // 0xbc _anewarray = 189, // 0xbd @@ -422,15 +448,18 @@ class Constants { // Ldc variants gain us only 0.007% improvement in compression ratio, // but they simplify the file format greatly. public final static int _xldc_op = _invokeinit_limit; - public final static int _aldc = _ldc; + public final static int _sldc = _ldc; // previously named _aldc public final static int _cldc = _xldc_op+0; public final static int _ildc = _xldc_op+1; public final static int _fldc = _xldc_op+2; - public final static int _aldc_w = _ldc_w; + public final static int _sldc_w = _ldc_w; // previously named _aldc_w public final static int _cldc_w = _xldc_op+3; public final static int _ildc_w = _xldc_op+4; public final static int _fldc_w = _xldc_op+5; public final static int _lldc2_w = _ldc2_w; public final static int _dldc2_w = _xldc_op+6; - public final static int _xldc_limit = _xldc_op+7; + // anything other than primitive, string, or class must be handled with qldc: + public final static int _qldc = _xldc_op+7; + public final static int _qldc_w = _xldc_op+8; + public final static int _xldc_limit = _xldc_op+9; } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java index 8d947689ae6..f488bede323 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -451,7 +451,7 @@ class Instruction { public static byte getCPRefOpTag(int bc) { if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return BC_TAG[0][bc]; - if (bc >= _xldc_op && bc < _xldc_limit) return CONSTANT_Literal; + if (bc >= _xldc_op && bc < _xldc_limit) return CONSTANT_LoadableValue; return CONSTANT_None; } @@ -500,7 +500,7 @@ class Instruction { def("bkf", _getstatic, _putfield); // pack kf (base=Field) def("bkm", _invokevirtual, _invokestatic); // pack kn (base=Method) def("bkixx", _invokeinterface); // pack ki (base=IMethod), omit xx - def("", _xxxunusedxxx); + def("bkyxx", _invokedynamic); // pack ky (base=Any), omit xx def("bkc", _new); // pack kc def("bx", _newarray); def("bkc", _anewarray); // pack kc @@ -515,7 +515,6 @@ class Instruction { //System.out.println(i+": l="+BC_LENGTH[0][i]+" i="+BC_INDEX[0][i]); //assert(BC_LENGTH[0][i] != -1); if (BC_LENGTH[0][i] == -1) { - assert(i == _xxxunusedxxx); continue; // unknown opcode } @@ -543,7 +542,7 @@ class Instruction { "if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple if_acmpeq if_acmpne "+ "goto jsr ret tableswitch lookupswitch ireturn lreturn freturn dreturn "+ "areturn return getstatic putstatic getfield putfield invokevirtual "+ - "invokespecial invokestatic invokeinterface xxxunusedxxx new newarray "+ + "invokespecial invokestatic invokeinterface invokedynamic new newarray "+ "anewarray arraylength athrow checkcast instanceof monitorenter "+ "monitorexit wide multianewarray ifnull ifnonnull goto_w jsr_w "; for (int bc = 0; names.length() > 0; bc++) { @@ -588,6 +587,8 @@ class Instruction { case _dldc2_w: iname = "*dldc2_w"; break; case _cldc: iname = "*cldc"; break; case _cldc_w: iname = "*cldc_w"; break; + case _qldc: iname = "*qldc"; break; + case _qldc_w: iname = "*qldc_w"; break; case _byte_escape: iname = "*byte_escape"; break; case _ref_escape: iname = "*ref_escape"; break; case _end_marker: iname = "*end"; break; @@ -618,15 +619,16 @@ class Instruction { if (index > 0 && index+1 < length) { switch (fmt.charAt(index+1)) { case 'c': tag = CONSTANT_Class; break; - case 'k': tag = CONSTANT_Literal; break; + case 'k': tag = CONSTANT_LoadableValue; break; case 'f': tag = CONSTANT_Fieldref; break; case 'm': tag = CONSTANT_Methodref; break; case 'i': tag = CONSTANT_InterfaceMethodref; break; + case 'y': tag = CONSTANT_InvokeDynamic; break; } assert(tag != CONSTANT_None); } else if (index > 0 && length == 2) { assert(from_bc == _ldc); - tag = CONSTANT_Literal; // _ldc opcode only + tag = CONSTANT_LoadableValue; // _ldc opcode only } for (int bc = from_bc; bc <= to_bc; bc++) { BC_FORMAT[w][bc] = fmt; @@ -649,7 +651,7 @@ class Instruction { Instruction i = at(code, 0); while (i != null) { int opcode = i.getBC(); - if (opcode == _xxxunusedxxx || opcode < _nop || opcode > _jsr_w) { + if (opcode < _nop || opcode > _jsr_w) { String message = "illegal opcode: " + opcode + " " + i; throw new FormatException(message); } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java index 2abe5452249..fee97f4d964 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ 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.BootstrapMethodEntry; import com.sun.java.util.jar.pack.ConstantPool.Index; import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry; import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; @@ -100,6 +101,8 @@ class Package { classes.clear(); files.clear(); BandStructure.nextSeqForDebug = 0; + package_minver = -1; // fill in later + package_majver = 0; // fill in later } int getPackageVersion() { @@ -108,6 +111,7 @@ class Package { // Special empty versions of Code and InnerClasses, used for markers. public static final Attribute.Layout attrCodeEmpty; + public static final Attribute.Layout attrBootstrapMethodsEmpty; public static final Attribute.Layout attrInnerClassesEmpty; public static final Attribute.Layout attrSourceFileSpecial; public static final Map attrDefs; @@ -115,6 +119,8 @@ class Package { Map ad = new HashMap<>(3); attrCodeEmpty = Attribute.define(ad, ATTR_CONTEXT_METHOD, "Code", "").layout(); + attrBootstrapMethodsEmpty = Attribute.define(ad, ATTR_CONTEXT_CLASS, + "BootstrapMethods", "").layout(); attrInnerClassesEmpty = Attribute.define(ad, ATTR_CONTEXT_CLASS, "InnerClasses", "").layout(); attrSourceFileSpecial = Attribute.define(ad, ATTR_CONTEXT_CLASS, @@ -153,9 +159,8 @@ class Package { package_minver = JAVA6_PACKAGE_MINOR_VERSION; } else { // Normal case. Use the newest archive format, when available - // TODO: replace the following with JAVA7* when the need arises - package_majver = JAVA6_PACKAGE_MAJOR_VERSION; - package_minver = JAVA6_PACKAGE_MINOR_VERSION; + package_majver = JAVA7_PACKAGE_MAJOR_VERSION; + package_minver = JAVA7_PACKAGE_MINOR_VERSION; } } @@ -168,13 +173,22 @@ class Package { String expMag = Integer.toHexString(JAVA_PACKAGE_MAGIC); throw new IOException("Unexpected package magic number: got "+gotMag+"; expected "+expMag); } - if ((package_majver != JAVA6_PACKAGE_MAJOR_VERSION && - package_majver != JAVA5_PACKAGE_MAJOR_VERSION) || - (package_minver != JAVA6_PACKAGE_MINOR_VERSION && - package_minver != JAVA5_PACKAGE_MINOR_VERSION)) { - + int[] majminFound = null; + for (int[] majmin : new int[][]{ + { JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION }, + { JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION }, + { JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION } + }) { + if (package_majver == majmin[0] && package_minver == majmin[1]) { + majminFound = majmin; + break; + } + } + if (majminFound == null) { String gotVer = package_majver+"."+package_minver; - String expVer = JAVA6_PACKAGE_MAJOR_VERSION+"."+JAVA6_PACKAGE_MINOR_VERSION+ + String expVer = JAVA7_PACKAGE_MAJOR_VERSION+"."+JAVA7_PACKAGE_MINOR_VERSION+ + " OR "+ + JAVA6_PACKAGE_MAJOR_VERSION+"."+JAVA6_PACKAGE_MINOR_VERSION+ " OR "+ JAVA5_PACKAGE_MAJOR_VERSION+"."+JAVA5_PACKAGE_MINOR_VERSION; throw new IOException("Unexpected package minor version: got "+gotVer+"; expected "+expVer); @@ -213,6 +227,7 @@ class Package { //ArrayList attributes; // in Attribute.Holder.this.attributes // Note that InnerClasses may be collected at the package level. ArrayList innerClasses; + ArrayList bootstrapMethods; Class(int flags, ClassEntry thisClass, ClassEntry superClass, ClassEntry[] interfaces) { this.magic = JAVA_MAGIC; @@ -313,6 +328,25 @@ class Package { this.cpMap = cpMap; } + boolean hasBootstrapMethods() { + return bootstrapMethods != null && !bootstrapMethods.isEmpty(); + } + + List getBootstrapMethods() { + return bootstrapMethods; + } + + BootstrapMethodEntry[] getBootstrapMethodMap() { + return (hasBootstrapMethods()) + ? bootstrapMethods.toArray(new BootstrapMethodEntry[bootstrapMethods.size()]) + : null; + } + + void setBootstrapMethods(Collection bsms) { + assert(bootstrapMethods == null); // do not do this twice + bootstrapMethods = new ArrayList<>(bsms); + } + boolean hasInnerClasses() { return innerClasses != null; } @@ -1283,7 +1317,8 @@ class Package { byTagU[tag] = null; // done with it } for (int i = 0; i < byTagU.length; i++) { - assert(byTagU[i] == null); // all consumed + Index ix = byTagU[i]; + assert(ix == null); // all consumed } for (int i = 0; i < ConstantPool.TAGS_IN_ORDER.length; i++) { byte tag = ConstantPool.TAGS_IN_ORDER[i]; diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java index a6886b42c7a..8813b5e3f25 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,7 @@ 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.Entry; -import com.sun.java.util.jar.pack.ConstantPool.Index; -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 com.sun.java.util.jar.pack.ConstantPool.*; import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.Package.File; import com.sun.java.util.jar.pack.Package.InnerClass; @@ -46,6 +40,7 @@ import java.util.ArrayList; import java.util.Map; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.HashMap; @@ -266,7 +261,6 @@ class PackageReader extends BandStructure { // #band_headers_size :UNSIGNED5[1] // #attr_definition_count :UNSIGNED5[1] // - assert(AH_LENGTH == 8+(ConstantPool.TAGS_IN_ORDER.length)+6); archive_header_0.expectLength(AH_LENGTH_0); archive_header_0.readFrom(in); @@ -282,6 +276,7 @@ class PackageReader extends BandStructure { boolean haveSpecial = testBit(archiveOptions, AO_HAVE_SPECIAL_FORMATS); boolean haveFiles = testBit(archiveOptions, AO_HAVE_FILE_HEADERS); boolean haveNumbers = testBit(archiveOptions, AO_HAVE_CP_NUMBERS); + boolean haveCPExtra = testBit(archiveOptions, AO_HAVE_CP_EXTRAS); initAttrIndexLimit(); // now we are ready to use the data: @@ -300,11 +295,11 @@ class PackageReader extends BandStructure { archive_header_S.doneDisbursing(); archiveSize0 = in.getBytesServed(); - int remainingHeaders = AH_LENGTH - AH_LENGTH_0 - AH_LENGTH_S; - if (!haveFiles) remainingHeaders -= AH_FILE_HEADER_LEN-AH_LENGTH_S; - if (!haveSpecial) remainingHeaders -= AH_SPECIAL_FORMAT_LEN; - if (!haveNumbers) remainingHeaders -= AH_CP_NUMBER_LEN; - assert(remainingHeaders >= AH_LENGTH_MIN - AH_LENGTH_0); + int remainingHeaders = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S; + if (haveFiles) remainingHeaders += AH_FILE_HEADER_LEN; + if (haveSpecial) remainingHeaders += AH_SPECIAL_FORMAT_LEN; + if (haveNumbers) remainingHeaders += AH_CP_NUMBER_LEN; + if (haveCPExtra) remainingHeaders += AH_CP_EXTRA_LEN; archive_header_1.expectLength(remainingHeaders); archive_header_1.readFrom(in); @@ -325,7 +320,7 @@ class PackageReader extends BandStructure { numAttrDefs = 0; } - readConstantPoolCounts(haveNumbers); + readConstantPoolCounts(haveNumbers, haveCPExtra); numInnerClasses = archive_header_1.getInt(); @@ -351,7 +346,7 @@ class PackageReader extends BandStructure { band_headers.doneDisbursing(); } - void readConstantPoolCounts(boolean haveNumbers) throws IOException { + void readConstantPoolCounts(boolean haveNumbers, boolean haveCPExtra) throws IOException { // size the constant pools: for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { // cp_counts: @@ -364,6 +359,7 @@ class PackageReader extends BandStructure { // #cp_Field_count :UNSIGNED5[1] // #cp_Method_count :UNSIGNED5[1] // #cp_Imethod_count :UNSIGNED5[1] + // (cp_attr_counts) ** (#have_cp_attr_counts) // // cp_number_counts: // #cp_Int_count :UNSIGNED5[1] @@ -371,6 +367,12 @@ class PackageReader extends BandStructure { // #cp_Long_count :UNSIGNED5[1] // #cp_Double_count :UNSIGNED5[1] // + // cp_extra_counts: + // #cp_MethodHandle_count :UNSIGNED5[1] + // #cp_MethodType_count :UNSIGNED5[1] + // #cp_InvokeDynamic_count :UNSIGNED5[1] + // #cp_BootstrapMethod_count :UNSIGNED5[1] + // byte tag = ConstantPool.TAGS_IN_ORDER[k]; if (!haveNumbers) { // These four counts are optional. @@ -382,6 +384,16 @@ class PackageReader extends BandStructure { continue; } } + if (!haveCPExtra) { + // These four counts are optional. + switch (tag) { + case CONSTANT_MethodHandle: + case CONSTANT_MethodType: + case CONSTANT_InvokeDynamic: + case CONSTANT_BootstrapMethod: + continue; + } + } tagCount[tag] = archive_header_1.getInt(); } } @@ -401,6 +413,11 @@ class PackageReader extends BandStructure { return index; } + void checkLegacy(String bandname) { + if (this.pkg.package_majver < JAVA7_PACKAGE_MAJOR_VERSION) { + throw new RuntimeException("unexpected band " + bandname); + } + } void readConstantPool() throws IOException { // cp_bands: // cp_Utf8 @@ -533,8 +550,82 @@ class PackageReader extends BandStructure { case CONSTANT_InterfaceMethodref: readMemberRefs(tag, cpMap, cp_Imethod_class, cp_Imethod_desc); break; + case CONSTANT_MethodHandle: + if (cpMap.length > 0) { + checkLegacy(cp_MethodHandle_refkind.name()); + } + cp_MethodHandle_refkind.expectLength(cpMap.length); + cp_MethodHandle_refkind.readFrom(in); + cp_MethodHandle_member.expectLength(cpMap.length); + cp_MethodHandle_member.readFrom(in); + cp_MethodHandle_member.setIndex(getCPIndex(CONSTANT_AnyMember)); + for (int i = 0; i < cpMap.length; i++) { + byte refKind = (byte) cp_MethodHandle_refkind.getInt(); + MemberEntry memRef = (MemberEntry) cp_MethodHandle_member.getRef(); + cpMap[i] = ConstantPool.getMethodHandleEntry(refKind, memRef); + } + cp_MethodHandle_refkind.doneDisbursing(); + cp_MethodHandle_member.doneDisbursing(); + break; + case CONSTANT_MethodType: + if (cpMap.length > 0) { + checkLegacy(cp_MethodType.name()); + } + cp_MethodType.expectLength(cpMap.length); + cp_MethodType.readFrom(in); + cp_MethodType.setIndex(getCPIndex(CONSTANT_Signature)); + for (int i = 0; i < cpMap.length; i++) { + SignatureEntry typeRef = (SignatureEntry) cp_MethodType.getRef(); + cpMap[i] = ConstantPool.getMethodTypeEntry(typeRef); + } + cp_MethodType.doneDisbursing(); + break; + case CONSTANT_InvokeDynamic: + if (cpMap.length > 0) { + checkLegacy(cp_InvokeDynamic_spec.name()); + } + cp_InvokeDynamic_spec.expectLength(cpMap.length); + cp_InvokeDynamic_spec.readFrom(in); + cp_InvokeDynamic_spec.setIndex(getCPIndex(CONSTANT_BootstrapMethod)); + cp_InvokeDynamic_desc.expectLength(cpMap.length); + cp_InvokeDynamic_desc.readFrom(in); + cp_InvokeDynamic_desc.setIndex(getCPIndex(CONSTANT_NameandType)); + for (int i = 0; i < cpMap.length; i++) { + BootstrapMethodEntry bss = (BootstrapMethodEntry) cp_InvokeDynamic_spec.getRef(); + DescriptorEntry descr = (DescriptorEntry) cp_InvokeDynamic_desc.getRef(); + cpMap[i] = ConstantPool.getInvokeDynamicEntry(bss, descr); + } + cp_InvokeDynamic_spec.doneDisbursing(); + cp_InvokeDynamic_desc.doneDisbursing(); + break; + case CONSTANT_BootstrapMethod: + if (cpMap.length > 0) { + checkLegacy(cp_BootstrapMethod_ref.name()); + } + cp_BootstrapMethod_ref.expectLength(cpMap.length); + cp_BootstrapMethod_ref.readFrom(in); + cp_BootstrapMethod_ref.setIndex(getCPIndex(CONSTANT_MethodHandle)); + cp_BootstrapMethod_arg_count.expectLength(cpMap.length); + cp_BootstrapMethod_arg_count.readFrom(in); + int totalArgCount = cp_BootstrapMethod_arg_count.getIntTotal(); + cp_BootstrapMethod_arg.expectLength(totalArgCount); + cp_BootstrapMethod_arg.readFrom(in); + cp_BootstrapMethod_arg.setIndex(getCPIndex(CONSTANT_LoadableValue)); + for (int i = 0; i < cpMap.length; i++) { + MethodHandleEntry bsm = (MethodHandleEntry) cp_BootstrapMethod_ref.getRef(); + int argc = cp_BootstrapMethod_arg_count.getInt(); + Entry[] argRefs = new Entry[argc]; + for (int j = 0; j < argc; j++) { + argRefs[j] = cp_BootstrapMethod_arg.getRef(); + } + cpMap[i] = ConstantPool.getBootstrapMethodEntry(bsm, argRefs); + } + cp_BootstrapMethod_ref.doneDisbursing(); + cp_BootstrapMethod_arg_count.doneDisbursing(); + cp_BootstrapMethod_arg.doneDisbursing(); + break; default: - assert(false); + throw new AssertionError("unexpected CP tag in package"); } Index index = initCPIndex(tag, cpMap); @@ -548,6 +639,21 @@ class PackageReader extends BandStructure { cp_bands.doneDisbursing(); + if (optDumpBands || verbose > 1) { + for (byte tag = CONSTANT_GroupFirst; tag < CONSTANT_GroupLimit; tag++) { + Index index = pkg.cp.getIndexByTag(tag); + if (index == null || index.isEmpty()) continue; + Entry[] cpMap = index.cpMap; + if (verbose > 1) + Utils.log.info("Index group "+ConstantPool.tagName(tag)+" contains "+cpMap.length+" entries."); + if (optDumpBands) { + try (PrintStream ps = new PrintStream(getDumpStream(index.debugName, tag, ".gidx", index))) { + printArrayTo(ps, cpMap, 0, cpMap.length, true); + } + } + } + } + setBandIndexes(); } @@ -1056,8 +1162,16 @@ class PackageReader extends BandStructure { // look for constant pool entries: cls.visitRefs(VRM_CLASSIC, cpRefs); + ArrayList bsms = new ArrayList<>(); + /* + * BootstrapMethod(BSMs) are added here before InnerClasses(ICs), + * so as to ensure the order. Noting that the BSMs may be + * removed if they are not found in the CP, after the ICs expansion. + */ + cls.addAttribute(Package.attrBootstrapMethodsEmpty.canonicalInstance()); + // flesh out the local constant pool - ConstantPool.completeReferencesIn(cpRefs, true); + ConstantPool.completeReferencesIn(cpRefs, true, bsms); // Now that we know all our local class references, // compute the InnerClasses attribute. @@ -1074,14 +1188,23 @@ class PackageReader extends BandStructure { } // flesh out the local constant pool, again - ConstantPool.completeReferencesIn(cpRefs, true); + ConstantPool.completeReferencesIn(cpRefs, true, bsms); + } + + // remove the attr previously set, otherwise add the bsm and + // references as required + if (bsms.isEmpty()) { + cls.attributes.remove(Package.attrBootstrapMethodsEmpty.canonicalInstance()); + } else { + cpRefs.add(Package.getRefString("BootstrapMethods")); + Collections.sort(bsms); + cls.setBootstrapMethods(bsms); } // construct a local constant pool int numDoubles = 0; for (Entry e : cpRefs) { if (e.isDoubleWord()) numDoubles++; - assert(e.tag != CONSTANT_Signature) : (e); } Entry[] cpMap = new Entry[1+numDoubles+cpRefs.size()]; int fillp = 1; @@ -1154,7 +1277,8 @@ class PackageReader extends BandStructure { int totalNM = class_method_count.getIntTotal(); field_descr.expectLength(totalNF); method_descr.expectLength(totalNM); - if (verbose > 1) Utils.log.fine("expecting #fields="+totalNF+" and #methods="+totalNM+" in #classes="+numClasses); + if (verbose > 1) Utils.log.fine("expecting #fields="+totalNF+ + " and #methods="+totalNM+" in #classes="+numClasses); List fields = new ArrayList<>(totalNF); field_descr.readFrom(in); @@ -1393,7 +1517,8 @@ class PackageReader extends BandStructure { MultiBand xxx_attr_bands = attrBands[ctype]; long flagMask = attrFlagMask[ctype]; if (verbose > 1) { - Utils.log.fine("scanning flags and attrs for "+Attribute.contextName(ctype)+"["+holders.size()+"]"); + Utils.log.fine("scanning flags and attrs for "+ + Attribute.contextName(ctype)+"["+holders.size()+"]"); } // Fetch the attribute layout definitions which govern the bands @@ -1751,8 +1876,10 @@ class PackageReader extends BandStructure { bc_local, bc_label, bc_intref, bc_floatref, bc_longref, bc_doubleref, bc_stringref, + bc_loadablevalueref, bc_classref, bc_fieldref, bc_methodref, bc_imethodref, + bc_indyref, bc_thisfield, bc_superfield, bc_thismethod, bc_supermethod, bc_initref, @@ -2099,7 +2226,8 @@ class PackageReader extends BandStructure { case _ildc: case _cldc: case _fldc: - case _aldc: + case _sldc: + case _qldc: origBC = _ldc; size = 1; ldcRefSet.add(ref); @@ -2107,7 +2235,8 @@ class PackageReader extends BandStructure { case _ildc_w: case _cldc_w: case _fldc_w: - case _aldc_w: + case _sldc_w: + case _qldc_w: origBC = _ldc_w; break; case _lldc2_w: @@ -2136,6 +2265,9 @@ class PackageReader extends BandStructure { int argSize = ((MemberEntry)ref).descRef.typeRef.computeSize(true); buf[pc++] = (byte)( 1 + argSize ); buf[pc++] = 0; + } else if (origBC == _invokedynamic) { + buf[pc++] = 0; + buf[pc++] = 0; } assert(Instruction.opLength(origBC) == (pc - curPC)); continue; diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java index 0f7f51a7ec3..d40a6d3889e 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,15 +25,7 @@ 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.Entry; -import com.sun.java.util.jar.pack.ConstantPool.Index; -import com.sun.java.util.jar.pack.ConstantPool.IndexGroup; -import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; -import com.sun.java.util.jar.pack.ConstantPool.NumberEntry; -import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; -import com.sun.java.util.jar.pack.ConstantPool.StringEntry; +import com.sun.java.util.jar.pack.ConstantPool.*; import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.Package.File; import com.sun.java.util.jar.pack.Package.InnerClass; @@ -281,7 +273,7 @@ class PackageWriter extends BandStructure { void writeArchiveHeader() throws IOException { // for debug only: number of words optimized away - int headerDiscountForDebug = 0; + int headerSizeForDebug = AH_LENGTH_MIN; // AO_HAVE_SPECIAL_FORMATS is set if non-default // coding techniques are used, or if there are @@ -293,8 +285,8 @@ class PackageWriter extends BandStructure { if (haveSpecial) archiveOptions |= AO_HAVE_SPECIAL_FORMATS; } - if (!haveSpecial) - headerDiscountForDebug += AH_SPECIAL_FORMAT_LEN; + if (haveSpecial) + headerSizeForDebug += AH_SPECIAL_FORMAT_LEN; // AO_HAVE_FILE_HEADERS is set if there is any // file or segment envelope information present. @@ -305,8 +297,8 @@ class PackageWriter extends BandStructure { if (haveFiles) archiveOptions |= AO_HAVE_FILE_HEADERS; } - if (!haveFiles) - headerDiscountForDebug += AH_FILE_HEADER_LEN; + if (haveFiles) + headerSizeForDebug += AH_FILE_HEADER_LEN; // AO_HAVE_CP_NUMBERS is set if there are any numbers // in the global constant pool. (Numbers are in 15% of classes.) @@ -316,8 +308,19 @@ class PackageWriter extends BandStructure { if (haveNumbers) archiveOptions |= AO_HAVE_CP_NUMBERS; } - if (!haveNumbers) - headerDiscountForDebug += AH_CP_NUMBER_LEN; + if (haveNumbers) + headerSizeForDebug += AH_CP_NUMBER_LEN; + + // AO_HAVE_CP_EXTRAS is set if there are constant pool entries + // beyond the Java 6 version of the class file format. + boolean haveCPExtra = testBit(archiveOptions, AO_HAVE_CP_EXTRAS); + if (!haveCPExtra) { + haveCPExtra |= pkg.cp.haveExtraTags(); + if (haveCPExtra) + archiveOptions |= AO_HAVE_CP_EXTRAS; + } + if (haveCPExtra) + headerSizeForDebug += AH_CP_EXTRA_LEN; assert(pkg.package_majver > 0); // caller must specify! archive_header_0.putInt(pkg.package_minver); @@ -355,18 +358,18 @@ class PackageWriter extends BandStructure { assert(attrDefsWritten.length == 0); } - writeConstantPoolCounts(haveNumbers); + writeConstantPoolCounts(haveNumbers, haveCPExtra); archive_header_1.putInt(pkg.getAllInnerClasses().size()); archive_header_1.putInt(pkg.default_class_minver); archive_header_1.putInt(pkg.default_class_majver); archive_header_1.putInt(pkg.classes.size()); - // Sanity: Make sure we came out to 26 (less optional fields): + // Sanity: Make sure we came out to 29 (less optional fields): assert(archive_header_0.length() + archive_header_S.length() + archive_header_1.length() - == AH_LENGTH - headerDiscountForDebug); + == headerSizeForDebug); // Figure out all the sizes now, first cut: archiveSize0 = 0; @@ -394,9 +397,8 @@ class PackageWriter extends BandStructure { assert(all_bands.outputSize() == archiveSize0+archiveSize1); } - void writeConstantPoolCounts(boolean haveNumbers) throws IOException { - for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { - byte tag = ConstantPool.TAGS_IN_ORDER[k]; + void writeConstantPoolCounts(boolean haveNumbers, boolean haveCPExtra) throws IOException { + for (byte tag : ConstantPool.TAGS_IN_ORDER) { int count = pkg.cp.getIndexByTag(tag).size(); switch (tag) { case CONSTANT_Utf8: @@ -416,6 +418,17 @@ class PackageWriter extends BandStructure { continue; } break; + + case CONSTANT_MethodHandle: + case CONSTANT_MethodType: + case CONSTANT_InvokeDynamic: + case CONSTANT_BootstrapMethod: + // Omit counts for newer entities if possible. + if (!haveCPExtra) { + assert(count == 0); + continue; + } + break; } archive_header_1.putInt(count); } @@ -449,8 +462,7 @@ class PackageWriter extends BandStructure { if (verbose > 0) Utils.log.info("Writing CP"); - for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { - byte tag = ConstantPool.TAGS_IN_ORDER[k]; + for (byte tag : ConstantPool.TAGS_IN_ORDER) { Index index = cp.getIndexByTag(tag); Entry[] cpMap = index.cpMap; @@ -530,8 +542,52 @@ class PackageWriter extends BandStructure { case CONSTANT_InterfaceMethodref: writeMemberRefs(tag, cpMap, cp_Imethod_class, cp_Imethod_desc); break; + case CONSTANT_MethodHandle: + for (int i = 0; i < cpMap.length; i++) { + MethodHandleEntry e = (MethodHandleEntry) cpMap[i]; + cp_MethodHandle_refkind.putInt(e.refKind); + cp_MethodHandle_member.putRef(e.memRef); + } + break; + case CONSTANT_MethodType: + for (int i = 0; i < cpMap.length; i++) { + MethodTypeEntry e = (MethodTypeEntry) cpMap[i]; + cp_MethodType.putRef(e.typeRef); + } + break; + case CONSTANT_InvokeDynamic: + for (int i = 0; i < cpMap.length; i++) { + InvokeDynamicEntry e = (InvokeDynamicEntry) cpMap[i]; + cp_InvokeDynamic_spec.putRef(e.bssRef); + cp_InvokeDynamic_desc.putRef(e.descRef); + } + break; + case CONSTANT_BootstrapMethod: + for (int i = 0; i < cpMap.length; i++) { + BootstrapMethodEntry e = (BootstrapMethodEntry) cpMap[i]; + cp_BootstrapMethod_ref.putRef(e.bsmRef); + cp_BootstrapMethod_arg_count.putInt(e.argRefs.length); + for (Entry argRef : e.argRefs) { + cp_BootstrapMethod_arg.putRef(argRef); + } + } + break; default: - assert(false); + throw new AssertionError("unexpected CP tag in package"); + } + } + if (optDumpBands || verbose > 1) { + for (byte tag = CONSTANT_GroupFirst; tag < CONSTANT_GroupLimit; tag++) { + Index index = cp.getIndexByTag(tag); + if (index == null || index.isEmpty()) continue; + Entry[] cpMap = index.cpMap; + if (verbose > 1) + Utils.log.info("Index group "+ConstantPool.tagName(tag)+" contains "+cpMap.length+" entries."); + if (optDumpBands) { + try (PrintStream ps = new PrintStream(getDumpStream(index.debugName, tag, ".gidx", index))) { + printArrayTo(ps, cpMap, 0, cpMap.length, true); + } + } } } } @@ -988,6 +1044,8 @@ class PackageWriter extends BandStructure { for (Class cls : pkg.classes) { // Replace "obvious" SourceFile attrs by null. cls.minimizeSourceFile(); + // BootstrapMethods should never have been inserted. + assert(cls.getAttribute(Package.attrBootstrapMethodsEmpty) == null); } } @@ -1325,9 +1383,7 @@ class PackageWriter extends BandStructure { // %%% Add a stress mode which issues _ref/_byte_escape. if (verbose > 3) Utils.log.fine(i.toString()); - if (i.isNonstandard() - && (!p200.getBoolean(Utils.COM_PREFIX+"invokedynamic") - || i.getBC() != _xxxunusedxxx)) { + if (i.isNonstandard()) { // Crash and burn with a complaint if there are funny // bytecodes in this class file. String complaint = code.getMethod() @@ -1427,24 +1483,6 @@ class PackageWriter extends BandStructure { continue; } - switch (bc) { - case _xxxunusedxxx: // %%% pretend this is invokedynamic - { - i.setNonstandardLength(3); - int refx = i.getShortAt(1); - Entry ref = (refx == 0)? null: curCPMap[refx]; - // transmit the opcode, carefully: - bc_codes.putByte(_byte_escape); - bc_escsize.putInt(1); // one byte of opcode - bc_escbyte.putByte(bc); // the opcode - // transmit the CP reference, carefully: - bc_codes.putByte(_ref_escape); - bc_escrefsize.putInt(2); // two bytes of ref - bc_escref.putRef(ref); // the ref - continue; - } - } - int branch = i.getBranchLabel(); if (branch >= 0) { bc_codes.putByte(bc); @@ -1458,7 +1496,7 @@ class PackageWriter extends BandStructure { CPRefBand bc_which; int vbc = bc; switch (i.getCPTag()) { - case CONSTANT_Literal: + case CONSTANT_LoadableValue: switch (ref.tag) { case CONSTANT_Integer: bc_which = bc_intref; @@ -1489,8 +1527,8 @@ class PackageWriter extends BandStructure { case CONSTANT_String: bc_which = bc_stringref; switch (bc) { - case _ldc: vbc = _aldc; break; - case _ldc_w: vbc = _aldc_w; break; + case _ldc: vbc = _sldc; break; + case _ldc_w: vbc = _sldc_w; break; default: assert(false); } break; @@ -1503,8 +1541,16 @@ class PackageWriter extends BandStructure { } break; default: - bc_which = null; - assert(false); + // CONSTANT_MethodHandle, etc. + if (getPackageMajver() < JAVA7_PACKAGE_MAJOR_VERSION) { + throw new IOException("bad package major version for Java 7 ldc"); + } + bc_which = bc_loadablevalueref; + switch (bc) { + case _ldc: vbc = _qldc; break; + case _ldc_w: vbc = _qldc_w; break; + default: assert(false); + } } break; case CONSTANT_Class: @@ -1517,6 +1563,8 @@ class PackageWriter extends BandStructure { bc_which = bc_methodref; break; case CONSTANT_InterfaceMethodref: bc_which = bc_imethodref; break; + case CONSTANT_InvokeDynamic: + bc_which = bc_indyref; break; default: bc_which = null; assert(false); @@ -1532,6 +1580,12 @@ class PackageWriter extends BandStructure { assert(i.getLength() == 5); // Make sure the discarded bytes are sane: assert(i.getConstant() == (1+((MemberEntry)ref).descRef.typeRef.computeSize(true)) << 8); + } else if (bc == _invokedynamic) { + if (getPackageMajver() < JAVA7_PACKAGE_MAJOR_VERSION) { + throw new IOException("bad package major version for Java 7 invokedynamic"); + } + assert(i.getLength() == 5); + assert(i.getConstant() == 0); // last 2 bytes MBZ } else { // Make sure there is nothing else to write. assert(i.getLength() == ((bc == _ldc)?2:3)); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java index fc9d0998870..12316768bb2 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,10 @@ 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.MethodHandleEntry; +import com.sun.java.util.jar.pack.ConstantPool.MethodTypeEntry; +import com.sun.java.util.jar.pack.ConstantPool.InvokeDynamicEntry; +import com.sun.java.util.jar.pack.ConstantPool.BootstrapMethodEntry; import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; import java.util.HashMap; @@ -56,6 +60,10 @@ class TLGlobals { private final Map signatureEntries; private final Map descriptorEntries; private final Map memberEntries; + private final Map methodHandleEntries; + private final Map methodTypeEntries; + private final Map invokeDynamicEntries; + private final Map bootstrapMethodEntries; TLGlobals() { utf8Entries = new HashMap<>(); @@ -64,6 +72,10 @@ class TLGlobals { signatureEntries = new HashMap<>(); descriptorEntries = new HashMap<>(); memberEntries = new HashMap<>(); + methodHandleEntries = new HashMap<>(); + methodTypeEntries = new HashMap<>(); + invokeDynamicEntries = new HashMap<>(); + bootstrapMethodEntries = new HashMap<>(); props = new PropMap(); } @@ -94,4 +106,20 @@ class TLGlobals { Map getMemberEntries() { return memberEntries; } + + Map getMethodHandleEntries() { + return methodHandleEntries; + } + + Map getMethodTypeEntries() { + return methodTypeEntries; + } + + Map getInvokeDynamicEntries() { + return invokeDynamicEntries; + } + + Map getBootstrapMethodEntries() { + return bootstrapMethodEntries; + } } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java index f9d26eb306a..06ecaef5bbf 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ class Utils { * If >3, print tons of comments (e.g., processing of references). * (installer only) */ - static final String DEBUG_VERBOSE = Utils.COM_PREFIX+"verbose"; + static final String DEBUG_VERBOSE = COM_PREFIX+"verbose"; /* * Disables use of native code, prefers the Java-coded implementation. @@ -134,35 +134,11 @@ class Utils { // to the engine code, especially the native code. static final ThreadLocal currentInstance = new ThreadLocal<>(); - // convenience methods to access the TL globals + // convenience method to access the TL globals static TLGlobals getTLGlobals() { return currentInstance.get(); } - static Map getUtf8Entries() { - return getTLGlobals().getUtf8Entries(); - } - - static Map getClassEntries() { - return getTLGlobals().getClassEntries(); - } - - static Map getLiteralEntries() { - return getTLGlobals().getLiteralEntries(); - } - - static Map getDescriptorEntries() { - return getTLGlobals().getDescriptorEntries(); - } - - static Map getSignatureEntries() { - return getTLGlobals().getSignatureEntries(); - } - - static Map getMemberEntries() { - return getTLGlobals().getMemberEntries(); - } - static PropMap currentPropMap() { Object obj = currentInstance.get(); if (obj instanceof PackerImpl) @@ -173,8 +149,19 @@ class Utils { } static final boolean nolog - = Boolean.getBoolean(Utils.COM_PREFIX+"nolog"); + = Boolean.getBoolean(COM_PREFIX+"nolog"); + static final boolean SORT_MEMBERS_DESCR_MAJOR + = Boolean.getBoolean(COM_PREFIX+"sort.members.descr.major"); + + static final boolean SORT_HANDLES_KIND_MAJOR + = Boolean.getBoolean(COM_PREFIX+"sort.handles.kind.major"); + + static final boolean SORT_INDY_BSS_MAJOR + = Boolean.getBoolean(COM_PREFIX+"sort.indy.bss.major"); + + static final boolean SORT_BSS_BSM_MAJOR + = Boolean.getBoolean(COM_PREFIX+"sort.bss.bsm.major"); static class Pack200Logger { private final String name; diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp index 88955faec34..08cdc8d3e76 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -188,9 +188,13 @@ void band::setIndexByTag(byte tag) { entry* band::getRefCommon(cpindex* ix_, bool nullOKwithCaller) { CHECK_0; assert(ix_->ixTag == ixTag - || (ixTag == CONSTANT_Literal - && ix_->ixTag >= CONSTANT_Integer - && ix_->ixTag <= CONSTANT_String)); + || ((ixTag == CONSTANT_All || + ixTag == CONSTANT_LoadableValue || + ixTag == CONSTANT_AnyMember) + || (ixTag == CONSTANT_FieldSpecific && + ix_->ixTag >= CONSTANT_Integer && + ix_->ixTag <= CONSTANT_String)) + ); int n = vs[0].getInt() - nullOK; // Note: band-local nullOK means null encodes as 0. // But nullOKwithCaller means caller is willing to tolerate a null. @@ -270,22 +274,15 @@ int band::getIntCount(int tag) { #define NO_INDEX 0 struct band_init { -#ifndef PRODUCT int bn; const char* name; -#endif int defc; int index; }; -#ifdef PRODUCT -#define BAND_INIT(name, cspec, ix) \ - { cspec, ix } -#else #define BAND_INIT(name, cspec, ix) \ { e_##name, #name, /*debug only*/ \ cspec, ix } -#endif const band_init all_band_inits[] = { //BAND_INIT(archive_magic, BYTE1_spec, 0), @@ -314,6 +311,14 @@ const band_init all_band_inits[] = { BAND_INIT(cp_Method_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)), BAND_INIT(cp_Imethod_class, DELTA5_spec, INDEX(CONSTANT_Class)), BAND_INIT(cp_Imethod_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)), + BAND_INIT(cp_MethodHandle_refkind, DELTA5_spec, 0), + BAND_INIT(cp_MethodHandle_member, UDELTA5_spec, INDEX(CONSTANT_AnyMember)), + BAND_INIT(cp_MethodType, UDELTA5_spec, INDEX(CONSTANT_Signature)), + BAND_INIT(cp_BootstrapMethod_ref, DELTA5_spec, INDEX(CONSTANT_MethodHandle)), + BAND_INIT(cp_BootstrapMethod_arg_count, UDELTA5_spec, 0), + BAND_INIT(cp_BootstrapMethod_arg, DELTA5_spec, INDEX(CONSTANT_LoadableValue)), + BAND_INIT(cp_InvokeDynamic_spec, DELTA5_spec, INDEX(CONSTANT_BootstrapMethod)), + BAND_INIT(cp_InvokeDynamic_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)), BAND_INIT(attr_definition_headers, BYTE1_spec, 0), BAND_INIT(attr_definition_name, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), BAND_INIT(attr_definition_layout, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), @@ -333,7 +338,7 @@ const band_init all_band_inits[] = { BAND_INIT(field_attr_count, UNSIGNED5_spec, 0), BAND_INIT(field_attr_indexes, UNSIGNED5_spec, 0), BAND_INIT(field_attr_calls, UNSIGNED5_spec, 0), - BAND_INIT(field_ConstantValue_KQ, UNSIGNED5_spec, INDEX(CONSTANT_Literal)), + BAND_INIT(field_ConstantValue_KQ, UNSIGNED5_spec, INDEX(CONSTANT_FieldSpecific)), BAND_INIT(field_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), BAND_INIT(field_metadata_bands, -1, -1), BAND_INIT(field_attr_bands, -1, -1), @@ -415,10 +420,12 @@ const band_init all_band_inits[] = { BAND_INIT(bc_longref, DELTA5_spec, INDEX(CONSTANT_Long)), BAND_INIT(bc_doubleref, DELTA5_spec, INDEX(CONSTANT_Double)), BAND_INIT(bc_stringref, DELTA5_spec, INDEX(CONSTANT_String)), + BAND_INIT(bc_loadablevalueref, DELTA5_spec, INDEX(CONSTANT_LoadableValue)), BAND_INIT(bc_classref, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)), BAND_INIT(bc_fieldref, DELTA5_spec, INDEX(CONSTANT_Fieldref)), BAND_INIT(bc_methodref, UNSIGNED5_spec, INDEX(CONSTANT_Methodref)), BAND_INIT(bc_imethodref, DELTA5_spec, INDEX(CONSTANT_InterfaceMethodref)), + BAND_INIT(bc_indyref, DELTA5_spec, INDEX(CONSTANT_InvokeDynamic)), BAND_INIT(bc_thisfield, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Fieldref)), BAND_INIT(bc_superfield, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Fieldref)), BAND_INIT(bc_thismethod, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)), @@ -471,7 +478,7 @@ void band::initIndexes(unpacker* u) { for (int i = 0; i < BAND_LIMIT; i++) { band* scan = &tmp_all_bands[i]; uint tag = scan->ixTag; // Cf. #define INDEX(tag) above - if (tag != 0 && tag != CONSTANT_Literal && (tag & SUBINDEX_BIT) == 0) { + if (tag != 0 && tag != CONSTANT_FieldSpecific && (tag & SUBINDEX_BIT) == 0) { scan->setIndex(u->cp.getIndex(tag)); } } diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h index 8e15dcb0111..b8e322aa1db 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,7 @@ struct cpindex; struct unpacker; struct band { -#ifndef PRODUCT const char* name; -#endif int bn; // band_number of this band coding* defc; // default coding method cpindex* ix; // CP entry mapping, if CPRefBand @@ -162,6 +160,14 @@ enum band_number { e_cp_Method_desc, e_cp_Imethod_class, e_cp_Imethod_desc, + e_cp_MethodHandle_refkind, + e_cp_MethodHandle_member, + e_cp_MethodType, + e_cp_BootstrapMethod_ref, + e_cp_BootstrapMethod_arg_count, + e_cp_BootstrapMethod_arg, + e_cp_InvokeDynamic_spec, + e_cp_InvokeDynamic_desc, // bands which define transmission of attributes e_attr_definition_headers, @@ -284,11 +290,13 @@ enum band_number { e_bc_longref, e_bc_doubleref, e_bc_stringref, + e_bc_loadablevalueref, e_bc_classref, e_bc_fieldref, e_bc_methodref, e_bc_imethodref, + e_bc_indyref, // _self_linker_op family e_bc_thisfield, @@ -343,6 +351,14 @@ enum band_number { #define cp_Method_desc all_bands[e_cp_Method_desc] #define cp_Imethod_class all_bands[e_cp_Imethod_class] #define cp_Imethod_desc all_bands[e_cp_Imethod_desc] +#define cp_MethodHandle_refkind all_bands[e_cp_MethodHandle_refkind] +#define cp_MethodHandle_member all_bands[e_cp_MethodHandle_member] +#define cp_MethodType all_bands[e_cp_MethodType] +#define cp_BootstrapMethod_ref all_bands[e_cp_BootstrapMethod_ref] +#define cp_BootstrapMethod_arg_count all_bands[e_cp_BootstrapMethod_arg_count] +#define cp_BootstrapMethod_arg all_bands[e_cp_BootstrapMethod_arg] +#define cp_InvokeDynamic_spec all_bands[e_cp_InvokeDynamic_spec] +#define cp_InvokeDynamic_desc all_bands[e_cp_InvokeDynamic_desc] #define attr_definition_headers all_bands[e_attr_definition_headers] #define attr_definition_name all_bands[e_attr_definition_name] #define attr_definition_layout all_bands[e_attr_definition_layout] @@ -437,10 +453,12 @@ enum band_number { #define bc_longref all_bands[e_bc_longref] #define bc_doubleref all_bands[e_bc_doubleref] #define bc_stringref all_bands[e_bc_stringref] +#define bc_loadablevalueref all_bands[e_bc_loadablevalueref] #define bc_classref all_bands[e_bc_classref] #define bc_fieldref all_bands[e_bc_fieldref] #define bc_methodref all_bands[e_bc_methodref] #define bc_imethodref all_bands[e_bc_imethodref] +#define bc_indyref all_bands[e_bc_indyref] #define bc_thisfield all_bands[e_bc_thisfield] #define bc_superfield all_bands[e_bc_superfield] #define bc_thismethod all_bands[e_bc_thismethod] diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h b/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h index 22a6b6c3e58..a3a8c553368 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,61 +49,82 @@ #define JAVA6_PACKAGE_MAJOR_VERSION 160 #define JAVA6_PACKAGE_MINOR_VERSION 1 +#define JAVA7_PACKAGE_MAJOR_VERSION 170 +#define JAVA7_PACKAGE_MINOR_VERSION 1 // magic number for gzip streams (for processing pack200-gzip data) #define GZIP_MAGIC 0x1F8B0800 #define GZIP_MAGIC_MASK 0xFFFFFF00 // last byte is variable "flg" field enum { - CONSTANT_None, - CONSTANT_Utf8, - CONSTANT_unused2, /* unused, was Unicode */ - CONSTANT_Integer, - CONSTANT_Float, - CONSTANT_Long, - CONSTANT_Double, - CONSTANT_Class, - CONSTANT_String, - CONSTANT_Fieldref, - CONSTANT_Methodref, - CONSTANT_InterfaceMethodref, - CONSTANT_NameandType, + CONSTANT_None = 0, + CONSTANT_Utf8 = 1, + CONSTANT_unused = 2, /* unused, was Unicode */ + 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, + CONSTANT_unused13 = 13, + CONSTANT_unused14 = 14, + CONSTANT_MethodHandle = 15, + CONSTANT_MethodType = 16, + CONSTANT_unused17 = 17, + CONSTANT_InvokeDynamic = 18, + CONSTANT_Limit = 19, + CONSTANT_Signature = CONSTANT_unused13, + CONSTANT_BootstrapMethod = CONSTANT_unused17, // used only for InvokeDynamic + CONSTANT_All = 50, // combined global map + CONSTANT_LoadableValue = 51, // used for 'KL' and qldc operands + CONSTANT_AnyMember = 52, // union of refs to field or (interface) method + CONSTANT_FieldSpecific = 53, // used only for 'KQ' ConstantValue attrs + CONSTANT_GroupFirst = CONSTANT_All, // start group marker + CONSTANT_GroupLimit = 54, // end group marker - CONSTANT_Signature = 13, - CONSTANT_All = 14, - CONSTANT_Limit = 15, - CONSTANT_NONE = 0, - - CONSTANT_Literal = 20, //pseudo-tag for debugging - CONSTANT_Member = 21, //pseudo-tag for debugging + // CONSTANT_MethodHandle reference kinds + REF_getField = 1, + REF_getStatic = 2, + REF_putField = 3, + REF_putStatic = 4, + REF_invokeVirtual = 5, + REF_invokeStatic = 6, + REF_invokeSpecial = 7, + REF_newInvokeSpecial = 8, + REF_invokeInterface = 9, SUBINDEX_BIT = 64, // combined with CONSTANT_xxx for ixTag ACC_STATIC = 0x0008, ACC_IC_LONG_FORM = (1<<16), //for ic_flags - CLASS_ATTR_SourceFile = 17, - CLASS_ATTR_EnclosingMethod = 18, - CLASS_ATTR_InnerClasses = 23, - CLASS_ATTR_ClassFile_version = 24, - FIELD_ATTR_ConstantValue = 17, - METHOD_ATTR_Code = 17, - METHOD_ATTR_Exceptions = 18, - METHOD_ATTR_RuntimeVisibleParameterAnnotations = 23, + CLASS_ATTR_SourceFile = 17, + CLASS_ATTR_EnclosingMethod = 18, + CLASS_ATTR_InnerClasses = 23, + CLASS_ATTR_ClassFile_version = 24, + CLASS_ATTR_BootstrapMethods = 25, + FIELD_ATTR_ConstantValue = 17, + METHOD_ATTR_Code = 17, + METHOD_ATTR_Exceptions = 18, + METHOD_ATTR_RuntimeVisibleParameterAnnotations = 23, METHOD_ATTR_RuntimeInvisibleParameterAnnotations = 24, - METHOD_ATTR_AnnotationDefault = 25, - CODE_ATTR_StackMapTable = 0, - CODE_ATTR_LineNumberTable = 1, - CODE_ATTR_LocalVariableTable = 2, + METHOD_ATTR_AnnotationDefault = 25, + CODE_ATTR_StackMapTable = 0, + CODE_ATTR_LineNumberTable = 1, + CODE_ATTR_LocalVariableTable = 2, CODE_ATTR_LocalVariableTypeTable = 3, //X_ATTR_Synthetic = 12, // ACC_SYNTHETIC; not predefined - X_ATTR_Signature = 19, - X_ATTR_Deprecated = 20, - X_ATTR_RuntimeVisibleAnnotations = 21, + X_ATTR_Signature = 19, + X_ATTR_Deprecated = 20, + X_ATTR_RuntimeVisibleAnnotations = 21, X_ATTR_RuntimeInvisibleAnnotations = 22, - X_ATTR_OVERFLOW = 16, - X_ATTR_LIMIT_NO_FLAGS_HI = 32, - X_ATTR_LIMIT_FLAGS_HI = 63, + X_ATTR_OVERFLOW = 16, + X_ATTR_LIMIT_NO_FLAGS_HI = 32, + X_ATTR_LIMIT_FLAGS_HI = 63, #define O_ATTR_DO(F) \ F(X_ATTR_OVERFLOW,01) \ @@ -121,6 +142,7 @@ enum { F(CLASS_ATTR_InnerClasses,InnerClasses) \ F(CLASS_ATTR_EnclosingMethod,EnclosingMethod) \ F(CLASS_ATTR_ClassFile_version,02) \ + F(CLASS_ATTR_BootstrapMethods,BootstrapMethods) \ /*(end)*/ #define FIELD_ATTR_DO(F) \ F(FIELD_ATTR_ConstantValue,ConstantValue) \ @@ -175,7 +197,7 @@ enum { AO_HAVE_SPECIAL_FORMATS = 1<<0, AO_HAVE_CP_NUMBERS = 1<<1, AO_HAVE_ALL_CODE_FLAGS = 1<<2, - AO_3_UNUSED_MBZ = 1<<3, + AO_HAVE_CP_EXTRAS = 1<<3, AO_HAVE_FILE_HEADERS = 1<<4, AO_DEFLATE_HINT = 1<<5, AO_HAVE_FILE_MODTIME = 1<<6, @@ -185,11 +207,13 @@ enum { AO_HAVE_FIELD_FLAGS_HI = 1<<10, AO_HAVE_METHOD_FLAGS_HI = 1<<11, AO_HAVE_CODE_FLAGS_HI = 1<<12, + AO_UNUSED_MBZ = (-1)<<13, // options bits reserved for future use. + #define ARCHIVE_BIT_DO(F) \ F(AO_HAVE_SPECIAL_FORMATS) \ F(AO_HAVE_CP_NUMBERS) \ F(AO_HAVE_ALL_CODE_FLAGS) \ - /*F(AO_3_UNUSED_MBZ)*/ \ + F(AO_HAVE_CP_EXTRAS) \ F(AO_HAVE_FILE_HEADERS) \ F(AO_DEFLATE_HINT) \ F(AO_HAVE_FILE_MODTIME) \ @@ -215,14 +239,14 @@ enum { NO_MODTIME = 0, // null modtime value // meta-coding - _meta_default = 0, + _meta_default = 0, _meta_canon_min = 1, _meta_canon_max = 115, - _meta_arb = 116, - _meta_run = 117, - _meta_pop = 141, - _meta_limit = 189, - _meta_error = 255, + _meta_arb = 116, + _meta_run = 117, + _meta_pop = 141, + _meta_limit = 189, + _meta_error = 255, _xxx_1_end }; @@ -416,7 +440,7 @@ enum { bc_invokespecial = 183, // 0xb7 bc_invokestatic = 184, // 0xb8 bc_invokeinterface = 185, // 0xb9 - bc_xxxunusedxxx = 186, // 0xba + bc_invokedynamic = 186, // 0xba bc_new = 187, // 0xbb bc_newarray = 188, // 0xbc bc_anewarray = 189, // 0xbd @@ -455,17 +479,19 @@ enum { _invokeinit_limit = _invokeinit_op+3, _xldc_op = _invokeinit_limit, - bc_aldc = bc_ldc, + bc_sldc = bc_ldc, // previously named bc_aldc bc_cldc = _xldc_op+0, bc_ildc = _xldc_op+1, bc_fldc = _xldc_op+2, - bc_aldc_w = bc_ldc_w, + bc_sldc_w = bc_ldc_w, // previously named bc_aldc_w bc_cldc_w = _xldc_op+3, bc_ildc_w = _xldc_op+4, bc_fldc_w = _xldc_op+5, bc_lldc2_w = bc_ldc2_w, bc_dldc2_w = _xldc_op+6, - _xldc_limit = _xldc_op+7, - + // anything other primitive, string, or class must be handled with qldc: + bc_qldc = _xldc_op+7, + bc_qldc_w = _xldc_op+8, + _xldc_limit = _xldc_op+9, _xxx_3_end }; diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/defines.h b/jdk/src/share/native/com/sun/java/util/jar/pack/defines.h index e49cade19b8..7fe36ffe576 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/defines.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/defines.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,7 +109,8 @@ typedef DWORDLONG julong; #define dup2(a,b) _dup2(a,b) #define strcasecmp(s1, s2) _stricmp(s1,s2) #define tempname _tempname -#define sleep Sleep +#define sleep Sleep +#define snprintf _snprintf #else typedef signed char byte; #ifdef _LP64 diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index cee146d4db4..d7c51978ded 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,12 @@ static const byte TAGS_IN_ORDER[] = { CONSTANT_NameandType, CONSTANT_Fieldref, CONSTANT_Methodref, - CONSTANT_InterfaceMethodref + CONSTANT_InterfaceMethodref, + // constants defined as of JDK 7 + CONSTANT_MethodHandle, + CONSTANT_MethodType, + CONSTANT_BootstrapMethod, + CONSTANT_InvokeDynamic }; #define N_TAGS_IN_ORDER (sizeof TAGS_IN_ORDER) @@ -101,6 +106,11 @@ static const char* TAG_NAME[] = { "InterfaceMethodref", "NameandType", "*Signature", + "unused14", + "MethodHandle", + "MethodType", + "*BootstrapMethod", + "InvokeDynamic", 0 }; @@ -114,9 +124,13 @@ static const char* ATTR_CONTEXT_NAME[] = { // match ATTR_CONTEXT_NAME, etc. #endif - -// REQUESTED must be -2 for u2 and REQUESTED_LDC must be -1 for u1 -enum { NOT_REQUESTED = 0, REQUESTED = -2, REQUESTED_LDC = -1 }; +// Note that REQUESTED_LDC comes first, then the normal REQUESTED, +// in the regular constant pool. +enum { REQUESTED_NONE = -1, + // The codes below REQUESTED_NONE are in constant pool output order, + // for the sake of outputEntry_cmp: + REQUESTED_LDC = -99, REQUESTED +}; #define NO_INORD ((uint)-1) @@ -146,7 +160,7 @@ struct entry { void requestOutputIndex(cpool& cp, int req = REQUESTED); int getOutputIndex() { - assert(outputIndex > NOT_REQUESTED); + assert(outputIndex > REQUESTED_NONE); return outputIndex; } @@ -167,12 +181,12 @@ struct entry { } entry* memberClass() { - assert(tagMatches(CONSTANT_Member)); + assert(tagMatches(CONSTANT_AnyMember)); return ref(0); } entry* memberDescr() { - assert(tagMatches(CONSTANT_Member)); + assert(tagMatches(CONSTANT_AnyMember)); return ref(1); } @@ -199,9 +213,9 @@ struct entry { return (tag2 == tag) || (tag2 == CONSTANT_Utf8 && tag == CONSTANT_Signature) #ifndef PRODUCT - || (tag2 == CONSTANT_Literal + || (tag2 == CONSTANT_FieldSpecific && tag >= CONSTANT_Integer && tag <= CONSTANT_String && tag != CONSTANT_Class) - || (tag2 == CONSTANT_Member + || (tag2 == CONSTANT_AnyMember && tag >= CONSTANT_Fieldref && tag <= CONSTANT_InterfaceMethodref) #endif ; @@ -309,6 +323,7 @@ void unpacker::free() { code_fixup_offset.free(); code_fixup_source.free(); requested_ics.free(); + cp.requested_bsms.free(); cur_classfile_head.free(); cur_classfile_tail.free(); for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) @@ -448,12 +463,12 @@ maybe_inline int unpacker::putref_index(entry* e, int size) { if (e == null) return 0; - else if (e->outputIndex > NOT_REQUESTED) + else if (e->outputIndex > REQUESTED_NONE) return e->outputIndex; else if (e->tag == CONSTANT_Signature) return putref_index(e->ref(0), size); else { - e->requestOutputIndex(cp, -size); + e->requestOutputIndex(cp, (size == 1 ? REQUESTED_LDC : REQUESTED)); // Later on we'll fix the bits. class_fixup_type.addByte(size); class_fixup_offset.add((int)wpoffset()); @@ -515,28 +530,33 @@ void unpacker::saveTo(bytes& b, byte* ptr, size_t len) { b.copyFrom(ptr, len); } +bool testBit(int archive_options, int bitMask) { + return (archive_options & bitMask) != 0; +} + // Read up through band_headers. // Do the archive_size dance to set the size of the input mega-buffer. void unpacker::read_file_header() { // Read file header to determine file type and total size. enum { MAGIC_BYTES = 4, - AH_LENGTH_0 = 3, //minver, majver, options are outside of archive_size + AH_LENGTH_0 = 3, // archive_header_0 = {minver, majver, options} + AH_LENGTH_MIN = 15, // observed in spec {header_0[3], cp_counts[8], class_counts[4]} AH_LENGTH_0_MAX = AH_LENGTH_0 + 1, // options might have 2 bytes - AH_LENGTH = 26, //maximum archive header length (w/ all fields) + AH_LENGTH = 30, //maximum archive header length (w/ all fields) // Length contributions from optional header fields: - AH_FILE_HEADER_LEN = 5, // sizehi/lo/next/modtime/files - AH_ARCHIVE_SIZE_LEN = 2, // sizehi/lo only; part of AH_FILE_HEADER_LEN - AH_CP_NUMBER_LEN = 4, // int/float/long/double - AH_SPECIAL_FORMAT_LEN = 2, // layouts/band-headers - AH_LENGTH_MIN = AH_LENGTH - -(AH_FILE_HEADER_LEN+AH_SPECIAL_FORMAT_LEN+AH_CP_NUMBER_LEN), - ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - (AH_LENGTH_0 + AH_ARCHIVE_SIZE_LEN), + AH_LENGTH_S = 2, // archive_header_S = optional {size_hi, size_lo} + AH_ARCHIVE_SIZE_HI = 0, // offset in archive_header_S + AH_ARCHIVE_SIZE_LO = 1, // offset in archive_header_S + AH_FILE_HEADER_LEN = 5, // file_counts = {{size_hi, size_lo), next, modtile, files} + AH_SPECIAL_FORMAT_LEN = 2, // special_count = {layouts, band_headers} + AH_CP_NUMBER_LEN = 4, // cp_number_counts = {int, float, long, double} + AH_CP_EXTRA_LEN = 4, // cp_attr_counts = {MH, MT, InDy, BSM} + ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S, FIRST_READ = MAGIC_BYTES + AH_LENGTH_MIN }; assert(AH_LENGTH_MIN == 15); // # of UNSIGNED5 fields required after archive_magic - assert(ARCHIVE_SIZE_MIN == 10); // # of UNSIGNED5 fields required after archive_size // An absolute minimum null archive is magic[4], {minver,majver,options}[3], // archive_size[0], cp_counts[8], class_counts[4], for a total of 19 bytes. // (Note that archive_size is optional; it may be 0..10 bytes in length.) @@ -622,23 +642,32 @@ void unpacker::read_file_header() { // Read the first 3 values from the header. value_stream hdr; int hdrVals = 0; - int hdrValsSkipped = 0; // debug only + int hdrValsSkipped = 0; // for assert hdr.init(rp, rplimit, UNSIGNED5_spec); minver = hdr.getInt(); majver = hdr.getInt(); hdrVals += 2; - if (magic != (int)JAVA_PACKAGE_MAGIC || - (majver != JAVA5_PACKAGE_MAJOR_VERSION && - majver != JAVA6_PACKAGE_MAJOR_VERSION) || - (minver != JAVA5_PACKAGE_MINOR_VERSION && - minver != JAVA6_PACKAGE_MINOR_VERSION)) { + int majmin[3][2] = { + {JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION}, + {JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION}, + {JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION} + }; + int majminfound = false; + for (int i = 0 ; i < 3 ; i++) { + if (majver == majmin[i][0] && minver == majmin[i][1]) { + majminfound = true; + break; + } + } + if (majminfound == null) { char message[200]; sprintf(message, "@" ERROR_FORMAT ": magic/ver = " - "%08X/%d.%d should be %08X/%d.%d OR %08X/%d.%d\n", + "%08X/%d.%d should be %08X/%d.%d OR %08X/%d.%d OR %08X/%d.%d\n", magic, majver, minver, JAVA_PACKAGE_MAGIC, JAVA5_PACKAGE_MAJOR_VERSION, JAVA5_PACKAGE_MINOR_VERSION, - JAVA_PACKAGE_MAGIC, JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION); + JAVA_PACKAGE_MAGIC, JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION, + JAVA_PACKAGE_MAGIC, JAVA7_PACKAGE_MAJOR_VERSION, JAVA7_PACKAGE_MINOR_VERSION); abort(message); } CHECK; @@ -646,18 +675,26 @@ void unpacker::read_file_header() { archive_options = hdr.getInt(); hdrVals += 1; assert(hdrVals == AH_LENGTH_0); // first three fields only + bool haveSizeHi = testBit(archive_options, AO_HAVE_FILE_SIZE_HI); + bool haveModTime = testBit(archive_options, AO_HAVE_FILE_MODTIME); + bool haveFileOpt = testBit(archive_options, AO_HAVE_FILE_OPTIONS); -#define ORBIT(bit) |(bit) - int OPTION_LIMIT = (0 ARCHIVE_BIT_DO(ORBIT)); -#undef ORBIT - if ((archive_options & ~OPTION_LIMIT) != 0) { - fprintf(errstrm, "Warning: Illegal archive options 0x%x\n", - archive_options); - abort("illegal archive options"); + bool haveSpecial = testBit(archive_options, AO_HAVE_SPECIAL_FORMATS); + bool haveFiles = testBit(archive_options, AO_HAVE_FILE_HEADERS); + bool haveNumbers = testBit(archive_options, AO_HAVE_CP_NUMBERS); + bool haveCPExtra = testBit(archive_options, AO_HAVE_CP_EXTRAS); + + if (majver < JAVA7_PACKAGE_MAJOR_VERSION) { + if (haveCPExtra) { + abort("Format bits for Java 7 must be zero in previous releases"); + return; + } + } + if (testBit(archive_options, AO_UNUSED_MBZ)) { + abort("High archive option bits are reserved and must be zero"); return; } - - if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) { + if (haveFiles) { uint hi = hdr.getInt(); uint lo = hdr.getInt(); julong x = band::makeLong(hi, lo); @@ -738,13 +775,23 @@ void unpacker::read_file_header() { return; } - // read the rest of the header fields - ensure_input((AH_LENGTH-AH_LENGTH_0) * B_MAX); + // read the rest of the header fields int assertSkipped = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S; + int remainingHeaders = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S; + if (haveSpecial) + remainingHeaders += AH_SPECIAL_FORMAT_LEN; + if (haveFiles) + remainingHeaders += AH_FILE_HEADER_LEN; + if (haveNumbers) + remainingHeaders += AH_CP_NUMBER_LEN; + if (haveCPExtra) + remainingHeaders += AH_CP_EXTRA_LEN; + + ensure_input(remainingHeaders * B_MAX); CHECK; hdr.rp = rp; hdr.rplimit = rplimit; - if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) { + if (haveFiles) { archive_next_count = hdr.getInt(); CHECK_COUNT(archive_next_count); archive_modtime = hdr.getInt(); @@ -755,7 +802,7 @@ void unpacker::read_file_header() { hdrValsSkipped += 3; } - if ((archive_options & AO_HAVE_SPECIAL_FORMATS) != 0) { + if (haveSpecial) { band_headers_size = hdr.getInt(); CHECK_COUNT(band_headers_size); attr_definition_count = hdr.getInt(); @@ -767,7 +814,7 @@ void unpacker::read_file_header() { int cp_counts[N_TAGS_IN_ORDER]; for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) { - if (!(archive_options & AO_HAVE_CP_NUMBERS)) { + if (!haveNumbers) { switch (TAGS_IN_ORDER[k]) { case CONSTANT_Integer: case CONSTANT_Float: @@ -778,6 +825,17 @@ void unpacker::read_file_header() { continue; } } + if (!haveCPExtra) { + switch(TAGS_IN_ORDER[k]) { + case CONSTANT_MethodHandle: + case CONSTANT_MethodType: + case CONSTANT_InvokeDynamic: + case CONSTANT_BootstrapMethod: + cp_counts[k] = 0; + hdrValsSkipped += 1; + continue; + } + } cp_counts[k] = hdr.getInt(); CHECK_COUNT(cp_counts[k]); hdrVals += 1; @@ -791,36 +849,26 @@ void unpacker::read_file_header() { CHECK_COUNT(class_count); hdrVals += 4; - // done with archive_header + // done with archive_header, time to reconcile to ensure + // we have read everything correctly hdrVals += hdrValsSkipped; assert(hdrVals == AH_LENGTH); -#ifndef PRODUCT - int assertSkipped = AH_LENGTH - AH_LENGTH_MIN; - if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) - assertSkipped -= AH_FILE_HEADER_LEN; - if ((archive_options & AO_HAVE_SPECIAL_FORMATS) != 0) - assertSkipped -= AH_SPECIAL_FORMAT_LEN; - if ((archive_options & AO_HAVE_CP_NUMBERS) != 0) - assertSkipped -= AH_CP_NUMBER_LEN; - assert(hdrValsSkipped == assertSkipped); -#endif //PRODUCT - rp = hdr.rp; if (rp > rplimit) abort("EOF reading archive header"); // Now size the CP. #ifndef PRODUCT - bool x = (N_TAGS_IN_ORDER == cpool::NUM_COUNTS); - assert(x); + // bool x = (N_TAGS_IN_ORDER == CONSTANT_Limit); + // assert(x); #endif //PRODUCT cp.init(this, cp_counts); CHECK; default_file_modtime = archive_modtime; - if (default_file_modtime == 0 && !(archive_options & AO_HAVE_FILE_MODTIME)) + if (default_file_modtime == 0 && haveModTime) default_file_modtime = DEFAULT_ARCHIVE_MODTIME; // taken from driver - if ((archive_options & AO_DEFLATE_HINT) != 0) + if (testBit(archive_options, AO_DEFLATE_HINT)) default_file_options |= FO_DEFLATE_HINT; // meta-bytes, if any, immediately follow archive header @@ -876,7 +924,7 @@ void unpacker::finish() { // Cf. PackageReader.readConstantPoolCounts -void cpool::init(unpacker* u_, int counts[NUM_COUNTS]) { +void cpool::init(unpacker* u_, int counts[CONSTANT_Limit]) { this->u = u_; // Fill-pointer for CP. @@ -924,13 +972,16 @@ void cpool::init(unpacker* u_, int counts[NUM_COUNTS]) { first_extra_entry = &entries[nentries]; // Initialize the standard indexes. - tag_count[CONSTANT_All] = nentries; - tag_base[ CONSTANT_All] = 0; for (int tag = 0; tag < CONSTANT_Limit; tag++) { entry* cpMap = &entries[tag_base[tag]]; tag_index[tag].init(tag_count[tag], cpMap, tag); } + // Initialize *all* our entries once + for (int i = 0 ; i < maxentries ; i++) + entries[i].outputIndex = REQUESTED_NONE; + + initGroupIndexes(); // Initialize hashTab to a generous power-of-two size. uint pow2 = 1; uint target = maxentries + maxentries/2; // 60% full @@ -1281,6 +1332,70 @@ void unpacker::read_signature_values(entry* cpMap, int len) { //cp_Signature_classes.done(); } +maybe_inline +void unpacker::checkLegacy(const char* name) { + if (u->majver < JAVA7_PACKAGE_MAJOR_VERSION) { + char message[100]; + snprintf(message, 99, "unexpected band %s\n", name); + abort(message); + } +} + +maybe_inline +void unpacker::read_method_handle(entry* cpMap, int len) { + if (len > 0) { + checkLegacy(cp_MethodHandle_refkind.name); + } + cp_MethodHandle_refkind.readData(len); + cp_MethodHandle_member.setIndexByTag(CONSTANT_AnyMember); + cp_MethodHandle_member.readData(len); + for (int i = 0 ; i < len ; i++) { + entry& e = cpMap[i]; + e.value.i = cp_MethodHandle_refkind.getInt(); + e.refs = U_NEW(entry*, e.nrefs = 1); + e.refs[0] = cp_MethodHandle_member.getRef(); + CHECK; + } +} + +maybe_inline +void unpacker::read_method_type(entry* cpMap, int len) { + if (len > 0) { + checkLegacy(cp_MethodType.name); + } + cp_MethodType.setIndexByTag(CONSTANT_Signature); + cp_MethodType.readData(len); + for (int i = 0 ; i < len ; i++) { + entry& e = cpMap[i]; + e.refs = U_NEW(entry*, e.nrefs = 1); + e.refs[0] = cp_MethodType.getRef(); + } +} + +maybe_inline +void unpacker::read_bootstrap_methods(entry* cpMap, int len) { + if (len > 0) { + checkLegacy(cp_BootstrapMethod_ref.name); + } + cp_BootstrapMethod_ref.setIndexByTag(CONSTANT_MethodHandle); + cp_BootstrapMethod_ref.readData(len); + + cp_BootstrapMethod_arg_count.readData(len); + int totalArgCount = cp_BootstrapMethod_arg_count.getIntTotal(); + cp_BootstrapMethod_arg.setIndexByTag(CONSTANT_LoadableValue); + cp_BootstrapMethod_arg.readData(totalArgCount); + for (int i = 0; i < len; i++) { + entry& e = cpMap[i]; + int argc = cp_BootstrapMethod_arg_count.getInt(); + e.value.i = argc; + e.refs = U_NEW(entry*, e.nrefs = argc + 1); + e.refs[0] = cp_BootstrapMethod_ref.getRef(); + for (int j = 1 ; j < e.nrefs ; j++) { + e.refs[j] = cp_BootstrapMethod_arg.getRef(); + CHECK; + } + } +} // Cf. PackageReader.readConstantPool void unpacker::read_cp() { byte* rp0 = rp; @@ -1298,6 +1413,14 @@ void unpacker::read_cp() { cpMap[i].tag = tag; cpMap[i].inord = i; } + // Initialize the tag's CP index right away, since it might be needed + // in the next pass to initialize the CP for another tag. +#ifndef PRODUCT + cpindex* ix = &cp.tag_index[tag]; + assert(ix->ixTag == tag); + assert((int)ix->len == len); + assert(ix->base1 == cpMap); +#endif switch (tag) { case CONSTANT_Utf8: @@ -1344,19 +1467,27 @@ void unpacker::read_cp() { CONSTANT_Class, CONSTANT_NameandType, cpMap, len); break; + case CONSTANT_MethodHandle: + // consumes cp_MethodHandle_refkind and cp_MethodHandle_member + read_method_handle(cpMap, len); + break; + case CONSTANT_MethodType: + // consumes cp_MethodType + read_method_type(cpMap, len); + break; + case CONSTANT_InvokeDynamic: + read_double_refs(cp_InvokeDynamic_spec, CONSTANT_BootstrapMethod, + CONSTANT_NameandType, + cpMap, len); + break; + case CONSTANT_BootstrapMethod: + // consumes cp_BootstrapMethod_ref, cp_BootstrapMethod_arg_count and cp_BootstrapMethod_arg + read_bootstrap_methods(cpMap, len); + break; default: assert(false); break; } - - // Initialize the tag's CP index right away, since it might be needed - // in the next pass to initialize the CP for another tag. -#ifndef PRODUCT - cpindex* ix = &cp.tag_index[tag]; - assert(ix->ixTag == tag); - assert((int)ix->len == len); - assert(ix->base1 == cpMap); -#endif CHECK; } @@ -1791,7 +1922,12 @@ unpacker::attr_definitions::parseLayout(const char* lp, band** &res, case 'F': ixTag = CONSTANT_Float; break; case 'D': ixTag = CONSTANT_Double; break; case 'S': ixTag = CONSTANT_String; break; - case 'Q': ixTag = CONSTANT_Literal; break; + case 'Q': ixTag = CONSTANT_FieldSpecific; break; + + // new in 1.7 + case 'M': ixTag = CONSTANT_MethodHandle; break; + case 'T': ixTag = CONSTANT_MethodType; break; + case 'L': ixTag = CONSTANT_LoadableValue; break; } } else { switch (*lp++) { @@ -1803,6 +1939,11 @@ unpacker::attr_definitions::parseLayout(const char* lp, band** &res, case 'I': ixTag = CONSTANT_InterfaceMethodref; break; case 'U': ixTag = CONSTANT_Utf8; break; //utf8_ref case 'Q': ixTag = CONSTANT_All; break; //untyped_ref + + // new in 1.7 + case 'Y': ixTag = CONSTANT_InvokeDynamic; break; + case 'B': ixTag = CONSTANT_BootstrapMethod; break; + case 'N': ixTag = CONSTANT_AnyMember; break; } } if (ixTag == CONSTANT_None) { @@ -1873,13 +2014,13 @@ void unpacker::read_attr_defs() { // Decide whether bands for the optional high flag words are present. attr_defs[ATTR_CONTEXT_CLASS] - .setHaveLongFlags((archive_options & AO_HAVE_CLASS_FLAGS_HI) != 0); + .setHaveLongFlags(testBit(archive_options, AO_HAVE_CLASS_FLAGS_HI)); attr_defs[ATTR_CONTEXT_FIELD] - .setHaveLongFlags((archive_options & AO_HAVE_FIELD_FLAGS_HI) != 0); + .setHaveLongFlags(testBit(archive_options, AO_HAVE_FIELD_FLAGS_HI)); attr_defs[ATTR_CONTEXT_METHOD] - .setHaveLongFlags((archive_options & AO_HAVE_METHOD_FLAGS_HI) != 0); + .setHaveLongFlags(testBit(archive_options, AO_HAVE_METHOD_FLAGS_HI)); attr_defs[ATTR_CONTEXT_CODE] - .setHaveLongFlags((archive_options & AO_HAVE_CODE_FLAGS_HI) != 0); + .setHaveLongFlags(testBit(archive_options, AO_HAVE_CODE_FLAGS_HI)); // Set up built-in attrs. // (The simple ones are hard-coded. The metadata layouts are not.) @@ -2579,7 +2720,7 @@ void unpacker::putlayout(band** body) { // It has data, so unparse an element. if (b.ixTag != CONSTANT_None) { assert(le_kind == EK_REF); - if (b.ixTag == CONSTANT_Literal) + if (b.ixTag == CONSTANT_FieldSpecific) e = b.getRefUsing(cp.getKQIndex()); else e = b.getRefN(); @@ -2653,13 +2794,13 @@ void unpacker::putlayout(band** body) { void unpacker::read_files() { file_name.readData(file_count); - if ((archive_options & AO_HAVE_FILE_SIZE_HI) != 0) + if (testBit(archive_options, AO_HAVE_FILE_SIZE_HI)) file_size_hi.readData(file_count); file_size_lo.readData(file_count); - if ((archive_options & AO_HAVE_FILE_MODTIME) != 0) + if (testBit(archive_options, AO_HAVE_FILE_MODTIME)) file_modtime.readData(file_count); int allFiles = file_count + class_count; - if ((archive_options & AO_HAVE_FILE_OPTIONS) != 0) { + if (testBit(archive_options, AO_HAVE_FILE_OPTIONS)) { file_options.readData(file_count); // FO_IS_CLASS_STUB might be set, causing overlap between classes and files for (int i = 0; i < file_count; i++) { @@ -2703,7 +2844,7 @@ void unpacker::get_code_header(int& max_stack, max_stack = sc % mod; max_na_locals = sc / mod; // caller must add static, siglen handler_count = nh; - if ((archive_options & AO_HAVE_ALL_CODE_FLAGS) != 0) + if (testBit(archive_options, AO_HAVE_ALL_CODE_FLAGS)) cflags = -1; else cflags = 0; // this one has no attributes @@ -2777,12 +2918,14 @@ band* unpacker::ref_band_for_op(int bc) { return &bc_longref; case bc_dldc2_w: return &bc_doubleref; - case bc_aldc: - case bc_aldc_w: + case bc_sldc: + case bc_sldc_w: return &bc_stringref; case bc_cldc: case bc_cldc_w: return &bc_classref; + case bc_qldc: case bc_qldc_w: + return &bc_loadablevalueref; case bc_getstatic: case bc_putstatic: @@ -2796,6 +2939,8 @@ band* unpacker::ref_band_for_op(int bc) { return &bc_methodref; case bc_invokeinterface: return &bc_imethodref; + case bc_invokedynamic: + return &bc_indyref; case bc_new: case bc_anewarray: @@ -3131,6 +3276,71 @@ void cpool::expandSignatures() { } } +bool isLoadableValue(int tag) { + switch(tag) { + case CONSTANT_Integer: + case CONSTANT_Float: + case CONSTANT_Long: + case CONSTANT_Double: + case CONSTANT_String: + case CONSTANT_Class: + case CONSTANT_MethodHandle: + case CONSTANT_MethodType: + return true; + default: + return false; + } +} +/* + * this method can be used to size an array using null as the parameter, + * thereafter can be reused to initialize the array using a valid pointer + * as a parameter. + */ +int cpool::initLoadableValues(entry** loadable_entries) { + int loadable_count = 0; + for (int i = 0; i < (int)N_TAGS_IN_ORDER; i++) { + int tag = TAGS_IN_ORDER[i]; + if (!isLoadableValue(tag)) + continue; + if (loadable_entries != NULL) { + for (int n = 0 ; n < tag_count[tag] ; n++) { + loadable_entries[loadable_count + n] = &entries[tag_base[tag] + n]; + } + } + loadable_count += tag_count[tag]; + } + return loadable_count; +} + +// Initialize various views into the constant pool. +void cpool::initGroupIndexes() { + // Initialize All + int all_count = 0; + for (int tag = CONSTANT_None ; tag < CONSTANT_Limit ; tag++) { + all_count += tag_count[tag]; + } + entry* all_entries = &entries[tag_base[CONSTANT_None]]; + tag_group_count[CONSTANT_All - CONSTANT_All] = all_count; + tag_group_index[CONSTANT_All - CONSTANT_All].init(all_count, all_entries, CONSTANT_All); + + // Initialize LoadableValues + int loadable_count = initLoadableValues(NULL); + entry** loadable_entries = U_NEW(entry*, loadable_count); + initLoadableValues(loadable_entries); + tag_group_count[CONSTANT_LoadableValue - CONSTANT_All] = loadable_count; + tag_group_index[CONSTANT_LoadableValue - CONSTANT_All].init(loadable_count, + loadable_entries, CONSTANT_LoadableValue); + +// Initialize AnyMembers + int any_count = tag_count[CONSTANT_Fieldref] + + tag_count[CONSTANT_Methodref] + + tag_count[CONSTANT_InterfaceMethodref]; + entry *any_entries = &entries[tag_base[CONSTANT_Fieldref]]; + tag_group_count[CONSTANT_AnyMember - CONSTANT_All] = any_count; + tag_group_index[CONSTANT_AnyMember - CONSTANT_All].init(any_count, + any_entries, CONSTANT_AnyMember); +} + void cpool::initMemberIndexes() { // This function does NOT refer to any class schema. // It is totally internal to the cpool. @@ -3238,13 +3448,13 @@ void cpool::initMemberIndexes() { } void entry::requestOutputIndex(cpool& cp, int req) { - assert(outputIndex <= NOT_REQUESTED); // must not have assigned indexes yet + assert(outputIndex <= REQUESTED_NONE); // must not have assigned indexes yet if (tag == CONSTANT_Signature) { ref(0)->requestOutputIndex(cp, req); return; } assert(req == REQUESTED || req == REQUESTED_LDC); - if (outputIndex != NOT_REQUESTED) { + if (outputIndex != REQUESTED_NONE) { if (req == REQUESTED_LDC) outputIndex = req; // this kind has precedence return; @@ -3252,31 +3462,52 @@ void entry::requestOutputIndex(cpool& cp, int req) { outputIndex = req; //assert(!cp.outputEntries.contains(this)); assert(tag != CONSTANT_Signature); - cp.outputEntries.add(this); + // The BSMs are jetisoned to a side table, however all references + // that the BSMs refer to, need to be considered. + if (tag == CONSTANT_BootstrapMethod) { + // this is a a pseudo-op entry; an attribute will be generated later on + cp.requested_bsms.add(this); + } else { + // all other tag types go into real output file CP: + cp.outputEntries.add(this); + } for (int j = 0; j < nrefs; j++) { ref(j)->requestOutputIndex(cp); } } void cpool::resetOutputIndexes() { - int i; - int noes = outputEntries.length(); + /* + * reset those few entries that are being used in the current class + * (Caution since this method is called after every class written, a loop + * over every global constant pool entry would be a quadratic cost.) + */ + + int noes = outputEntries.length(); entry** oes = (entry**) outputEntries.base(); - for (i = 0; i < noes; i++) { + for (int i = 0 ; i < noes ; i++) { entry& e = *oes[i]; - e.outputIndex = NOT_REQUESTED; + e.outputIndex = REQUESTED_NONE; + } + + // do the same for bsms and reset them if required + int nbsms = requested_bsms.length(); + entry** boes = (entry**) requested_bsms.base(); + for (int i = 0 ; i < nbsms ; i++) { + entry& e = *boes[i]; + e.outputIndex = REQUESTED_NONE; } outputIndexLimit = 0; outputEntries.empty(); #ifndef PRODUCT - // they must all be clear now - for (i = 0; i < (int)nentries; i++) - assert(entries[i].outputIndex == NOT_REQUESTED); + // ensure things are cleared out + for (int i = 0; i < (int)maxentries; i++) + assert(entries[i].outputIndex == REQUESTED_NONE); #endif } static const byte TAG_ORDER[CONSTANT_Limit] = { - 0, 1, 0, 2, 3, 4, 5, 7, 6, 10, 11, 12, 9, 8 + 0, 1, 0, 2, 3, 4, 5, 7, 6, 10, 11, 12, 9, 8, 0, 13, 14, 15, 16 }; extern "C" @@ -3323,10 +3554,18 @@ void cpool::computeOutputIndexes() { if (nentries > 100) checkStep = nentries / 100; for (i = (int)(checkStart++ % checkStep); i < (int)nentries; i += checkStep) { entry& e = entries[i]; - if (e.outputIndex != NOT_REQUESTED) { - assert(outputEntries.contains(&e)); + if (e.tag == CONSTANT_BootstrapMethod) { + if (e.outputIndex != REQUESTED_NONE) { + assert(requested_bsms.contains(&e)); + } else { + assert(!requested_bsms.contains(&e)); + } } else { - assert(!outputEntries.contains(&e)); + if (e.outputIndex != REQUESTED_NONE) { + assert(outputEntries.contains(&e)); + } else { + assert(!outputEntries.contains(&e)); + } } } @@ -3348,7 +3587,7 @@ void cpool::computeOutputIndexes() { int nextIndex = 1; // always skip index #0 in output cpool for (i = 0; i < noes; i++) { entry& e = *oes[i]; - assert(e.outputIndex == REQUESTED || e.outputIndex == REQUESTED_LDC); + assert(e.outputIndex >= REQUESTED_LDC); e.outputIndex = nextIndex++; if (e.isDoubleWord()) nextIndex++; // do not use the next index } @@ -3396,7 +3635,7 @@ char* entry::string() { default: if (nrefs == 0) { buf = getbuf(20); - sprintf((char*)buf.ptr, "", tag); + sprintf((char*)buf.ptr, TAG_NAME[tag]); } else if (nrefs == 1) { return refs[0]->string(); } else { @@ -3674,6 +3913,7 @@ void unpacker::reset_cur_classfile() { class_fixup_offset.empty(); class_fixup_ref.empty(); requested_ics.empty(); + cp.requested_bsms.empty(); } cpindex* cpool::getKQIndex() { @@ -3931,13 +4171,15 @@ void unpacker::write_bc_ops() { case bc_ildc: case bc_cldc: case bc_fldc: - case bc_aldc: + case bc_sldc: + case bc_qldc: origBC = bc_ldc; break; case bc_ildc_w: case bc_cldc_w: case bc_fldc_w: - case bc_aldc_w: + case bc_sldc_w: + case bc_qldc_w: origBC = bc_ldc_w; break; case bc_lldc2_w: @@ -3962,6 +4204,10 @@ void unpacker::write_bc_ops() { int argSize = ref->memberDescr()->descrType()->typeSize(); putu1_fast(1 + argSize); putu1_fast(0); + } else if (origBC == bc_invokedynamic) { + // pad the next two byte + putu1_fast(0); + putu1_fast(0); } continue; } @@ -4353,49 +4599,12 @@ int raw_address_cmp(const void* p1p, const void* p2p) { return (p1 > p2)? 1: (p1 < p2)? -1: 0; } -void unpacker::write_classfile_tail() { - cur_classfile_tail.empty(); - set_output(&cur_classfile_tail); - - int i, num; - - attr_definitions& ad = attr_defs[ATTR_CONTEXT_CLASS]; - - bool haveLongFlags = ad.haveLongFlags(); - julong kflags = class_flags_hi.getLong(class_flags_lo, haveLongFlags); - julong indexMask = ad.flagIndexMask(); - - cur_class = class_this.getRef(); - cur_super = class_super.getRef(); - - CHECK; - - if (cur_super == cur_class) cur_super = null; - // special representation for java/lang/Object - - putu2((ushort)(kflags & ~indexMask)); - putref(cur_class); - putref(cur_super); - - putu2(num = class_interface_count.getInt()); - for (i = 0; i < num; i++) { - putref(class_interface.getRef()); - } - - write_members(class_field_count.getInt(), ATTR_CONTEXT_FIELD); - write_members(class_method_count.getInt(), ATTR_CONTEXT_METHOD); - CHECK; - - cur_class_has_local_ics = false; // may be set true by write_attrs - - - int naOffset = (int)wpoffset(); - int na = write_attrs(ATTR_CONTEXT_CLASS, (kflags & indexMask)); - - - // at the very last, choose which inner classes (if any) pertain to k: +/* + * writes the InnerClass attributes and returns the updated attribute + */ +int unpacker::write_ics(int naOffset, int na) { #ifdef ASSERT - for (i = 0; i < ic_count; i++) { + for (int i = 0; i < ic_count; i++) { assert(!ics[i].requested); } #endif @@ -4416,7 +4625,7 @@ void unpacker::write_classfile_tail() { // include it and all its outers. int noes = cp.outputEntries.length(); entry** oes = (entry**) cp.outputEntries.base(); - for (i = 0; i < noes; i++) { + for (int i = 0; i < noes; i++) { entry& e = *oes[i]; if (e.tag != CONSTANT_Class) continue; // wrong sort for (inner_class* ic = cp.getIC(&e); @@ -4442,10 +4651,10 @@ void unpacker::write_classfile_tail() { // Note: extra_ics will be freed up by next call to get_next_file(). } } - for (i = 0; i < num_extra_ics; i++) { + for (int i = 0; i < num_extra_ics; i++) { inner_class& extra_ic = extra_ics[i]; extra_ic.inner = class_InnerClasses_RC.getRef(); - CHECK; + CHECK_0; // Find the corresponding equivalent global IC: inner_class* global_ic = cp.getIC(extra_ic.inner); int flags = class_InnerClasses_F.getInt(); @@ -4493,7 +4702,7 @@ void unpacker::write_classfile_tail() { putu2(local_ics); PTRLIST_QSORT(requested_ics, raw_address_cmp); int num_global_ics = requested_ics.length(); - for (i = -num_global_ics; i < num_extra_ics; i++) { + for (int i = -num_global_ics; i < num_extra_ics; i++) { inner_class* ic; if (i < 0) ic = (inner_class*) requested_ics.get(num_global_ics+i); @@ -4512,17 +4721,99 @@ void unpacker::write_classfile_tail() { } // Tidy up global 'requested' bits: - for (i = requested_ics.length(); --i >= 0; ) { + for (int i = requested_ics.length(); --i >= 0; ) { inner_class* ic = (inner_class*) requested_ics.get(i); ic->requested = false; } requested_ics.empty(); + return na; +} +/* + * Writes the BootstrapMethods attribute and returns the updated attribute count + */ +int unpacker::write_bsms(int naOffset, int na) { + cur_class_local_bsm_count = cp.requested_bsms.length(); + if (cur_class_local_bsm_count > 0) { + int noes = cp.outputEntries.length(); + entry** oes = (entry**) cp.outputEntries.base(); + PTRLIST_QSORT(cp.requested_bsms, outputEntry_cmp); + // append the BootstrapMethods attribute (after the InnerClasses attr): + putref(cp.sym[cpool::s_BootstrapMethods]); + int sizeOffset = (int)wpoffset(); + byte* sizewp = wp; + putu4(-99); // attr size will be patched + putu2(cur_class_local_bsm_count); + int written_bsms = 0; + for (int i = 0 ; i < cur_class_local_bsm_count ; i++) { + entry* e = (entry*)cp.requested_bsms.get(i); + assert(e->outputIndex != REQUESTED_NONE); + // output index is the index within the array + e->outputIndex = i; + putref(e->refs[0]); // bsm + putu2(e->nrefs-1); // number of args after bsm + for (int j = 1; j < e->nrefs; j++) { + putref(e->refs[j]); + } + written_bsms += 1; + } + assert(written_bsms == cur_class_local_bsm_count); // else insane + putu4_at(sizewp, (int)(wp - (sizewp+4))); // size of code attr + putu2_at(wp_at(naOffset), ++na); // increment class attr count + } + return na; +} + +void unpacker::write_classfile_tail() { + + cur_classfile_tail.empty(); + set_output(&cur_classfile_tail); + + int i, num; + + attr_definitions& ad = attr_defs[ATTR_CONTEXT_CLASS]; + + bool haveLongFlags = ad.haveLongFlags(); + julong kflags = class_flags_hi.getLong(class_flags_lo, haveLongFlags); + julong indexMask = ad.flagIndexMask(); + + cur_class = class_this.getRef(); + cur_super = class_super.getRef(); CHECK; + + if (cur_super == cur_class) cur_super = null; + // special representation for java/lang/Object + + putu2((ushort)(kflags & ~indexMask)); + putref(cur_class); + putref(cur_super); + + putu2(num = class_interface_count.getInt()); + for (i = 0; i < num; i++) { + putref(class_interface.getRef()); + } + + write_members(class_field_count.getInt(), ATTR_CONTEXT_FIELD); + write_members(class_method_count.getInt(), ATTR_CONTEXT_METHOD); + CHECK; + + cur_class_has_local_ics = false; // may be set true by write_attrs + + int naOffset = (int)wpoffset(); // note the attr count location + int na = write_attrs(ATTR_CONTEXT_CLASS, (kflags & indexMask)); + CHECK; + + na = write_bsms(naOffset, na); + CHECK; + + // choose which inner classes (if any) pertain to k: + na = write_ics(naOffset, na); + CHECK; + close_output(); + cp.computeOutputIndexes(); // rewrite CP references in the tail - cp.computeOutputIndexes(); int nextref = 0; for (i = 0; i < (int)class_fixup_type.size(); i++) { int type = class_fixup_type.getByte(i); @@ -4579,9 +4870,18 @@ void unpacker::write_classfile_head() { case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: case CONSTANT_NameandType: + case CONSTANT_InvokeDynamic: putu2(e.refs[0]->getOutputIndex()); putu2(e.refs[1]->getOutputIndex()); break; + case CONSTANT_MethodHandle: + putu1(e.value.i); + putu2(e.refs[0]->getOutputIndex()); + break; + case CONSTANT_MethodType: + putu2(e.refs[0]->getOutputIndex()); + break; + case CONSTANT_BootstrapMethod: // should not happen default: abort(ERROR_INTERNAL); } @@ -4620,11 +4920,11 @@ unpacker::file* unpacker::get_next_file() { entry* e = file_name.getRef(); CHECK_0; cur_file.name = e->utf8String(); - bool haveLongSize = ((archive_options & AO_HAVE_FILE_SIZE_HI) != 0); + bool haveLongSize = (testBit(archive_options, AO_HAVE_FILE_SIZE_HI)); cur_file.size = file_size_hi.getLong(file_size_lo, haveLongSize); - if ((archive_options & AO_HAVE_FILE_MODTIME) != 0) + if (testBit(archive_options, AO_HAVE_FILE_MODTIME)) cur_file.modtime += file_modtime.getInt(); //relative to archive modtime - if ((archive_options & AO_HAVE_FILE_OPTIONS) != 0) + if (testBit(archive_options, AO_HAVE_FILE_OPTIONS)) cur_file.options |= file_options.getInt() & ~suppress_file_options; } else if (classes_written < class_count) { // there is a class for a missing file record diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h index 0f66b7ef6f5..cec7a88b24e 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - - - // Global Structures struct jar; struct gunzip; @@ -70,6 +67,9 @@ struct cpool { cpindex tag_index[CONSTANT_Limit]; ptrlist tag_extras[CONSTANT_Limit]; + int tag_group_count[CONSTANT_GroupLimit - CONSTANT_GroupFirst]; + cpindex tag_group_index[CONSTANT_GroupLimit - CONSTANT_GroupFirst]; + cpindex* member_indexes; // indexed by 2*CONSTANT_Class.inord cpindex* getFieldIndex(entry* classRef); cpindex* getMethodIndex(entry* classRef); @@ -82,6 +82,7 @@ struct cpool { int outputIndexLimit; // index limit after renumbering ptrlist outputEntries; // list of entry* needing output idx assigned + ptrlist requested_bsms; // which bsms need output? entry** hashTab; uint hashTabLength; @@ -100,24 +101,36 @@ struct cpool { entry* sym[s_LIMIT]; // read counts from hdr, allocate main arrays - enum { NUM_COUNTS = 12 }; - void init(unpacker* u, int counts[NUM_COUNTS]); + void init(unpacker* u, int counts[CONSTANT_Limit]); // pointer to outer unpacker, for error checks etc. unpacker* u; int getCount(byte tag) { - assert((uint)tag < CONSTANT_Limit); - return tag_count[tag]; + if ((uint)tag >= CONSTANT_GroupFirst) { + assert((uint)tag < CONSTANT_GroupLimit); + return tag_group_count[(uint)tag - CONSTANT_GroupFirst]; + } else { + assert((uint)tag < CONSTANT_Limit); + return tag_count[(uint)tag]; + } } cpindex* getIndex(byte tag) { - assert((uint)tag < CONSTANT_Limit); - return &tag_index[tag]; + if ((uint)tag >= CONSTANT_GroupFirst) { + assert((uint)tag < CONSTANT_GroupLimit); + return &tag_group_index[(uint)tag - CONSTANT_GroupFirst]; + } else { + assert((uint)tag < CONSTANT_Limit); + return &tag_index[(uint)tag]; + } } + cpindex* getKQIndex(); // uses cur_descr void expandSignatures(); + void initGroupIndexes(); void initMemberIndexes(); + int initLoadableValues(entry** loadable_entries); void computeOutputOrder(); void computeOutputIndexes(); @@ -234,6 +247,7 @@ struct unpacker { int cur_descr_flags; // flags corresponding to cur_descr int cur_class_minver, cur_class_majver; bool cur_class_has_local_ics; + int cur_class_local_bsm_count; fillbytes cur_classfile_head; fillbytes cur_classfile_tail; int files_written; // also tells which file we're working on @@ -412,7 +426,7 @@ struct unpacker { void abort(const char* s = null); bool aborting() { return abort_message != null; } static unpacker* current(); // find current instance - + void checkLegacy(const char* name); // Output management void set_output(fillbytes* which) { assert(wp == null); @@ -464,6 +478,8 @@ struct unpacker { void write_bc_ops(); void write_members(int num, int attrc); // attrc=ATTR_CONTEXT_FIELD/METHOD int write_attrs(int attrc, julong indexBits); + int write_ics(int naOffset, int na); + int write_bsms(int naOffset, int na); // The readers void read_bands(); @@ -484,6 +500,9 @@ struct unpacker { void read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len); void read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag, entry* cpMap, int len); void read_signature_values(entry* cpMap, int len); + void read_method_handle(entry* cpMap, int len); + void read_method_type(entry* cpMap, int len); + void read_bootstrap_methods(entry* cpMap, int len); }; inline void cpool::abort(const char* msg) { u->abort(msg); } diff --git a/jdk/test/tools/pack200/AttributeTests.java b/jdk/test/tools/pack200/AttributeTests.java index e7107996cc8..69547083025 100644 --- a/jdk/test/tools/pack200/AttributeTests.java +++ b/jdk/test/tools/pack200/AttributeTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ import java.util.Arrays; import java.util.List; /* * @test - * @bug 6982312 + * @bug 6746111 * @summary tests various classfile format and attribute handling by pack200 * @compile -XDignore.symbol.file Utils.java AttributeTests.java * @run main AttributeTests @@ -36,40 +36,8 @@ import java.util.List; public class AttributeTests { public static void main(String... args) throws Exception { - test6982312(); test6746111(); } - /* - * This is an interim test, which ensures pack200 handles JSR-292 related - * classfile changes seamlessly, until all the classfile changes in jdk7 - * and jdk8 are fully supported. At that time this test should be jettisoned, - * along with the associated jar file. - * - * The jar file contains sources and classes noting the classes were - * derived by using the javac from the lambda project, - * see http://openjdk.java.net/projects/lambda/. - * Therefore the classes contained in the jar cannot be compiled, using - * the standard jdk7's javac compiler. - */ - static void test6982312() throws IOException { - String pack200Cmd = Utils.getPack200Cmd(); - File dynJar = new File(".", "dyn.jar"); - Utils.copyFile(new File(Utils.TEST_SRC_DIR, "dyn.jar"), dynJar); - File testJar = new File(".", "test.jar"); - List cmds = new ArrayList(); - cmds.add(pack200Cmd); - cmds.add("--repack"); - cmds.add(testJar.getAbsolutePath()); - cmds.add(dynJar.getAbsolutePath()); - Utils.runExec(cmds); - /* - * compare the repacked jar bit-wise, as all the files - * should be transmitted "as-is". - */ - Utils.doCompareBitWise(dynJar.getAbsoluteFile(), testJar.getAbsoluteFile()); - testJar.delete(); - dynJar.delete(); - } /* * this test checks to see if we get the expected strings for output diff --git a/jdk/test/tools/pack200/PackageVersionTest.java b/jdk/test/tools/pack200/PackageVersionTest.java index 538b92ecafc..8569781a6ec 100644 --- a/jdk/test/tools/pack200/PackageVersionTest.java +++ b/jdk/test/tools/pack200/PackageVersionTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,6 +51,9 @@ public class PackageVersionTest { public final static int JAVA6_PACKAGE_MAJOR_VERSION = 160; public final static int JAVA6_PACKAGE_MINOR_VERSION = 1; + public final static int JAVA7_PACKAGE_MAJOR_VERSION = 170; + public final static int JAVA7_PACKAGE_MINOR_VERSION = 1; + public static void main(String... args) { if (!javaHome.getName().endsWith("jre")) { throw new RuntimeException("Error: requires an SDK to run"); @@ -68,9 +71,8 @@ public class PackageVersionTest { verifyPack("Test6.class", JAVA6_PACKAGE_MAJOR_VERSION, JAVA6_PACKAGE_MINOR_VERSION); - // TODO: change this to the java7 package version as needed. - verifyPack("Test7.class", JAVA6_PACKAGE_MAJOR_VERSION, - JAVA6_PACKAGE_MINOR_VERSION); + verifyPack("Test7.class", JAVA7_PACKAGE_MAJOR_VERSION, + JAVA7_PACKAGE_MINOR_VERSION); // test for resource file, ie. no class files verifyPack("Test6.java", JAVA5_PACKAGE_MAJOR_VERSION, diff --git a/jdk/test/tools/pack200/Utils.java b/jdk/test/tools/pack200/Utils.java index 8158f486ca2..0e2269822f5 100644 --- a/jdk/test/tools/pack200/Utils.java +++ b/jdk/test/tools/pack200/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,8 +129,10 @@ class Utils { init(); List cmds = new ArrayList(); cmds.add(getJavaCmd()); - cmds.add("-jar"); - cmds.add(VerifierJar.getName()); + cmds.add("-cp"); + cmds.add(Utils.locateJar("tools.jar") + + System.getProperty("path.separator") + VerifierJar.getName()); + cmds.add("sun.tools.pack.verify.Main"); cmds.add(reference.getAbsolutePath()); cmds.add(specimen.getAbsolutePath()); cmds.add("-O"); @@ -142,8 +144,10 @@ class Utils { init(); List cmds = new ArrayList(); cmds.add(getJavaCmd()); - cmds.add("-jar"); - cmds.add(VerifierJar.getName()); + cmds.add("-cp"); + cmds.add(Utils.locateJar("tools.jar") + + System.getProperty("path.separator") + VerifierJar.getName()); + cmds.add("sun.tools.pack.verify.Main"); cmds.add(reference.getName()); cmds.add(specimen.getName()); cmds.add("-O"); diff --git a/jdk/test/tools/pack200/dyn.jar b/jdk/test/tools/pack200/dyn.jar deleted file mode 100644 index b04c2a9e825b1201cbdcd2f863478587356ce7ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1963 zcmWIWW@Zs#U|`^2c-v!byUlj8x<8PY48(j4G7O%1X{kl2dC94IS&3zdp&^_M%yyOw zeXja1^eL_2W?*D_%gn&Q!pOwHaQck4r>>W`k6$Q9*_Y52&z@?XKJOEF;_8Jh&z`P& z`t;FLuXCO{dSM)%x_XQ!#ipxFOHtEy5RuHx&d1H~Dgj+?o~Swaqc4$yzY58#_4Sl{Zs zK1N`(P0!DM{(Pq5+3)o?!x{Pm^cS_5vYX4^Dcab_%RZZL$JIOc?Efp&&5J&J z=-6~~d%L_{J9>4+%Qw7zu&!J7&gQ_)4~--ILzkQ}Zp%4qpLSyJh1!!F?gUP>k>KBL zWG8fY!i+f+I}fFpj2|xI=~uL$ zkhtQcUy01OlWZHOh`cIXJ9*VNCqdTg^}E$KrAtkp;VisbBV)^7SJ6;g8TY@1P7gxV zoqZ3yeCZ&WxT5E3)as}DZb=zFU!QQ!=V^JEYd1ydk=th%pPgRsJ_l;JD(&o4jh)@- zwWCkP-)+-!7YRSfFum*5YeM%=G&{q$B%a)b5y)b zwJOz*uCiBV%6}cV@65ixN5d?m|2AuH(AGFp&}uOIAnTsh#yS(rC#G@x&6+I~S(2RG z`$tyfgMjOs%cs?Bqg7q|zFg0UpMSmnu{k24Yy>8hHCO-V{Q#!jtH8tpNx!g!0#Cns z*wabxgwt7v4Fp`j|LbzRYmwkHb;`bM(bP@qwxH_&xZN!d;>-5V zZnR9_VX*A&31gWn3qEP>s(H_5^(eYzm1)&G#g5UUOfiZzss^bF!HmfdN?7ky zNHN!(bDk=ue`?P6PYtskvaDB-+A{6PyHj;vpKf)3@?}b+#L3%UDGJwTU%g*;d-p2- z$@}*1{@-4=%JSQoZ(MdvD`MLTXh ze=o;Jx9t;vvHJn3BPhRd!$>;GTaTX<&! z>tUC>PX(QYmO5pfd;Eb3;hgEAdbULcnR=?gsB8mbkaI#(i%XEQeBYLSY*{|G|E%|6 z2Z5va&2od1bFyEDe|)s@>xBln)lDKxoK`t?v*+JVxw7S?+b6|u=RYl}5IFxY@R5or z7vGyVpDI4j-hSU+em+CrMYDyA!>$LKUohC%xvX(oqb}p$BjI&bY70ttZD)Gw_++BP z-H)QNsSl?->YT&2X38OD#$uV&jo#vQ>#pcswLQ8d=GECJo3|t^$Xe8to7Q{Yovlpg zO;Z0%VXvS@w|ASESIWJ4{j%rIl|xpmn11Jp-11!Z#v*v7{G?i8cl~ZfR(}!hHLXQ{ ztx5&A3c1?02YlEoYQj@nb6 zJ(PCYe5GmG-o<}d&sL^Rtv`ELM@Do?<*HfF|IN-#j!a6u`ZKO+yUN**-Xr08)7ENv?Yzx!DhnpCbSR-8VV}J@feDk z#Sso&(s%$^J9y^7425KPpqZcykH<{RWRGkn0}BI6CIFfT$^>}K!%Vjbj~{642bzbR bih<^VQZa^ktZblwVg3?iFylWjC2)mwwRynnZR_RD z>uBj~$?I(CYR`*w^>uTyJB%*Mcpxl|L9we zlyMFP`n8p4={Jdzz$9&VEGh~FIw90d+nsu=Pies4yaOU2z%$TX@QqVSlcdvGdT~2H z%&9kyk&U_rb;!hMZHD)X@dtfhGe;o<<8!ByJ_HT@sF>4K#X%;_=i`g?6n>%4w$%|k z>v4@GEb1T1nXfv1FthDL%n$fJ(68@j^}6eKRKfz|s_JK!r={MV=C8!h;o$k)oL`!Q zAB%W31Igg6;>#gp_V1`Al)BlGAX(aPr?5dyuqGrtgOXkAf@b8@4cPdyI~lGAv>97z z$lS`1*Q%Z#HA=kR_`RRuS-H5{eC4w{6g@2R)?_&wMdDW%T1sjb8#39F3t009%S-~9 zdaSFQ9lvL5y8hUdIZ*jpEiU%j5l`ptqQn94nFAIT5+2kMS#j@*GUwN>r*SFG#TfPi zPP2E{ITca-tn*|P3S9loRT!OVtsR=p@*_l-b{Nmxf{vW)3zifv{_%;R#5YnXRfGeQ@ON947Y5tdk8q3C$Yh1RSK)1xVg<5YT@ zm>I|WO-Xcec#qT6ox-P5xw$uEAVqz9oap+2{!?WX4QE1YN8igiJM9K#<0#JvCrVTt zO<*ZD11`Xm`U6wQ|2OEc3Njc*e)N_e`QomBs9x*}O$8v9#PTeaXrq!v}Xt)fdNc)p;7Xbsv(e<}4*%^13Smbh) zMtv4v6_)9$$W|(lObLFKd@~w0NKaODmQ%D(M_-GTv-vdwDZBBF`; zCySA@a(nJUj(FxS9aMSKq0+e%e=$fQCjJ`47Aul1*`XjlA`95L{R?p#h8I$N9yv?G z<`~MCvY*5)h~I%Dd*UEfmuMlubb>v#JR@%&MApyxbIYFI>X~RuWXHP*Tr<`c&bi23 z8I-`4qa1eBH$90Cj!7Iw?p`H~Ns)Vi0s2M({z6MM9!0n`lj;7u_Hb!)!Xffrs=$cq zQ(+<(#$;8Js_5}q>)vRS*glt5=9$@c;|LzesWRQqc(aCf56bf={Pr=6XcN&n#-M#a zFS>X9YIJX+Bz~S@Uv#?uL%~`C7zE;gy7H&h{dXr4`CmHGW#efxy5g_%IrZ!@%bMf> zF`obl!iwpdY^#zmp6pwAn8@3%9wJW%aye9n{V@%Jjk40cP~{P3mo#B!7vy9^5x2`I zv!H4zRvfA5L*~(B4ZA__abK~G_0jilN^;aPymIxYI^PDR%!Qw9N*+$v&v>1C)%c%K z*$-kFYEWg1Cd{TS`ehI8Jc^t3vAX((_vx(8&dKhtaDh|CGo@~N@j4o5l78ZxBeGMJ zQUIzP^G@I>mheoiJ8$5SSNF8oI`~WH*o`fzptkpCsha1;-Lt*l-1JU$d$v^e{64VSx3*Q7d>^V5*;}*qR%@4`2od-k8iI2-B6U;ybv?^%nT129Y{HluH1BnmX_JJ^VS372#<_(!2&q>Z#g4~3PY*r=DOr?#$=CZ= z6pgt)sB>~_t=OeH>XuWKh-K9HB}cbv$Um3qE)$qmO~mKcbI6dDVk>AcEzxI3c@soO z>U*{>>oe9Qe|1D=W>Xi~MUJyK=;!-ze&qDdA`3*e#fj)Tl5Xl-I(u0~OzN$Y^utqy z(}r2K#>+7oEdwzHD&%l#Sh2Gh|JV9;$`B=rs4Ne!m zz8dX36~FQZ^?YJd&Vc#+7@D|sl;bGc64fh+XKc@G)iu=_z+}mc$8zQxc9WKFT{$zN z<^Jn~-~em(NeAxzEDt$)B*L(Tj}wS14IhYgJF1 zw=st+*p?*|clR|T_-aaG)Qm*YZmS)VGXY%at#wfnK`T3UT4i=`DobDY3A|0@e16&8 z_fetKH<7>nBAUk+;c8<>XNQ4<58vboTT7kNyQTf zdHO3j+~>xa*M`yMF@T;)3aXX#W>2FgQ`h24c_uBLriA(Xt8qPkLYo?%)U+pt$r0?d zx0$N0c?(fLVkO+<^f%5Aku~DFm8GfEHFkz+bezfZrK~j7)iHTX^}^Y0UHJXn@;6pV z0cv5#<*XNb-o!+A2#hubM8TT@*!q|#ks|+ z+Z%?{s4Zun+W9CJB;|a0m}5demqgtA(~2~2oRMYY$-RIq0m&*a)j$h2`)u68_2QsOdu<&6xfRfDf)T8Mfr zWS=<*&ZIp78xqCGM^AGBS$ znVt~+UTZ6cZrG2;<0|jmb6IhrpDYpzhN+P(eoSIk%?C%-3o)epGjp1qYW~wff6b4t zpFO#=K0ec<^d8}J_oiZsqS#f3BOYyh93firtgo_h^S%6}chqjmp;3nsB`VomOd&#O zFTR1>MRQ>a^LX}1?1)w0am*vzsw@Y?@F=o^?FUFR^qs3qNh1!xzS-M&+7N|+SxZ_o zDr{`pt2#=BGY!$LCU{)v~fe5)TD#_S-L-M+BZPSU*E!<;B z^8>-kt=pc3{WcM(dGr%&!dIhrwUXyjyfx8OJ1mh>#lxj5wTgN9Y(hV|f?YdZi#p=s zU2<*i6S7il5|$wM$%D-bd51`O=ym3}bqwqIO6MA~AC<1e(+0=BsT|h&8K-DoT%*j8 zI~V4!9LhZHt-vQar>QPu+c{aGa@r@t!oRmhNJ1k|xs>+_wS1?we0VPmA*@KmNSDG? z_KxBwJlx9cOQVCslN}#=)HG{Weaz<(0_`}i?M0Ss7he1w7TFn=CxCkF=HYHx%vw^H zrl6En?fXy8_d0JZm?Vo|J=w&PV;CjG$v}mx5#Dtk}PN77Q1ymMs7YynK$@uobdijAzU`)W4rV^WJdA52E=>zon}CU z%cLVt*u0oYV=TMiy|7*R*GGglW-E++1v%YcL=cZR@0p`s+Aoz=4LeK>-Nb30_@bkU zZ%QeIjOt9xDIxu=&f%eo9~aF}ZdZ9_<92|R0Jjfc`=q5!^|Dv|bfD8#t|3y9tfa$F z+C-O5I8JXAousTvkW2h&)QSl0nmOt57gblbfxJp-OiRgx{Of~Ser{duA1iZ3!?&3Q zHhEfE?U>%7KFfXP3DLLVxiYgtKt3fhw<(S^c6}3&kVlw6{MCv`gVENN^h3%~ys0_c zUWJ{YN%zv2nyvGju1$BCX)IF+cV$Kow~_5_%zNQ*>k$)o?DRZ6m+#skQJ;V%Bbwbb zQ!UZV`WEZhddIedYpw4;Nj3Q^_R3E5a1H5yTKL*ehRW^5JPAizv^6d*W#H#cjSqOT zXRB?0Dw$4L5mv(DiFxQBYq;b(% zVL;3OP_D&V+^v(+=5f7*Thu`p<$Neoa^+Ze^5(dORilmfF4}&G&nmbj+gLPs!=An~ zW7Ryc1;ysPDf!Mrjko`+D{Ey#%zNuCf_-1UbczhmN95DDPK9(tOGti}YVsU<`Ve{G zA6E%z43+Bbv!Y54qfAD2AkmeShCs~cIR=f_3Q`kPGrSi_F7zD!Bwuu%BFgu3Zl zIHzH=(0;_|9lIQ*8WD+A&s}ZhC`^&~=^NRKWwOwegkQaD7gn=e*N_}R@NASq@R=6w z)n1fEYZzgoaIz)#V^apPQY|W)k-);RD8bbdMk|6Y0ob-X+kFn>a=Byo=i~EY;y{m4tEROT$EU2U+^ex}3Y= zhSB$%ufDFMGjFoe)?VqX*MGc?5I>YS$@5(fJf(;}P2Klo$)OGxk5owA|DYn4y3wB9 ziNbi#rgf@waJ4|XLkNHDI}G#d&baaldt~Db+K-NZTTH+f`RjXQ&dl<+j6}l(jodA} zM<1MhsT!@~ZMQu|G5C+}H-wDy&e6GOZzsm5U%}J}j%N$imY_aPX)n(b`19AdPjv^L zRaaJ^i0W5){;H^;m-|3E@%V9}FyEtBZ;`06*Amv-_+FR-RHg$Kt(Dfd@$+jQ61g$qQe-piM=!o`g-W z^owg>Rh)4rjdpov4jMeKu~dJ%XuL)|aewXfq4sB&vrzQQuk@O$zpy@i!Vv3j=Ve@@>PhyaAM9u63Md?Nze*^oZ>0xn#mr}Y!6nE+H{OS$#ji%2& zpYlwcObmi&Zl@cVZ#ccUjiR6*+>LhjUdO!l;c%A3md;;;{d^_4H2y_@a%r+6uLGUi z;%lyh{6#aZoIp|Ej4odBsk{@V{W&@lp;xT;Xg^j8j*{`-!qn=gE?SxJkv*Zgi*haD z8{XtePlg5der%jc`P613;Pf%=H1725rRP}aiKrrd2jTQ!^EPC@Gd!qSDvmCQ5Kf25 zi1xsHyj|u`zO>_U8oDCgVSU6wG)ySry0IfBni}7H#TSR|n3tcfHQI^iMXPrF?grsb zaPu8f5E)^f;Z2#>jUZAHE*s=K@F@~dS>>Y0e#Wu>t=;;l_7) zsdwMxyi0@BZ*YG00-vHiZ7L@6Jwu4ts^}@pJGPY{{983kf@Z*RyIzz>W@q2^o$Gf# zZmQX&>9HdyiJyQcfIAyS3llx^5vI(8!^fBTAmv((gfR@&Y6 zNH)gQ$)05|>O4#N-JPTQQ(jrRgu*!Ovbw$_UIn; zW>dTp6p9NPL6U-VDZCCy>Olklu^#)qE(J%57d~1B&~s3&WeD8}0#W)C6qo2S6eVzf z9vTkX=H{Upnji)WVvj&U1m~Ew_#mFkU^gm)*cgMYj|bw_By3uK5ZODiSH(ai`-Pn^ z0OCttSjL6lJ%LMH5xm535!jQ963$HFluev>V9N{_PR6kIn;?z`!@>zcG>C(Z!$IUp zg8jJI4hsO=1c5vqmJV90(qW7jp$9Wz+!y#O8}=4V32d8#A;$(`8DRV-*I}5^1@?}> zxFSG2(8mcr0MSbg9)&~l_ssX7qg>#MHe47C@s~E70V@u$)P_@oEC6Jb2rLN1$_MFe z!-KTZRKe2TlQ+%s~?t9T2Jm7X;bM z3qh+6prs2J2CnMD89^JbE~uafG8<*i_-%=&}jOYn`Ax0t&koIzr^d}2&4DJ+4UJhRs+IvOnhqu5g_H_SSPndh3G!1pH@`%K&4f#`8m0ArN9N z2n7G%0#NTQLm{5FmNqW7|MC9ZG6MH=@&iye`n`FV3z~WeJT`)JfM?MHQfyu&Y~YC? zHr>Czt1x3w2UP`Fjeoza#uv0+4+t`bgKYw+zMziTz>qOq4y5EJAnhmugiYYLn87dQ z#b#Z)Y`zzYK_H()ArRVst9AMlHXzxFeI0ma0>1)!mxJEe??_<42NO6e0UqSHyM`N+ z6%Yz`7bsE=pfrWkfkLneQ3463aC|7XB4BW7^ECxi=O_W`m$V6_FcDQ41n>}rkpY{g zaAMFA>{1NSUNwN>KAaPzs`o+BI~P#YVFn}P|8v&(7pMAn0Z(Ys##IQx#tz<%KQK1C6fab+R`Y;$SKxg(lJC7Oo08@1F;1-xY=z@MJztlCE z!NGr-fZhvRZw0UlB1j3$!2&HS!2;{DU=+YaI*bs|H2-~AV7H_M+|A+mu<+{3=X5}} z`R_cHpck~R7WioXyH$XFlmY5F4_vc=gH0I#J1HfgW&t`feFq)sMqmO!g2ivgYzt5s zv delta 1849 zcmZWpeN0nV6uKn3RYsX5kr@0BHcYMd>y4|sel=W5+4hu`!9>oVmaOEP$y*gTIiW1y zIkD`P?RWRITOw7)=oogc?c;TX5HZ3k{&)Qn>CBYMByz?k{gA*>_in|PohO0@=(6y{ zGrk2wndr+ZKK3NSr7aDK2-!__*$8b%4AlrdL3M*f;E|Op^Ucl{@2))WPH#BD!CnlKPEoI$eUTk>? zPgR7l#K=0Z?7&zhd!&kZCp({k*zRZh;t&&$v+u+rCQq_I#3IH&WOoq8`dJrRZ6C38 zv02j|t_1o9Sh7g*$q>6BQob2vgF^c0o2*XY{t5QXe#GJCsJ-_P^SAQ@Q3*3m^6$aJ zh?y6m*&L=ko2kku(Ig_83>@f_OmNu3pU240kA*zWlL|aM|Mx?{)CSHiF6&XFh1>&u|s8j#yB3*>mEfKjC;;h_=k+oKg+;gOJ zFsML>RV(BJVLBQ_Q;s%IM|9Y#qOnvd0BJTY-*Yx(H=xGG(@|xoV7sB)##4}WG;=j= za~UNrlgX3+QoSi}lQXZ;QSb3Ylrf4ybfOHVn>n^L=75qd`)f3BHoWNKPoUOX7fKJj4NWdyinL$QC_h|r@#RSW5>&ki zDJ^^%(lsrp5c^ODQwz^RjyFn)n=SoxKAdjRcHpuITvxzAEoVuQO%mUVg5!md->Svo z)r%C^T?{R)93L{kyQn~aE7!5O7Z?Hc6=s0Pm5fJf;XPIKv)N;}Vc@urC4#}t=b;AP zUj<6ssPXk)bou+3QaF3gp{^y`X*7;}`qO)y5HT`m74d8Hp_!Rba-8YmoLk$p5jR&^ zmOt!L`xs03ud;Y1BFjsKaQH?KpD&i!KWFW6UC`#?sz@&yWXhFsHi(y9jPyAro$6w6 zVgQ%+qep8Fe0Ws(i}y9-vRrY4B9|8TS$5sw0z$-4=IGq(WpH(fCBt5?wy1+%)HyrK zpgqV8k^6iF9n|s-{O0AQ88hX@TsF7e-$#fTi{{8)xCYfej_)VnBd0*SkL&1E4fKR; a=Y6PUuf%iWN%|sEL@e_Nx%)EiJNXCDBjq6g diff --git a/jdk/test/tools/pack200/pack200-verifier/make/build.xml b/jdk/test/tools/pack200/pack200-verifier/make/build.xml index 76e5f72cf89..b783ffda881 100644 --- a/jdk/test/tools/pack200/pack200-verifier/make/build.xml +++ b/jdk/test/tools/pack200/pack200-verifier/make/build.xml @@ -1,5 +1,5 @@ - + @@ -22,7 +22,7 @@ diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java index 4a3af66344e..0579b5b99cd 100644 --- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,16 +24,58 @@ */ package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- +import com.sun.tools.classfile.AccessFlags; +import com.sun.tools.classfile.Annotation; +import com.sun.tools.classfile.Annotation.*; +import com.sun.tools.classfile.AnnotationDefault_attribute; +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.Attributes; +import com.sun.tools.classfile.BootstrapMethods_attribute; +import com.sun.tools.classfile.CharacterRangeTable_attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.CompilationID_attribute; +import com.sun.tools.classfile.ConstantPool; +import com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.ConstantValue_attribute; +import com.sun.tools.classfile.DefaultAttribute; +import com.sun.tools.classfile.Deprecated_attribute; +import com.sun.tools.classfile.Descriptor.InvalidDescriptor; +import com.sun.tools.classfile.EnclosingMethod_attribute; +import com.sun.tools.classfile.Exceptions_attribute; +import com.sun.tools.classfile.Field; +import com.sun.tools.classfile.InnerClasses_attribute; +import com.sun.tools.classfile.InnerClasses_attribute.Info; +import com.sun.tools.classfile.Instruction; +import com.sun.tools.classfile.Instruction.TypeKind; +import com.sun.tools.classfile.LineNumberTable_attribute; +import com.sun.tools.classfile.LocalVariableTable_attribute; +import com.sun.tools.classfile.LocalVariableTypeTable_attribute; +import com.sun.tools.classfile.Method; +import com.sun.tools.classfile.Opcode; +import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; +import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; +import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute; +import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute; +import com.sun.tools.classfile.Signature_attribute; +import com.sun.tools.classfile.SourceDebugExtension_attribute; +import com.sun.tools.classfile.SourceFile_attribute; +import com.sun.tools.classfile.SourceID_attribute; +import com.sun.tools.classfile.StackMapTable_attribute; +import com.sun.tools.classfile.StackMapTable_attribute.*; +import com.sun.tools.classfile.StackMap_attribute; +import com.sun.tools.classfile.Synthetic_attribute; import java.util.*; -import java.util.jar.*; -import java.lang.reflect.*; import java.io.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import xmlkit.XMLKit.Element; /* - * @author jrose + * @author jrose, ksrini */ -public class ClassReader extends ClassSyntax { +public class ClassReader { private static final CommandLineParser CLP = new CommandLineParser("" + "-source: +> = \n" @@ -41,23 +83,24 @@ public class ClassReader extends ClassSyntax { + "-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"); + + // Protected state for representing the class file. + protected Element cfile; // + protected Element cpool; // + protected Element klass; // + protected List thePool; // stringified flattened Constant Pool + public static void main(String[] ava) throws IOException { - ArrayList av = new ArrayList(Arrays.asList(ava)); - HashMap props = new HashMap(); + ArrayList av = new ArrayList<>(Arrays.asList(ava)); + HashMap props = new HashMap<>(); props.put("-encoding:", "UTF8"); // default props.put("-keepOrder", null); // CLI default props.put("-pretty", "1"); // CLI default @@ -80,7 +123,7 @@ public class ClassReader extends ClassSyntax { } */ if (av.isEmpty()) { - av.add("doit"); //to enter this loop + av.add(""); //to enter this loop } boolean readList = false; for (String a : av) { @@ -119,7 +162,7 @@ public class ClassReader extends ClassSyntax { private static void doFile(String a, File source, File dest, ClassReader options, String encoding, - boolean contError) throws IOException { + boolean contError) throws IOException { if (!contError) { doFile(a, source, dest, options, encoding); } else { @@ -127,40 +170,49 @@ public class ClassReader extends ClassSyntax { doFile(a, source, dest, options, encoding); } catch (Exception ee) { System.out.println("Error processing " + source + ": " + ee); + ee.printStackTrace(); } } } - private static void doJar(String a, File source, File dest, ClassReader options, - String encoding, Boolean contError) throws IOException { + 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) jf.entries())) { + for (JarEntry je : Collections.list(jf.entries())) { String name = je.getName(); if (!name.endsWith(".class")) { continue; } - doStream(name, jf.getInputStream(je), dest, options, encoding); + try { + doStream(name, jf.getInputStream(je), dest, options, encoding); + } catch (Exception e) { + if (contError) { + System.out.println("Error processing " + source + ": " + e); + e.printStackTrace(); + continue; + } + } } } catch (IOException ioe) { - if (contError) { - System.out.println("Error processing " + source + ": " + ioe); - } else { - throw ioe; - } + throw ioe; } } private static void doStream(String a, InputStream in, File dest, - ClassReader options, String encoding) throws IOException { + ClassReader options, String encoding) throws IOException { File f = new File(a); ClassReader cr = new ClassReader(options); - Element e = cr.readFrom(in); + Element e; + if (options.verbose) { + System.out.println("Reading " + f); + } + 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()); @@ -202,20 +254,8 @@ public class ClassReader extends ClassSyntax { } - 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; - } + public static BufferedReader makeReader(InputStream in, + String encoding) throws IOException { Reader inw; in = new BufferedInputStream(in); // add buffering if (encoding == null) { @@ -226,20 +266,8 @@ public class ClassReader extends ClassSyntax { 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; - } + public static Writer makeWriter(OutputStream out, + String encoding) throws IOException { Writer outw; if (encoding == null) { outw = new OutputStreamWriter(out); @@ -252,12 +280,9 @@ public class ClassReader extends ClassSyntax { 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; @@ -270,7 +295,7 @@ public class ClassReader extends ClassSyntax { public boolean keepSizes = false; public ClassReader() { - super.cfile = new Element("ClassFile"); + cfile = new Element("ClassFile"); } public ClassReader(ClassReader options) { @@ -283,12 +308,7 @@ public class ClassReader extends ClassSyntax { 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 options) { @@ -304,274 +324,177 @@ public class ClassReader extends ClassSyntax { 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(); - } + } + + protected String getCpString(int i) { + return thePool.get(i); } 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)); + try { + this.in = in; + ClassFile c = ClassFile.read(in); + // read the file header + if (c.magic != 0xCAFEBABE) { + throw new RuntimeException("bad magic number " + + Integer.toHexString(c.magic)); + } + cfile.setAttr("magic", "" + c.magic); + int minver = c.minor_version; + int majver = c.major_version; + cfile.setAttr("minver", "" + minver); + cfile.setAttr("majver", "" + majver); + readCP(c); + readClass(c); + return result(); + } catch (InvalidDescriptor | ConstantPoolException ex) { + throw new IOException("Fatal error", ex); } - 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)); + try (InputStream strm = new FileInputStream(file)) { + Element e = readFrom(new BufferedInputStream(strm)); if (keepPath) { e.setAttr("path", file.toString()); } return e; - } finally { - if (in != null) { - in.close(); - } } } - private void readClass() throws IOException { + private void readClass(ClassFile c) throws IOException, + ConstantPoolException, + InvalidDescriptor { klass = new Element("Class"); cfile.add(klass); - int flags = u2(); - String thisk = cpRef(); - String superk = cpRef(); + String thisk = c.getName(); + 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"; + + AccessFlags af = new AccessFlags(c.access_flags.flags); + klass.setAttr("flags", flagString(af, klass)); + if (!"java/lang/Object".equals(thisk)) { + klass.setAttr("super", c.getSuperclassName()); } - 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)); + for (int i : c.interfaces) { + klass.add(new Element("Interface", "name", getCpString(i))); + } + readFields(c, klass); + readMethods(c, klass); + readAttributesFor(c, c.attributes, klass); + klass.trimToSize(); + } + + private void readFields(ClassFile c, Element klass) throws IOException { + int len = c.fields.length; + Element fields = new Element(len); + for (Field f : c.fields) { + Element field = new Element("Field"); + field.setAttr("name", getCpString(f.name_index)); + field.setAttr("type", getCpString(f.descriptor.index)); + field.setAttr("flags", flagString(f.access_flags.flags, field)); + readAttributesFor(c, f.attributes, field); + + field.trimToSize(); + fields.add(field); + } + if (!keepOrder) { + fields.sort(); } - Element fields = readMembers("Field"); klass.addAll(fields); - Element methods = readMembers("Method"); + } + + + private void readMethods(ClassFile c, Element klass) throws IOException { + int len = c.methods.length; + Element methods = new Element(len); + for (Method m : c.methods) { + Element member = new Element("Method"); + member.setAttr("name", getCpString(m.name_index)); + member.setAttr("type", getCpString(m.descriptor.index)); + member.setAttr("flags", flagString(m.access_flags.flags, member)); + readAttributesFor(c, m.attributes, member); + + member.trimToSize(); + methods.add(member); + } 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); + private AccessFlags.Kind getKind(Element e) { + switch(e.getName()) { + case "Class": + return AccessFlags.Kind.Class; + case "InnerClass": + return AccessFlags.Kind.InnerClass; + case "Field": + return AccessFlags.Kind.Field ; + case "Method": + return AccessFlags.Kind.Method; + default: throw new RuntimeException("should not reach here"); } - return members; } protected String flagString(int flags, Element holder) { - // Superset of Modifier.toString. - int kind = 0; - if (holder.getName() == "Field") { - kind = 1; + return flagString(new AccessFlags(flags), holder); + } + protected String flagString(AccessFlags af, Element holder) { + return flagString(af, holder.getName()); + } + protected String flagString(int flags, String kind) { + return flagString(new AccessFlags(flags), kind); + } + protected String flagString(AccessFlags af, String kind) { + Set mods = null; + switch (kind) { + case "Class": + mods = af.getClassFlags(); + break; + case "InnerClass": + mods = af.getInnerClassFlags(); + break; + case "Field": + mods = af.getFieldFlags(); + break; + case "Method": + mods = af.getMethodFlags(); + break; + default: + throw new RuntimeException("should not reach here"); } - if (holder.getName() == "Method") { - kind = 2; + StringBuilder sb = new StringBuilder(); + for (String x : mods) { + sb.append(x.substring(x.indexOf('_') + 1).toLowerCase()).append(" "); } - 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(); + return sb.toString().trim(); } - 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)); // , 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("...")) { - // delve into Code attribute - aval = readCode(); - } else if (type.equals("...")) { - // delve into StackMap attribute - aval = readStackMap(false); - } else if (type.equals("...")) { - // 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; + + protected void readAttributesFor(ClassFile c, Attributes attrs, Element x) { + Element container = new Element(); + AttributeVisitor av = new AttributeVisitor(this, c); + for (Attribute a : attrs) { + av.visit(a, container); } if (!keepOrder) { - y.sort(); - y.sortAttrs(); + container.sort(); } - //System.out.println("attachTo 2 "+x+" <- "+y); - attachTo(x, y); + x.addAll(container); } - private int fileSize = 0; - private int paddingSize = 0; - private HashMap attrSizes = new HashMap(); - private Element formatAttrSizes() { - Element e = new Element("Sizes"); - e.setAttr("fileSize", "" + fileSize); - for (Map.Entry 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 int fileSize = 0; + private HashMap attrSizes = new HashMap<>(); 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; @@ -589,7 +512,6 @@ public class ClassReader extends ClassSyntax { } 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; @@ -597,407 +519,1003 @@ public class ClassReader extends ClassSyntax { 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); + private void readCP(ClassFile c) throws IOException { + cpool = new Element("ConstantPool", c.constant_pool.size()); + ConstantPoolVisitor cpv = new ConstantPoolVisitor(cpool, c, + c.constant_pool.size()); + for (int i = 1 ; i < c.constant_pool.size() ; i++) { + try { + cpv.visit(c.constant_pool.get(i), i); + } catch (InvalidIndex ex) { + // can happen periodically when accessing doubles etc. ignore it + // ex.printStackTrace(); } } - //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(); + thePool = cpv.getPoolList(); + if (verbose) { + for (int i = 0; i < thePool.size(); i++) { + System.out.println("[" + i + "]: " + thePool.get(i)); } - } 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; +class ConstantPoolVisitor implements ConstantPool.Visitor { + final List slist; + final Element xpool; + final ClassFile cf; + final ConstantPool cfpool; + final List bsmlist; + + + public ConstantPoolVisitor(Element xpool, ClassFile cf, int size) { + slist = new ArrayList<>(size); + for (int i = 0 ; i < size; i++) { + slist.add(null); + } + this.xpool = xpool; + this.cf = cf; + this.cfpool = cf.constant_pool; + bsmlist = readBSM(); + } + + public List getPoolList() { + return Collections.unmodifiableList(slist); + } + + public List getBSMList() { + return Collections.unmodifiableList(bsmlist); + } + + public String visit(CPInfo c, int index) { + return c.accept(this, index); + } + + private List readBSM() { + BootstrapMethods_attribute bsmAttr = + (BootstrapMethods_attribute) cf.getAttribute(Attribute.BootstrapMethods); + if (bsmAttr != null) { + List out = + new ArrayList<>(bsmAttr.bootstrap_method_specifiers.length); + for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsms : + bsmAttr.bootstrap_method_specifiers) { + int index = bsms.bootstrap_method_ref; + try { + String value = slist.get(index); + String bsmStr = value; + if (value == null) { + value = visit(cfpool.get(index), index); + slist.set(index, value); + } + bsmStr = value; + for (int idx : bsms.bootstrap_arguments) { + value = slist.get(idx); + if (value == null) { + value = visit(cfpool.get(idx), idx); + slist.set(idx, value); + } + bsmStr = bsmStr.concat("," + value); + } + out.add(bsmStr); + } catch (InvalidIndex ex) { + ex.printStackTrace(); + } + } + return out; + } + return new ArrayList<>(0); + } + + @Override + public String visitClass(CONSTANT_Class_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + try { + value = visit(cfpool.get(c.name_index), c.name_index); + slist.set(p, value); + xpool.add(new Element("CONSTANT_Class", + new String[]{"id", p.toString()}, + value)); + } catch (ConstantPoolException ex) { + ex.printStackTrace(); + } + } + return value; + } + + @Override + public String visitDouble(CONSTANT_Double_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + value = Double.toString(c.value); + slist.set(p, value); + xpool.add(new Element("CONSTANT_Double", + new String[]{"id", p.toString()}, + value)); + } + return value; + } + + @Override + public String visitFieldref(CONSTANT_Fieldref_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + try { + value = visit(cfpool.get(c.class_index), c.class_index); + value = value.concat(" " + visit(cfpool.get(c.name_and_type_index), + c.name_and_type_index)); + slist.set(p, value); + xpool.add(new Element("CONSTANT_Fieldref", + new String[]{"id", p.toString()}, + value)); + } catch (ConstantPoolException ex) { + ex.printStackTrace(); + } + } + return value; + } + + @Override + public String visitFloat(CONSTANT_Float_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + value = Float.toString(c.value); + slist.set(p, value); + xpool.add(new Element("CONSTANT_Float", + new String[]{"id", p.toString()}, + value)); + } + return value; + } + + @Override + public String visitInteger(CONSTANT_Integer_info cnstnt, Integer p) { + String value = slist.get(p); + if (value == null) { + value = Integer.toString(cnstnt.value); + slist.set(p, value); + xpool.add(new Element("CONSTANT_Integer", + new String[]{"id", p.toString()}, + value)); + } + return value; + } + + @Override + public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info c, + Integer p) { + String value = slist.get(p); + if (value == null) { + try { + value = visit(cfpool.get(c.class_index), c.class_index); + value = value.concat(" " + + visit(cfpool.get(c.name_and_type_index), + c.name_and_type_index)); + slist.set(p, value); + xpool.add(new Element("CONSTANT_InterfaceMethodref", + new String[]{"id", p.toString()}, + value)); + + } catch (ConstantPoolException ex) { + ex.printStackTrace(); + } + } + return value; + } + + @Override + public String visitInvokeDynamic(CONSTANT_InvokeDynamic_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + try { + value = bsmlist.get(c.bootstrap_method_attr_index) + " " + + visit(cfpool.get(c.name_and_type_index), c.name_and_type_index); + slist.set(p, value); + xpool.add(new Element("CONSTANT_InvokeDynamic", + new String[]{"id", p.toString()}, + value)); + + } catch (ConstantPoolException ex) { + ex.printStackTrace(); + } + } + return value; + } + + @Override + public String visitLong(CONSTANT_Long_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + value = Long.toString(c.value); + slist.set(p, value); + xpool.add(new Element("CONSTANT_Long", + new String[]{"id", p.toString()}, + value)); + } + return value; + } + + @Override + public String visitNameAndType(CONSTANT_NameAndType_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + try { + value = visit(cfpool.get(c.name_index), c.name_index); + value = value.concat(" " + + visit(cfpool.get(c.type_index), c.type_index)); + slist.set(p, value); + xpool.add(new Element("CONSTANT_NameAndType", + new String[]{"id", p.toString()}, + value)); + } catch (InvalidIndex ex) { + ex.printStackTrace(); + } + } + return value; + } + + @Override + public String visitMethodref(CONSTANT_Methodref_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + try { + value = visit(cfpool.get(c.class_index), c.class_index); + value = value.concat(" " + + visit(cfpool.get(c.name_and_type_index), + c.name_and_type_index)); + slist.set(p, value); + xpool.add(new Element("CONSTANT_Methodref", + new String[]{"id", p.toString()}, + value)); + + } catch (ConstantPoolException ex) { + ex.printStackTrace(); + } + } + return value; + } + + @Override + public String visitMethodHandle(CONSTANT_MethodHandle_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + try { + value = c.reference_kind.name(); + value = value.concat(" " + + visit(cfpool.get(c.reference_index), c.reference_index)); + slist.set(p, value); + xpool.add(new Element("CONSTANT_MethodHandle", + new String[]{"id", p.toString()}, + value)); + + } catch (ConstantPoolException ex) { + ex.printStackTrace(); + } + } + return value; + } + + @Override + public String visitMethodType(CONSTANT_MethodType_info c, Integer p) { + String value = slist.get(p); + if (value == null) { + try { + value = visit(cfpool.get(c.descriptor_index), c.descriptor_index); + slist.set(p, value); + xpool.add(new Element("CONSTANT_MethodType", + new String[]{"id", p.toString()}, + value)); + } catch (ConstantPoolException ex) { + ex.printStackTrace(); + } + } + return value; + } + + @Override + public String visitString(CONSTANT_String_info c, Integer p) { + try { + + String value = slist.get(p); + if (value == null) { + value = c.getString(); + slist.set(p, value); + xpool.add(new Element("CONSTANT_String", + new String[]{"id", p.toString()}, + value)); + } + return value; + } catch (ConstantPoolException ex) { + throw new RuntimeException("Fatal error", ex); } } - private String cpName(int id) { - if (id >= 0 && id < cpName.length) { - return cpName[id]; - } else { - return "[CP#" + Integer.toHexString(id) + "]"; + @Override + public String visitUtf8(CONSTANT_Utf8_info cnstnt, Integer p) { + String value = slist.get(p); + if (value == null) { + value = cnstnt.value; + slist.set(p, value); + xpool.add(new Element("CONSTANT_Utf8", + new String[]{"id", p.toString()}, + value)); } - } + return value; - 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; } } +class AttributeVisitor implements Attribute.Visitor { + final ClassFile cf; + final ClassReader x; + final AnnotationsElementVisitor aev; + final InstructionVisitor iv; + + public AttributeVisitor(ClassReader x, ClassFile cf) { + this.x = x; + this.cf = cf; + iv = new InstructionVisitor(x, cf); + aev = new AnnotationsElementVisitor(x, cf); + } + + public void visit(Attribute a, Element parent) { + a.accept(this, parent); + } + + @Override + public Element visitBootstrapMethods(BootstrapMethods_attribute bm, Element p) { + Element e = new Element(x.getCpString(bm.attribute_name_index)); + for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : bm.bootstrap_method_specifiers) { + Element be = new Element("BootstrapMethodSpecifier"); + be.setAttr("ref", x.getCpString(bsm.bootstrap_method_ref)); + if (bsm.bootstrap_arguments.length > 0) { + Element bme = new Element("MethodArguments"); + for (int index : bsm.bootstrap_arguments) { + bme.add(x.getCpString(index)); + } + bme.trimToSize(); + be.add(bme); + } + be.trimToSize(); + e.add(be); + } + e.trimToSize(); + if (!x.keepOrder) { + e.sort(); + } + p.add(e); + return null; + } + + @Override + public Element visitDefault(DefaultAttribute da, Element p) { + Element e = new Element(x.getCpString(da.attribute_name_index)); + StringBuilder sb = new StringBuilder(); + for (byte x : da.info) { + sb.append("0x").append(Integer.toHexString(x)).append(" "); + } + e.setAttr("bytes", sb.toString().trim()); + e.trimToSize(); + p.add(e); + return null; + } + + @Override + public Element visitAnnotationDefault(AnnotationDefault_attribute ad, Element p) { + Element e = new Element(x.getCpString(ad.attribute_name_index)); + e.setAttr("tag", "" + ad.default_value.tag); + Element child = aev.visit(ad.default_value, e); + if (child != null) { + e.add(child); + } + e.trimToSize(); + p.add(e); + return null; + } + + @Override + public Element visitCharacterRangeTable(CharacterRangeTable_attribute crt, + Element p) { + Element e = new Element(x.getCpString(crt.attribute_name_index)); + for (CharacterRangeTable_attribute.Entry ce : crt.character_range_table) { + e.setAttr("start_pc", "" + ce.start_pc); + e.setAttr("end_pc", "" + ce.end_pc); + e.setAttr("range_start", "" + ce.character_range_start); + e.setAttr("range_end", "" + ce.character_range_end); + e.setAttr("flags", x.flagString(ce.flags, "Method")); + } + e.trimToSize(); + p.add(e); + return null; + } + + private Element instructions(Element code, Code_attribute c) { + Element ielement = new Element("Instructions"); + for (Instruction ins : c.getInstructions()) { + ielement.add(iv.visit(ins)); + } + ielement.trimToSize(); + return ielement; + } + + @Override + public Element visitCode(Code_attribute c, Element p) { + Element e = null; + + e = new Element(x.getCpString(c.attribute_name_index), + "stack", "" + c.max_stack, + "local", "" + c.max_locals); + + e.add(instructions(e, c)); + + for (Code_attribute.Exception_data edata : c.exception_table) { + e.add(new Element("Handler", + "start", "" + edata.start_pc, + "end", "" + edata.end_pc, + "catch", "" + edata.handler_pc, + "class", x.getCpString(edata.catch_type))); + + } + this.x.readAttributesFor(cf, c.attributes, e); + e.trimToSize(); + p.add(e); + return null; + } + + @Override + public Element visitCompilationID(CompilationID_attribute cid, Element p) { + Element e = new Element(x.getCpString(cid.attribute_name_index), + x.getCpString(cid.compilationID_index)); + p.add(e); + return null; + } + + @Override + public Element visitConstantValue(ConstantValue_attribute cv, Element p) { + Element e = new Element(x.getCpString(cv.attribute_name_index)); + e.add(x.getCpString(cv.constantvalue_index)); + p.add(e); + return null; + } + + @Override + public Element visitDeprecated(Deprecated_attribute d, Element p) { + Element e = new Element(x.getCpString(d.attribute_name_index)); + p.add(e); + return null; + } + + @Override + public Element visitEnclosingMethod(EnclosingMethod_attribute em, Element p) { + Element e = new Element(x.getCpString(em.attribute_name_index)); + e.setAttr("class", x.getCpString(em.class_index)); + e.setAttr("desc", x.getCpString(em.method_index)); + e.trimToSize(); + p.add(e); + return null; + } + + @Override + public Element visitExceptions(Exceptions_attribute e, Element p) { + Element ee = new Element(x.getCpString(e.attribute_name_index)); + for (int idx : e.exception_index_table) { + Element n = new Element("Item"); + n.setAttr("class", x.getCpString(idx)); + ee.add(n); + } + ee.trimToSize(); + p.add(ee); + return null; + } + + @Override + public Element visitInnerClasses(InnerClasses_attribute ic, Element p) { + for (Info info : ic.classes) { + Element e = new Element(x.getCpString(ic.attribute_name_index)); + e.setAttr("class", x.getCpString(info.inner_class_info_index)); + e.setAttr("outer", x.getCpString(info.outer_class_info_index)); + e.setAttr("name", x.getCpString(info.inner_name_index)); + e.setAttr("flags", x.flagString(info.inner_class_access_flags, + "InnerClass")); + e.trimToSize(); + p.add(e); + } + return null; + } + + @Override + public Element visitLineNumberTable(LineNumberTable_attribute lnt, Element p) { + String name = x.getCpString(lnt.attribute_name_index); + for (LineNumberTable_attribute.Entry e : lnt.line_number_table) { + Element l = new Element(name); + l.setAttr("bci", "" + e.start_pc); + l.setAttr("line", "" + e.line_number); + l.trimToSize(); + p.add(l); + } + return null; // already added to parent + } + + @Override + public Element visitLocalVariableTable(LocalVariableTable_attribute lvt, + Element p) { + String name = x.getCpString(lvt.attribute_name_index); + for (LocalVariableTable_attribute.Entry e : lvt.local_variable_table) { + Element l = new Element(name); + l.setAttr("bci", "" + e.start_pc); + l.setAttr("span", "" + e.length); + l.setAttr("name", x.getCpString(e.name_index)); + l.setAttr("type", x.getCpString(e.descriptor_index)); + l.setAttr("slot", "" + e.index); + l.trimToSize(); + p.add(l); + } + return null; // already added to parent + } + + @Override + public Element visitLocalVariableTypeTable(LocalVariableTypeTable_attribute lvtt, + Element p) { + String name = x.getCpString(lvtt.attribute_name_index); + for (LocalVariableTypeTable_attribute.Entry e : lvtt.local_variable_table) { + Element l = new Element(name); + l.setAttr("bci", "" + e.start_pc); + l.setAttr("span", "" + e.length); + l.setAttr("name", x.getCpString(e.name_index)); + l.setAttr("type", x.getCpString(e.signature_index)); + l.setAttr("slot", "" + e.index); + l.trimToSize(); + p.add(l); + } + return null; // already added to parent + } + + private void parseAnnotations(Annotation[] ra, Element p) { + for (Annotation anno : ra) { + Element ea = new Element("Member"); + ea.setAttr("name", "" + x.getCpString(anno.type_index)); + for (Annotation.element_value_pair evp : anno.element_value_pairs) { + Element evpe = new Element("Element"); + evpe.setAttr("tag", "" + evp.value.tag); + evpe.setAttr("value", x.getCpString(evp.element_name_index)); + Element child = aev.visit(evp.value, evpe); + if (child != null) { + evpe.add(child); + } + ea.add(evpe); + } + ea.trimToSize(); + p.add(ea); + } + } + + @Override + public Element visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute rva, + Element p) { + Element e = new Element(x.getCpString(rva.attribute_name_index)); + parseAnnotations(rva.annotations, e); + e.trimToSize(); + p.add(e); + return null; + } + + @Override + public Element visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute ria, + Element p) { + Element e = new Element(x.getCpString(ria.attribute_name_index)); + parseAnnotations(ria.annotations, e); + e.trimToSize(); + p.add(e); + return null; + } + + @Override + public Element visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute rvpa, + Element p) { + Element e = new Element(x.getCpString(rvpa.attribute_name_index)); + for (Annotation[] pa : rvpa.parameter_annotations) { + parseAnnotations(pa, e); + } + p.add(e); + return null; + } + + @Override + public Element visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute ripa, + Element p) { + Element e = new Element(x.getCpString(ripa.attribute_name_index)); + for (Annotation[] pa : ripa.parameter_annotations) { + parseAnnotations(pa, e); + } + p.add(e); + return null; + } + + @Override + public Element visitSignature(Signature_attribute s, Element p) { + String aname = x.getCpString(s.attribute_name_index); + String sname = x.getCpString(s.signature_index); + Element se = new Element(aname); + se.add(sname); + se.trimToSize(); + p.add(se); + return null; + } + + @Override + public Element visitSourceDebugExtension(SourceDebugExtension_attribute sde, + Element p) { + String aname = x.getCpString(sde.attribute_name_index); + Element se = new Element(aname); + se.setAttr("val", sde.getValue()); + se.trimToSize(); + p.add(se); + return null; + } + + @Override + public Element visitSourceFile(SourceFile_attribute sf, Element p) { + String aname = x.getCpString(sf.attribute_name_index); + String sname = x.getCpString(sf.sourcefile_index); + Element se = new Element(aname); + se.add(sname); + se.trimToSize(); + p.add(se); + return null; + } + + @Override + public Element visitSourceID(SourceID_attribute sid, Element p) { + Element e = new Element(x.getCpString(sid.attribute_name_index)); + e.add(x.getCpString(sid.sourceID_index)); + e.trimToSize(); + p.add(e); + return null; + } + + @Override + public Element visitStackMap(StackMap_attribute sm, Element p) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Element visitStackMapTable(StackMapTable_attribute smt, Element p) { + Element stackmap = new Element(x.getCpString(smt.attribute_name_index)); + for (StackMapTable_attribute.stack_map_frame f : smt.entries) { + StackMapVisitor smv = new StackMapVisitor(x, cf, stackmap); + stackmap.add(smv.visit(f)); + } + stackmap.trimToSize(); + p.add(stackmap); + return null; + } + + @Override + public Element visitSynthetic(Synthetic_attribute s, Element p) { + Element e = new Element(x.getCpString(s.attribute_name_index)); + e.trimToSize(); + p.add(e); + return null; + } +} + +class StackMapVisitor implements StackMapTable_attribute.stack_map_frame.Visitor { + + final ClassFile cf; + final ClassReader x; + final Element parent; + + public StackMapVisitor(ClassReader x, ClassFile cf, Element parent) { + this.x = x; + this.cf = cf; + this.parent = parent; + } + + public Element visit(StackMapTable_attribute.stack_map_frame frame) { + return frame.accept(this, null); + } + + @Override + public Element visit_same_frame(same_frame sm_frm, Void p) { + Element e = new Element("SameFrame"); + e.setAttr("tag", "" + sm_frm.frame_type); + return e; + } + + @Override + public Element visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame s, Void p) { + Element e = new Element("SameLocals1StackItemFrame"); + e.setAttr("tag", "" + s.frame_type); + e.addAll(getVerificationTypeInfo("Stack", s.stack)); + e.trimToSize(); + return e; + } + + @Override + public Element visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended s, Void p) { + Element e = new Element("SameLocals1StackItemFrameExtended"); + e.setAttr("tag", "" + s.frame_type); + e.addAll(getVerificationTypeInfo("Stack", s.stack)); + e.trimToSize(); + return e; + } + + @Override + public Element visit_chop_frame(chop_frame c, Void p) { + Element e = new Element("Chop" + (251 - c.frame_type)); + e.setAttr("tag", "" + c.frame_type); + e.setAttr("offset", "" + c.offset_delta); + return e; + } + + @Override + public Element visit_same_frame_extended(same_frame_extended s, Void p) { + Element e = new Element("SameFrameExtended"); + e.setAttr("tag", "" + s.frame_type); + e.setAttr("offset", "" + s.offset_delta); + return e; + } + + @Override + public Element visit_append_frame(append_frame a, Void p) { + Element e = new Element("AppendFrame" + (a.frame_type - 251)); + e.setAttr("tag", "" + a.frame_type); + e.addAll(getVerificationTypeInfo("Local", a.locals)); + e.trimToSize(); + return e; + } + + @Override + public Element visit_full_frame(full_frame fl_frm, Void p) { + Element e = new Element("FullFrame"); + e.setAttr("tag", "" + fl_frm.frame_type); + e.addAll(getVerificationTypeInfo("Local", fl_frm.locals)); + e.trimToSize(); + return e; + } + + private Element getVerificationTypeInfo(String kind, + StackMapTable_attribute.verification_type_info velems[]) { + Element container = new Element(velems.length); + for (StackMapTable_attribute.verification_type_info v : velems) { + Element ve = null; + int offset = 0; + int index = 0; + switch (v.tag) { + case StackMapTable_attribute.verification_type_info.ITEM_Top: + ve = new Element("ITEM_Top"); + break; + case StackMapTable_attribute.verification_type_info.ITEM_Integer: + ve = new Element("ITEM_Integer"); + break; + case StackMapTable_attribute.verification_type_info.ITEM_Float: + ve = new Element("ITEM_Float"); + break; + case StackMapTable_attribute.verification_type_info.ITEM_Long: + ve = new Element("ITEM_Long"); + break; + case StackMapTable_attribute.verification_type_info.ITEM_Double: + ve = new Element("ITEM_Double"); + break; + case StackMapTable_attribute.verification_type_info.ITEM_Null: + ve = new Element("ITEM_Null"); + break; + case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized: + ve = new Element("ITEM_Uninitialized"); + offset = ((StackMapTable_attribute.Uninitialized_variable_info) v).offset; + ve.setAttr("offset", "" + offset); + break; + case StackMapTable_attribute.verification_type_info.ITEM_UninitializedThis: + ve = new Element("ITEM_UnitializedtThis"); + break; + case StackMapTable_attribute.verification_type_info.ITEM_Object: + ve = new Element("ITEM_Object"); + index = ((StackMapTable_attribute.Object_variable_info) v).cpool_index; + ve.setAttr("class", x.getCpString(index)); + break; + default: + ve = new Element("Unknown"); + } + Element kindE = new Element(kind); + kindE.setAttr("tag", "" + v.tag); + container.add(kindE); + kindE.add(ve); + } + container.trimToSize(); + return container; + } +} + +class InstructionVisitor implements Instruction.KindVisitor { + + final ClassReader x; + final ClassFile cf; + + public InstructionVisitor(ClassReader x, ClassFile cf) { + this.x = x; + this.cf = cf; + } + + public Element visit(Instruction i) { + Element ie = i.accept(this, null); + ie.trimToSize(); + return ie; + } + + @Override + public Element visitNoOperands(Instruction i, Void p) { + Opcode o = i.getOpcode(); + Element e = new Element(i.getMnemonic()); + if (o.opcode > 0xab && o.opcode <= 0xb1) { + e.setAttr("pc", "" + i.getPC()); + } + return e; + } + + @Override + public Element visitArrayType(Instruction i, TypeKind tk, Void p) { + Element ie = new Element(i.getMnemonic()); + ie.setAttr("num", "" + tk.value); + ie.setAttr("val", tk.name); + return ie; + } + + @Override + public Element visitBranch(Instruction i, int i1, Void p) { + Element ie = new Element(i.getMnemonic()); + ie.setAttr("lab", "" + (i.getPC() + i1)); + return ie; + } + + @Override + public Element visitConstantPoolRef(Instruction i, int i1, Void p) { + Element ie = new Element(i.getMnemonic()); + ie.setAttr("ref", x.getCpString(i1)); + return ie; + } + + @Override + public Element visitConstantPoolRefAndValue(Instruction i, int i1, int i2, Void p) { + // workaround for a potential bug in classfile + Element ie = new Element(i.getMnemonic()); + if (i.getOpcode().equals(Opcode.IINC_W)) { + ie.setAttr("loc", "" + i1); + ie.setAttr("num", "" + i2); + } else { + ie.setAttr("ref", x.getCpString(i1)); + ie.setAttr("val", "" + i2); + } + return ie; + } + + @Override + public Element visitLocal(Instruction i, int i1, Void p) { + Element ie = new Element(i.getMnemonic()); + ie.setAttr("loc", "" + i1); + return ie; + } + + @Override + public Element visitLocalAndValue(Instruction i, int i1, int i2, Void p) { + Element ie = new Element(i.getMnemonic()); + ie.setAttr("loc", "" + i1); + ie.setAttr("num", "" + i2); + return ie; + } + + @Override + public Element visitLookupSwitch(Instruction i, int i1, int i2, int[] ints, + int[] ints1, Void p) { + Element ie = new Element(i.getMnemonic()); + int pc = i.getPC(); + ie.setAttr("lab", "" + (pc + i1)); + for (int k = 0 ; k < i2 ; k++) { + Element c = new Element("Case"); + c.setAttr("num", "" + (ints[k])); + c.setAttr("lab", "" + (pc + ints1[k])); + c.trimToSize(); + ie.add(c); + } + return ie; + } + + @Override + public Element visitTableSwitch(Instruction i, int i1, int i2, int i3, + int[] ints, Void p) { + Element ie = new Element(i.getMnemonic()); + int pc = i.getPC(); + ie.setAttr("lab", "" + (pc + i1)); + for (int k : ints) { + Element c = new Element("Case"); + c.setAttr("num", "" + (k + i2)); + c.setAttr("lab", "" + (pc + k)); + c.trimToSize(); + ie.add(c); + } + return ie; + } + + @Override + public Element visitValue(Instruction i, int i1, Void p) { + Element ie = new Element(i.getMnemonic()); + ie.setAttr("num", "" + i1); + return ie; + } + + @Override + public Element visitUnknown(Instruction i, Void p) { + Element e = new Element(i.getMnemonic()); + e.setAttr("pc", "" + i.getPC()); + e.setAttr("opcode", "" + i.getOpcode().opcode); + return e; + } +} + +class AnnotationsElementVisitor implements Annotation.element_value.Visitor { + final ClassReader x; + final ClassFile cf; + + public AnnotationsElementVisitor(ClassReader x, ClassFile cf) { + this.x = x; + this.cf = cf; + } + + public Element visit(Annotation.element_value v, Element p) { + return v.accept(this, p); + } + + @Override + public Element visitPrimitive(Primitive_element_value e, Element p) { + Element el = new Element("String"); + el.setAttr("val", x.getCpString(e.const_value_index)); + el.trimToSize(); + return el; + } + + @Override + public Element visitEnum(Enum_element_value e, Element p) { + Element el = new Element("Enum"); + el.setAttr("name", x.getCpString(e.const_name_index)); + el.setAttr("type", x.getCpString(e.type_name_index)); + el.trimToSize(); + return el; + } + + @Override + public Element visitClass(Class_element_value c, Element p) { + Element el = new Element("Class"); + el.setAttr("name", x.getCpString(c.class_info_index)); + el.trimToSize(); + return el; + } + + @Override + public Element visitAnnotation(Annotation_element_value a, Element p) { + Element el = new Element("Annotation"); + Annotation anno = a.annotation_value; + for (Annotation.element_value_pair evp : anno.element_value_pairs) { + Element child = visit(evp.value, el); + if (child != null) { + el.add(child); + } + } + el.trimToSize(); + return el; + } + + @Override + public Element visitArray(Array_element_value a, Element p) { + Element el = new Element("Array"); + for (Annotation.element_value v : a.values) { + Element child = visit(v, el); + if (child != null) { + el.add(child); + } + } + el.trimToSize(); + return el; + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java deleted file mode 100644 index d34ecbad004..00000000000 --- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java +++ /dev/null @@ -1,518 +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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 cpTagNames; - - static { - Set set = new HashSet(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 itemTagNames; - - static { - Set set = new HashSet(Arrays.asList(itemTagName)); - set.remove(null); - itemTagNames = Collections.unmodifiableSet(set); - } - protected static final HashMap attrTypesBacking; - protected static final Map attrTypesInit; - - static { - HashMap at = new HashMap(); - - //at.put("*.Deprecated", ""); - //at.put("*.Synthetic", ""); - ////at.put("Field.ConstantValue", "KQH"); - //at.put("Class.SourceFile", "RUH"); - at.put("Method.Bridge", ""); - at.put("Method.Varargs", ""); - at.put("Class.Enum", ""); - at.put("*.Signature", "RSH"); - //at.put("*.Deprecated", ""); - //at.put("*.Synthetic", ""); - at.put("Field.ConstantValue", "KQH"); - at.put("Class.SourceFile", "RUH"); - at.put("Class.InnerClasses", "NH[RCHRCHRUHFH]"); - at.put("Code.LineNumberTable", "NH[PHH]"); - at.put("Code.LocalVariableTable", "NH[PHHRUHRSHH]"); - at.put("Code.LocalVariableTypeTable", "NH[PHHRUHRSHH]"); - at.put("Method.Exceptions", "NH[RCH]"); - at.put("Method.Code", "..."); - at.put("Code.StackMapTable", "..."); - //at.put("Code.StkMapX", "..."); - if (true) { - at.put("Code.StackMapTable", - "[NH[(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" - + ")[(4)]" - + "(247)[H(4)]" - + "(248)[H]" - + "(249)[H]" - + "(250)[H]" - + "(251)[H]" - + "(252)[H(4)]" - + "(253)[H(4)(4)]" - + "(254)[H(4)(4)(4)]" - + "(255)[H(2)(3)]" - + "()[]]" - + "[NH[(4)]]" - + "[NH[(4)]]" - + "[TB" - + ("(0)[]" - + "(1)[](2)[](3)[](4)[]" - + "(5)[](6)[]" - + "(7)[RCH]" - + "(8)[PH]" - + "()[]]")); - } - - at.put("Class.EnclosingMethod", "RCHRDH");//RDNH - - // Layouts of metadata attrs: - String vpf = "["; - String ipf = "["; - String apf = "["; - String mdanno2 = "" - + "RSHNH[RUH(3)]]" - + ("[TB" - + "(\\B,\\C,\\I,\\S,\\Z)[KIH]" - + "(\\D)[KDH]" - + "(\\F)[KFH]" - + "(\\J)[KJH]" - + "(\\c)[RSH]" - + "(\\e)[RSHRUH]" - + "(\\s)[RUH]" - + "(\\@)[(2)]" - + "(\\[)[NH[(3)]]" - + "()[]" - + "]"); - String visanno = "[NH[(2)]][(1)]" + vpf + mdanno2; - String invanno = "[NH[(2)]][(1)]" + ipf + mdanno2; - String vparamanno = "" - + "[NB[(1)]][NH[(2)]]" - + apf + mdanno2; - String iparamanno = "" - + "[NB[(1)]][NH[(2)]]" - + apf + mdanno2; - String mdannodef = "[(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[PHHII]", - "Code.CharacterRangeTable=NH[PHPOHIIH]", - "Class.SourceID=RUH", - "Class.CompilationID=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 nonAttrTags; - - static { - HashSet tagSet = new HashSet(); - 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 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 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 at) { - for (String attr : at.keySet()) { - checkAttr(attr); - } - } - - private void modAttrs() { - if (attrTypes == attrTypesInit) { - // Make modifiable. - attrTypes = new HashMap(attrTypesBacking); - } - } - - public void addAttrType(String attr, String fmt) { - checkAttr(attr); - modAttrs(); - attrTypes.put(attr, fmt); - } - - public void addAttrTypes(Map at) { - checkAttrs(at); - modAttrs(); - attrTypes.putAll(at); - } - - public Map getAttrTypes() { - if (attrTypes == attrTypesInit) { - return attrTypes; - } - return Collections.unmodifiableMap(attrTypes); - } - - public void setAttrTypes(Map 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 bodies = new ArrayList(); - 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; // - protected Element cpool; // - protected Element klass; // - protected Element currentMember; // varies during scans - protected Element currentCode; // varies during scans -} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java deleted file mode 100644 index 037de37e540..00000000000 --- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java +++ /dev/null @@ -1,818 +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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 av = new ArrayList(Arrays.asList(ava)); - HashMap props = new HashMap(); - 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 attrTypesByTag; - protected OutputStream out; - protected HashMap cpMap = new HashMap(); - protected ArrayList attrBufs = new ArrayList(); - - private void setupAttrTypes() { - attrTypesByTag = new HashMap(); - 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 attrNames = new LinkedHashSet(); - 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("...")) { - writeCode((Element) attrs.get(0)); // assume only 1 - } else if (type.equals("...")) { - writeStackMap(attrs, false); - } else if (type.equals("...")) { - 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); - } -} - diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java deleted file mode 100644 index cbe34e6b960..00000000000 --- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java +++ /dev/null @@ -1,464 +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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 labels = new HashMap(); - - 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