8341141: Optimize DirectCodeBuilder
Co-authored-by: Claes Redestad <redestad@openjdk.org> Co-authored-by: Chen Liang <liach@openjdk.org> Reviewed-by: liach, redestad
This commit is contained in:
parent
d636e0d314
commit
047c2d7f26
@ -801,7 +801,12 @@ public abstract sealed class AbstractInstruction
|
||||
|
||||
@Override
|
||||
public void writeTo(DirectCodeBuilder writer) {
|
||||
writer.writeLocalVar(op, slot);
|
||||
var op = this.op;
|
||||
if (op.sizeIfFixed() == 1) {
|
||||
writer.writeBytecode(op);
|
||||
} else {
|
||||
writer.writeLocalVar(op, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -832,7 +837,12 @@ public abstract sealed class AbstractInstruction
|
||||
|
||||
@Override
|
||||
public void writeTo(DirectCodeBuilder writer) {
|
||||
writer.writeLocalVar(op, slot);
|
||||
var op = this.op;
|
||||
if (op.sizeIfFixed() == 1) {
|
||||
writer.writeBytecode(op);
|
||||
} else {
|
||||
writer.writeLocalVar(op, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -461,14 +461,13 @@ public abstract sealed class AbstractPoolEntry {
|
||||
|
||||
@Override
|
||||
void writeTo(BufWriterImpl pool) {
|
||||
pool.writeU1(TAG_UTF8);
|
||||
if (rawBytes != null) {
|
||||
pool.writeU2(rawLen);
|
||||
pool.writeU1U2(TAG_UTF8, rawLen);
|
||||
pool.writeBytes(rawBytes, offset, rawLen);
|
||||
}
|
||||
else {
|
||||
// state == STRING and no raw bytes
|
||||
pool.writeUTF(stringValue);
|
||||
pool.writeUtfEntry(stringValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,8 +501,7 @@ public abstract sealed class AbstractPoolEntry {
|
||||
}
|
||||
|
||||
void writeTo(BufWriterImpl pool) {
|
||||
pool.writeU1(tag());
|
||||
pool.writeU2(ref1.index());
|
||||
pool.writeU1U2(tag(), ref1.index());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -532,9 +530,7 @@ public abstract sealed class AbstractPoolEntry {
|
||||
}
|
||||
|
||||
void writeTo(BufWriterImpl pool) {
|
||||
pool.writeU1(tag());
|
||||
pool.writeU2(ref1.index());
|
||||
pool.writeU2(ref2.index());
|
||||
pool.writeU1U2U2(tag(), ref1.index(), ref2.index());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -864,9 +860,7 @@ public abstract sealed class AbstractPoolEntry {
|
||||
}
|
||||
|
||||
void writeTo(BufWriterImpl pool) {
|
||||
pool.writeU1(tag());
|
||||
pool.writeU2(bsmIndex);
|
||||
pool.writeU2(nameAndType.index());
|
||||
pool.writeU1U2U2(tag(), bsmIndex, nameAndType.index());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -984,9 +978,7 @@ public abstract sealed class AbstractPoolEntry {
|
||||
|
||||
@Override
|
||||
void writeTo(BufWriterImpl pool) {
|
||||
pool.writeU1(TAG_METHOD_HANDLE);
|
||||
pool.writeU1(refKind);
|
||||
pool.writeU2(reference.index());
|
||||
pool.writeU1U1U2(TAG_METHOD_HANDLE, refKind, reference.index());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -315,8 +315,7 @@ public final class AnnotationReader {
|
||||
case TypeAnnotation.TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex());
|
||||
case TypeAnnotation.SupertypeTarget st -> buf.writeU2(st.supertypeIndex());
|
||||
case TypeAnnotation.TypeParameterBoundTarget tpbt -> {
|
||||
buf.writeU1(tpbt.typeParameterIndex());
|
||||
buf.writeU1(tpbt.boundIndex());
|
||||
buf.writeU1U1(tpbt.typeParameterIndex(), tpbt.boundIndex());
|
||||
}
|
||||
case TypeAnnotation.EmptyTarget _ -> {
|
||||
// nothing to write
|
||||
@ -327,9 +326,7 @@ public final class AnnotationReader {
|
||||
buf.writeU2(lvt.table().size());
|
||||
for (var e : lvt.table()) {
|
||||
int startPc = labelToBci(lr, e.startLabel(), ta);
|
||||
buf.writeU2(startPc);
|
||||
buf.writeU2(labelToBci(lr, e.endLabel(), ta) - startPc);
|
||||
buf.writeU2(e.index());
|
||||
buf.writeU2U2U2(startPc, labelToBci(lr, e.endLabel(), ta) - startPc, e.index());
|
||||
}
|
||||
}
|
||||
case TypeAnnotation.CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex());
|
||||
@ -343,8 +340,7 @@ public final class AnnotationReader {
|
||||
// target_path
|
||||
buf.writeU1(ta.targetPath().size());
|
||||
for (TypeAnnotation.TypePathComponent component : ta.targetPath()) {
|
||||
buf.writeU1(component.typePathKind().tag());
|
||||
buf.writeU1(component.typeArgumentIndex());
|
||||
buf.writeU1U1(component.typePathKind().tag(), component.typeArgumentIndex());
|
||||
}
|
||||
|
||||
// annotation data
|
||||
|
@ -24,14 +24,15 @@
|
||||
*/
|
||||
package jdk.internal.classfile.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.lang.classfile.Attribute;
|
||||
import java.lang.classfile.AttributeMapper;
|
||||
|
||||
public class AttributeHolder {
|
||||
private final List<Attribute<?>> attributes = new ArrayList<>();
|
||||
private static final Attribute<?>[] EMPTY_ATTRIBUTE_ARRAY = {};
|
||||
private int attributesCount = 0;
|
||||
private Attribute<?>[] attributes = EMPTY_ATTRIBUTE_ARRAY;
|
||||
|
||||
public <A extends Attribute<A>> void withAttribute(Attribute<?> a) {
|
||||
if (a == null)
|
||||
@ -39,36 +40,54 @@ public class AttributeHolder {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
AttributeMapper<A> am = (AttributeMapper<A>) a.attributeMapper();
|
||||
if (!am.allowMultiple() && isPresent(am)) {
|
||||
remove(am);
|
||||
int attributesCount = this.attributesCount;
|
||||
var attributes = this.attributes;
|
||||
if (!am.allowMultiple()) {
|
||||
// remove if
|
||||
for (int i = attributesCount - 1; i >= 0; i--) {
|
||||
if (attributes[i].attributeMapper() == am) {
|
||||
attributesCount--;
|
||||
System.arraycopy(attributes, i + 1, attributes, i, attributesCount - i);
|
||||
}
|
||||
}
|
||||
}
|
||||
attributes.add(a);
|
||||
|
||||
// add attribute
|
||||
if (attributesCount >= attributes.length) {
|
||||
int newCapacity = attributesCount + 4;
|
||||
this.attributes = attributes = Arrays.copyOf(attributes, newCapacity);
|
||||
}
|
||||
attributes[attributesCount] = a;
|
||||
this.attributesCount = attributesCount + 1;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return attributes.size();
|
||||
return attributesCount;
|
||||
}
|
||||
|
||||
public void writeTo(BufWriterImpl buf) {
|
||||
Util.writeAttributes(buf, attributes);
|
||||
int attributesCount = this.attributesCount;
|
||||
buf.writeU2(attributesCount);
|
||||
for (int i = 0; i < attributesCount; i++) {
|
||||
Util.writeAttribute(buf, attributes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<A extends Attribute<A>> A get(AttributeMapper<A> am) {
|
||||
for (Attribute<?> a : attributes)
|
||||
for (int i = 0; i < attributesCount; i++) {
|
||||
Attribute<?> a = attributes[i];
|
||||
if (a.attributeMapper() == am)
|
||||
return (A)a;
|
||||
return (A) a;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean isPresent(AttributeMapper<?> am) {
|
||||
for (Attribute<?> a : attributes)
|
||||
if (a.attributeMapper() == am)
|
||||
for (int i = 0; i < attributesCount; i++) {
|
||||
if (attributes[i].attributeMapper() == am)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void remove(AttributeMapper<?> am) {
|
||||
attributes.removeIf(a -> a.attributeMapper() == am);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import jdk.internal.access.JavaLangAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
|
||||
import static java.lang.classfile.constantpool.PoolEntry.TAG_UTF8;
|
||||
import static jdk.internal.util.ModifiedUtf.putChar;
|
||||
import static jdk.internal.util.ModifiedUtf.utfLen;
|
||||
|
||||
@ -114,6 +115,83 @@ public final class BufWriterImpl implements BufWriter {
|
||||
this.offset = offset + 2;
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
public void writeU1U1(int x1, int x2) {
|
||||
reserveSpace(2);
|
||||
byte[] elems = this.elems;
|
||||
int offset = this.offset;
|
||||
elems[offset ] = (byte) x1;
|
||||
elems[offset + 1] = (byte) x2;
|
||||
this.offset = offset + 2;
|
||||
}
|
||||
|
||||
public void writeU1U2(int u1, int u2) {
|
||||
reserveSpace(3);
|
||||
byte[] elems = this.elems;
|
||||
int offset = this.offset;
|
||||
elems[offset ] = (byte) u1;
|
||||
elems[offset + 1] = (byte) (u2 >> 8);
|
||||
elems[offset + 2] = (byte) u2;
|
||||
this.offset = offset + 3;
|
||||
}
|
||||
|
||||
public void writeU1U1U1(int x1, int x2, int x3) {
|
||||
reserveSpace(3);
|
||||
byte[] elems = this.elems;
|
||||
int offset = this.offset;
|
||||
elems[offset ] = (byte) x1;
|
||||
elems[offset + 1] = (byte) x2;
|
||||
elems[offset + 2] = (byte) x3;
|
||||
this.offset = offset + 3;
|
||||
}
|
||||
|
||||
public void writeU1U1U2(int x1, int x2, int x3) {
|
||||
reserveSpace(4);
|
||||
byte[] elems = this.elems;
|
||||
int offset = this.offset;
|
||||
elems[offset ] = (byte) x1;
|
||||
elems[offset + 1] = (byte) x2;
|
||||
elems[offset + 2] = (byte) (x3 >> 8);
|
||||
elems[offset + 3] = (byte) x3;
|
||||
this.offset = offset + 4;
|
||||
}
|
||||
|
||||
public void writeU1U2U2(int x1, int x2, int x3) {
|
||||
reserveSpace(5);
|
||||
byte[] elems = this.elems;
|
||||
int offset = this.offset;
|
||||
elems[offset ] = (byte) x1;
|
||||
elems[offset + 1] = (byte) (x2 >> 8);
|
||||
elems[offset + 2] = (byte) x2;
|
||||
elems[offset + 3] = (byte) (x3 >> 8);
|
||||
elems[offset + 4] = (byte) x3;
|
||||
this.offset = offset + 5;
|
||||
}
|
||||
|
||||
public void writeU2U2(int x1, int x2) {
|
||||
reserveSpace(4);
|
||||
byte[] elems = this.elems;
|
||||
int offset = this.offset;
|
||||
elems[offset ] = (byte) (x1 >> 8);
|
||||
elems[offset + 1] = (byte) x1;
|
||||
elems[offset + 2] = (byte) (x2 >> 8);
|
||||
elems[offset + 3] = (byte) x2;
|
||||
this.offset = offset + 4;
|
||||
}
|
||||
|
||||
public void writeU2U2U2(int x1, int x2, int x3) {
|
||||
reserveSpace(6);
|
||||
byte[] elems = this.elems;
|
||||
int offset = this.offset;
|
||||
elems[offset ] = (byte) (x1 >> 8);
|
||||
elems[offset + 1] = (byte) x1;
|
||||
elems[offset + 2] = (byte) (x2 >> 8);
|
||||
elems[offset + 3] = (byte) x2;
|
||||
elems[offset + 4] = (byte) (x3 >> 8);
|
||||
elems[offset + 5] = (byte) x3;
|
||||
this.offset = offset + 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInt(int x) {
|
||||
reserveSpace(4);
|
||||
@ -162,21 +240,22 @@ public final class BufWriterImpl implements BufWriter {
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
void writeUTF(String str) {
|
||||
void writeUtfEntry(String str) {
|
||||
int strlen = str.length();
|
||||
int countNonZeroAscii = JLA.countNonZeroAscii(str);
|
||||
int utflen = utfLen(str, countNonZeroAscii);
|
||||
if (utflen > 65535) {
|
||||
throw new IllegalArgumentException("string too long");
|
||||
}
|
||||
reserveSpace(utflen + 2);
|
||||
reserveSpace(utflen + 3);
|
||||
|
||||
int offset = this.offset;
|
||||
byte[] elems = this.elems;
|
||||
|
||||
elems[offset ] = (byte) (utflen >> 8);
|
||||
elems[offset + 1] = (byte) utflen;
|
||||
offset += 2;
|
||||
elems[offset ] = (byte) TAG_UTF8;
|
||||
elems[offset + 1] = (byte) (utflen >> 8);
|
||||
elems[offset + 2] = (byte) utflen;
|
||||
offset += 3;
|
||||
|
||||
str.getBytes(0, countNonZeroAscii, elems, offset);
|
||||
offset += countNonZeroAscii;
|
||||
@ -269,13 +348,21 @@ public final class BufWriterImpl implements BufWriter {
|
||||
// writeIndex methods ensure that any CP info written
|
||||
// is relative to the correct constant pool
|
||||
|
||||
@ForceInline
|
||||
@Override
|
||||
public void writeIndex(PoolEntry entry) {
|
||||
public int cpIndex(PoolEntry entry) {
|
||||
int idx = AbstractPoolEntry.maybeClone(constantPool, entry).index();
|
||||
if (idx < 1 || idx > Character.MAX_VALUE)
|
||||
throw invalidIndex(idx, entry);
|
||||
writeU2(idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
@Override
|
||||
public void writeIndex(PoolEntry entry) {
|
||||
writeU2(cpIndex(entry));
|
||||
}
|
||||
|
||||
public void writeIndex(int bytecode, PoolEntry entry) {
|
||||
writeU1U2(bytecode, cpIndex(entry));
|
||||
}
|
||||
|
||||
static IllegalArgumentException invalidIndex(int idx, PoolEntry entry) {
|
||||
|
@ -264,6 +264,11 @@ public class BytecodeHelpers {
|
||||
};
|
||||
}
|
||||
|
||||
public static int returnBytecode(TypeKind tk) {
|
||||
int kind = Math.max(0, tk.ordinal() - 4); // BYTE, SHORT, CHAR, BOOLEAN becomes INT
|
||||
return IRETURN + kind;
|
||||
}
|
||||
|
||||
public static Opcode arrayLoadOpcode(TypeKind tk) {
|
||||
return switch (tk) {
|
||||
case BYTE, BOOLEAN -> Opcode.BALOAD;
|
||||
@ -278,6 +283,20 @@ public class BytecodeHelpers {
|
||||
};
|
||||
}
|
||||
|
||||
public static int arrayLoadBytecode(TypeKind tk) {
|
||||
return switch (tk) {
|
||||
case BYTE, BOOLEAN -> BALOAD;
|
||||
case SHORT -> SALOAD;
|
||||
case INT -> IALOAD;
|
||||
case FLOAT -> FALOAD;
|
||||
case LONG -> LALOAD;
|
||||
case DOUBLE -> DALOAD;
|
||||
case REFERENCE -> AALOAD;
|
||||
case CHAR -> CALOAD;
|
||||
case VOID -> throw new IllegalArgumentException("void not an allowable array type");
|
||||
};
|
||||
}
|
||||
|
||||
public static Opcode arrayStoreOpcode(TypeKind tk) {
|
||||
return switch (tk) {
|
||||
case BYTE, BOOLEAN -> Opcode.BASTORE;
|
||||
@ -292,6 +311,20 @@ public class BytecodeHelpers {
|
||||
};
|
||||
}
|
||||
|
||||
public static int arrayStoreBytecode(TypeKind tk) {
|
||||
return switch (tk) {
|
||||
case BYTE, BOOLEAN -> BASTORE;
|
||||
case SHORT -> SASTORE;
|
||||
case INT -> IASTORE;
|
||||
case FLOAT -> FASTORE;
|
||||
case LONG -> LASTORE;
|
||||
case DOUBLE -> DASTORE;
|
||||
case REFERENCE -> AASTORE;
|
||||
case CHAR -> CASTORE;
|
||||
case VOID -> throw new IllegalArgumentException("void not an allowable array type");
|
||||
};
|
||||
}
|
||||
|
||||
public static Opcode reverseBranchOpcode(Opcode op) {
|
||||
return switch (op) {
|
||||
case IFEQ -> Opcode.IFNE;
|
||||
@ -314,6 +347,29 @@ public class BytecodeHelpers {
|
||||
};
|
||||
}
|
||||
|
||||
public static int reverseBranchOpcode(int bytecode) {
|
||||
return switch (bytecode) {
|
||||
case IFEQ -> IFNE;
|
||||
case IFNE -> IFEQ;
|
||||
case IFLT -> IFGE;
|
||||
case IFGE -> IFLT;
|
||||
case IFGT -> IFLE;
|
||||
case IFLE -> IFGT;
|
||||
case IF_ICMPEQ -> IF_ICMPNE;
|
||||
case IF_ICMPNE -> IF_ICMPEQ;
|
||||
case IF_ICMPLT -> IF_ICMPGE;
|
||||
case IF_ICMPGE -> IF_ICMPLT;
|
||||
case IF_ICMPGT -> IF_ICMPLE;
|
||||
case IF_ICMPLE -> IF_ICMPGT;
|
||||
case IF_ACMPEQ -> IF_ACMPNE;
|
||||
case IF_ACMPNE -> IF_ACMPEQ;
|
||||
case IFNULL -> IFNONNULL;
|
||||
case IFNONNULL -> IFNULL;
|
||||
default -> throw new IllegalArgumentException(
|
||||
String.format("Wrong opcode kind specified; found %d, expected %s", bytecode, Opcode.Kind.BRANCH));
|
||||
};
|
||||
}
|
||||
|
||||
public static Opcode convertOpcode(TypeKind from, TypeKind to) {
|
||||
return switch (from) {
|
||||
case INT ->
|
||||
|
@ -353,7 +353,11 @@ public final class ClassReaderImpl
|
||||
|
||||
static <T extends PoolEntry> T checkType(PoolEntry e, int index, Class<T> cls) {
|
||||
if (cls.isInstance(e)) return cls.cast(e);
|
||||
throw new ConstantPoolException("Not a " + cls.getSimpleName() + " at index: " + index);
|
||||
throw checkTypeError(index, cls);
|
||||
}
|
||||
|
||||
private static ConstantPoolException checkTypeError(int index, Class<?> cls) {
|
||||
return new ConstantPoolException("Not a " + cls.getSimpleName() + " at index: " + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,6 +31,7 @@ import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
@ -54,9 +56,13 @@ public final class DirectClassBuilder
|
||||
|
||||
/** The value of default class access flags */
|
||||
static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC;
|
||||
static final Util.Writable[] EMPTY_WRITABLE_ARRAY = {};
|
||||
static final ClassEntry[] EMPTY_CLASS_ENTRY_ARRAY = {};
|
||||
final ClassEntry thisClassEntry;
|
||||
private final List<Util.Writable> fields = new ArrayList<>();
|
||||
private final List<Util.Writable> methods = new ArrayList<>();
|
||||
private Util.Writable[] fields = EMPTY_WRITABLE_ARRAY;
|
||||
private Util.Writable[] methods = EMPTY_WRITABLE_ARRAY;
|
||||
private int fieldsCount = 0;
|
||||
private int methodsCount = 0;
|
||||
private ClassEntry superclassEntry;
|
||||
private List<ClassEntry> interfaceEntries;
|
||||
private int majorVersion;
|
||||
@ -137,12 +143,20 @@ public final class DirectClassBuilder
|
||||
// internal / for use by elements
|
||||
|
||||
ClassBuilder withField(Util.Writable field) {
|
||||
fields.add(field);
|
||||
if (fieldsCount >= fields.length) {
|
||||
int newCapacity = fieldsCount + 8;
|
||||
this.fields = Arrays.copyOf(fields, newCapacity);
|
||||
}
|
||||
fields[fieldsCount++] = field;
|
||||
return this;
|
||||
}
|
||||
|
||||
ClassBuilder withMethod(Util.Writable method) {
|
||||
methods.add(method);
|
||||
if (methodsCount >= methods.length) {
|
||||
int newCapacity = methodsCount + 8;
|
||||
this.methods = Arrays.copyOf(methods, newCapacity);
|
||||
}
|
||||
methods[methodsCount++] = method;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -184,9 +198,7 @@ public final class DirectClassBuilder
|
||||
else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisClassEntry.asInternalName()))
|
||||
superclass = constantPool.classEntry(ConstantDescs.CD_Object);
|
||||
int interfaceEntriesSize = interfaceEntries.size();
|
||||
List<ClassEntry> ies = new ArrayList<>(interfaceEntriesSize);
|
||||
for (int i = 0; i < interfaceEntriesSize; i++)
|
||||
ies.add(AbstractPoolEntry.maybeClone(constantPool, interfaceEntries.get(i)));
|
||||
ClassEntry[] ies = interfaceEntriesSize == 0 ? EMPTY_CLASS_ENTRY_ARRAY : buildInterfaceEnties(interfaceEntriesSize);
|
||||
|
||||
// We maintain two writers, and then we join them at the end
|
||||
int size = sizeHint == 0 ? 256 : sizeHint;
|
||||
@ -195,8 +207,8 @@ public final class DirectClassBuilder
|
||||
|
||||
// The tail consists of fields and methods, and attributes
|
||||
// This should trigger all the CP/BSM mutation
|
||||
Util.writeList(tail, fields);
|
||||
Util.writeList(tail, methods);
|
||||
Util.writeList(tail, fields, fieldsCount);
|
||||
Util.writeList(tail, methods, methodsCount);
|
||||
int attributesOffset = tail.size();
|
||||
attributes.writeTo(tail);
|
||||
|
||||
@ -211,12 +223,21 @@ public final class DirectClassBuilder
|
||||
| ((minorVersion & 0xFFFFL) << 16)
|
||||
| (majorVersion & 0xFFFFL));
|
||||
constantPool.writeTo(head);
|
||||
head.writeU2(flags);
|
||||
head.writeIndex(thisClassEntry);
|
||||
head.writeU2U2(flags, head.cpIndex(thisClassEntry));
|
||||
head.writeIndexOrZero(superclass);
|
||||
Util.writeListIndices(head, ies);
|
||||
head.writeU2(interfaceEntriesSize);
|
||||
for (int i = 0; i < interfaceEntriesSize; i++) {
|
||||
head.writeIndex(ies[i]);
|
||||
}
|
||||
|
||||
// Join head and tail into an exact-size buffer
|
||||
return BufWriterImpl.join(head, tail);
|
||||
}
|
||||
|
||||
private ClassEntry[] buildInterfaceEnties(int interfaceEntriesSize) {
|
||||
var ies = new ClassEntry[interfaceEntriesSize];
|
||||
for (int i = 0; i < interfaceEntriesSize; i++)
|
||||
ies[i] = AbstractPoolEntry.maybeClone(constantPool, interfaceEntries.get(i));
|
||||
return ies;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -148,9 +148,7 @@ public final class DirectMethodBuilder
|
||||
|
||||
@Override
|
||||
public void writeTo(BufWriterImpl buf) {
|
||||
buf.writeU2(flags);
|
||||
buf.writeIndex(name);
|
||||
buf.writeIndex(desc);
|
||||
buf.writeU2U2U2(flags, buf.cpIndex(name), buf.cpIndex(desc));
|
||||
attributes.writeTo(buf);
|
||||
}
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ public final class EntryMap {
|
||||
throw new IllegalArgumentException("hash must be nonzero");
|
||||
|
||||
int ptr = (hash & mask1) << 1;
|
||||
var data = this.data;
|
||||
int k = data[ptr];
|
||||
if (k == 0) {
|
||||
data[ptr] = hash;
|
||||
|
@ -24,8 +24,6 @@
|
||||
*/
|
||||
package jdk.internal.classfile.impl;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import java.lang.classfile.Label;
|
||||
import java.lang.classfile.instruction.LabelTarget;
|
||||
|
||||
@ -52,7 +50,7 @@ public final class LabelImpl
|
||||
private int bci;
|
||||
|
||||
public LabelImpl(LabelContext labelContext, int bci) {
|
||||
this.labelContext = Objects.requireNonNull(labelContext);
|
||||
this.labelContext = labelContext;
|
||||
this.bci = bci;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,6 @@ import java.lang.classfile.ClassReader;
|
||||
import java.lang.classfile.BootstrapMethodEntry;
|
||||
import java.lang.classfile.attribute.BootstrapMethodsAttribute;
|
||||
import java.lang.classfile.constantpool.*;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.constant.ConstantUtils;
|
||||
|
||||
@ -87,20 +86,27 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
|
||||
@Override
|
||||
public PoolEntry entryByIndex(int index) {
|
||||
if (index <= 0 || index >= size()) {
|
||||
throw new ConstantPoolException("Bad CP index: " + index);
|
||||
throw badCP(index);
|
||||
}
|
||||
PoolEntry pe = (index < parentSize)
|
||||
? parent.entryByIndex(index)
|
||||
: myEntries[index - parentSize];
|
||||
if (pe == null) {
|
||||
throw new ConstantPoolException("Unusable CP index: " + index);
|
||||
throw unusableCP(index);
|
||||
}
|
||||
return pe;
|
||||
}
|
||||
|
||||
private static ConstantPoolException badCP(int index) {
|
||||
return new ConstantPoolException("Bad CP index: " + index);
|
||||
}
|
||||
|
||||
private static ConstantPoolException unusableCP(int index) {
|
||||
return new ConstantPoolException("Unusable CP index: " + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends PoolEntry> T entryByIndex(int index, Class<T> cls) {
|
||||
Objects.requireNonNull(cls);
|
||||
return ClassReaderImpl.checkType(entryByIndex(index), index, cls);
|
||||
}
|
||||
|
||||
@ -165,8 +171,10 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
|
||||
}
|
||||
|
||||
private EntryMap map() {
|
||||
int parentSize = this.parentSize;
|
||||
var map = this.map;
|
||||
if (map == null) {
|
||||
map = new EntryMap(Math.max(size, 1024), .75f);
|
||||
this.map = map = new EntryMap(Math.max(size, 1024), .75f);
|
||||
|
||||
// Doing a full scan here yields fall-off-the-cliff performance results,
|
||||
// especially if we only need a few entries that are already
|
||||
@ -203,8 +211,10 @@ public final class SplitConstantPool implements ConstantPoolBuilder {
|
||||
}
|
||||
|
||||
private EntryMap bsmMap() {
|
||||
int bsmSize = this.bsmSize;
|
||||
var bsmMap = this.bsmMap;
|
||||
if (bsmMap == null) {
|
||||
bsmMap = new EntryMap(Math.max(bsmSize, 16), .75f);
|
||||
this.bsmMap = bsmMap = new EntryMap(Math.max(bsmSize, 16), .75f);
|
||||
for (int i=0; i<parentBsmSize; i++) {
|
||||
BootstrapMethodEntryImpl bsm = parent.bootstrapMethodEntry(i);
|
||||
bsmMap.put(bsm.hash, bsm.index);
|
||||
|
@ -48,7 +48,7 @@ public class StackMapDecoder {
|
||||
private static final int
|
||||
SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247,
|
||||
SAME_EXTENDED = 251;
|
||||
private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = new StackMapFrameInfo[0];
|
||||
private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {};
|
||||
|
||||
private final ClassReader classReader;
|
||||
private final int pos;
|
||||
|
@ -163,7 +163,7 @@ public final class StackMapGenerator {
|
||||
private static final int FLAG_THIS_UNINIT = 0x01;
|
||||
private static final int FRAME_DEFAULT_CAPACITY = 10;
|
||||
private static final int T_BOOLEAN = 4, T_LONG = 11;
|
||||
private static final Frame[] EMPTY_FRAME_ARRAY = new Frame[0];
|
||||
private static final Frame[] EMPTY_FRAME_ARRAY = {};
|
||||
|
||||
private static final int ITEM_TOP = 0,
|
||||
ITEM_INTEGER = 1,
|
||||
@ -1219,7 +1219,9 @@ public final class StackMapGenerator {
|
||||
return Arrays.equals(l1, 0, commonSize, l2, 0, commonSize);
|
||||
}
|
||||
|
||||
void writeTo(BufWriter out, Frame prevFrame, ConstantPoolBuilder cp) {
|
||||
void writeTo(BufWriterImpl out, Frame prevFrame, ConstantPoolBuilder cp) {
|
||||
int localsSize = this.localsSize;
|
||||
int stackSize = this.stackSize;
|
||||
int offsetDelta = offset - prevFrame.offset - 1;
|
||||
if (stackSize == 0) {
|
||||
int commonLocalsSize = localsSize > prevFrame.localsSize ? prevFrame.localsSize : localsSize;
|
||||
@ -1228,8 +1230,7 @@ public final class StackMapGenerator {
|
||||
if (diffLocalsSize == 0 && offsetDelta < 64) { //same frame
|
||||
out.writeU1(offsetDelta);
|
||||
} else { //chop, same extended or append frame
|
||||
out.writeU1(251 + diffLocalsSize);
|
||||
out.writeU2(offsetDelta);
|
||||
out.writeU1U2(251 + diffLocalsSize, offsetDelta);
|
||||
for (int i=commonLocalsSize; i<localsSize; i++) locals[i].writeTo(out, cp);
|
||||
}
|
||||
return;
|
||||
@ -1238,15 +1239,13 @@ public final class StackMapGenerator {
|
||||
if (offsetDelta < 64) { //same locals 1 stack item frame
|
||||
out.writeU1(64 + offsetDelta);
|
||||
} else { //same locals 1 stack item extended frame
|
||||
out.writeU1(247);
|
||||
out.writeU2(offsetDelta);
|
||||
out.writeU1U2(247, offsetDelta);
|
||||
}
|
||||
stack[0].writeTo(out, cp);
|
||||
return;
|
||||
}
|
||||
//full frame
|
||||
out.writeU1(255);
|
||||
out.writeU2(offsetDelta);
|
||||
out.writeU1U2(255, offsetDelta);
|
||||
out.writeU2(localsSize);
|
||||
for (int i=0; i<localsSize; i++) locals[i].writeTo(out, cp);
|
||||
out.writeU2(stackSize);
|
||||
|
@ -232,7 +232,7 @@ public class Util {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends Attribute<T>> void writeAttribute(BufWriterImpl writer, Attribute<?> attr) {
|
||||
public static <T extends Attribute<T>> void writeAttribute(BufWriterImpl writer, Attribute<?> attr) {
|
||||
if (attr instanceof CustomAttribute<?> ca) {
|
||||
var mapper = (AttributeMapper<T>) ca.attributeMapper();
|
||||
mapper.writeAttribute(writer, (T) ca);
|
||||
@ -252,11 +252,10 @@ public class Util {
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static void writeList(BufWriterImpl buf, List<Writable> list) {
|
||||
int size = list.size();
|
||||
static void writeList(BufWriterImpl buf, Writable[] array, int size) {
|
||||
buf.writeU2(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.get(i).writeTo(buf);
|
||||
array[i].writeTo(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,6 +400,7 @@ public class Util {
|
||||
0x54fbc001, 0xb9f78001, 0x2ef34001, 0xb3ef0001, 0x48eac001, 0xede68001, 0xa2e24001,
|
||||
0x67de0001, 0xcfbc0001, 0x379a0001, 0x9f780001, 0x07560001, 0x6f340001, 0xd7120001,
|
||||
0x3ef00001, 0x7de00001, 0xbcd00001, 0xfbc00001, 0x3ab00001, 0x79a00001, 0xb8900001,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static int powersIndex(int digit, int index) {
|
||||
@ -411,6 +411,6 @@ public class Util {
|
||||
// digit: 0 - 7
|
||||
// index: 0 - SIGNIFICANT_OCTAL_DIGITS - 1
|
||||
private static int powerOctal(int digit, int index) {
|
||||
return digit == 0 ? 1 : powers[powersIndex(digit, index)];
|
||||
return digit == 0 ? 1 : powers[powersIndex(digit, index) & 0x3F]; // & 0x3F eliminates bound check
|
||||
}
|
||||
}
|
||||
|
@ -287,15 +287,31 @@ public final class MethodTypeDescImpl implements MethodTypeDesc {
|
||||
if (desc != null)
|
||||
return desc;
|
||||
|
||||
int len = 2 + returnType.descriptorString().length();
|
||||
for (ClassDesc argType : argTypes) {
|
||||
len += argType.descriptorString().length();
|
||||
return buildDescriptorString();
|
||||
}
|
||||
|
||||
private String buildDescriptorString() {
|
||||
var returnType = this.returnType;
|
||||
var returnTypeDesc = returnType.descriptorString();
|
||||
var argTypes = this.argTypes;
|
||||
String desc;
|
||||
if (argTypes.length == 0) {
|
||||
// getter
|
||||
desc = "()".concat(returnTypeDesc);
|
||||
} else if (argTypes.length == 1 && returnType == ConstantDescs.CD_void) {
|
||||
// setter
|
||||
desc = ConstantUtils.concat("(", argTypes[0].descriptorString(), ")V");
|
||||
} else {
|
||||
int len = 2 + returnTypeDesc.length();
|
||||
for (ClassDesc argType : argTypes) {
|
||||
len += argType.descriptorString().length();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(len).append('(');
|
||||
for (ClassDesc argType : argTypes) {
|
||||
sb.append(argType.descriptorString());
|
||||
}
|
||||
desc = sb.append(')').append(returnTypeDesc).toString();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(len).append('(');
|
||||
for (ClassDesc argType : argTypes) {
|
||||
sb.append(argType.descriptorString());
|
||||
}
|
||||
desc = sb.append(')').append(returnType.descriptorString()).toString();
|
||||
cachedDescriptorString = desc;
|
||||
return desc;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ class UtilTest {
|
||||
// Ensures the initialization statement of the powers array is filling in the right values
|
||||
@Test
|
||||
void testPowersArray() {
|
||||
int[] powers = new int[7 * UtilAccess.significantOctalDigits()];
|
||||
int[] powers = new int[64];
|
||||
for (int i = 1, k = 31; i <= 7; i++, k *= 31) {
|
||||
int t = powers[UtilAccess.powersIndex(i, 0)] = k;
|
||||
|
||||
|
@ -141,9 +141,9 @@ public class Write {
|
||||
cb.withVersion(52, 0);
|
||||
cb.with(SourceFileAttribute.of(cb.constantPool().utf8Entry(("MyClass.java"))))
|
||||
.withMethod(INIT_NAME, MTD_void, 0, mb -> mb
|
||||
.withCode(codeb -> codeb.loadLocal(REFERENCE, 0)
|
||||
.invoke(INVOKESPECIAL, CD_Object, INIT_NAME, MTD_void, false)
|
||||
.return_(VOID)
|
||||
.withCode(codeb -> codeb.aload(0)
|
||||
.invokespecial(CD_Object, INIT_NAME, MTD_void)
|
||||
.return_()
|
||||
)
|
||||
);
|
||||
for (int xi = 0; xi < 40; ++xi) {
|
||||
@ -180,54 +180,6 @@ public class Write {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
public byte[] jdkTreePrimitive() {
|
||||
|
||||
byte[] bytes = ClassFile.of().build(CD_MyClass, cb -> {
|
||||
cb.withFlags(AccessFlag.PUBLIC);
|
||||
cb.withVersion(52, 0);
|
||||
cb.with(SourceFileAttribute.of(cb.constantPool().utf8Entry(("MyClass.java"))))
|
||||
.withMethod(INIT_NAME, MTD_void, 0,
|
||||
mb -> mb.withCode(codeb -> codeb.loadLocal(REFERENCE, 0)
|
||||
.invokespecial(CD_Object, INIT_NAME, MTD_void, false)
|
||||
.return_()
|
||||
)
|
||||
);
|
||||
for (int xi = 0; xi < 40; ++xi) {
|
||||
cb.withMethod("main" + ((xi == 0) ? "" : "" + xi), MTD_void_StringArray,
|
||||
ACC_PUBLIC | ACC_STATIC,
|
||||
mb -> mb.withCode(c0 -> {
|
||||
java.lang.classfile.Label loopTop = c0.newLabel();
|
||||
java.lang.classfile.Label loopEnd = c0.newLabel();
|
||||
int vFac = 1;
|
||||
int vI = 2;
|
||||
c0.iconst_1() // 0
|
||||
.istore(1) // 1
|
||||
.iconst_1() // 2
|
||||
.istore(2) // 3
|
||||
.labelBinding(loopTop)
|
||||
.iload(2) // 4
|
||||
.bipush(10) // 5
|
||||
.if_icmpge(loopEnd) // 6
|
||||
.iload(1) // 7
|
||||
.iload(2) // 8
|
||||
.imul() // 9
|
||||
.istore(1) // 10
|
||||
.iinc(2, 1) // 11
|
||||
.goto_(loopTop) // 12
|
||||
.labelBinding(loopEnd)
|
||||
.getstatic(CD_System, "out", CD_PrintStream) // 13
|
||||
.iload(1)
|
||||
.invokevirtual(CD_PrintStream, "println", MTD_void_int) // 15
|
||||
.return_();
|
||||
}));
|
||||
}
|
||||
});
|
||||
if (writeClassBc) writeClass(bytes, checkFileBc);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private void writeClass(byte[] bytes, String fn) {
|
||||
try {
|
||||
FileOutputStream out = new FileOutputStream(fn);
|
||||
|
Loading…
Reference in New Issue
Block a user