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.code;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpecList;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.SourcePosition;
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.AnnotatedOutput;
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.Hex;
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.IntList;
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Pseudo-instruction which holds switch data. The switch data is
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * a map of values to target addresses, and this class writes the data
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * in either a "packed" or "sparse" form.
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class SwitchData extends VariableSizeInsn {
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code non-null;} address representing the instruction that uses this
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * instance
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final CodeAddress user;
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} sorted list of switch cases (keys) */
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final IntList cases;
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code non-null;} corresponding list of code addresses; the branch
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * target for each case
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final CodeAddress[] targets;
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** whether the output table will be packed (vs. sparse) */
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final boolean packed;
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance. The output address of this instance is initially
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * unknown ({@code -1}).
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param position {@code non-null;} source position
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param user {@code non-null;} address representing the instruction that
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * uses this instance
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param cases {@code non-null;} sorted list of switch cases (keys)
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param targets {@code non-null;} corresponding list of code addresses; the
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * branch target for each case
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public SwitchData(SourcePosition position, CodeAddress user,
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                      IntList cases, CodeAddress[] targets) {
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        super(position, RegisterSpecList.EMPTY);
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (user == null) {
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("user == null");
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (cases == null) {
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("cases == null");
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (targets == null) {
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("targets == null");
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = cases.size();
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (sz != targets.length) {
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("cases / targets mismatch");
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (sz > 65535) {
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IllegalArgumentException("too many cases");
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.user = user;
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.cases = cases;
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.targets = targets;
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.packed = shouldPack(cases);
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public int codeSize() {
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return packed ? (int) packedCodeSize(cases) :
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            (int) sparseCodeSize(cases);
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void writeTo(AnnotatedOutput out) {
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int baseAddress = user.getAddress();
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int defaultTarget = Dops.PACKED_SWITCH.getFormat().codeSize();
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = targets.length;
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (packed) {
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int firstCase = (sz == 0) ? 0 : cases.get(0);
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int lastCase = (sz == 0) ? 0 : cases.get(sz - 1);
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int outSz = lastCase - firstCase + 1;
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.writeShort(0x100 | DalvOps.NOP);
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.writeShort(outSz);
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.writeInt(firstCase);
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int caseAt = 0;
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < outSz; i++) {
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int outCase = firstCase + i;
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int oneCase = cases.get(caseAt);
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int relTarget;
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (oneCase > outCase) {
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    relTarget = defaultTarget;
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                } else {
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    relTarget = targets[caseAt].getAddress() - baseAddress;
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    caseAt++;
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                out.writeInt(relTarget);
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.writeShort(0x200 | DalvOps.NOP);
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.writeShort(sz);
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < sz; i++) {
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                out.writeInt(cases.get(i));
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < sz; i++) {
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int relTarget = targets[i].getAddress() - baseAddress;
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                out.writeInt(relTarget);
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public DalvInsn withRegisters(RegisterSpecList registers) {
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return new SwitchData(getPosition(), user, cases, targets);
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns whether or not this instance's data will be output as packed.
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code true} iff the data is to be packed
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public boolean isPacked() {
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return packed;
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    protected String argString() {
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        StringBuffer sb = new StringBuffer(100);
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = targets.length;
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append("\n    ");
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(cases.get(i));
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(": ");
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(targets[i]);
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return sb.toString();
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    protected String listingString0(boolean noteIndices) {
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int baseAddress = user.getAddress();
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        StringBuffer sb = new StringBuffer(100);
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = targets.length;
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append(packed ? "packed" : "sparse");
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append("-switch-data // for switch @ ");
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sb.append(Hex.u2(baseAddress));
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int absTarget = targets[i].getAddress();
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int relTarget = absTarget - baseAddress;
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append("\n  ");
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(cases.get(i));
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(": ");
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(Hex.u4(absTarget));
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(" // ");
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            sb.append(Hex.s4(relTarget));
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return sb.toString();
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the size of a packed table for the given cases, in 16-bit code
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * units.
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param cases {@code non-null;} sorted list of cases
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code >= -1;} the packed table size or {@code -1} if the
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * cases couldn't possibly be represented as a packed table
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static long packedCodeSize(IntList cases) {
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = cases.size();
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        long low = cases.get(0);
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        long high = cases.get(sz - 1);
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        long result = ((high - low + 1)) * 2 + 4;
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (result <= 0x7fffffff) ? result : -1;
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the size of a sparse table for the given cases, in 16-bit code
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * units.
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param cases {@code non-null;} sorted list of cases
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code > 0;} the sparse table size
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static long sparseCodeSize(IntList cases) {
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = cases.size();
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (sz * 4L) + 2;
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Determines whether the given list of cases warrant being packed.
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param cases {@code non-null;} sorted list of cases
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code true} iff the table encoding the cases
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * should be packed
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static boolean shouldPack(IntList cases) {
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = cases.size();
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (sz < 2) {
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return true;
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        long packedSize = packedCodeSize(cases);
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        long sparseSize = sparseCodeSize(cases);
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * We pick the packed representation if it is possible and
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * would be as small or smaller than 5/4 of the sparse
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * representation. That is, we accept some size overhead on
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * the packed representation, since that format is faster to
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * execute at runtime.
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (packedSize >= 0) && (packedSize <= ((sparseSize * 5) / 4));
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
258