Path: blob/master/sourcetools/j9constantpool/com/ibm/oti/VMCPTool/ConstantPoolStream.java
6004 views
/*******************************************************************************1* Copyright (c) 2004, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/21package com.ibm.oti.VMCPTool;2223import java.io.PrintWriter;24import java.nio.charset.StandardCharsets;25import java.util.ArrayList;26import java.util.Collections;27import java.util.HashMap;28import java.util.Iterator;29import java.util.List;30import java.util.Map;31import java.util.Set;3233// The ConstantPoolStream class is a little ugly because it captures and writes state in 2 passes.34// The two passes should consist of exactly the same sequence of calls to write*(). The first pass35// captures offsets that may be "forward references". The second pass then provides correct offsets36// of ConstantPoolItems from getOffset(ConstantPoolItem).37//38// The size of the constant pool is captured from the offset when open() is called. The offset is39// then reset to 0. Buffers are flushed and the output stream is attached.40//41// Thus a correct call sequence would be something like:42// ConstantPoolStream s = new ConstantPoolStream("jcl", constantPool, itemCount);43// /* First sequence of s.writeByte() and friends */44// s.open(out);45// /* Second sequence of s.writeByte() and friends */46// s.close();4748@SuppressWarnings("nls")49public class ConstantPoolStream {50public final int version;51public final Set<String> flags;52private final List<byte[]> outputQueue = new ArrayList<>();53private ConstantPool constantPool;54private int[] cpDescription;55private PrintWriter out;56private int offset;57private int itemCount;58private boolean even = true;5960// These constants are taken from j9.h61private static final int J9CPTYPE_UNUSED = 0;62private static final int J9CPTYPE_CLASS = 1;63private static final int J9CPTYPE_INSTANCE_FIELD = 7;64private static final int J9CPTYPE_STATIC_FIELD = 8;65private static final int J9CPTYPE_VIRTUAL_METHOD = 9;66private static final int J9CPTYPE_STATIC_METHOD = 10;67private static final int J9CPTYPE_SPECIAL_METHOD = 11;68private static final int J9CPTYPE_INTERFACE_METHOD = 12;69private static final int J9_CP_BITS_PER_DESCRIPTION = 8;70private static final int J9_CP_DESCRIPTION_MASK = 0xff;71private static final int J9_CP_DESCRIPTIONS_PER_U32 = 4;7273public static final int ITEM_SIZE = 8; // Bytes per Constant Pool Item7475public ConstantPoolStream(int version, Set<String> flags, ConstantPool constantPool, int itemCount) {76this.version = version;77this.flags = Collections.unmodifiableSet(flags);78this.constantPool = constantPool;79this.itemCount = itemCount;80this.cpDescription = new int[(itemCount + J9_CP_DESCRIPTIONS_PER_U32 - 1) / J9_CP_DESCRIPTIONS_PER_U32];8182// Initialize constant pool descriptors83for (int i = 0; i < itemCount; i++) {84mark(i, J9CPTYPE_UNUSED);85}86}8788private void mark(int cpIndex, int type) {89int index = cpIndex / J9_CP_DESCRIPTIONS_PER_U32;90int shift = (cpIndex % J9_CP_DESCRIPTIONS_PER_U32) * J9_CP_BITS_PER_DESCRIPTION;91cpDescription[index] |= (type & J9_CP_DESCRIPTION_MASK) << shift;92}9394private void mark(int type) {95if (0 != offset % ITEM_SIZE) {96throw new Error("Constant Pool offset is not Item-aligned");97}9899mark(offset / ITEM_SIZE, type);100}101102public void markInstanceField() {103mark(J9CPTYPE_INSTANCE_FIELD);104}105106public void markStaticField() {107mark(J9CPTYPE_STATIC_FIELD);108}109110public void markStaticMethod() {111mark(J9CPTYPE_STATIC_METHOD);112}113114public void markVirtualMethod() {115mark(J9CPTYPE_VIRTUAL_METHOD);116}117118public void markSpecialMethod() {119mark(J9CPTYPE_SPECIAL_METHOD);120}121122public void markInterfaceMethod() {123mark(J9CPTYPE_INTERFACE_METHOD);124}125126public void markClass() {127mark(J9CPTYPE_CLASS);128}129130public void writeBoolean(boolean arg0) {131writeByte(arg0 ? 1 : 0);132}133134public void writeByte(int arg0) {135write(new byte[] { (byte) arg0 });136}137138public void writeBytes(String arg0) {139throw new UnsupportedOperationException("writeBytes not supported");140}141142public void writeChar(int arg0) {143writeShort((short) arg0);144}145146public void writeChars(String arg0) {147throw new UnsupportedOperationException("writeChars not supported");148}149150public void writeDouble(double arg0) {151writeLong(Double.doubleToLongBits(arg0));152}153154public void writeFloat(float arg0) {155writeInt(Float.floatToIntBits(arg0));156}157158public void writeInt(int arg0) {159write(new byte[] { (byte) (arg0 >> 24), (byte) (arg0 >> 16), (byte) (arg0 >> 8), (byte) arg0 });160}161162public void writeLong(long arg0) {163write(new byte[] {164(byte) (arg0 >> 56), (byte) (arg0 >> 48), (byte) (arg0 >> 40), (byte) (arg0 >> 32),165(byte) (arg0 >> 24), (byte) (arg0 >> 16), (byte) (arg0 >> 8), (byte) arg0 });166}167168public void writeShort(int arg0) {169write(new byte[] { (byte) (arg0 >> 8), (byte) arg0 });170}171172public void writeUTF(String arg0) {173byte[] data = arg0.getBytes(StandardCharsets.UTF_8);174for (int i = 0; i < data.length; i++) {175writeByte(data[i]);176}177}178179/**180* Add the specified bytes to the constant pool.181* The bytes must be in big endian order. They will182* be reversed on little endian platforms.183*/184protected void write(byte[] data) {185if (null != out) {186outputQueue.add(data);187if (data.length == 4) {188flushQueue();189}190}191192offset += data.length;193}194195public int getOffset() {196return offset;197}198199public void alignTo(int alignment) {200while ((getOffset() % alignment) != 0) {201writeByte(0);202}203}204205private void flushQueue() {206for (Iterator<byte[]> iter = outputQueue.iterator(); iter.hasNext();) {207if (even) {208out.print("\t\t{");209}210211byte[] r0 = iter.next();212if (r0.length == 4) {213out.print(hex(r0));214} else {215byte[] r1 = iter.next();216if (r0.length == 2 && r1.length == 2) {217out.print("WORD_WORD(" + hex(r0) + ", " + hex(r1) + ")");218} else {219byte[] r2 = iter.next();220if (r0.length == 2 && r1.length == 1 && r2.length == 1) {221out.print("WORD_BYTE_BYTE(" + hex(r0) + ", " + hex(r1) + ", " + hex(r2) + ")");222} else if (r0.length == 1 && r1.length == 1 && r2.length == 2) {223out.print("BYTE_BYTE_WORD(" + hex(r0) + ", " + hex(r1) + ", " + hex(r2) + ")");224} else {225byte[] r3 = iter.next();226if (r0.length == 1 && r1.length == 1 && r2.length == 1 && r3.length == 1) {227out.print("BYTE_BYTE_BYTE_BYTE(" + hex(r0) + ", " + hex(r1) + ", " + hex(r2) + ", " + hex(r3) + ")");228} else {229throw new Error();230}231}232}233}234235if (even) {236out.print(", ");237} else {238out.println("},");239}240even = !even;241}242outputQueue.clear();243}244245private static final String HEX = "0123456789ABCDEF";246247private static String hex(byte[] array) {248StringBuilder buffer = new StringBuilder(array.length * 2 + 2);249250buffer.append("0x");251252for (int i = 0; i < array.length; i++) {253buffer.append(HEX.charAt((array[i] >> 4) & 0x0F));254buffer.append(HEX.charAt((array[i] >> 0) & 0x0F));255}256257return buffer.toString();258}259260private final Map<ConstantPoolItem, Offset> secondaryItems = new HashMap<>();261262private class Offset {263final int offset;264final boolean wrote;265266Offset(int offset, boolean wrote) {267this.offset = offset;268this.wrote = wrote;269}270}271272public void writeSecondaryItem(ConstantPoolItem item) {273// We "write" the secondary item if it hasn't been previously seen or written.274// The secondary item can only have been written if there is an output stream.275Offset offset = secondaryItems.get(item);276if (null == offset || (null != out && !offset.wrote)) {277item.write(this);278}279}280281public void setOffset(ConstantPoolItem item) {282Offset offset = secondaryItems.get(item);283if (null != offset && getOffset() != offset.offset) {284throw new Error("Mismatched offset in secondary item");285}286secondaryItems.put(item, new Offset(getOffset(), null != out));287}288289public int getOffset(ConstantPoolItem item) {290Offset offset = secondaryItems.get(item);291return null == offset ? -1 : offset.offset;292}293294public void open(PrintWriter out) {295int size = offset;296offset = 0;297outputQueue.clear();298this.out = out;299writeHeader(size);300}301302public void close() {303flushQueue();304writeFooter();305}306307private void writeFooter() {308out.println("\t},");309writeUnsplitDescription();310out.println("};");311out.println();312out.println("const J9ROMClass * jclROMClass = &_jclROMClass.romClass;");313}314315private void writeHeader(int size) {316if (null != out) {317if (0 == size || 0 != size % ConstantPoolStream.ITEM_SIZE) {318throw new Error("Constant Pool size is not Item-aligned");319}320321int totalCPSize = size / ConstantPoolStream.ITEM_SIZE;322323out.println("static const struct {");324out.println("\tJ9ROMClass romClass;");325out.println("\tJ9ROMConstantPoolItem romConstantPool[" + totalCPSize + "];");326out.println("\tU_32 cpDescription[" + cpDescription.length + "];");327out.println("} _jclROMClass = {");328329String shapeDescriptionOffset = "sizeof(J9ROMClass) - offsetof(J9ROMClass, cpShapeDescription) + " + size;330out.println("\t{0,0,0,0,0,J9AccClassUnsafe, 0,0,0,0,0,0,0,0, " + itemCount + ", " + itemCount + ", 0,0,0, " + shapeDescriptionOffset + ", 0,},");331out.println("\t{");332}333}334335private void writeUnsplitDescription() {336final int J9CPTYPE_FIELD = 7;337final int J9CPTYPE_INSTANCE_METHOD = 9;338339out.print("\t{");340for (int i = 0; i < cpDescription.length; i++) {341int descriptionWord = cpDescription[i];342for (int j = 0; j < J9_CP_DESCRIPTIONS_PER_U32; j++) {343int shift = j * J9_CP_BITS_PER_DESCRIPTION;344int oldNibble = (descriptionWord >>> shift) & J9_CP_DESCRIPTION_MASK;345int newNibble = oldNibble;346if ((J9CPTYPE_INSTANCE_FIELD == oldNibble) || (J9CPTYPE_STATIC_FIELD == oldNibble)) {347newNibble = J9CPTYPE_FIELD;348} else if ((J9CPTYPE_VIRTUAL_METHOD == oldNibble) || (J9CPTYPE_SPECIAL_METHOD == oldNibble)) {349newNibble = J9CPTYPE_INSTANCE_METHOD;350}351if (newNibble != oldNibble) {352descriptionWord &= ~(J9_CP_DESCRIPTION_MASK << shift);353descriptionWord |= (newNibble & J9_CP_DESCRIPTION_MASK) << shift;354}355}356out.print("0x" + Integer.toHexString(descriptionWord) + ", ");357}358out.println("}");359}360361public int getIndex(PrimaryItem item) {362return constantPool.getIndex(item);363}364365public PrimaryItem findPrimaryItem(Object obj) {366return constantPool.findPrimaryItem(obj);367}368369public void comment(String string) {370if (null != out) {371out.print("\t/* " + string + " */");372}373}374375}376377378