| // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| package com.android.tools.r8.dex; | |
| import com.android.tools.r8.graph.DexDebugEvent; | |
| import com.android.tools.r8.graph.DexDebugInfo; | |
| import com.android.tools.r8.graph.DexString; | |
| import com.android.tools.r8.graph.DexType; | |
| import com.android.tools.r8.graph.GraphLens; | |
| import com.android.tools.r8.graph.ObjectToOffsetMapping; | |
| import com.android.tools.r8.utils.LebUtils; | |
| import java.nio.ByteBuffer; | |
| import java.util.Arrays; | |
| public class DebugBytecodeWriter { | |
| private final ObjectToOffsetMapping mapping; | |
| private final GraphLens graphLens; | |
| private final DexDebugInfo info; | |
| private ByteBuffer buffer; | |
| public DebugBytecodeWriter( | |
| DexDebugInfo info, ObjectToOffsetMapping mapping, GraphLens graphLens) { | |
| this.info = info; | |
| this.mapping = mapping; | |
| this.graphLens = graphLens; | |
| // Never allocate a zero-sized buffer, as we need to write the header, and the growth policy | |
| // requires it to have a positive capacity. | |
| this.buffer = ByteBuffer.allocate(info.events.length * 5 + 4); | |
| } | |
| public byte[] generate() { | |
| // Header. | |
| putUleb128(info.startLine); // line_start | |
| putUleb128(info.parameters.length); | |
| for (DexString name : info.parameters) { | |
| putString(name); | |
| } | |
| // Body. | |
| for (DexDebugEvent event : info.events) { | |
| event.writeOn(this, mapping, graphLens); | |
| } | |
| // Tail. | |
| putByte(Constants.DBG_END_SEQUENCE); | |
| return Arrays.copyOf(buffer.array(), buffer.position()); | |
| } | |
| private void maybeGrow(int size) { | |
| if (buffer.remaining() < size) { | |
| ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity() * 2); | |
| newBuffer.put(buffer.array(), 0, buffer.position()); | |
| buffer = newBuffer; | |
| } | |
| } | |
| public void putByte(int item) { | |
| maybeGrow(1); | |
| buffer.put((byte) item); | |
| } | |
| public void putSleb128(int item) { | |
| byte[] encoded = LebUtils.encodeSleb128(item); | |
| maybeGrow(encoded.length); | |
| buffer.put(encoded, 0, encoded.length); | |
| } | |
| public void putUleb128(int item) { | |
| byte[] encoded = LebUtils.encodeUleb128(item); | |
| maybeGrow(encoded.length); | |
| buffer.put(encoded, 0, encoded.length); | |
| } | |
| private void putUleb128p1(int item) { | |
| putUleb128(item + 1); | |
| } | |
| private void putNoIndex() { | |
| putUleb128(0); | |
| } | |
| public void putType(DexType type) { | |
| if (type == null) { | |
| putNoIndex(); | |
| } else { | |
| int index = mapping.getOffsetFor(type); | |
| putUleb128p1(index); | |
| } | |
| } | |
| public void putString(DexString string) { | |
| if (string == null) { | |
| putNoIndex(); | |
| } else { | |
| int index = mapping.getOffsetFor(string); | |
| putUleb128p1(index); | |
| } | |
| } | |
| } |