提交 d183c7bc 编写于 作者: K ksrini

6981776: Pack200 must support -target 7 bytecodes

Summary: pack200 implementation of JSR-200 updated for JSR-292 changes
Reviewed-by: jrose, ksrini
Contributed-by: john.r.rose@oracle.com, kumar.x.srinivasan@oracle.com
上级 4ef15b70
/*
* 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<Attribute> {
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<Attribute> {
// 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<Attribute> {
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<Attribute> {
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<Attribute> {
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<Attribute> {
// 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<Attribute> {
"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<Attribute> {
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<Attribute> {
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("}");
}
......
/*
* 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<<CLASS_ATTR_ClassFile_version);
}
private void adjustToMajver() {
private void adjustToMajver() throws IOException {
if (getPackageMajver() < JAVA6_PACKAGE_MAJOR_VERSION) {
if (verbose > 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);
......
/*
* 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<InnerClass> ics = new ArrayList<>(nc);
......
/*
* 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<BootstrapMethodEntry> 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<InnerClass> ics = cls.getInnerClasses();
writeShort(ics.size());
......
/*
* 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_All = 19; // combined global map
public final static byte CONSTANT_Literal = 20; // used only for ldc fields
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 = 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;
}
/*
* 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);
}
......
/*
* 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<Attribute.Layout, Attribute> attrDefs;
......@@ -115,6 +119,8 @@ class Package {
Map<Layout, Attribute> 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<InnerClass> innerClasses;
ArrayList<BootstrapMethodEntry> 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<BootstrapMethodEntry> getBootstrapMethods() {
return bootstrapMethods;
}
BootstrapMethodEntry[] getBootstrapMethodMap() {
return (hasBootstrapMethods())
? bootstrapMethods.toArray(new BootstrapMethodEntry[bootstrapMethods.size()])
: null;
}
void setBootstrapMethods(Collection<BootstrapMethodEntry> 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];
......
/*
* 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<BootstrapMethodEntry> 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<Class.Field> 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;
......
/*
* 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));
......
/*
* 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<String, SignatureEntry> signatureEntries;
private final Map<String, DescriptorEntry> descriptorEntries;
private final Map<String, MemberEntry> memberEntries;
private final Map<String, MethodHandleEntry> methodHandleEntries;
private final Map<String, MethodTypeEntry> methodTypeEntries;
private final Map<String, InvokeDynamicEntry> invokeDynamicEntries;
private final Map<String, BootstrapMethodEntry> 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<String, MemberEntry> getMemberEntries() {
return memberEntries;
}
Map<String, MethodHandleEntry> getMethodHandleEntries() {
return methodHandleEntries;
}
Map<String, MethodTypeEntry> getMethodTypeEntries() {
return methodTypeEntries;
}
Map<String, InvokeDynamicEntry> getInvokeDynamicEntries() {
return invokeDynamicEntries;
}
Map<String, BootstrapMethodEntry> getBootstrapMethodEntries() {
return bootstrapMethodEntries;
}
}
/*
* 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<TLGlobals> 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<String, Utf8Entry> getUtf8Entries() {
return getTLGlobals().getUtf8Entries();
}
static Map<String, ClassEntry> getClassEntries() {
return getTLGlobals().getClassEntries();
}
static Map<Object, LiteralEntry> getLiteralEntries() {
return getTLGlobals().getLiteralEntries();
}
static Map<String, DescriptorEntry> getDescriptorEntries() {
return getTLGlobals().getDescriptorEntries();
}
static Map<String, SignatureEntry> getSignatureEntries() {
return getTLGlobals().getSignatureEntries();
}
static Map<String, MemberEntry> getMemberEntries() {
return getTLGlobals().getMemberEntries();
}
static PropMap currentPropMap() {
Object obj = currentInstance.get();
if (obj instanceof PackerImpl)
......@@ -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;
......
/*
* 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));
}
}
......
/*
* 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]
......
/*
* 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
};
/*
* 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
......
/*
* 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); }
......
/*
* 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<String> cmds = new ArrayList<String>();
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
......
/*
* 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,
......
/*
* 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<String> cmds = new ArrayList<String>();
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<String> cmds = new ArrayList<String>();
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");
......
......@@ -2,19 +2,19 @@ The files contained in the golden.jar have been harvested from many
different sources, some are hand-crafted invalid class files (odds directory),
or from random JDK builds.
Generally these files serve to ensure the integrity of the packer and unpacker
by,
1. maximizing the test coverage.
2. exercising all the Bands in the pack200 specification.
2. testing the behavior of the packer with invalid classes.
3. testing the archive integrity, ordering and description (date, sizes,
Generally these files serve to ensure the integrity of the packer and
unpacker by,
* maximizing the test coverage.
* exercising all the Bands in the pack200 specification.
* testing the behavior of the packer with invalid classes.
* testing the archive integrity, ordering and description (date, sizes,
CRC etc.)
Build:
To rebuild this JAR follow these steps:
1. unzip the golden.jar to some directory lets call it "example"
2. now we can add any directories with files into example.
2. run the script BUILDME.sh as
3. run the script BUILDME.sh as
% sh BUILDME.sh example
Note: the BUILDME.sh is known to work on all Unix platforms as well as Windows
......@@ -32,7 +32,7 @@ Test:
Basic:
% pack200 --repack test.jar golden.jar
Advanced:
Advanced: inspection of band contents
Create a pack.conf as follows:
% cat pack.conf
com.sun.java.util.jar.pack.dump.bands=true
......@@ -41,5 +41,6 @@ Test:
--verbose golden.jar.pack golden.jar
This command will dump the Bands in a unique directory BD_XXXXXX,
one can inspect the directory to ensure all of the bands are being
generated. Familiarity of the Pack200 specification is suggested.
\ No newline at end of file
one can then inspect the directory to ensure all of the bands are being
generated. Familiarity of the Pack200 specification is strongly
suggested.
<project name="PackageVerify" default="dist" basedir="..">
<!-- Requires ant 1.6.1+ and JDK 1.6+-->
<!-- Requires ant 1.6.1+ and JDK 1.7+-->
<!-- set global properties for this build -->
<property name="src" value="${basedir}/src"/>
......@@ -22,7 +22,7 @@
<target name="compile" depends="init">
<!-- Compile the java code from ${src} into ${build} -->
<javac
source="1.6"
source="1.7"
srcdir="${src}"
destdir="${build}/classes"
verbose="no"
......@@ -32,7 +32,7 @@
<target name="doc" depends="init, compile">
<javadoc
source="1.6"
source="1.7"
sourcepath="${src}"
destdir="${api}"
/>
......
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
import xmlkit.XMLKit.*;
import java.util.*;
import java.security.MessageDigest;
import java.nio.ByteBuffer;
import xmlkit.XMLKit.Element;
/*
* @author jrose
*/
public abstract class ClassSyntax {
public interface GetCPIndex {
int getCPIndex(int tag, String name); // cp finder
}
public static final int CONSTANT_Utf8 = 1,
CONSTANT_Integer = 3,
CONSTANT_Float = 4,
CONSTANT_Long = 5,
CONSTANT_Double = 6,
CONSTANT_Class = 7,
CONSTANT_String = 8,
CONSTANT_Fieldref = 9,
CONSTANT_Methodref = 10,
CONSTANT_InterfaceMethodref = 11,
CONSTANT_NameAndType = 12;
private static final String[] cpTagName = {
/* 0: */null,
/* 1: */ "Utf8",
/* 2: */ null,
/* 3: */ "Integer",
/* 4: */ "Float",
/* 5: */ "Long",
/* 6: */ "Double",
/* 7: */ "Class",
/* 8: */ "String",
/* 9: */ "Fieldref",
/* 10: */ "Methodref",
/* 11: */ "InterfaceMethodref",
/* 12: */ "NameAndType",
null
};
private static final Set<String> cpTagNames;
static {
Set<String> set = new HashSet<String>(Arrays.asList(cpTagName));
set.remove(null);
cpTagNames = Collections.unmodifiableSet(set);
}
public static final int ITEM_Top = 0, // replicates by [1..4,1..4]
ITEM_Integer = 1, // (ditto)
ITEM_Float = 2,
ITEM_Double = 3,
ITEM_Long = 4,
ITEM_Null = 5,
ITEM_UninitializedThis = 6,
ITEM_Object = 7,
ITEM_Uninitialized = 8,
ITEM_ReturnAddress = 9,
ITEM_LIMIT = 10;
private static final String[] itemTagName = {
"Top",
"Integer",
"Float",
"Double",
"Long",
"Null",
"UninitializedThis",
"Object",
"Uninitialized",
"ReturnAddress",};
private static final Set<String> itemTagNames;
static {
Set<String> set = new HashSet<String>(Arrays.asList(itemTagName));
set.remove(null);
itemTagNames = Collections.unmodifiableSet(set);
}
protected static final HashMap<String, String> attrTypesBacking;
protected static final Map<String, String> attrTypesInit;
static {
HashMap<String, String> at = new HashMap<String, String>();
//at.put("*.Deprecated", "<deprecated=true>");
//at.put("*.Synthetic", "<synthetic=true>");
////at.put("Field.ConstantValue", "<constantValue=>KQH");
//at.put("Class.SourceFile", "<sourceFile=>RUH");
at.put("Method.Bridge", "<Bridge>");
at.put("Method.Varargs", "<Varargs>");
at.put("Class.Enum", "<Enum>");
at.put("*.Signature", "<Signature>RSH");
//at.put("*.Deprecated", "<Deprecated>");
//at.put("*.Synthetic", "<Synthetic>");
at.put("Field.ConstantValue", "<ConstantValue>KQH");
at.put("Class.SourceFile", "<SourceFile>RUH");
at.put("Class.InnerClasses", "NH[<InnerClass><class=>RCH<outer=>RCH<name=>RUH<flags=>FH]");
at.put("Code.LineNumberTable", "NH[<LineNumber><bci=>PH<line=>H]");
at.put("Code.LocalVariableTable", "NH[<LocalVariable><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]");
at.put("Code.LocalVariableTypeTable", "NH[<LocalVariableType><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]");
at.put("Method.Exceptions", "NH[<Exception><name=>RCH]");
at.put("Method.Code", "<Code>...");
at.put("Code.StackMapTable", "<Frame>...");
//at.put("Code.StkMapX", "<FrameX>...");
if (true) {
at.put("Code.StackMapTable",
"[NH[<Frame>(1)]]"
+ "[TB"
+ "(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79"
+ ",80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95"
+ ",96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111"
+ ",112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127"
+ ")[<SameLocals1StackItemFrame>(4)]"
+ "(247)[<SameLocals1StackItemExtended>H(4)]"
+ "(248)[<Chop3>H]"
+ "(249)[<Chop2>H]"
+ "(250)[<Chop1>H]"
+ "(251)[<SameFrameExtended>H]"
+ "(252)[<Append1>H(4)]"
+ "(253)[<Append2>H(4)(4)]"
+ "(254)[<Append3>H(4)(4)(4)]"
+ "(255)[<FullFrame>H(2)(3)]"
+ "()[<SameFrame>]]"
+ "[NH[<Local>(4)]]"
+ "[NH[<Stack>(4)]]"
+ "[TB"
+ ("(0)[<Top>]"
+ "(1)[<ItemInteger>](2)[<ItemFloat>](3)[<ItemDouble>](4)[<ItemLong>]"
+ "(5)[<ItemNull>](6)[<ItemUninitializedThis>]"
+ "(7)[<ItemObject><class=>RCH]"
+ "(8)[<ItemUninitialized><bci=>PH]"
+ "()[<ItemUnknown>]]"));
}
at.put("Class.EnclosingMethod", "<EnclosingMethod><class=>RCH<desc=>RDH");//RDNH
// Layouts of metadata attrs:
String vpf = "[<RuntimeVisibleAnnotation>";
String ipf = "[<RuntimeInvisibleAnnotation>";
String apf = "[<Annotation>";
String mdanno2 = ""
+ "<type=>RSHNH[<Member><name=>RUH(3)]]"
+ ("[TB"
+ "(\\B,\\C,\\I,\\S,\\Z)[<value=>KIH]"
+ "(\\D)[<value=>KDH]"
+ "(\\F)[<value=>KFH]"
+ "(\\J)[<value=>KJH]"
+ "(\\c)[<class=>RSH]"
+ "(\\e)[<type=>RSH<name=>RUH]"
+ "(\\s)[<String>RUH]"
+ "(\\@)[(2)]"
+ "(\\[)[NH[<Element>(3)]]"
+ "()[]"
+ "]");
String visanno = "[NH[(2)]][(1)]" + vpf + mdanno2;
String invanno = "[NH[(2)]][(1)]" + ipf + mdanno2;
String vparamanno = ""
+ "[NB[<RuntimeVisibleParameterAnnotation>(1)]][NH[(2)]]"
+ apf + mdanno2;
String iparamanno = ""
+ "[NB[<RuntimeInvisibleParameterAnnotation>(1)]][NH[(2)]]"
+ apf + mdanno2;
String mdannodef = "[<AnnotationDefault>(3)][(1)]" + apf + mdanno2;
String[] mdplaces = {"Class", "Field", "Method"};
for (String place : mdplaces) {
at.put(place + ".RuntimeVisibleAnnotations", visanno);
at.put(place + ".RuntimeInvisibleAnnotations", invanno);
}
at.put("Method.RuntimeVisibleParameterAnnotations", vparamanno);
at.put("Method.RuntimeInvisibleParameterAnnotations", iparamanno);
at.put("Method.AnnotationDefault", mdannodef);
attrTypesBacking = at;
attrTypesInit = Collections.unmodifiableMap(at);
}
;
private static final String[] jcovAttrTypes = {
"Code.CoverageTable=NH[<Coverage><bci=>PH<type=>H<line=>I<pos=>I]",
"Code.CharacterRangeTable=NH[<CharacterRange><bci=>PH<endbci=>POH<from=>I<to=>I<flag=>H]",
"Class.SourceID=<SourceID><id=>RUH",
"Class.CompilationID=<CompilationID><id=>RUH"
};
protected static final String[][] modifierNames = {
{"public"},
{"private"},
{"protected"},
{"static"},
{"final"},
{"synchronized"},
{null, "volatile", "bridge"},
{null, "transient", "varargs"},
{null, null, "native"},
{"interface"},
{"abstract"},
{"strictfp"},
{"synthetic"},
{"annotation"},
{"enum"},};
protected static final String EIGHT_BIT_CHAR_ENCODING = "ISO8859_1";
protected static final String UTF8_ENCODING = "UTF8";
// What XML tags are used by this syntax, apart from attributes?
protected static final Set<String> nonAttrTags;
static {
HashSet<String> tagSet = new HashSet<String>();
Collections.addAll(tagSet, new String[]{
"ConstantPool",// the CP
"Class", // the class
"Interface", // implemented interfaces
"Method", // methods
"Field", // fields
"Handler", // exception handler pseudo-attribute
"Attribute", // unparsed attribute
"Bytes", // bytecodes
"Instructions" // bytecodes, parsed
});
nonAttrTags = Collections.unmodifiableSet(tagSet);
}
// Accessors.
public static Set<String> nonAttrTags() {
return nonAttrTags;
}
public static String cpTagName(int t) {
t &= 0xFF;
String ts = null;
if (t < cpTagName.length) {
ts = cpTagName[t];
}
if (ts != null) {
return ts;
}
return ("UnknownTag" + (int) t).intern();
}
public static int cpTagValue(String name) {
for (int t = 0; t < cpTagName.length; t++) {
if (name.equals(cpTagName[t])) {
return t;
}
}
return 0;
}
public static String itemTagName(int t) {
t &= 0xFF;
String ts = null;
if (t < itemTagName.length) {
ts = itemTagName[t];
}
if (ts != null) {
return ts;
}
return ("UnknownItem" + (int) t).intern();
}
public static int itemTagValue(String name) {
for (int t = 0; t < itemTagName.length; t++) {
if (name.equals(itemTagName[t])) {
return t;
}
}
return -1;
}
public void addJcovAttrTypes() {
addAttrTypes(jcovAttrTypes);
}
// Public methods for declaring attribute types.
protected Map<String, String> attrTypes = attrTypesInit;
public void addAttrType(String opt) {
int eqpos = opt.indexOf('=');
addAttrType(opt.substring(0, eqpos), opt.substring(eqpos + 1));
}
public void addAttrTypes(String[] opts) {
for (String opt : opts) {
addAttrType(opt);
}
}
private void checkAttr(String attr) {
if (!attr.startsWith("Class.")
&& !attr.startsWith("Field.")
&& !attr.startsWith("Method.")
&& !attr.startsWith("Code.")
&& !attr.startsWith("*.")) {
throw new IllegalArgumentException("attr name must start with 'Class.', etc.");
}
String uattr = attr.substring(attr.indexOf('.') + 1);
if (nonAttrTags.contains(uattr)) {
throw new IllegalArgumentException("attr name must not be one of " + nonAttrTags);
}
}
private void checkAttrs(Map<String, String> at) {
for (String attr : at.keySet()) {
checkAttr(attr);
}
}
private void modAttrs() {
if (attrTypes == attrTypesInit) {
// Make modifiable.
attrTypes = new HashMap<String, String>(attrTypesBacking);
}
}
public void addAttrType(String attr, String fmt) {
checkAttr(attr);
modAttrs();
attrTypes.put(attr, fmt);
}
public void addAttrTypes(Map<String, String> at) {
checkAttrs(at);
modAttrs();
attrTypes.putAll(at);
}
public Map<String, String> getAttrTypes() {
if (attrTypes == attrTypesInit) {
return attrTypes;
}
return Collections.unmodifiableMap(attrTypes);
}
public void setAttrTypes(Map<String, String> at) {
checkAttrs(at);
modAttrs();
attrTypes.keySet().retainAll(at.keySet());
attrTypes.putAll(at);
}
// attr format helpers
protected static boolean matchTag(int tagValue, String caseStr) {
//System.out.println("matchTag "+tagValue+" in "+caseStr);
for (int pos = 0, max = caseStr.length(), comma;
pos < max;
pos = comma + 1) {
int caseValue;
if (caseStr.charAt(pos) == '\\') {
caseValue = caseStr.charAt(pos + 1);
comma = pos + 2;
assert (comma == max || caseStr.charAt(comma) == ',');
} else {
comma = caseStr.indexOf(',', pos);
if (comma < 0) {
comma = max;
}
caseValue = Integer.parseInt(caseStr.substring(pos, comma));
}
if (tagValue == caseValue) {
return true;
}
}
return false;
}
protected static String[] getBodies(String type) {
ArrayList<String> bodies = new ArrayList<String>();
for (int i = 0; i < type.length();) {
String body = getBody(type, i);
bodies.add(body);
i += body.length() + 2; // skip body and brackets
}
return bodies.toArray(new String[bodies.size()]);
}
protected static String getBody(String type, int i) {
assert (type.charAt(i) == '[');
int next = ++i; // skip bracket
for (int depth = 1; depth > 0; next++) {
switch (type.charAt(next)) {
case '[':
depth++;
break;
case ']':
depth--;
break;
case '(':
next = type.indexOf(')', next);
break;
case '<':
next = type.indexOf('>', next);
break;
}
assert (next > 0);
}
--next; // get before bracket
assert (type.charAt(next) == ']');
return type.substring(i, next);
}
public Element makeCPDigest(int length) {
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch (java.security.NoSuchAlgorithmException ee) {
throw new Error(ee);
}
int items = 0;
for (Element e : cpool.elements()) {
if (items == length) {
break;
}
if (cpTagNames.contains(e.getName())) {
items += 1;
md.update((byte) cpTagValue(e.getName()));
try {
md.update(e.getText().toString().getBytes(UTF8_ENCODING));
} catch (java.io.UnsupportedEncodingException ee) {
throw new Error(ee);
}
}
}
ByteBuffer bb = ByteBuffer.wrap(md.digest());
String l0 = Long.toHexString(bb.getLong(0));
String l1 = Long.toHexString(bb.getLong(8));
while (l0.length() < 16) {
l0 = "0" + l0;
}
while (l1.length() < 16) {
l1 = "0" + l1;
}
return new Element("Digest",
"length", "" + items,
"bytes", l0 + l1);
}
public Element getCPDigest(int length) {
if (length == -1) {
length = cpool.countAll(XMLKit.elementFilter(cpTagNames));
}
for (Element md : cpool.findAllElements("Digest").elements()) {
if (md.getAttrLong("length") == length) {
return md;
}
}
Element md = makeCPDigest(length);
cpool.add(md);
return md;
}
public Element getCPDigest() {
return getCPDigest(-1);
}
public boolean checkCPDigest(Element md) {
return md.equals(getCPDigest((int) md.getAttrLong("length")));
}
public static int computeInterfaceNum(String intMethRef) {
intMethRef = intMethRef.substring(1 + intMethRef.lastIndexOf(' '));
if (!intMethRef.startsWith("(")) {
return -1;
}
int signum = 1; // start with one for "this"
scanSig:
for (int i = 1; i < intMethRef.length(); i++) {
char ch = intMethRef.charAt(i);
signum++;
switch (ch) {
case ')':
--signum;
break scanSig;
case 'L':
i = intMethRef.indexOf(';', i);
break;
case '[':
while (ch == '[') {
ch = intMethRef.charAt(++i);
}
if (ch == 'L') {
i = intMethRef.indexOf(';', i);
}
break;
}
}
int num = (signum << 8) | 0;
//System.out.println("computeInterfaceNum "+intMethRef+" => "+num);
return num;
}
// Protected state for representing the class file.
protected Element cfile; // <ClassFile ...>
protected Element cpool; // <ConstantPool ...>
protected Element klass; // <Class ...>
protected Element currentMember; // varies during scans
protected Element currentCode; // varies during scans
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
import xmlkit.XMLKit.Element;
import java.util.HashMap;
/*
* @author jrose
*/
abstract class InstructionAssembler extends InstructionSyntax {
InstructionAssembler() {
}
public static String assemble(Element instructions, String pcAttrName,
ClassSyntax.GetCPIndex getCPI) {
int insCount = instructions.size();
Element[] insElems = new Element[insCount];
int[] elemToIndexMap;
int[] insLocs;
byte[] ops = new byte[insCount];
int[] operands = new int[insCount];
boolean[] isWide = new boolean[insCount];
int[] branches;
int[] branchInsLocs;
HashMap<String, String> labels = new HashMap<String, String>();
final int WIDE = 0xc4;
final int GOTO = 0xa7;
final int GOTO_W = 0xc8;
final int GOTO_LEN = 3;
final int GOTO_W_LEN = 5;
assert ("wide".equals(bcNames[WIDE]));
assert ("goto".equals(bcNames[GOTO]));
assert ("goto_w".equals(bcNames[GOTO_W]));
assert (bcFormats[GOTO].length() == GOTO_LEN);
assert (bcFormats[GOTO_W].length() == GOTO_W_LEN);
// Unpack instructions into temp. arrays, and find branches and labels.
{
elemToIndexMap = (pcAttrName != null) ? new int[insCount] : null;
int[] buffer = operands;
int id = 0;
int branchCount = 0;
for (int i = 0; i < insCount; i++) {
Element ins = (Element) instructions.get(i);
if (elemToIndexMap != null) {
elemToIndexMap[i] = (ins.getAttr(pcAttrName) != null ? id : -1);
}
String lab = ins.getAttr("pc");
if (lab != null) {
labels.put(lab, String.valueOf(id));
}
int op = opCode(ins.getName());
if (op < 0) {
assert (ins.getAttr(pcAttrName) != null
|| ins.getName().equals("label"));
continue; // delete PC holder element
}
if (op == WIDE) { //0xc4
isWide[id] = true; // force wide format
continue;
}
if (bcFormats[op].indexOf('o') >= 0) {
buffer[branchCount++] = id;
}
if (bcFormats[op] == bcWideFormats[op]) {
isWide[id] = false;
}
insElems[id] = ins;
ops[id] = (byte) op;
id++;
}
insCount = id; // maybe we deleted some wide prefixes, etc.
branches = new int[branchCount + 1];
System.arraycopy(buffer, 0, branches, 0, branchCount);
branches[branchCount] = -1; // sentinel
}
// Compute instruction sizes. These sizes are final,
// except for branch instructions, which may need lengthening.
// Some instructions (ldc, bipush, iload, iinc) are automagically widened.
insLocs = new int[insCount + 1];
int loc = 0;
for (int bn = 0, id = 0; id < insCount; id++) {
insLocs[id] = loc;
Element ins = insElems[id];
int op = ops[id] & 0xFF;
String format = opFormat(op, isWide[id]);
// Make sure operands fit within the given format.
for (int j = 1, jlimit = format.length(); j < jlimit; j++) {
char fc = format.charAt(j);
int x = 0;
switch (fc) {
case 'l':
x = (int) ins.getAttrLong("loc");
assert (x >= 0);
if (x > 0xFF && !isWide[id]) {
isWide[id] = true;
format = opFormat(op, isWide[id]);
}
assert (x <= 0xFFFF);
break;
case 'k':
char fc2 = format.charAt(Math.min(j + 1, format.length() - 1));
x = getCPIndex(ins, fc2, getCPI);
if (x > 0xFF && j == jlimit - 1) {
assert (op == 0x12); //ldc
ops[id] = (byte) (op = 0x13); //ldc_w
format = opFormat(op);
}
assert (x <= 0xFFFF);
j++; // skip type-of-constant marker
break;
case 'x':
x = (int) ins.getAttrLong("num");
assert (x >= 0 && x <= ((j == jlimit - 1) ? 0xFF : 0xFFFF));
break;
case 's':
x = (int) ins.getAttrLong("num");
if (x != (byte) x && j == jlimit - 1) {
switch (op) {
case 0x10: //bipush
ops[id] = (byte) (op = 0x11); //sipush
break;
case 0x84: //iinc
isWide[id] = true;
format = opFormat(op, isWide[id]);
break;
default:
assert (false); // cannot lengthen
}
}
// unsign the value now, to make later steps clearer
if (j == jlimit - 1) {
assert (x == (byte) x);
x = x & 0xFF;
} else {
assert (x == (short) x);
x = x & 0xFFFF;
}
break;
case 'o':
assert (branches[bn] == id);
bn++;
// make local copies of the branches, and fix up labels
insElems[id] = ins = new Element(ins);
String newLab = labels.get(ins.getAttr("lab"));
assert (newLab != null);
ins.setAttr("lab", newLab);
int prevCas = 0;
int k = 0;
for (Element cas : ins.elements()) {
assert (cas.getName().equals("Case"));
ins.set(k++, cas = new Element(cas));
newLab = labels.get(cas.getAttr("lab"));
assert (newLab != null);
cas.setAttr("lab", newLab);
int thisCas = (int) cas.getAttrLong("num");
assert (op == 0xab
|| op == 0xaa && (k == 0 || thisCas == prevCas + 1));
prevCas = thisCas;
}
break;
case 't':
// switch table is represented as Switch.Case sub-elements
break;
default:
assert (false);
}
operands[id] = x; // record operand (last if there are 2)
// skip redundant chars
while (j + 1 < jlimit && format.charAt(j + 1) == fc) {
++j;
}
}
switch (op) {
case 0xaa: //tableswitch
loc = switchBase(loc);
loc += 4 * (3 + ins.size());
break;
case 0xab: //lookupswitch
loc = switchBase(loc);
loc += 4 * (2 + 2 * ins.size());
break;
default:
if (isWide[id]) {
loc++; // 'wide' opcode prefix
}
loc += format.length();
break;
}
}
insLocs[insCount] = loc;
// compute branch offsets, and see if any branches need expansion
for (int maxTries = 9, tries = 0;; ++tries) {
boolean overflowing = false;
boolean[] branchExpansions = null;
for (int bn = 0; bn < branches.length - 1; bn++) {
int id = branches[bn];
Element ins = insElems[id];
int insSize = insLocs[id + 1] - insLocs[id];
int origin = insLocs[id];
int target = insLocs[(int) ins.getAttrLong("lab")];
int offset = target - origin;
operands[id] = offset;
//System.out.println("branch id="+id+" len="+insSize+" to="+target+" offset="+offset);
assert (insSize == GOTO_LEN || insSize == GOTO_W_LEN || ins.getName().indexOf("switch") > 0);
boolean thisOverflow = (insSize == GOTO_LEN && (offset != (short) offset));
if (thisOverflow && !overflowing) {
overflowing = true;
branchExpansions = new boolean[branches.length];
}
if (thisOverflow || tries == maxTries - 1) {
// lengthen the branch
assert (!(thisOverflow && isWide[id]));
isWide[id] = true;
branchExpansions[bn] = true;
}
}
if (!overflowing) {
break; // done, usually on first try
}
assert (tries <= maxTries);
// Walk over all instructions, expanding branches and updating locations.
int fixup = 0;
for (int bn = 0, id = 0; id < insCount; id++) {
insLocs[id] += fixup;
if (branches[bn] == id) {
int op = ops[id] & 0xFF;
int wop;
boolean invert;
if (branchExpansions[bn]) {
switch (op) {
case GOTO: //0xa7
wop = GOTO_W; //0xc8
invert = false;
break;
case 0xa8: //jsr
wop = 0xc9; //jsr_w
invert = false;
break;
default:
wop = invertBranchOp(op);
invert = true;
break;
}
assert (op != wop);
ops[id] = (byte) wop;
isWide[id] = invert;
if (invert) {
fixup += GOTO_W_LEN; //branch around a wide goto
} else {
fixup += (GOTO_W_LEN - GOTO_LEN);
}
// done expanding: ops and isWide reflect the decision
}
bn++;
}
}
insLocs[insCount] += fixup;
}
// we know the layout now
// notify the caller of offsets, if requested
if (elemToIndexMap != null) {
for (int i = 0; i < elemToIndexMap.length; i++) {
int id = elemToIndexMap[i];
if (id >= 0) {
Element ins = (Element) instructions.get(i);
ins.setAttr(pcAttrName, "" + insLocs[id]);
}
}
elemToIndexMap = null; // release the pointer
}
// output the bytes
StringBuffer sbuf = new StringBuffer(insLocs[insCount]);
for (int bn = 0, id = 0; id < insCount; id++) {
//System.out.println("output id="+id+" loc="+insLocs[id]+" len="+(insLocs[id+1]-insLocs[id])+" #sbuf="+sbuf.length());
assert (sbuf.length() == insLocs[id]);
Element ins;
int pc = insLocs[id];
int nextpc = insLocs[id + 1];
int op = ops[id] & 0xFF;
int opnd = operands[id];
String format;
if (branches[bn] == id) {
bn++;
sbuf.append((char) op);
if (isWide[id]) {
// emit <ifop lab=1f> <goto_w target> <label pc=1f>
int target = pc + opnd;
putInt(sbuf, nextpc - pc, -2);
assert (sbuf.length() == pc + GOTO_LEN);
sbuf.append((char) GOTO_W);
putInt(sbuf, target - (pc + GOTO_LEN), 4);
} else if (op == 0xaa || //tableswitch
op == 0xab) { //lookupswitch
ins = insElems[id];
for (int pad = switchBase(pc) - (pc + 1); pad > 0; pad--) {
sbuf.append((char) 0);
}
assert (pc + opnd == insLocs[(int) ins.getAttrLong("lab")]);
putInt(sbuf, opnd, 4); // default label
if (op == 0xaa) { //tableswitch
Element cas0 = (Element) ins.get(0);
int lowCase = (int) cas0.getAttrLong("num");
Element casN = (Element) ins.get(ins.size() - 1);
int highCase = (int) casN.getAttrLong("num");
assert (highCase - lowCase + 1 == ins.size());
putInt(sbuf, lowCase, 4);
putInt(sbuf, highCase, 4);
int caseForAssert = lowCase;
for (Element cas : ins.elements()) {
int target = insLocs[(int) cas.getAttrLong("lab")];
assert (cas.getAttrLong("num") == caseForAssert++);
putInt(sbuf, target - pc, 4);
}
} else { //lookupswitch
int caseCount = ins.size();
putInt(sbuf, caseCount, 4);
for (Element cas : ins.elements()) {
int target = insLocs[(int) cas.getAttrLong("lab")];
putInt(sbuf, (int) cas.getAttrLong("num"), 4);
putInt(sbuf, target - pc, 4);
}
}
assert (nextpc == sbuf.length());
} else {
putInt(sbuf, opnd, -(nextpc - (pc + 1)));
}
} else if (nextpc == pc + 1) {
// a single-byte instruction
sbuf.append((char) op);
} else {
// picky stuff
boolean wide = isWide[id];
if (wide) {
sbuf.append((char) WIDE);
pc++;
}
sbuf.append((char) op);
int opnd1;
int opnd2 = opnd;
switch (op) {
case 0x84: //iinc
ins = insElems[id];
opnd1 = (int) ins.getAttrLong("loc");
if (isWide[id]) {
putInt(sbuf, opnd1, 2);
putInt(sbuf, opnd2, 2);
} else {
putInt(sbuf, opnd1, 1);
putInt(sbuf, opnd2, 1);
}
break;
case 0xc5: //multianewarray
ins = insElems[id];
opnd1 = getCPIndex(ins, 'c', getCPI);
putInt(sbuf, opnd1, 2);
putInt(sbuf, opnd2, 1);
break;
case 0xb9: //invokeinterface
ins = insElems[id];
opnd1 = getCPIndex(ins, 'n', getCPI);
putInt(sbuf, opnd1, 2);
opnd2 = (int) ins.getAttrLong("num");
if (opnd2 == 0) {
opnd2 = ClassSyntax.computeInterfaceNum(ins.getAttr("val"));
}
putInt(sbuf, opnd2, 2);
break;
default:
// put the single operand and be done
putInt(sbuf, opnd, nextpc - (pc + 1));
break;
}
}
}
assert (sbuf.length() == insLocs[insCount]);
return sbuf.toString();
}
static int getCPIndex(Element ins, char ctype,
ClassSyntax.GetCPIndex getCPI) {
int x = (int) ins.getAttrLong("ref");
if (x == 0 && getCPI != null) {
String val = ins.getAttr("val");
if (val == null || val.equals("")) {
val = ins.getText().toString();
}
byte tag;
switch (ctype) {
case 'k':
tag = (byte) ins.getAttrLong("tag");
break;
case 'c':
tag = ClassSyntax.CONSTANT_Class;
break;
case 'f':
tag = ClassSyntax.CONSTANT_Fieldref;
break;
case 'm':
tag = ClassSyntax.CONSTANT_Methodref;
break;
case 'n':
tag = ClassSyntax.CONSTANT_InterfaceMethodref;
break;
default:
throw new Error("bad ctype " + ctype + " in " + ins);
}
x = getCPI.getCPIndex(tag, val);
//System.out.println("getCPIndex "+ins+" => "+tag+"/"+val+" => "+x);
} else {
assert (x > 0);
}
return x;
}
static void putInt(StringBuffer sbuf, int x, int len) {
//System.out.println("putInt x="+x+" len="+len);
boolean isSigned = false;
if (len < 0) {
len = -len;
isSigned = true;
}
assert (len == 1 || len == 2 || len == 4);
int insig = ((4 - len) * 8); // how many insignificant bits?
int sx = x << insig;
;
assert (x == (isSigned ? (sx >> insig) : (sx >>> insig)));
for (int i = 0; i < len; i++) {
sbuf.append((char) (sx >>> 24));
sx <<= 8;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册