1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file 2 // for details. All rights reserved. Use of this source code is governed by a 3 // BSD-style license that can be found in the LICENSE file. 4 package com.android.tools.r8.dex; 5 6 import com.android.tools.r8.code.Instruction; 7 import com.android.tools.r8.graph.ObjectToOffsetMapping; 8 import com.android.tools.r8.utils.EncodedValueUtils; 9 import com.android.tools.r8.utils.LebUtils; 10 import java.nio.ByteBuffer; 11 import java.nio.ByteOrder; 12 import java.nio.ShortBuffer; 13 14 /** 15 * Provides an abstraction around a {@link ByteBuffer} with write operations for 16 * additional DEX specific formats, like Leb128. 17 */ 18 public class DexOutputBuffer { 19 private static final int DEFAULT_BUFFER_SIZE = 256 * 1024; 20 21 private ByteBuffer byteBuffer; 22 DexOutputBuffer()23 public DexOutputBuffer() { 24 byteBuffer = allocate(DEFAULT_BUFFER_SIZE); 25 } 26 ensureSpaceFor(int bytes)27 private void ensureSpaceFor(int bytes) { 28 if (byteBuffer.remaining() < bytes) { 29 int newSize = byteBuffer.capacity() + Math.max(byteBuffer.capacity(), bytes * 2); 30 ByteBuffer newBuffer = allocate(newSize); 31 System.arraycopy(byteBuffer.array(), 0, newBuffer.array(), 0, byteBuffer.position()); 32 newBuffer.position(byteBuffer.position()); 33 byteBuffer = newBuffer; 34 } 35 } 36 allocate(int size)37 private ByteBuffer allocate(int size) { 38 ByteBuffer buffer = ByteBuffer.allocate(size); 39 buffer.order(ByteOrder.LITTLE_ENDIAN); 40 return buffer; 41 } 42 putUleb128(int value)43 public void putUleb128(int value) { 44 LebUtils.putUleb128(this, value); 45 } 46 putSleb128(int value)47 public void putSleb128(int value) { 48 LebUtils.putSleb128(this, value); 49 } 50 putSignedEncodedValue(long value, int expectedSize)51 public int putSignedEncodedValue(long value, int expectedSize) { 52 return EncodedValueUtils.putSigned(this, value, expectedSize); 53 } 54 putUnsignedEncodedValue(long value, int expectedSize)55 public int putUnsignedEncodedValue(long value, int expectedSize) { 56 return EncodedValueUtils.putUnsigned(this, value, expectedSize); 57 } 58 putInstructions(Instruction[] insns, ObjectToOffsetMapping mapping)59 public void putInstructions(Instruction[] insns, ObjectToOffsetMapping mapping) { 60 int size = 0; 61 for (Instruction insn : insns) { 62 size += insn.getSize(); 63 } 64 ensureSpaceFor(size * Short.BYTES); 65 assert byteBuffer.position() % 2 == 0; 66 ShortBuffer shortBuffer = byteBuffer.asShortBuffer(); 67 for (int i = 0; i < insns.length; i++) { 68 insns[i].write(shortBuffer, mapping); 69 } 70 byteBuffer.position(byteBuffer.position() + shortBuffer.position() * Short.BYTES); 71 } 72 putByte(byte aByte)73 public void putByte(byte aByte) { 74 ensureSpaceFor(Byte.BYTES); 75 byteBuffer.put(aByte); 76 } 77 putBytes(byte[] bytes)78 public void putBytes(byte[] bytes) { 79 ensureSpaceFor(bytes.length); 80 byteBuffer.put(bytes); 81 } 82 putShort(short aShort)83 public void putShort(short aShort) { 84 ensureSpaceFor(Short.BYTES); 85 byteBuffer.putShort(aShort); 86 } 87 putInt(int anInteger)88 public void putInt(int anInteger) { 89 ensureSpaceFor(Integer.BYTES); 90 byteBuffer.putInt(anInteger); 91 } 92 93 /** 94 * Moves the position in the bytebuffer forward until it is aligned. 95 * 96 * @param bytes alignment requirement in bytes 97 * @return the new position after alignment 98 */ align(int bytes)99 public int align(int bytes) { 100 assert bytes > 0; 101 int mask = bytes - 1; 102 int newPosition = (byteBuffer.position() + mask) & ~mask; 103 ensureSpaceFor(newPosition - position()); 104 byteBuffer.position(newPosition); 105 return newPosition; 106 } 107 position()108 public int position() { 109 return byteBuffer.position(); 110 } 111 forward(int bytes)112 public void forward(int bytes) { 113 ensureSpaceFor(bytes); 114 byteBuffer.position(byteBuffer.position() + bytes); 115 } 116 rewind(int bytes)117 public void rewind(int bytes) { 118 forward(-bytes); 119 } 120 moveTo(int position)121 public void moveTo(int position) { 122 ensureSpaceFor(position - byteBuffer.position()); 123 byteBuffer.position(position); 124 } 125 isAligned(int bytes)126 public boolean isAligned(int bytes) { 127 return position() % bytes == 0; 128 } 129 asArray()130 public byte[] asArray() { 131 return byteBuffer.array(); 132 } 133 } 134