1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/*
2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project
3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License");
5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License.
6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at
7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *      http://www.apache.org/licenses/LICENSE-2.0
9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software
11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS,
12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and
14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License.
15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.dex.file;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.dex.code.LocalList;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.dex.code.PositionList;
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpec;
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.SourcePosition;
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstMethodRef;
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstType;
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstUtf8;
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.Prototype;
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.StdTypeList;
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.Type;
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.AnnotatedOutput;
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.ByteArrayAnnotatedOutput;
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.ExceptionWithContext;
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.IOException;
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.PrintWriter;
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.ArrayList;
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Collections;
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Comparator;
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.BitSet;
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport static com.android.dexgen.dex.file.DebugInfoConstants.*;
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * An encoder for the dex debug info state machine format. The format
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * for each method enrty is as follows:
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <ol>
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <li> signed LEB128: initial value for line register.
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <li> n instances of signed LEB128: string indicies (offset by 1)
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * for each method argument in left-to-right order
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * with {@code this} excluded. A value of '0' indicates "no name"
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <li> A sequence of special or normal opcodes as defined in
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@code DebugInfoConstants}.
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <li> A single terminating {@code OP_END_SEQUENCE}
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * </ol>
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class DebugInfoEncoder {
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static final boolean DEBUG = false;
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code null-ok;} positions (line numbers) to encode */
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final PositionList positions;
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code null-ok;} local variables to encode */
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final LocalList locals;
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final ByteArrayAnnotatedOutput output;
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final DexFile file;
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int codeSize;
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int regSize;
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final Prototype desc;
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final boolean isStatic;
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** current encoding state: bytecode address */
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int address = 0;
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** current encoding state: line number */
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int line = 1;
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * if non-null: the output to write annotations to. No normal
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * output is written to this.
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private AnnotatedOutput annotateTo;
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** if non-null: another possible output for annotations */
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private PrintWriter debugPrint;
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** if non-null: the prefix for each annotation or debugPrint line */
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private String prefix;
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** true if output should be consumed during annotation */
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private boolean shouldConsume;
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** indexed by register; last local alive in register */
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final LocalList.Entry[] lastEntryForReg;
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Creates an instance.
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param positions {@code null-ok;} positions (line numbers) to encode
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param locals {@code null-ok;} local variables to encode
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param file {@code null-ok;} may only be {@code null} if simply using
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * this class to do a debug print
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param codeSize
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param regSize
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param isStatic
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param ref
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public DebugInfoEncoder(PositionList positions, LocalList locals,
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DexFile file, int codeSize, int regSize,
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean isStatic, CstMethodRef ref) {
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.positions = positions;
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.locals = locals;
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.file = file;
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.desc = ref.getPrototype();
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.isStatic = isStatic;
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.codeSize = codeSize;
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.regSize = regSize;
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output = new ByteArrayAnnotatedOutput();
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        lastEntryForReg = new LocalList.Entry[regSize];
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Annotates or writes a message to the {@code debugPrint} writer
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * if applicable.
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param length the number of bytes associated with this message
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param message the message itself
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void annotate(int length, String message) {
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (prefix != null) {
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            message = prefix + message;
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null) {
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotateTo.annotate(shouldConsume ? length : 0, message);
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (debugPrint != null) {
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            debugPrint.println(message);
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Converts this (PositionList, LocalList) pair into a state machine
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * sequence.
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} encoded byte sequence without padding and
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * terminated with a {@code 0x00} byte
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public byte[] convert() {
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        try {
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            byte[] ret;
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            ret = convert0();
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (DEBUG) {
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                for (int i = 0 ; i < ret.length; i++) {
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    System.err.printf("byte %02x\n", (0xff & ret[i]));
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return ret;
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } catch (IOException ex) {
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw ExceptionWithContext
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    .withContext(ex, "...while encoding debug info");
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Converts and produces annotations on a stream. Does not write
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * actual bits to the {@code AnnotatedOutput}.
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param prefix {@code null-ok;} prefix to attach to each line of output
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param debugPrint {@code null-ok;} if specified, an alternate output for
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * annotations
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param out {@code null-ok;} if specified, where annotations should go
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param consume whether to claim to have consumed output for
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code out}
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} encoded output
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public byte[] convertAndAnnotate(String prefix, PrintWriter debugPrint,
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            AnnotatedOutput out, boolean consume) {
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.prefix = prefix;
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.debugPrint = debugPrint;
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        annotateTo = out;
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        shouldConsume = consume;
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        byte[] result = convert();
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private byte[] convert0() throws IOException {
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        ArrayList<PositionList.Entry> sortedPositions = buildSortedPositions();
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        ArrayList<LocalList.Entry> methodArgs = extractMethodArguments();
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitHeader(sortedPositions, methodArgs);
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // TODO: Make this mark be the actual prologue end.
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeByte(DBG_SET_PROLOGUE_END);
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null || debugPrint != null) {
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(1, String.format("%04x: prologue end",address));
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int positionsSz = sortedPositions.size();
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int localsSz = locals.size();
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Current index in sortedPositions
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int curPositionIdx = 0;
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Current index in locals
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int curLocalIdx = 0;
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (;;) {
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * Emit any information for the current address.
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            curLocalIdx = emitLocalsAtAddress(curLocalIdx);
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            curPositionIdx =
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                emitPositionsAtAddress(curPositionIdx, sortedPositions);
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * Figure out what the next important address is.
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int nextAddrL = Integer.MAX_VALUE; // local variable
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int nextAddrP = Integer.MAX_VALUE; // position (line number)
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (curLocalIdx < localsSz) {
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                nextAddrL = locals.get(curLocalIdx).getAddress();
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (curPositionIdx < positionsSz) {
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                nextAddrP = sortedPositions.get(curPositionIdx).getAddress();
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int next = Math.min(nextAddrP, nextAddrL);
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // No next important address == done.
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (next == Integer.MAX_VALUE) {
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * If the only work remaining are local ends at the end of the
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * block, stop here. Those are implied anyway.
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (next == codeSize
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    && nextAddrL == Integer.MAX_VALUE
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    && nextAddrP == Integer.MAX_VALUE) {
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (next == nextAddrP) {
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // Combined advance PC + position entry
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                emitPosition(sortedPositions.get(curPositionIdx++));
258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                emitAdvancePc(next - address);
260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitEndSequence();
264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return output.toByteArray();
266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits all local variable activity that occurs at the current
270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@link #address} starting at the given index into {@code
271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * locals} and including all subsequent activity at the same
272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * address.
273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param curLocalIdx Current index in locals
275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return new value for {@code curLocalIdx}
276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int emitLocalsAtAddress(int curLocalIdx)
279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throws IOException {
280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = locals.size();
281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // TODO: Don't emit ends implied by starts.
283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        while ((curLocalIdx < sz)
285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                && (locals.get(curLocalIdx).getAddress() == address)) {
286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalList.Entry entry = locals.get(curLocalIdx++);
287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int reg = entry.getRegister();
288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalList.Entry prevEntry = lastEntryForReg[reg];
289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (entry == prevEntry) {
291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Here we ignore locals entries for parameters,
293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * which have already been represented and placed in the
294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * lastEntryForReg array.
295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                continue;
297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // At this point we have a new entry one way or another.
300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            lastEntryForReg[reg] = entry;
301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (entry.isStart()) {
303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if ((prevEntry != null) && entry.matches(prevEntry)) {
304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * The previous local in this register has the same
306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * name and type as the one being introduced now, so
307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * use the more efficient "restart" form.
308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (prevEntry.isStart()) {
310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        /*
311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * We should never be handed a start when a
312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * a matching local is already active.
313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         */
314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        throw new RuntimeException("shouldn't happen");
315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    emitLocalRestart(entry);
317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                } else {
318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    emitLocalStart(entry);
319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Only emit a local end if it is *not* due to a direct
323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * replacement. Direct replacements imply an end of the
324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * previous local in the same register.
325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 *
326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * TODO: Make sure the runtime can deal with implied
327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * local ends from category-2 interactions, and when so,
328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * also stop emitting local ends for those cases.
329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (entry.getDisposition()
331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        != LocalList.Disposition.END_REPLACED) {
332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    emitLocalEnd(entry);
333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return curLocalIdx;
338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits all positions that occur at the current {@code address}
342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param curPositionIdx Current index in sortedPositions
344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param sortedPositions positions, sorted by ascending address
345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return new value for {@code curPositionIdx}
346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int emitPositionsAtAddress(int curPositionIdx,
349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            ArrayList<PositionList.Entry> sortedPositions)
350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throws IOException {
351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int positionsSz = sortedPositions.size();
352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        while ((curPositionIdx < positionsSz)
353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                && (sortedPositions.get(curPositionIdx).getAddress()
354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        == address)) {
355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            emitPosition(sortedPositions.get(curPositionIdx++));
356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return curPositionIdx;
358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits the header sequence, which consists of LEB128-encoded initial
362917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * line number and string indicies for names of all non-"this" arguments.
363917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
364917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param sortedPositions positions, sorted by ascending address
365917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param methodArgs local list entries for method argumens arguments,
366917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * in left-to-right order omitting "this"
367917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
368917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
369917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitHeader(ArrayList<PositionList.Entry> sortedPositions,
370917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            ArrayList<LocalList.Entry> methodArgs) throws IOException {
371917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        boolean annotate = (annotateTo != null) || (debugPrint != null);
372917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int mark = output.getCursor();
373917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
374917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Start by initializing the line number register.
375917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (sortedPositions.size() > 0) {
376917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            PositionList.Entry entry = sortedPositions.get(0);
377917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            line = entry.getPosition().getLine();
378917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
379917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeUnsignedLeb128(line);
380917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
381917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotate) {
382917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(output.getCursor() - mark, "line_start: " + line);
383917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
384917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
385917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int curParam = getParamBase();
386917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // paramTypes will not include 'this'
387917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        StdTypeList paramTypes = desc.getParameterTypes();
388917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int szParamTypes = paramTypes.size();
389917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
390917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
391917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Initialize lastEntryForReg to have an initial
392917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * entry for the 'this' pointer.
393917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
394917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (!isStatic) {
395917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (LocalList.Entry arg : methodArgs) {
396917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (curParam == arg.getRegister()) {
397917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    lastEntryForReg[curParam] = arg;
398917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
399917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
400917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
401917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            curParam++;
402917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
403917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
404917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Write out the number of parameter entries that will follow.
405917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        mark = output.getCursor();
406917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeUnsignedLeb128(szParamTypes);
407917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
408917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotate) {
409917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(output.getCursor() - mark,
410917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    String.format("parameters_size: %04x", szParamTypes));
411917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
412917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
413917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
414917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Then emit the string indicies of all the method parameters.
415917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Note that 'this', if applicable, is excluded.
416917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
417917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < szParamTypes; i++) {
418917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Type pt = paramTypes.get(i);
419917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalList.Entry found = null;
420917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
421917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            mark = output.getCursor();
422917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
423917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (LocalList.Entry arg : methodArgs) {
424917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (curParam == arg.getRegister()) {
425917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    found = arg;
426917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
427917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (arg.getSignature() != null) {
428917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        /*
429917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * Parameters with signatures will be re-emitted
430917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * in complete as LOCAL_START_EXTENDED's below.
431917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         */
432917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        emitStringIndex(null);
433917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    } else {
434917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        emitStringIndex(arg.getName());
435917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
436917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    lastEntryForReg[curParam] = arg;
437917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
438917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
439917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
440917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
441917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
442917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (found == null) {
443917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
444917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Emit a null symbol for "unnamed." This is common
445917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * for, e.g., synthesized methods and inner-class
446917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * this$0 arguments.
447917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
448917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                emitStringIndex(null);
449917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
450917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
451917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (annotate) {
452917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                String parameterName
453917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        = (found == null || found.getSignature() != null)
454917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                ? "<unnamed>" : found.getName().toHuman();
455917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                annotate(output.getCursor() - mark,
456917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        "parameter " + parameterName + " "
457917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                + RegisterSpec.PREFIX + curParam);
458917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
459917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
460917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            curParam += pt.getCategory();
461917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
462917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
463917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
464917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * If anything emitted above has a type signature, emit it again as
465917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * a LOCAL_RESTART_EXTENDED
466917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
467917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
468917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (LocalList.Entry arg : lastEntryForReg) {
469917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (arg == null) {
470917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                continue;
471917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
472917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
473917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CstUtf8 signature = arg.getSignature();
474917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
475917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (signature != null) {
476917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                emitLocalStartExtended(arg);
477917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
478917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
479917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
480917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
481917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
482917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Builds a list of position entries, sorted by ascending address.
483917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
484917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return A sorted positions list
485917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
486917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private ArrayList<PositionList.Entry> buildSortedPositions() {
487917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = (positions == null) ? 0 : positions.size();
488917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        ArrayList<PositionList.Entry> result = new ArrayList(sz);
489917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
490917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
491917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result.add(positions.get(i));
492917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
493917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
494917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Sort ascending by address.
495917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Collections.sort (result, new Comparator<PositionList.Entry>() {
496917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            public int compare (PositionList.Entry a, PositionList.Entry b) {
497917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return a.getAddress() - b.getAddress();
498917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
499917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
500917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            public boolean equals (Object obj) {
501917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul               return obj == this;
502917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
503917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        });
504917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
505917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
506917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
507917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
508917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the register that begins the method's parameter range (including
509917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * the 'this' parameter for non-static methods). The range continues until
510917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code regSize}
511917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
512917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return register as noted above
513917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
514917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int getParamBase() {
515917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return regSize
516917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
517917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
518917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
519917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
520917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Extracts method arguments from a locals list. These will be collected
521917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * from the input list and sorted by ascending register in the
522917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * returned list.
523917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
524917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return list of non-{@code this} method argument locals,
525917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * sorted by ascending register
526917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
527917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private ArrayList<LocalList.Entry> extractMethodArguments() {
528917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        ArrayList<LocalList.Entry> result
529917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                = new ArrayList(desc.getParameterTypes().size());
530917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int argBase = getParamBase();
531917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        BitSet seen = new BitSet(regSize - argBase);
532917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = locals.size();
533917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
534917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
535917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalList.Entry e = locals.get(i);
536917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int reg = e.getRegister();
537917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
538917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (reg < argBase) {
539917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                continue;
540917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
541917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
542917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // only the lowest-start-address entry is included.
543917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (seen.get(reg - argBase)) {
544917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                continue;
545917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
546917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
547917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            seen.set(reg - argBase);
548917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result.add(e);
549917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
550917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
551917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Sort by ascending register.
552917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Collections.sort(result, new Comparator<LocalList.Entry>() {
553917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            public int compare(LocalList.Entry a, LocalList.Entry b) {
554917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return a.getRegister() - b.getRegister();
555917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
556917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
557917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            public boolean equals(Object obj) {
558917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul               return obj == this;
559917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
560917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        });
561917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
562917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
563917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
564917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
565917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
566917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns a string representation of this LocalList entry that is
567917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * appropriate for emitting as an annotation.
568917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
569917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param e {@code non-null;} entry
570917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} annotation string
571917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
572917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private String entryAnnotationString(LocalList.Entry e) {
573917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        StringBuilder sb = new StringBuilder();
574917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
575917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append(RegisterSpec.PREFIX);
576917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append(e.getRegister());
577917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append(' ');
578917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
579917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        CstUtf8 name = e.getName();
580917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (name == null) {
581917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append("null");
582917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
583917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(name.toHuman());
584917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
585917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append(' ');
586917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
587917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        CstType type = e.getType();
588917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (type == null) {
589917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append("null");
590917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
591917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(type.toHuman());
592917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
593917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
594917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        CstUtf8 signature = e.getSignature();
595917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
596917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (signature != null) {
597917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(' ');
598917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(signature.toHuman());
599917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
600917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
601917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return sb.toString();
602917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
603917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
604917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
605917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits a {@link DebugInfoConstants#DBG_RESTART_LOCAL DBG_RESTART_LOCAL}
606917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * sequence.
607917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
608917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param entry entry associated with this restart
609917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
610917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
611917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitLocalRestart(LocalList.Entry entry)
612917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throws IOException {
613917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
614917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int mark = output.getCursor();
615917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
616917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeByte(DBG_RESTART_LOCAL);
617917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitUnsignedLeb128(entry.getRegister());
618917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
619917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null || debugPrint != null) {
620917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(output.getCursor() - mark,
621917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    String.format("%04x: +local restart %s",
622917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            address, entryAnnotationString(entry)));
623917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
624917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
625917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (DEBUG) {
626917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.println("emit local restart");
627917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
628917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
629917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
630917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
631917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits a string index as an unsigned LEB128. The actual value written
632917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * is shifted by 1, so that the '0' value is reserved for "null". The
633917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * null symbol is used in some cases by the parameter name list
634917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * at the beginning of the sequence.
635917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
636917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param string {@code null-ok;} string to emit
637917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
638917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
639917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitStringIndex(CstUtf8 string) throws IOException {
640917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((string == null) || (file == null)) {
641917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            output.writeUnsignedLeb128(0);
642917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
643917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            output.writeUnsignedLeb128(
644917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                1 + file.getStringIds().indexOf(string));
645917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
646917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
647917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (DEBUG) {
648917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.printf("Emit string %s\n",
649917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    string == null ? "<null>" : string.toQuoted());
650917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
651917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
652917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
653917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
654917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits a type index as an unsigned LEB128. The actual value written
655917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * is shifted by 1, so that the '0' value is reserved for "null".
656917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
657917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param type {@code null-ok;} type to emit
658917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
659917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
660917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitTypeIndex(CstType type) throws IOException {
661917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((type == null) || (file == null)) {
662917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            output.writeUnsignedLeb128(0);
663917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
664917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            output.writeUnsignedLeb128(
665917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                1 + file.getTypeIds().indexOf(type));
666917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
667917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
668917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (DEBUG) {
669917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.printf("Emit type %s\n",
670917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    type == null ? "<null>" : type.toHuman());
671917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
672917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
673917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
674917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
675917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits a {@link DebugInfoConstants#DBG_START_LOCAL DBG_START_LOCAL} or
676917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
677917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * DBG_START_LOCAL_EXTENDED} sequence.
678917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
679917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param entry entry to emit
680917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
681917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
682917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitLocalStart(LocalList.Entry entry)
683917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        throws IOException {
684917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
685917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (entry.getSignature() != null) {
686917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            emitLocalStartExtended(entry);
687917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return;
688917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
689917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
690917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int mark = output.getCursor();
691917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
692917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeByte(DBG_START_LOCAL);
693917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
694917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitUnsignedLeb128(entry.getRegister());
695917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitStringIndex(entry.getName());
696917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitTypeIndex(entry.getType());
697917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
698917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null || debugPrint != null) {
699917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(output.getCursor() - mark,
700917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    String.format("%04x: +local %s", address,
701917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            entryAnnotationString(entry)));
702917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
703917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
704917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (DEBUG) {
705917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.println("emit local start");
706917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
707917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
708917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
709917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
710917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits a {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED
711917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * DBG_START_LOCAL_EXTENDED} sequence.
712917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
713917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param entry entry to emit
714917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
715917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
716917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitLocalStartExtended(LocalList.Entry entry)
717917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        throws IOException {
718917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
719917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int mark = output.getCursor();
720917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
721917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeByte(DBG_START_LOCAL_EXTENDED);
722917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
723917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitUnsignedLeb128(entry.getRegister());
724917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitStringIndex(entry.getName());
725917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitTypeIndex(entry.getType());
726917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        emitStringIndex(entry.getSignature());
727917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
728917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null || debugPrint != null) {
729917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(output.getCursor() - mark,
730917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    String.format("%04x: +localx %s", address,
731917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            entryAnnotationString(entry)));
732917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
733917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
734917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (DEBUG) {
735917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.println("emit local start");
736917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
737917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
738917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
739917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
740917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits a {@link DebugInfoConstants#DBG_END_LOCAL DBG_END_LOCAL} sequence.
741917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
742917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param entry {@code entry non-null;} entry associated with end.
743917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
744917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
745917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitLocalEnd(LocalList.Entry entry)
746917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throws IOException {
747917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
748917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int mark = output.getCursor();
749917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
750917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeByte(DBG_END_LOCAL);
751917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeUnsignedLeb128(entry.getRegister());
752917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
753917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null || debugPrint != null) {
754917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(output.getCursor() - mark,
755917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    String.format("%04x: -local %s", address,
756917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            entryAnnotationString(entry)));
757917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
758917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
759917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (DEBUG) {
760917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.println("emit local end");
761917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
762917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
763917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
764917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
765917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits the necessary byte sequences to emit the given position table
766917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * entry. This will typically be a single special opcode, although
767917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE.
768917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
769917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param entry position entry to emit.
770917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
771917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
772917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitPosition(PositionList.Entry entry)
773917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throws IOException {
774917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
775917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        SourcePosition pos = entry.getPosition();
776917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int newLine = pos.getLine();
777917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int newAddress = entry.getAddress();
778917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
779917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int opcode;
780917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
781917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int deltaLines = newLine - line;
782917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int deltaAddress = newAddress - address;
783917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
784917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (deltaAddress < 0) {
785917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new RuntimeException(
786917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    "Position entries must be in ascending address order");
787917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
788917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
789917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((deltaLines < DBG_LINE_BASE)
790917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1))) {
791917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            emitAdvanceLine(deltaLines);
792917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            deltaLines = 0;
793917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
794917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
795917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        opcode = computeOpcode (deltaLines, deltaAddress);
796917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
797917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((opcode & ~0xff) > 0) {
798917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            emitAdvancePc(deltaAddress);
799917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            deltaAddress = 0;
800917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            opcode = computeOpcode (deltaLines, deltaAddress);
801917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
802917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((opcode & ~0xff) > 0) {
803917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                emitAdvanceLine(deltaLines);
804917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                deltaLines = 0;
805917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                opcode = computeOpcode (deltaLines, deltaAddress);
806917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
807917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
808917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
809917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeByte(opcode);
810917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
811917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        line += deltaLines;
812917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        address += deltaAddress;
813917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
814917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null || debugPrint != null) {
815917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(1,
816917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    String.format("%04x: line %d", address, line));
817917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
818917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
819917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
820917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
821917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Computes a special opcode that will encode the given position change.
822917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * If the return value is > 0xff, then the request cannot be fulfilled.
823917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Essentially the same as described in "DWARF Debugging Format Version 3"
824917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * section 6.2.5.1.
825917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
826917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param deltaLines {@code >= DBG_LINE_BASE, <= DBG_LINE_BASE +
827917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * DBG_LINE_RANGE;} the line change to encode
828917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param deltaAddress {@code >= 0;} the address change to encode
829917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code <= 0xff} if in range, otherwise parameters are out
830917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * of range
831917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
832917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static int computeOpcode(int deltaLines, int deltaAddress) {
833917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (deltaLines < DBG_LINE_BASE
834917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                || deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1)) {
835917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
836917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new RuntimeException("Parameter out of range");
837917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
838917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
839917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (deltaLines - DBG_LINE_BASE)
840917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            + (DBG_LINE_RANGE * deltaAddress) + DBG_FIRST_SPECIAL;
841917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
842917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
843917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
844917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits an {@link DebugInfoConstants#DBG_ADVANCE_LINE DBG_ADVANCE_LINE}
845917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * sequence.
846917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
847917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param deltaLines amount to change line number register by
848917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
849917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
850917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitAdvanceLine(int deltaLines) throws IOException {
851917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int mark = output.getCursor();
852917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
853917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeByte(DBG_ADVANCE_LINE);
854917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeSignedLeb128(deltaLines);
855917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        line += deltaLines;
856917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
857917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null || debugPrint != null) {
858917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(output.getCursor() - mark,
859917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    String.format("line = %d", line));
860917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
861917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
862917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (DEBUG) {
863917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.printf("Emitting advance_line for %d\n", deltaLines);
864917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
865917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
866917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
867917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
868917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits an  {@link DebugInfoConstants#DBG_ADVANCE_PC DBG_ADVANCE_PC}
869917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * sequence.
870917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
871917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param deltaAddress {@code >= 0;} amount to change program counter by
872917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
873917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
874917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitAdvancePc(int deltaAddress) throws IOException {
875917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int mark = output.getCursor();
876917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
877917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeByte(DBG_ADVANCE_PC);
878917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeUnsignedLeb128(deltaAddress);
879917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        address += deltaAddress;
880917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
881917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null || debugPrint != null) {
882917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(output.getCursor() - mark,
883917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    String.format("%04x: advance pc", address));
884917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
885917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
886917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (DEBUG) {
887917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.printf("Emitting advance_pc for %d\n", deltaAddress);
888917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
889917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
890917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
891917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
892917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits an unsigned LEB128 value.
893917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
894917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param n {@code >= 0;} value to emit. Note that, although this can
895917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * represent integers larger than Integer.MAX_VALUE, we currently don't
896917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * allow that.
897917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
898917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
899917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitUnsignedLeb128(int n) throws IOException {
900917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // We'll never need the top end of the unsigned range anyway.
901917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (n < 0) {
902917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new RuntimeException(
903917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    "Signed value where unsigned required: " + n);
904917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
905917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
906917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeUnsignedLeb128(n);
907917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
908917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
909917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
910917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Emits the {@link DebugInfoConstants#DBG_END_SEQUENCE DBG_END_SEQUENCE}
911917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * bytecode.
912917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
913917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void emitEndSequence() {
914917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.writeByte(DBG_END_SEQUENCE);
915917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
916917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotateTo != null || debugPrint != null) {
917917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            annotate(1, "end sequence");
918917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
919917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
920917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
921