1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "Dalvik.h" 18 #include "libdex/DexOpcodes.h" 19 20 #include "../../CompilerInternals.h" 21 #include "ArmLIR.h" 22 #include "Codegen.h" 23 #include <sys/mman.h> /* for protection change */ 24 25 #define MAX_ASSEMBLER_RETRIES 10 26 27 /* 28 * opcode: ArmOpcode enum 29 * skeleton: pre-designated bit-pattern for this opcode 30 * k0: key to applying ds/de 31 * ds: dest start bit position 32 * de: dest end bit position 33 * k1: key to applying s1s/s1e 34 * s1s: src1 start bit position 35 * s1e: src1 end bit position 36 * k2: key to applying s2s/s2e 37 * s2s: src2 start bit position 38 * s2e: src2 end bit position 39 * operands: number of operands (for sanity check purposes) 40 * name: mnemonic name 41 * fmt: for pretty-printing 42 */ 43 #define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \ 44 k3, k3s, k3e, flags, name, fmt, size) \ 45 {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \ 46 {k3, k3s, k3e}}, opcode, flags, name, fmt, size} 47 48 /* Instruction dump string format keys: !pf, where "!" is the start 49 * of the key, "p" is which numeric operand to use and "f" is the 50 * print format. 51 * 52 * [p]ositions: 53 * 0 -> operands[0] (dest) 54 * 1 -> operands[1] (src1) 55 * 2 -> operands[2] (src2) 56 * 3 -> operands[3] (extra) 57 * 58 * [f]ormats: 59 * h -> 4-digit hex 60 * d -> decimal 61 * E -> decimal*4 62 * F -> decimal*2 63 * c -> branch condition (beq, bne, etc.) 64 * t -> pc-relative target 65 * u -> 1st half of bl[x] target 66 * v -> 2nd half ob bl[x] target 67 * R -> register list 68 * s -> single precision floating point register 69 * S -> double precision floating point register 70 * m -> Thumb2 modified immediate 71 * n -> complimented Thumb2 modified immediate 72 * M -> Thumb2 16-bit zero-extended immediate 73 * b -> 4-digit binary 74 * B -> dmb option string (sy, st, ish, ishst, nsh, hshst) 75 * H -> operand shift 76 * 77 * [!] escape. To insert "!", use "!!" 78 */ 79 /* NOTE: must be kept in sync with enum ArmOpcode from ArmLIR.h */ 80 ArmEncodingMap EncodingMap[kArmLast] = { 81 ENCODING_MAP(kArm16BitData, 0x0000, 82 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 83 kFmtUnused, -1, -1, IS_UNARY_OP, "data", "0x!0h(!0d)", 1), 84 ENCODING_MAP(kThumbAdcRR, 0x4140, 85 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 86 kFmtUnused, -1, -1, 87 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES | USES_CCODES, 88 "adcs", "r!0d, r!1d", 1), 89 ENCODING_MAP(kThumbAddRRI3, 0x1c00, 90 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 91 kFmtUnused, -1, -1, 92 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, 93 "adds", "r!0d, r!1d, #!2d", 1), 94 ENCODING_MAP(kThumbAddRI8, 0x3000, 95 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, 96 kFmtUnused, -1, -1, 97 IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES, 98 "adds", "r!0d, r!0d, #!1d", 1), 99 ENCODING_MAP(kThumbAddRRR, 0x1800, 100 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 101 kFmtUnused, -1, -1, 102 IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES, 103 "adds", "r!0d, r!1d, r!2d", 1), 104 ENCODING_MAP(kThumbAddRRLH, 0x4440, 105 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 106 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01, 107 "add", "r!0d, r!1d", 1), 108 ENCODING_MAP(kThumbAddRRHL, 0x4480, 109 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 110 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01, 111 "add", "r!0d, r!1d", 1), 112 ENCODING_MAP(kThumbAddRRHH, 0x44c0, 113 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 114 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01, 115 "add", "r!0d, r!1d", 1), 116 ENCODING_MAP(kThumbAddPcRel, 0xa000, 117 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, 118 kFmtUnused, -1, -1, IS_TERTIARY_OP | IS_BRANCH, 119 "add", "r!0d, pc, #!1E", 1), 120 ENCODING_MAP(kThumbAddSpRel, 0xa800, 121 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0, 122 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF_SP | REG_USE_SP, 123 "add", "r!0d, sp, #!2E", 1), 124 ENCODING_MAP(kThumbAddSpI7, 0xb000, 125 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 126 kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP, 127 "add", "sp, #!0d*4", 1), 128 ENCODING_MAP(kThumbAndRR, 0x4000, 129 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 130 kFmtUnused, -1, -1, 131 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, 132 "ands", "r!0d, r!1d", 1), 133 ENCODING_MAP(kThumbAsrRRI5, 0x1000, 134 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, 135 kFmtUnused, -1, -1, 136 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, 137 "asrs", "r!0d, r!1d, #!2d", 1), 138 ENCODING_MAP(kThumbAsrRR, 0x4100, 139 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 140 kFmtUnused, -1, -1, 141 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, 142 "asrs", "r!0d, r!1d", 1), 143 ENCODING_MAP(kThumbBCond, 0xd000, 144 kFmtBitBlt, 7, 0, kFmtBitBlt, 11, 8, kFmtUnused, -1, -1, 145 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | USES_CCODES, 146 "b!1c", "!0t", 1), 147 ENCODING_MAP(kThumbBUncond, 0xe000, 148 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 149 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH, 150 "b", "!0t", 1), 151 ENCODING_MAP(kThumbBicRR, 0x4380, 152 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 153 kFmtUnused, -1, -1, 154 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, 155 "bics", "r!0d, r!1d", 1), 156 ENCODING_MAP(kThumbBkpt, 0xbe00, 157 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 158 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH, 159 "bkpt", "!0d", 1), 160 ENCODING_MAP(kThumbBlx1, 0xf000, 161 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 162 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR, 163 "blx_1", "!0u", 1), 164 ENCODING_MAP(kThumbBlx2, 0xe800, 165 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 166 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR, 167 "blx_2", "!0v", 1), 168 ENCODING_MAP(kThumbBl1, 0xf000, 169 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 170 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR, 171 "bl_1", "!0u", 1), 172 ENCODING_MAP(kThumbBl2, 0xf800, 173 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 174 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR, 175 "bl_2", "!0v", 1), 176 ENCODING_MAP(kThumbBlxR, 0x4780, 177 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 178 kFmtUnused, -1, -1, 179 IS_UNARY_OP | REG_USE0 | IS_BRANCH | REG_DEF_LR, 180 "blx", "r!0d", 1), 181 ENCODING_MAP(kThumbBx, 0x4700, 182 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 183 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH, 184 "bx", "r!0d", 1), 185 ENCODING_MAP(kThumbCmnRR, 0x42c0, 186 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 187 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, 188 "cmn", "r!0d, r!1d", 1), 189 ENCODING_MAP(kThumbCmpRI8, 0x2800, 190 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, 191 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | SETS_CCODES, 192 "cmp", "r!0d, #!1d", 1), 193 ENCODING_MAP(kThumbCmpRR, 0x4280, 194 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 195 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, 196 "cmp", "r!0d, r!1d", 1), 197 ENCODING_MAP(kThumbCmpLH, 0x4540, 198 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 199 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, 200 "cmp", "r!0d, r!1d", 1), 201 ENCODING_MAP(kThumbCmpHL, 0x4580, 202 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 203 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, 204 "cmp", "r!0d, r!1d", 1), 205 ENCODING_MAP(kThumbCmpHH, 0x45c0, 206 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 207 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES, 208 "cmp", "r!0d, r!1d", 1), 209 ENCODING_MAP(kThumbEorRR, 0x4040, 210 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 211 kFmtUnused, -1, -1, 212 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, 213 "eors", "r!0d, r!1d", 1), 214 ENCODING_MAP(kThumbLdmia, 0xc800, 215 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, 216 kFmtUnused, -1, -1, 217 IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD, 218 "ldmia", "r!0d!!, <!1R>", 1), 219 ENCODING_MAP(kThumbLdrRRI5, 0x6800, 220 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, 221 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 222 "ldr", "r!0d, [r!1d, #!2E]", 1), 223 ENCODING_MAP(kThumbLdrRRR, 0x5800, 224 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 225 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, 226 "ldr", "r!0d, [r!1d, r!2d]", 1), 227 ENCODING_MAP(kThumbLdrPcRel, 0x4800, 228 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, 229 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC 230 | IS_LOAD, "ldr", "r!0d, [pc, #!1E]", 1), 231 ENCODING_MAP(kThumbLdrSpRel, 0x9800, 232 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0, 233 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_SP 234 | IS_LOAD, "ldr", "r!0d, [sp, #!2E]", 1), 235 ENCODING_MAP(kThumbLdrbRRI5, 0x7800, 236 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, 237 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 238 "ldrb", "r!0d, [r!1d, #2d]", 1), 239 ENCODING_MAP(kThumbLdrbRRR, 0x5c00, 240 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 241 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, 242 "ldrb", "r!0d, [r!1d, r!2d]", 1), 243 ENCODING_MAP(kThumbLdrhRRI5, 0x8800, 244 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, 245 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 246 "ldrh", "r!0d, [r!1d, #!2F]", 1), 247 ENCODING_MAP(kThumbLdrhRRR, 0x5a00, 248 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 249 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, 250 "ldrh", "r!0d, [r!1d, r!2d]", 1), 251 ENCODING_MAP(kThumbLdrsbRRR, 0x5600, 252 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 253 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, 254 "ldrsb", "r!0d, [r!1d, r!2d]", 1), 255 ENCODING_MAP(kThumbLdrshRRR, 0x5e00, 256 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 257 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12 | IS_LOAD, 258 "ldrsh", "r!0d, [r!1d, r!2d]", 1), 259 ENCODING_MAP(kThumbLslRRI5, 0x0000, 260 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, 261 kFmtUnused, -1, -1, 262 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, 263 "lsls", "r!0d, r!1d, #!2d", 1), 264 ENCODING_MAP(kThumbLslRR, 0x4080, 265 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 266 kFmtUnused, -1, -1, 267 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, 268 "lsls", "r!0d, r!1d", 1), 269 ENCODING_MAP(kThumbLsrRRI5, 0x0800, 270 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, 271 kFmtUnused, -1, -1, 272 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, 273 "lsrs", "r!0d, r!1d, #!2d", 1), 274 ENCODING_MAP(kThumbLsrRR, 0x40c0, 275 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 276 kFmtUnused, -1, -1, 277 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, 278 "lsrs", "r!0d, r!1d", 1), 279 ENCODING_MAP(kThumbMovImm, 0x2000, 280 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, 281 kFmtUnused, -1, -1, 282 IS_BINARY_OP | REG_DEF0 | SETS_CCODES, 283 "movs", "r!0d, #!1d", 1), 284 ENCODING_MAP(kThumbMovRR, 0x1c00, 285 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 286 kFmtUnused, -1, -1, 287 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES, 288 "movs", "r!0d, r!1d", 1), 289 ENCODING_MAP(kThumbMovRR_H2H, 0x46c0, 290 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 291 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 292 "mov", "r!0d, r!1d", 1), 293 ENCODING_MAP(kThumbMovRR_H2L, 0x4640, 294 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 295 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 296 "mov", "r!0d, r!1d", 1), 297 ENCODING_MAP(kThumbMovRR_L2H, 0x4680, 298 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 299 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 300 "mov", "r!0d, r!1d", 1), 301 ENCODING_MAP(kThumbMul, 0x4340, 302 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 303 kFmtUnused, -1, -1, 304 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, 305 "muls", "r!0d, r!1d", 1), 306 ENCODING_MAP(kThumbMvn, 0x43c0, 307 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 308 kFmtUnused, -1, -1, 309 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES, 310 "mvns", "r!0d, r!1d", 1), 311 ENCODING_MAP(kThumbNeg, 0x4240, 312 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 313 kFmtUnused, -1, -1, 314 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES, 315 "negs", "r!0d, r!1d", 1), 316 ENCODING_MAP(kThumbOrr, 0x4300, 317 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 318 kFmtUnused, -1, -1, 319 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, 320 "orrs", "r!0d, r!1d", 1), 321 ENCODING_MAP(kThumbPop, 0xbc00, 322 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 323 kFmtUnused, -1, -1, 324 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 325 | IS_LOAD, "pop", "<!0R>", 1), 326 ENCODING_MAP(kThumbPush, 0xb400, 327 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 328 kFmtUnused, -1, -1, 329 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0 330 | IS_STORE, "push", "<!0R>", 1), 331 ENCODING_MAP(kThumbRorRR, 0x41c0, 332 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 333 kFmtUnused, -1, -1, 334 IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES, 335 "rors", "r!0d, r!1d", 1), 336 ENCODING_MAP(kThumbSbc, 0x4180, 337 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 338 kFmtUnused, -1, -1, 339 IS_BINARY_OP | REG_DEF0_USE01 | USES_CCODES | SETS_CCODES, 340 "sbcs", "r!0d, r!1d", 1), 341 ENCODING_MAP(kThumbStmia, 0xc000, 342 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, 343 kFmtUnused, -1, -1, 344 IS_BINARY_OP | REG_DEF0 | REG_USE0 | REG_USE_LIST1 | IS_STORE, 345 "stmia", "r!0d!!, <!1R>", 1), 346 ENCODING_MAP(kThumbStrRRI5, 0x6000, 347 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, 348 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, 349 "str", "r!0d, [r!1d, #!2E]", 1), 350 ENCODING_MAP(kThumbStrRRR, 0x5000, 351 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 352 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE, 353 "str", "r!0d, [r!1d, r!2d]", 1), 354 ENCODING_MAP(kThumbStrSpRel, 0x9000, 355 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0, 356 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE0 | REG_USE_SP 357 | IS_STORE, "str", "r!0d, [sp, #!2E]", 1), 358 ENCODING_MAP(kThumbStrbRRI5, 0x7000, 359 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, 360 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, 361 "strb", "r!0d, [r!1d, #!2d]", 1), 362 ENCODING_MAP(kThumbStrbRRR, 0x5400, 363 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 364 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE, 365 "strb", "r!0d, [r!1d, r!2d]", 1), 366 ENCODING_MAP(kThumbStrhRRI5, 0x8000, 367 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6, 368 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, 369 "strh", "r!0d, [r!1d, #!2F]", 1), 370 ENCODING_MAP(kThumbStrhRRR, 0x5200, 371 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 372 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012 | IS_STORE, 373 "strh", "r!0d, [r!1d, r!2d]", 1), 374 ENCODING_MAP(kThumbSubRRI3, 0x1e00, 375 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 376 kFmtUnused, -1, -1, 377 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, 378 "subs", "r!0d, r!1d, #!2d]", 1), 379 ENCODING_MAP(kThumbSubRI8, 0x3800, 380 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, 381 kFmtUnused, -1, -1, 382 IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES, 383 "subs", "r!0d, #!1d", 1), 384 ENCODING_MAP(kThumbSubRRR, 0x1a00, 385 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6, 386 kFmtUnused, -1, -1, 387 IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES, 388 "subs", "r!0d, r!1d, r!2d", 1), 389 ENCODING_MAP(kThumbSubSpI7, 0xb080, 390 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 391 kFmtUnused, -1, -1, 392 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP, 393 "sub", "sp, #!0d", 1), 394 ENCODING_MAP(kThumbSwi, 0xdf00, 395 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH, 396 "swi", "!0d", 1), 397 ENCODING_MAP(kThumbTst, 0x4200, 398 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1, 399 kFmtUnused, -1, -1, IS_UNARY_OP | REG_USE01 | SETS_CCODES, 400 "tst", "r!0d, r!1d", 1), 401 ENCODING_MAP(kThumb2Vldrs, 0xed900a00, 402 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, 403 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 404 "vldr", "!0s, [r!1d, #!2E]", 2), 405 ENCODING_MAP(kThumb2Vldrd, 0xed900b00, 406 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, 407 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 408 "vldr", "!0S, [r!1d, #!2E]", 2), 409 ENCODING_MAP(kThumb2Vmuls, 0xee200a00, 410 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0, 411 kFmtUnused, -1, -1, 412 IS_TERTIARY_OP | REG_DEF0_USE12, 413 "vmuls", "!0s, !1s, !2s", 2), 414 ENCODING_MAP(kThumb2Vmuld, 0xee200b00, 415 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0, 416 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 417 "vmuld", "!0S, !1S, !2S", 2), 418 ENCODING_MAP(kThumb2Vstrs, 0xed800a00, 419 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, 420 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, 421 "vstr", "!0s, [r!1d, #!2E]", 2), 422 ENCODING_MAP(kThumb2Vstrd, 0xed800b00, 423 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, 424 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, 425 "vstr", "!0S, [r!1d, #!2E]", 2), 426 ENCODING_MAP(kThumb2Vsubs, 0xee300a40, 427 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0, 428 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 429 "vsub", "!0s, !1s, !2s", 2), 430 ENCODING_MAP(kThumb2Vsubd, 0xee300b40, 431 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0, 432 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 433 "vsub", "!0S, !1S, !2S", 2), 434 ENCODING_MAP(kThumb2Vadds, 0xee300a00, 435 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0, 436 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 437 "vadd", "!0s, !1s, !2s", 2), 438 ENCODING_MAP(kThumb2Vaddd, 0xee300b00, 439 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0, 440 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 441 "vadd", "!0S, !1S, !2S", 2), 442 ENCODING_MAP(kThumb2Vdivs, 0xee800a00, 443 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0, 444 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 445 "vdivs", "!0s, !1s, !2s", 2), 446 ENCODING_MAP(kThumb2Vdivd, 0xee800b00, 447 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0, 448 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 449 "vdivd", "!0S, !1S, !2S", 2), 450 ENCODING_MAP(kThumb2VcvtIF, 0xeeb80ac0, 451 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 452 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 453 "vcvt.f32", "!0s, !1s", 2), 454 ENCODING_MAP(kThumb2VcvtID, 0xeeb80bc0, 455 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 456 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 457 "vcvt.f64", "!0S, !1s", 2), 458 ENCODING_MAP(kThumb2VcvtFI, 0xeebd0ac0, 459 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 460 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 461 "vcvt.s32.f32 ", "!0s, !1s", 2), 462 ENCODING_MAP(kThumb2VcvtDI, 0xeebd0bc0, 463 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, 464 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 465 "vcvt.s32.f64 ", "!0s, !1S", 2), 466 ENCODING_MAP(kThumb2VcvtFd, 0xeeb70ac0, 467 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 468 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 469 "vcvt.f64.f32 ", "!0S, !1s", 2), 470 ENCODING_MAP(kThumb2VcvtDF, 0xeeb70bc0, 471 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, 472 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 473 "vcvt.f32.f64 ", "!0s, !1S", 2), 474 ENCODING_MAP(kThumb2Vsqrts, 0xeeb10ac0, 475 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 476 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 477 "vsqrt.f32 ", "!0s, !1s", 2), 478 ENCODING_MAP(kThumb2Vsqrtd, 0xeeb10bc0, 479 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, 480 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 481 "vsqrt.f64 ", "!0S, !1S", 2), 482 ENCODING_MAP(kThumb2MovImmShift, 0xf04f0000, /* no setflags encoding */ 483 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1, 484 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, 485 "mov", "r!0d, #!1m", 2), 486 ENCODING_MAP(kThumb2MovImm16, 0xf2400000, 487 kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1, 488 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, 489 "mov", "r!0d, #!1M", 2), 490 ENCODING_MAP(kThumb2StrRRI12, 0xf8c00000, 491 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, 492 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, 493 "str", "r!0d, [r!1d, #!2d]", 2), 494 ENCODING_MAP(kThumb2LdrRRI12, 0xf8d00000, 495 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, 496 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 497 "ldr", "r!0d, [r!1d, #!2d]", 2), 498 ENCODING_MAP(kThumb2StrRRI8Predec, 0xf8400c00, 499 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0, 500 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, 501 "str", "r!0d, [r!1d, #-!2d]", 2), 502 ENCODING_MAP(kThumb2LdrRRI8Predec, 0xf8500c00, 503 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0, 504 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 505 "ldr", "r!0d, [r!1d, #-!2d]", 2), 506 ENCODING_MAP(kThumb2Cbnz, 0xb900, /* Note: does not affect flags */ 507 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1, 508 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH, 509 "cbnz", "r!0d,!1t", 1), 510 ENCODING_MAP(kThumb2Cbz, 0xb100, /* Note: does not affect flags */ 511 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1, 512 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH, 513 "cbz", "r!0d,!1t", 1), 514 ENCODING_MAP(kThumb2AddRRI12, 0xf2000000, 515 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1, 516 kFmtUnused, -1, -1, 517 IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */ 518 "add", "r!0d,r!1d,#!2d", 2), 519 ENCODING_MAP(kThumb2MovRR, 0xea4f0000, /* no setflags encoding */ 520 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, 521 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 522 "mov", "r!0d, r!1d", 2), 523 ENCODING_MAP(kThumb2Vmovs, 0xeeb00a40, 524 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 525 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 526 "vmov.f32 ", " !0s, !1s", 2), 527 ENCODING_MAP(kThumb2Vmovd, 0xeeb00b40, 528 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, 529 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 530 "vmov.f64 ", " !0S, !1S", 2), 531 ENCODING_MAP(kThumb2Ldmia, 0xe8900000, 532 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, 533 kFmtUnused, -1, -1, 534 IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD, 535 "ldmia", "r!0d!!, <!1R>", 2), 536 ENCODING_MAP(kThumb2Stmia, 0xe8800000, 537 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, 538 kFmtUnused, -1, -1, 539 IS_BINARY_OP | REG_DEF0_USE0 | REG_USE_LIST1 | IS_STORE, 540 "stmia", "r!0d!!, <!1R>", 2), 541 ENCODING_MAP(kThumb2AddRRR, 0xeb100000, /* setflags encoding */ 542 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 543 kFmtShift, -1, -1, 544 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES, 545 "adds", "r!0d, r!1d, r!2d!3H", 2), 546 ENCODING_MAP(kThumb2SubRRR, 0xebb00000, /* setflags enconding */ 547 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 548 kFmtShift, -1, -1, 549 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES, 550 "subs", "r!0d, r!1d, r!2d!3H", 2), 551 ENCODING_MAP(kThumb2SbcRRR, 0xeb700000, /* setflags encoding */ 552 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 553 kFmtShift, -1, -1, 554 IS_QUAD_OP | REG_DEF0_USE12 | USES_CCODES | SETS_CCODES, 555 "sbcs", "r!0d, r!1d, r!2d!3H", 2), 556 ENCODING_MAP(kThumb2CmpRR, 0xebb00f00, 557 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, 558 kFmtUnused, -1, -1, 559 IS_TERTIARY_OP | REG_USE01 | SETS_CCODES, 560 "cmp", "r!0d, r!1d", 2), 561 ENCODING_MAP(kThumb2SubRRI12, 0xf2a00000, 562 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1, 563 kFmtUnused, -1, -1, 564 IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */ 565 "sub", "r!0d,r!1d,#!2d", 2), 566 ENCODING_MAP(kThumb2MvnImmShift, 0xf06f0000, /* no setflags encoding */ 567 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1, 568 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, 569 "mvn", "r!0d, #!1n", 2), 570 ENCODING_MAP(kThumb2Sel, 0xfaa0f080, 571 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 572 kFmtUnused, -1, -1, 573 IS_TERTIARY_OP | REG_DEF0_USE12 | USES_CCODES, 574 "sel", "r!0d, r!1d, r!2d", 2), 575 ENCODING_MAP(kThumb2Ubfx, 0xf3c00000, 576 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1, 577 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1, 578 "ubfx", "r!0d, r!1d, #!2d, #!3d", 2), 579 ENCODING_MAP(kThumb2Sbfx, 0xf3400000, 580 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1, 581 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1, 582 "sbfx", "r!0d, r!1d, #!2d, #!3d", 2), 583 ENCODING_MAP(kThumb2LdrRRR, 0xf8500000, 584 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 585 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, 586 "ldr", "r!0d, [r!1d, r!2d, LSL #!3d]", 2), 587 ENCODING_MAP(kThumb2LdrhRRR, 0xf8300000, 588 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 589 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, 590 "ldrh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2), 591 ENCODING_MAP(kThumb2LdrshRRR, 0xf9300000, 592 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 593 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, 594 "ldrsh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2), 595 ENCODING_MAP(kThumb2LdrbRRR, 0xf8100000, 596 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 597 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, 598 "ldrb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2), 599 ENCODING_MAP(kThumb2LdrsbRRR, 0xf9100000, 600 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 601 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12 | IS_LOAD, 602 "ldrsb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2), 603 ENCODING_MAP(kThumb2StrRRR, 0xf8400000, 604 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 605 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE, 606 "str", "r!0d, [r!1d, r!2d, LSL #!3d]", 2), 607 ENCODING_MAP(kThumb2StrhRRR, 0xf8200000, 608 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 609 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE, 610 "strh", "r!0d, [r!1d, r!2d, LSL #!3d]", 2), 611 ENCODING_MAP(kThumb2StrbRRR, 0xf8000000, 612 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 613 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012 | IS_STORE, 614 "strb", "r!0d, [r!1d, r!2d, LSL #!3d]", 2), 615 ENCODING_MAP(kThumb2LdrhRRI12, 0xf8b00000, 616 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, 617 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 618 "ldrh", "r!0d, [r!1d, #!2d]", 2), 619 ENCODING_MAP(kThumb2LdrshRRI12, 0xf9b00000, 620 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, 621 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 622 "ldrsh", "r!0d, [r!1d, #!2d]", 2), 623 ENCODING_MAP(kThumb2LdrbRRI12, 0xf8900000, 624 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, 625 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 626 "ldrb", "r!0d, [r!1d, #!2d]", 2), 627 ENCODING_MAP(kThumb2LdrsbRRI12, 0xf9900000, 628 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, 629 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 630 "ldrsb", "r!0d, [r!1d, #!2d]", 2), 631 ENCODING_MAP(kThumb2StrhRRI12, 0xf8a00000, 632 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, 633 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, 634 "strh", "r!0d, [r!1d, #!2d]", 2), 635 ENCODING_MAP(kThumb2StrbRRI12, 0xf8800000, 636 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0, 637 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01 | IS_STORE, 638 "strb", "r!0d, [r!1d, #!2d]", 2), 639 ENCODING_MAP(kThumb2Pop, 0xe8bd0000, 640 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 641 kFmtUnused, -1, -1, 642 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 643 | IS_LOAD, "pop", "<!0R>", 2), 644 ENCODING_MAP(kThumb2Push, 0xe92d0000, 645 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 646 kFmtUnused, -1, -1, 647 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0 648 | IS_STORE, "push", "<!0R>", 2), 649 ENCODING_MAP(kThumb2CmpRI8, 0xf1b00f00, 650 kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1, 651 kFmtUnused, -1, -1, 652 IS_BINARY_OP | REG_USE0 | SETS_CCODES, 653 "cmp", "r!0d, #!1m", 2), 654 ENCODING_MAP(kThumb2AdcRRR, 0xeb500000, /* setflags encoding */ 655 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 656 kFmtShift, -1, -1, 657 IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES, 658 "adcs", "r!0d, r!1d, r!2d!3H", 2), 659 ENCODING_MAP(kThumb2AndRRR, 0xea000000, 660 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 661 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12, 662 "and", "r!0d, r!1d, r!2d!3H", 2), 663 ENCODING_MAP(kThumb2BicRRR, 0xea200000, 664 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 665 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12, 666 "bic", "r!0d, r!1d, r!2d!3H", 2), 667 ENCODING_MAP(kThumb2CmnRR, 0xeb000000, 668 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, 669 kFmtUnused, -1, -1, 670 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, 671 "cmn", "r!0d, r!1d, shift !2d", 2), 672 ENCODING_MAP(kThumb2EorRRR, 0xea800000, 673 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 674 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12, 675 "eor", "r!0d, r!1d, r!2d!3H", 2), 676 ENCODING_MAP(kThumb2MulRRR, 0xfb00f000, 677 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 678 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 679 "mul", "r!0d, r!1d, r!2d", 2), 680 ENCODING_MAP(kThumb2MnvRR, 0xea6f0000, 681 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, 682 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, 683 "mvn", "r!0d, r!1d, shift !2d", 2), 684 ENCODING_MAP(kThumb2RsubRRI8, 0xf1d00000, 685 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, 686 kFmtUnused, -1, -1, 687 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, 688 "rsb", "r!0d,r!1d,#!2m", 2), 689 ENCODING_MAP(kThumb2NegRR, 0xf1d00000, /* instance of rsub */ 690 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtUnused, -1, -1, 691 kFmtUnused, -1, -1, 692 IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES, 693 "neg", "r!0d,r!1d", 2), 694 ENCODING_MAP(kThumb2OrrRRR, 0xea400000, 695 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 696 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12, 697 "orr", "r!0d, r!1d, r!2d!3H", 2), 698 ENCODING_MAP(kThumb2TstRR, 0xea100f00, 699 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, 700 kFmtUnused, -1, -1, 701 IS_TERTIARY_OP | REG_USE01 | SETS_CCODES, 702 "tst", "r!0d, r!1d, shift !2d", 2), 703 ENCODING_MAP(kThumb2LslRRR, 0xfa00f000, 704 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 705 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 706 "lsl", "r!0d, r!1d, r!2d", 2), 707 ENCODING_MAP(kThumb2LsrRRR, 0xfa20f000, 708 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 709 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 710 "lsr", "r!0d, r!1d, r!2d", 2), 711 ENCODING_MAP(kThumb2AsrRRR, 0xfa40f000, 712 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 713 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 714 "asr", "r!0d, r!1d, r!2d", 2), 715 ENCODING_MAP(kThumb2RorRRR, 0xfa60f000, 716 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 717 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 718 "ror", "r!0d, r!1d, r!2d", 2), 719 ENCODING_MAP(kThumb2LslRRI5, 0xea4f0000, 720 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1, 721 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, 722 "lsl", "r!0d, r!1d, #!2d", 2), 723 ENCODING_MAP(kThumb2LsrRRI5, 0xea4f0010, 724 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1, 725 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, 726 "lsr", "r!0d, r!1d, #!2d", 2), 727 ENCODING_MAP(kThumb2AsrRRI5, 0xea4f0020, 728 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1, 729 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, 730 "asr", "r!0d, r!1d, #!2d", 2), 731 ENCODING_MAP(kThumb2RorRRI5, 0xea4f0030, 732 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1, 733 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, 734 "ror", "r!0d, r!1d, #!2d", 2), 735 ENCODING_MAP(kThumb2BicRRI8, 0xf0200000, 736 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, 737 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, 738 "bic", "r!0d, r!1d, #!2m", 2), 739 ENCODING_MAP(kThumb2AndRRI8, 0xf0000000, 740 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, 741 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, 742 "and", "r!0d, r!1d, #!2m", 2), 743 ENCODING_MAP(kThumb2OrrRRI8, 0xf0400000, 744 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, 745 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, 746 "orr", "r!0d, r!1d, #!2m", 2), 747 ENCODING_MAP(kThumb2EorRRI8, 0xf0800000, 748 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, 749 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, 750 "eor", "r!0d, r!1d, #!2m", 2), 751 ENCODING_MAP(kThumb2AddRRI8, 0xf1100000, 752 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, 753 kFmtUnused, -1, -1, 754 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, 755 "adds", "r!0d, r!1d, #!2m", 2), 756 ENCODING_MAP(kThumb2AdcRRI8, 0xf1500000, 757 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, 758 kFmtUnused, -1, -1, 759 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES, 760 "adcs", "r!0d, r!1d, #!2m", 2), 761 ENCODING_MAP(kThumb2SubRRI8, 0xf1b00000, 762 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, 763 kFmtUnused, -1, -1, 764 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES, 765 "subs", "r!0d, r!1d, #!2m", 2), 766 ENCODING_MAP(kThumb2SbcRRI8, 0xf1700000, 767 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, 768 kFmtUnused, -1, -1, 769 IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES, 770 "sbcs", "r!0d, r!1d, #!2m", 2), 771 ENCODING_MAP(kThumb2It, 0xbf00, 772 kFmtBitBlt, 7, 4, kFmtBitBlt, 3, 0, kFmtModImm, -1, -1, 773 kFmtUnused, -1, -1, IS_BINARY_OP | IS_IT | USES_CCODES, 774 "it:!1b", "!0c", 1), 775 ENCODING_MAP(kThumb2Fmstat, 0xeef1fa10, 776 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 777 kFmtUnused, -1, -1, NO_OPERAND | SETS_CCODES, 778 "fmstat", "", 2), 779 ENCODING_MAP(kThumb2Vcmpd, 0xeeb40b40, 780 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, 781 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01, 782 "vcmp.f64", "!0S, !1S", 2), 783 ENCODING_MAP(kThumb2Vcmps, 0xeeb40a40, 784 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 785 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01, 786 "vcmp.f32", "!0s, !1s", 2), 787 ENCODING_MAP(kThumb2LdrPcRel12, 0xf8df0000, 788 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, 789 kFmtUnused, -1, -1, 790 IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD, 791 "ldr", "r!0d, [r15pc, #!1d]", 2), 792 ENCODING_MAP(kThumb2BCond, 0xf0008000, 793 kFmtBrOffset, -1, -1, kFmtBitBlt, 25, 22, kFmtUnused, -1, -1, 794 kFmtUnused, -1, -1, 795 IS_BINARY_OP | IS_BRANCH | USES_CCODES, 796 "b!1c", "!0t", 2), 797 ENCODING_MAP(kThumb2Vmovd_RR, 0xeeb00b40, 798 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, 799 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 800 "vmov.f64", "!0S, !1S", 2), 801 ENCODING_MAP(kThumb2Vmovs_RR, 0xeeb00a40, 802 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 803 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 804 "vmov.f32", "!0s, !1s", 2), 805 ENCODING_MAP(kThumb2Fmrs, 0xee100a10, 806 kFmtBitBlt, 15, 12, kFmtSfp, 7, 16, kFmtUnused, -1, -1, 807 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 808 "fmrs", "r!0d, !1s", 2), 809 ENCODING_MAP(kThumb2Fmsr, 0xee000a10, 810 kFmtSfp, 7, 16, kFmtBitBlt, 15, 12, kFmtUnused, -1, -1, 811 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 812 "fmsr", "!0s, r!1d", 2), 813 ENCODING_MAP(kThumb2Fmrrd, 0xec500b10, 814 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtDfp, 5, 0, 815 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF01_USE2, 816 "fmrrd", "r!0d, r!1d, !2S", 2), 817 ENCODING_MAP(kThumb2Fmdrr, 0xec400b10, 818 kFmtDfp, 5, 0, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, 819 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, 820 "fmdrr", "!0S, r!1d, r!2d", 2), 821 ENCODING_MAP(kThumb2Vabsd, 0xeeb00bc0, 822 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, 823 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 824 "vabs.f64", "!0S, !1S", 2), 825 ENCODING_MAP(kThumb2Vabss, 0xeeb00ac0, 826 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 827 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 828 "vabs.f32", "!0s, !1s", 2), 829 ENCODING_MAP(kThumb2Vnegd, 0xeeb10b40, 830 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1, 831 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 832 "vneg.f64", "!0S, !1S", 2), 833 ENCODING_MAP(kThumb2Vnegs, 0xeeb10a40, 834 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1, 835 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1, 836 "vneg.f32", "!0s, !1s", 2), 837 ENCODING_MAP(kThumb2Vmovs_IMM8, 0xeeb00a00, 838 kFmtSfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1, 839 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, 840 "vmov.f32", "!0s, #0x!1h", 2), 841 ENCODING_MAP(kThumb2Vmovd_IMM8, 0xeeb00b00, 842 kFmtDfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1, 843 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0, 844 "vmov.f64", "!0S, #0x!1h", 2), 845 ENCODING_MAP(kThumb2Mla, 0xfb000000, 846 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, 847 kFmtBitBlt, 15, 12, 848 IS_QUAD_OP | REG_DEF0 | REG_USE1 | REG_USE2 | REG_USE3, 849 "mla", "r!0d, r!1d, r!2d, r!3d", 2), 850 ENCODING_MAP(kThumb2Umull, 0xfba00000, 851 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, 852 kFmtBitBlt, 3, 0, 853 IS_QUAD_OP | REG_DEF0 | REG_DEF1 | REG_USE2 | REG_USE3, 854 "umull", "r!0d, r!1d, r!2d, r!3d", 2), 855 ENCODING_MAP(kThumb2Ldrex, 0xe8500f00, 856 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0, 857 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1 | IS_LOAD, 858 "ldrex", "r!0d, [r!1d, #!2E]", 2), 859 ENCODING_MAP(kThumb2Strex, 0xe8400000, 860 kFmtBitBlt, 11, 8, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, 861 kFmtBitBlt, 7, 0, IS_QUAD_OP | REG_DEF0_USE12 | IS_STORE, 862 "strex", "r!0d,r!1d, [r!2d, #!2E]", 2), 863 ENCODING_MAP(kThumb2Clrex, 0xf3bf8f2f, 864 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 865 kFmtUnused, -1, -1, NO_OPERAND, 866 "clrex", "", 2), 867 ENCODING_MAP(kThumb2Bfi, 0xf3600000, 868 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtShift5, -1, -1, 869 kFmtBitBlt, 4, 0, IS_QUAD_OP | REG_DEF0_USE1, 870 "bfi", "r!0d,r!1d,#!2d,#!3d", 2), 871 ENCODING_MAP(kThumb2Bfc, 0xf36f0000, 872 kFmtBitBlt, 11, 8, kFmtShift5, -1, -1, kFmtBitBlt, 4, 0, 873 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0, 874 "bfc", "r!0d,#!1d,#!2d", 2), 875 ENCODING_MAP(kThumb2Dmb, 0xf3bf8f50, 876 kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 877 kFmtUnused, -1, -1, IS_UNARY_OP, 878 "dmb","#!0B",2), 879 ENCODING_MAP(kThumb2LdrPcReln12, 0xf85f0000, 880 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1, 881 kFmtUnused, -1, -1, 882 IS_BINARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD, 883 "ldr", "r!0d, [r15pc, -#!1d]", 2), 884 ENCODING_MAP(kThumbUndefined, 0xde00, 885 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1, 886 kFmtUnused, -1, -1, NO_OPERAND, 887 "undefined", "", 1), 888 }; 889 890 /* 891 * The fake NOP of moving r0 to r0 actually will incur data stalls if r0 is 892 * not ready. Since r5FP is not updated often, it is less likely to 893 * generate unnecessary stall cycles. 894 */ 895 #define PADDING_MOV_R5_R5 0x1C2D 896 897 /* Track the number of times that the code cache is patched */ 898 #if defined(WITH_JIT_TUNING) 899 #define UPDATE_CODE_CACHE_PATCHES() (gDvmJit.codeCachePatches++) 900 #else 901 #define UPDATE_CODE_CACHE_PATCHES() 902 #endif 903 904 /* Write the numbers in the constant and class pool to the output stream */ 905 static void installLiteralPools(CompilationUnit *cUnit) 906 { 907 int *dataPtr = (int *) ((char *) cUnit->baseAddr + cUnit->dataOffset); 908 /* Install number of class pointer literals */ 909 *dataPtr++ = cUnit->numClassPointers; 910 ArmLIR *dataLIR = (ArmLIR *) cUnit->classPointerList; 911 while (dataLIR) { 912 /* 913 * Install the callsiteinfo pointers into the cells for now. They will 914 * be converted into real pointers in dvmJitInstallClassObjectPointers. 915 */ 916 *dataPtr++ = dataLIR->operands[0]; 917 dataLIR = NEXT_LIR(dataLIR); 918 } 919 dataLIR = (ArmLIR *) cUnit->literalList; 920 while (dataLIR) { 921 *dataPtr++ = dataLIR->operands[0]; 922 dataLIR = NEXT_LIR(dataLIR); 923 } 924 } 925 926 /* 927 * Assemble the LIR into binary instruction format. Note that we may 928 * discover that pc-relative displacements may not fit the selected 929 * instruction. In those cases we will try to substitute a new code 930 * sequence or request that the trace be shortened and retried. 931 */ 932 static AssemblerStatus assembleInstructions(CompilationUnit *cUnit, 933 intptr_t startAddr) 934 { 935 short *bufferAddr = (short *) cUnit->codeBuffer; 936 ArmLIR *lir; 937 938 for (lir = (ArmLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) { 939 if (lir->opcode < 0) { 940 if ((lir->opcode == kArmPseudoPseudoAlign4) && 941 /* 1 means padding is needed */ 942 (lir->operands[0] == 1)) { 943 *bufferAddr++ = PADDING_MOV_R5_R5; 944 } 945 continue; 946 } 947 948 if (lir->flags.isNop) { 949 continue; 950 } 951 952 if (lir->opcode == kThumbLdrPcRel || 953 lir->opcode == kThumb2LdrPcRel12 || 954 lir->opcode == kThumbAddPcRel || 955 ((lir->opcode == kThumb2Vldrs) && (lir->operands[1] == r15pc))) { 956 ArmLIR *lirTarget = (ArmLIR *) lir->generic.target; 957 intptr_t pc = (lir->generic.offset + 4) & ~3; 958 intptr_t target = lirTarget->generic.offset; 959 int delta = target - pc; 960 if (delta & 0x3) { 961 LOGE("PC-rel distance is not multiples of 4: %d", delta); 962 dvmCompilerAbort(cUnit); 963 } 964 if ((lir->opcode == kThumb2LdrPcRel12) && (delta > 4091)) { 965 if (cUnit->printMe) { 966 LOGD("kThumb2LdrPcRel12@%x: delta=%d", lir->generic.offset, 967 delta); 968 dvmCompilerCodegenDump(cUnit); 969 } 970 return kRetryHalve; 971 } else if (delta > 1020) { 972 if (cUnit->printMe) { 973 LOGD("kThumbLdrPcRel@%x: delta=%d", lir->generic.offset, 974 delta); 975 dvmCompilerCodegenDump(cUnit); 976 } 977 return kRetryHalve; 978 } 979 if (lir->opcode == kThumb2Vldrs) { 980 lir->operands[2] = delta >> 2; 981 } else { 982 lir->operands[1] = (lir->opcode == kThumb2LdrPcRel12) ? 983 delta : delta >> 2; 984 } 985 } else if (lir->opcode == kThumb2Cbnz || lir->opcode == kThumb2Cbz) { 986 ArmLIR *targetLIR = (ArmLIR *) lir->generic.target; 987 intptr_t pc = lir->generic.offset + 4; 988 intptr_t target = targetLIR->generic.offset; 989 int delta = target - pc; 990 if (delta > 126 || delta < 0) { 991 /* Convert to cmp rx,#0 / b[eq/ne] tgt pair */ 992 ArmLIR *newInst = 993 (ArmLIR *)dvmCompilerNew(sizeof(ArmLIR), true); 994 /* Make new branch instruction and insert after */ 995 newInst->opcode = kThumbBCond; 996 newInst->operands[0] = 0; 997 newInst->operands[1] = (lir->opcode == kThumb2Cbz) ? 998 kArmCondEq : kArmCondNe; 999 newInst->generic.target = lir->generic.target; 1000 dvmCompilerSetupResourceMasks(newInst); 1001 dvmCompilerInsertLIRAfter((LIR *)lir, (LIR *)newInst); 1002 /* Convert the cb[n]z to a cmp rx, #0 ] */ 1003 lir->opcode = kThumbCmpRI8; 1004 /* operand[0] is src1 in both cb[n]z & CmpRI8 */ 1005 lir->operands[1] = 0; 1006 lir->generic.target = 0; 1007 dvmCompilerSetupResourceMasks(lir); 1008 if (cUnit->printMe) { 1009 LOGD("kThumb2Cbnz/kThumb2Cbz@%x: delta=%d", 1010 lir->generic.offset, delta); 1011 dvmCompilerCodegenDump(cUnit); 1012 } 1013 return kRetryAll; 1014 } else { 1015 lir->operands[1] = delta >> 1; 1016 } 1017 } else if (lir->opcode == kThumbBCond || 1018 lir->opcode == kThumb2BCond) { 1019 ArmLIR *targetLIR = (ArmLIR *) lir->generic.target; 1020 intptr_t pc = lir->generic.offset + 4; 1021 intptr_t target = targetLIR->generic.offset; 1022 int delta = target - pc; 1023 if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) { 1024 if (cUnit->printMe) { 1025 LOGD("kThumbBCond@%x: delta=%d", lir->generic.offset, 1026 delta); 1027 dvmCompilerCodegenDump(cUnit); 1028 } 1029 return kRetryHalve; 1030 } 1031 lir->operands[0] = delta >> 1; 1032 } else if (lir->opcode == kThumbBUncond) { 1033 ArmLIR *targetLIR = (ArmLIR *) lir->generic.target; 1034 intptr_t pc = lir->generic.offset + 4; 1035 intptr_t target = targetLIR->generic.offset; 1036 int delta = target - pc; 1037 if (delta > 2046 || delta < -2048) { 1038 LOGE("Unconditional branch distance out of range: %d", delta); 1039 dvmCompilerAbort(cUnit); 1040 } 1041 lir->operands[0] = delta >> 1; 1042 } else if (lir->opcode == kThumbBlx1) { 1043 assert(NEXT_LIR(lir)->opcode == kThumbBlx2); 1044 /* curPC is Thumb */ 1045 intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3; 1046 intptr_t target = lir->operands[1]; 1047 1048 /* Match bit[1] in target with base */ 1049 if (curPC & 0x2) { 1050 target |= 0x2; 1051 } 1052 int delta = target - curPC; 1053 assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2))); 1054 1055 lir->operands[0] = (delta >> 12) & 0x7ff; 1056 NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff; 1057 } else if (lir->opcode == kThumbBl1) { 1058 assert(NEXT_LIR(lir)->opcode == kThumbBl2); 1059 /* Both curPC and target are Thumb */ 1060 intptr_t curPC = startAddr + lir->generic.offset + 4; 1061 intptr_t target = lir->operands[1]; 1062 1063 int delta = target - curPC; 1064 assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2))); 1065 1066 lir->operands[0] = (delta >> 12) & 0x7ff; 1067 NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff; 1068 } 1069 1070 ArmEncodingMap *encoder = &EncodingMap[lir->opcode]; 1071 u4 bits = encoder->skeleton; 1072 int i; 1073 for (i = 0; i < 4; i++) { 1074 u4 operand; 1075 u4 value; 1076 operand = lir->operands[i]; 1077 switch(encoder->fieldLoc[i].kind) { 1078 case kFmtUnused: 1079 break; 1080 case kFmtFPImm: 1081 value = ((operand & 0xF0) >> 4) << encoder->fieldLoc[i].end; 1082 value |= (operand & 0x0F) << encoder->fieldLoc[i].start; 1083 bits |= value; 1084 break; 1085 case kFmtBrOffset: 1086 value = ((operand & 0x80000) >> 19) << 26; 1087 value |= ((operand & 0x40000) >> 18) << 11; 1088 value |= ((operand & 0x20000) >> 17) << 13; 1089 value |= ((operand & 0x1f800) >> 11) << 16; 1090 value |= (operand & 0x007ff); 1091 bits |= value; 1092 break; 1093 case kFmtShift5: 1094 value = ((operand & 0x1c) >> 2) << 12; 1095 value |= (operand & 0x03) << 6; 1096 bits |= value; 1097 break; 1098 case kFmtShift: 1099 value = ((operand & 0x70) >> 4) << 12; 1100 value |= (operand & 0x0f) << 4; 1101 bits |= value; 1102 break; 1103 case kFmtBWidth: 1104 value = operand - 1; 1105 bits |= value; 1106 break; 1107 case kFmtLsb: 1108 value = ((operand & 0x1c) >> 2) << 12; 1109 value |= (operand & 0x03) << 6; 1110 bits |= value; 1111 break; 1112 case kFmtImm6: 1113 value = ((operand & 0x20) >> 5) << 9; 1114 value |= (operand & 0x1f) << 3; 1115 bits |= value; 1116 break; 1117 case kFmtBitBlt: 1118 value = (operand << encoder->fieldLoc[i].start) & 1119 ((1 << (encoder->fieldLoc[i].end + 1)) - 1); 1120 bits |= value; 1121 break; 1122 case kFmtDfp: { 1123 assert(DOUBLEREG(operand)); 1124 assert((operand & 0x1) == 0); 1125 int regName = (operand & FP_REG_MASK) >> 1; 1126 /* Snag the 1-bit slice and position it */ 1127 value = ((regName & 0x10) >> 4) << 1128 encoder->fieldLoc[i].end; 1129 /* Extract and position the 4-bit slice */ 1130 value |= (regName & 0x0f) << 1131 encoder->fieldLoc[i].start; 1132 bits |= value; 1133 break; 1134 } 1135 case kFmtSfp: 1136 assert(SINGLEREG(operand)); 1137 /* Snag the 1-bit slice and position it */ 1138 value = (operand & 0x1) << 1139 encoder->fieldLoc[i].end; 1140 /* Extract and position the 4-bit slice */ 1141 value |= ((operand & 0x1e) >> 1) << 1142 encoder->fieldLoc[i].start; 1143 bits |= value; 1144 break; 1145 case kFmtImm12: 1146 case kFmtModImm: 1147 value = ((operand & 0x800) >> 11) << 26; 1148 value |= ((operand & 0x700) >> 8) << 12; 1149 value |= operand & 0x0ff; 1150 bits |= value; 1151 break; 1152 case kFmtImm16: 1153 value = ((operand & 0x0800) >> 11) << 26; 1154 value |= ((operand & 0xf000) >> 12) << 16; 1155 value |= ((operand & 0x0700) >> 8) << 12; 1156 value |= operand & 0x0ff; 1157 bits |= value; 1158 break; 1159 default: 1160 assert(0); 1161 } 1162 } 1163 if (encoder->size == 2) { 1164 *bufferAddr++ = (bits >> 16) & 0xffff; 1165 } 1166 *bufferAddr++ = bits & 0xffff; 1167 } 1168 return kSuccess; 1169 } 1170 1171 static int assignLiteralOffsetCommon(LIR *lir, int offset) 1172 { 1173 for (;lir != NULL; lir = lir->next) { 1174 lir->offset = offset; 1175 offset += 4; 1176 } 1177 return offset; 1178 } 1179 1180 /* Determine the offset of each literal field */ 1181 static int assignLiteralOffset(CompilationUnit *cUnit, int offset) 1182 { 1183 /* Reserved for the size field of class pointer pool */ 1184 offset += 4; 1185 offset = assignLiteralOffsetCommon(cUnit->classPointerList, offset); 1186 offset = assignLiteralOffsetCommon(cUnit->literalList, offset); 1187 return offset; 1188 } 1189 1190 /* 1191 * Translation layout in the code cache. Note that the codeAddress pointer 1192 * in JitTable will point directly to the code body (field codeAddress). The 1193 * chain cell offset codeAddress - 2, and the address of the trace profile 1194 * counter is at codeAddress - 6. 1195 * 1196 * +----------------------------+ 1197 * | Trace Profile Counter addr | -> 4 bytes (PROF_COUNTER_ADDR_SIZE) 1198 * +----------------------------+ 1199 * +--| Offset to chain cell counts| -> 2 bytes (CHAIN_CELL_OFFSET_SIZE) 1200 * | +----------------------------+ 1201 * | | Trace profile code | <- entry point when profiling 1202 * | . - - - - - - - . 1203 * | | Code body | <- entry point when not profiling 1204 * | . . 1205 * | | | 1206 * | +----------------------------+ 1207 * | | Chaining Cells | -> 12/16 bytes, 4 byte aligned 1208 * | . . 1209 * | . . 1210 * | | | 1211 * | +----------------------------+ 1212 * | | Gap for large switch stmt | -> # cases >= MAX_CHAINED_SWITCH_CASES 1213 * | +----------------------------+ 1214 * +->| Chaining cell counts | -> 8 bytes, chain cell counts by type 1215 * +----------------------------+ 1216 * | Trace description | -> variable sized 1217 * . . 1218 * | | 1219 * +----------------------------+ 1220 * | # Class pointer pool size | -> 4 bytes 1221 * +----------------------------+ 1222 * | Class pointer pool | -> 4-byte aligned, variable size 1223 * . . 1224 * . . 1225 * | | 1226 * +----------------------------+ 1227 * | Literal pool | -> 4-byte aligned, variable size 1228 * . . 1229 * . . 1230 * | | 1231 * +----------------------------+ 1232 * 1233 */ 1234 1235 #define PROF_COUNTER_ADDR_SIZE 4 1236 #define CHAIN_CELL_OFFSET_SIZE 2 1237 1238 /* 1239 * Utility functions to navigate various parts in a trace. If we change the 1240 * layout/offset in the future, we just modify these functions and we don't need 1241 * to propagate the changes to all the use cases. 1242 */ 1243 static inline char *getTraceBase(const JitEntry *p) 1244 { 1245 return (char*)p->codeAddress - 1246 (PROF_COUNTER_ADDR_SIZE + CHAIN_CELL_OFFSET_SIZE + 1247 (p->u.info.instructionSet == DALVIK_JIT_ARM ? 0 : 1)); 1248 } 1249 1250 /* Handy function to retrieve the profile count */ 1251 static inline JitTraceCounter_t getProfileCount(const JitEntry *entry) 1252 { 1253 if (entry->dPC == 0 || entry->codeAddress == 0 || 1254 entry->codeAddress == dvmCompilerGetInterpretTemplate()) 1255 return 0; 1256 1257 JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry); 1258 1259 return **p; 1260 } 1261 1262 /* Handy function to reset the profile count */ 1263 static inline void resetProfileCount(const JitEntry *entry) 1264 { 1265 if (entry->dPC == 0 || entry->codeAddress == 0 || 1266 entry->codeAddress == dvmCompilerGetInterpretTemplate()) 1267 return; 1268 1269 JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry); 1270 1271 **p = 0; 1272 } 1273 1274 /* Get the pointer of the chain cell count */ 1275 static inline ChainCellCounts* getChainCellCountsPointer(const char *base) 1276 { 1277 /* 4 is the size of the profile count */ 1278 u2 *chainCellOffsetP = (u2 *) (base + PROF_COUNTER_ADDR_SIZE); 1279 u2 chainCellOffset = *chainCellOffsetP; 1280 return (ChainCellCounts *) ((char *) chainCellOffsetP + chainCellOffset); 1281 } 1282 1283 /* Get the size of all chaining cells */ 1284 static inline u4 getChainCellSize(const ChainCellCounts* pChainCellCounts) 1285 { 1286 int cellSize = 0; 1287 int i; 1288 1289 /* Get total count of chain cells */ 1290 for (i = 0; i < kChainingCellGap; i++) { 1291 if (i != kChainingCellInvokePredicted) { 1292 cellSize += pChainCellCounts->u.count[i] * 1293 (CHAIN_CELL_NORMAL_SIZE >> 2); 1294 } else { 1295 cellSize += pChainCellCounts->u.count[i] * 1296 (CHAIN_CELL_PREDICTED_SIZE >> 2); 1297 } 1298 } 1299 return cellSize; 1300 } 1301 1302 /* Get the starting pointer of the trace description section */ 1303 static JitTraceDescription* getTraceDescriptionPointer(const char *base) 1304 { 1305 ChainCellCounts* pCellCounts = getChainCellCountsPointer(base); 1306 return (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts)); 1307 } 1308 1309 /* Get the size of a trace description */ 1310 static int getTraceDescriptionSize(const JitTraceDescription *desc) 1311 { 1312 int runCount; 1313 /* Trace end is always of non-meta type (ie isCode == true) */ 1314 for (runCount = 0; ; runCount++) { 1315 if (desc->trace[runCount].isCode && 1316 desc->trace[runCount].info.frag.runEnd) 1317 break; 1318 } 1319 return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun)); 1320 } 1321 1322 #if defined(SIGNATURE_BREAKPOINT) 1323 /* Inspect the assembled instruction stream to find potential matches */ 1324 static void matchSignatureBreakpoint(const CompilationUnit *cUnit, 1325 unsigned int size) 1326 { 1327 unsigned int i, j; 1328 u4 *ptr = (u4 *) cUnit->codeBuffer; 1329 1330 for (i = 0; i < size - gDvmJit.signatureBreakpointSize + 1; i++) { 1331 if (ptr[i] == gDvmJit.signatureBreakpoint[0]) { 1332 for (j = 1; j < gDvmJit.signatureBreakpointSize; j++) { 1333 if (ptr[i+j] != gDvmJit.signatureBreakpoint[j]) { 1334 break; 1335 } 1336 } 1337 if (j == gDvmJit.signatureBreakpointSize) { 1338 LOGD("Signature match starting from offset %#x (%d words)", 1339 i*4, gDvmJit.signatureBreakpointSize); 1340 int descSize = getTraceDescriptionSize(cUnit->traceDesc); 1341 JitTraceDescription *newCopy = 1342 (JitTraceDescription *) malloc(descSize); 1343 memcpy(newCopy, cUnit->traceDesc, descSize); 1344 dvmCompilerWorkEnqueue(NULL, kWorkOrderTraceDebug, newCopy); 1345 break; 1346 } 1347 } 1348 } 1349 } 1350 #endif 1351 1352 /* 1353 * Go over each instruction in the list and calculate the offset from the top 1354 * before sending them off to the assembler. If out-of-range branch distance is 1355 * seen rearrange the instructions a bit to correct it. 1356 */ 1357 void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info) 1358 { 1359 ArmLIR *armLIR; 1360 int offset = 0; 1361 int i; 1362 ChainCellCounts chainCellCounts; 1363 int descSize = (cUnit->jitMode == kJitMethod) ? 1364 0 : getTraceDescriptionSize(cUnit->traceDesc); 1365 int chainingCellGap = 0; 1366 1367 info->instructionSet = cUnit->instructionSet; 1368 1369 /* Beginning offset needs to allow space for chain cell offset */ 1370 for (armLIR = (ArmLIR *) cUnit->firstLIRInsn; 1371 armLIR; 1372 armLIR = NEXT_LIR(armLIR)) { 1373 armLIR->generic.offset = offset; 1374 if (armLIR->opcode >= 0 && !armLIR->flags.isNop) { 1375 armLIR->flags.size = EncodingMap[armLIR->opcode].size * 2; 1376 offset += armLIR->flags.size; 1377 } else if (armLIR->opcode == kArmPseudoPseudoAlign4) { 1378 if (offset & 0x2) { 1379 offset += 2; 1380 armLIR->operands[0] = 1; 1381 } else { 1382 armLIR->operands[0] = 0; 1383 } 1384 } 1385 /* Pseudo opcodes don't consume space */ 1386 } 1387 1388 /* Const values have to be word aligned */ 1389 offset = (offset + 3) & ~3; 1390 1391 u4 chainCellOffset = offset; 1392 ArmLIR *chainCellOffsetLIR = NULL; 1393 1394 if (cUnit->jitMode != kJitMethod) { 1395 /* 1396 * Get the gap (# of u4) between the offset of chaining cell count and 1397 * the bottom of real chaining cells. If the translation has chaining 1398 * cells, the gap is guaranteed to be multiples of 4. 1399 */ 1400 chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2; 1401 1402 /* Add space for chain cell counts & trace description */ 1403 chainCellOffsetLIR = (ArmLIR *) cUnit->chainCellOffsetLIR; 1404 assert(chainCellOffsetLIR); 1405 assert(chainCellOffset < 0x10000); 1406 assert(chainCellOffsetLIR->opcode == kArm16BitData && 1407 chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG); 1408 1409 /* 1410 * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the 1411 * space occupied by the pointer to the trace profiling counter. 1412 */ 1413 chainCellOffsetLIR->operands[0] = chainCellOffset - 4; 1414 1415 offset += sizeof(chainCellCounts) + descSize; 1416 1417 assert((offset & 0x3) == 0); /* Should still be word aligned */ 1418 } 1419 1420 /* Set up offsets for literals */ 1421 cUnit->dataOffset = offset; 1422 1423 /* 1424 * Assign each class pointer/constant an offset from the beginning of the 1425 * compilation unit. 1426 */ 1427 offset = assignLiteralOffset(cUnit, offset); 1428 1429 cUnit->totalSize = offset; 1430 1431 if (gDvmJit.codeCacheByteUsed + cUnit->totalSize > gDvmJit.codeCacheSize) { 1432 gDvmJit.codeCacheFull = true; 1433 info->discardResult = true; 1434 return; 1435 } 1436 1437 /* Allocate enough space for the code block */ 1438 cUnit->codeBuffer = (unsigned char *)dvmCompilerNew(chainCellOffset, true); 1439 if (cUnit->codeBuffer == NULL) { 1440 LOGE("Code buffer allocation failure"); 1441 info->discardResult = true; 1442 return; 1443 } 1444 1445 /* 1446 * Attempt to assemble the trace. Note that assembleInstructions 1447 * may rewrite the code sequence and request a retry. 1448 */ 1449 cUnit->assemblerStatus = assembleInstructions(cUnit, 1450 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed); 1451 1452 switch(cUnit->assemblerStatus) { 1453 case kSuccess: 1454 break; 1455 case kRetryAll: 1456 if (cUnit->assemblerRetries < MAX_ASSEMBLER_RETRIES) { 1457 if (cUnit->jitMode != kJitMethod) { 1458 /* Restore pristine chain cell marker on retry */ 1459 chainCellOffsetLIR->operands[0] = CHAIN_CELL_OFFSET_TAG; 1460 } 1461 return; 1462 } 1463 /* Too many retries - reset and try cutting the trace in half */ 1464 cUnit->assemblerRetries = 0; 1465 cUnit->assemblerStatus = kRetryHalve; 1466 return; 1467 case kRetryHalve: 1468 return; 1469 default: 1470 LOGE("Unexpected assembler status: %d", cUnit->assemblerStatus); 1471 dvmAbort(); 1472 } 1473 1474 #if defined(SIGNATURE_BREAKPOINT) 1475 if (info->discardResult == false && gDvmJit.signatureBreakpoint != NULL && 1476 chainCellOffset/4 >= gDvmJit.signatureBreakpointSize) { 1477 matchSignatureBreakpoint(cUnit, chainCellOffset/4); 1478 } 1479 #endif 1480 1481 /* Don't go all the way if the goal is just to get the verbose output */ 1482 if (info->discardResult) return; 1483 1484 /* 1485 * The cache might disappear - acquire lock and check version 1486 * Continue holding lock until translation cache update is complete. 1487 * These actions are required here in the compiler thread because 1488 * it is unaffected by suspend requests and doesn't know if a 1489 * translation cache flush is in progress. 1490 */ 1491 dvmLockMutex(&gDvmJit.compilerLock); 1492 if (info->cacheVersion != gDvmJit.cacheVersion) { 1493 /* Cache changed - discard current translation */ 1494 info->discardResult = true; 1495 info->codeAddress = NULL; 1496 dvmUnlockMutex(&gDvmJit.compilerLock); 1497 return; 1498 } 1499 1500 cUnit->baseAddr = (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed; 1501 gDvmJit.codeCacheByteUsed += offset; 1502 1503 UNPROTECT_CODE_CACHE(cUnit->baseAddr, offset); 1504 1505 /* Install the code block */ 1506 memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset); 1507 gDvmJit.numCompilations++; 1508 1509 if (cUnit->jitMode != kJitMethod) { 1510 /* Install the chaining cell counts */ 1511 for (i=0; i< kChainingCellGap; i++) { 1512 chainCellCounts.u.count[i] = cUnit->numChainingCells[i]; 1513 } 1514 1515 /* Set the gap number in the chaining cell count structure */ 1516 chainCellCounts.u.count[kChainingCellGap] = chainingCellGap; 1517 1518 memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts, 1519 sizeof(chainCellCounts)); 1520 1521 /* Install the trace description */ 1522 memcpy((char*) cUnit->baseAddr + chainCellOffset + 1523 sizeof(chainCellCounts), 1524 cUnit->traceDesc, descSize); 1525 } 1526 1527 /* Write the literals directly into the code cache */ 1528 installLiteralPools(cUnit); 1529 1530 /* Flush dcache and invalidate the icache to maintain coherence */ 1531 dvmCompilerCacheFlush((long)cUnit->baseAddr, 1532 (long)((char *) cUnit->baseAddr + offset), 0); 1533 UPDATE_CODE_CACHE_PATCHES(); 1534 1535 PROTECT_CODE_CACHE(cUnit->baseAddr, offset); 1536 1537 /* Translation cache update complete - release lock */ 1538 dvmUnlockMutex(&gDvmJit.compilerLock); 1539 1540 /* Record code entry point and instruction set */ 1541 info->codeAddress = (char*)cUnit->baseAddr + cUnit->headerSize; 1542 /* If applicable, mark low bit to denote thumb */ 1543 if (info->instructionSet != DALVIK_JIT_ARM) 1544 info->codeAddress = (char*)info->codeAddress + 1; 1545 /* transfer the size of the profiling code */ 1546 info->profileCodeSize = cUnit->profileCodeSize; 1547 } 1548 1549 /* 1550 * Returns the skeleton bit pattern associated with an opcode. All 1551 * variable fields are zeroed. 1552 */ 1553 static u4 getSkeleton(ArmOpcode op) 1554 { 1555 return EncodingMap[op].skeleton; 1556 } 1557 1558 static u4 assembleChainingBranch(int branchOffset, bool thumbTarget) 1559 { 1560 u4 thumb1, thumb2; 1561 1562 if (!thumbTarget) { 1563 thumb1 = (getSkeleton(kThumbBlx1) | ((branchOffset>>12) & 0x7ff)); 1564 thumb2 = (getSkeleton(kThumbBlx2) | ((branchOffset>> 1) & 0x7ff)); 1565 } else if ((branchOffset < -2048) | (branchOffset > 2046)) { 1566 thumb1 = (getSkeleton(kThumbBl1) | ((branchOffset>>12) & 0x7ff)); 1567 thumb2 = (getSkeleton(kThumbBl2) | ((branchOffset>> 1) & 0x7ff)); 1568 } else { 1569 thumb1 = (getSkeleton(kThumbBUncond) | ((branchOffset>> 1) & 0x7ff)); 1570 thumb2 = getSkeleton(kThumbOrr); /* nop -> or r0, r0 */ 1571 } 1572 1573 return thumb2<<16 | thumb1; 1574 } 1575 1576 /* 1577 * Perform translation chain operation. 1578 * For ARM, we'll use a pair of thumb instructions to generate 1579 * an unconditional chaining branch of up to 4MB in distance. 1580 * Use a BL, because the generic "interpret" translation needs 1581 * the link register to find the dalvik pc of teh target. 1582 * 111HHooooooooooo 1583 * Where HH is 10 for the 1st inst, and 11 for the second and 1584 * the "o" field is each instruction's 11-bit contribution to the 1585 * 22-bit branch offset. 1586 * If the target is nearby, use a single-instruction bl. 1587 * If one or more threads is suspended, don't chain. 1588 */ 1589 void* dvmJitChain(void* tgtAddr, u4* branchAddr) 1590 { 1591 int baseAddr = (u4) branchAddr + 4; 1592 int branchOffset = (int) tgtAddr - baseAddr; 1593 u4 newInst; 1594 bool thumbTarget; 1595 1596 /* 1597 * Only chain translations when there is no urge to ask all threads to 1598 * suspend themselves via the interpreter. 1599 */ 1600 if ((gDvmJit.pProfTable != NULL) && (gDvm.sumThreadSuspendCount == 0) && 1601 (gDvmJit.codeCacheFull == false)) { 1602 assert((branchOffset >= -(1<<22)) && (branchOffset <= ((1<<22)-2))); 1603 1604 gDvmJit.translationChains++; 1605 1606 COMPILER_TRACE_CHAINING( 1607 LOGD("Jit Runtime: chaining %#x to %#x", 1608 (int) branchAddr, (int) tgtAddr & -2)); 1609 1610 /* 1611 * NOTE: normally, all translations are Thumb[2] mode, with 1612 * a single exception: the default TEMPLATE_INTERPRET 1613 * pseudo-translation. If the need ever arises to 1614 * mix Arm & Thumb[2] translations, the following code should be 1615 * generalized. 1616 */ 1617 thumbTarget = (tgtAddr != dvmCompilerGetInterpretTemplate()); 1618 1619 newInst = assembleChainingBranch(branchOffset, thumbTarget); 1620 1621 /* 1622 * The second half-word instruction of the chaining cell must 1623 * either be a nop (which represents initial state), or is the 1624 * same exact branch halfword that we are trying to install. 1625 */ 1626 assert( ((*branchAddr >> 16) == getSkeleton(kThumbOrr)) || 1627 ((*branchAddr >> 16) == (newInst >> 16))); 1628 1629 UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr)); 1630 1631 *branchAddr = newInst; 1632 dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4, 0); 1633 UPDATE_CODE_CACHE_PATCHES(); 1634 1635 PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr)); 1636 1637 gDvmJit.hasNewChain = true; 1638 } 1639 1640 return tgtAddr; 1641 } 1642 1643 #if !defined(WITH_SELF_VERIFICATION) 1644 /* 1645 * Attempt to enqueue a work order to patch an inline cache for a predicted 1646 * chaining cell for virtual/interface calls. 1647 */ 1648 static void inlineCachePatchEnqueue(PredictedChainingCell *cellAddr, 1649 PredictedChainingCell *newContent) 1650 { 1651 /* 1652 * Make sure only one thread gets here since updating the cell (ie fast 1653 * path and queueing the request (ie the queued path) have to be done 1654 * in an atomic fashion. 1655 */ 1656 dvmLockMutex(&gDvmJit.compilerICPatchLock); 1657 1658 /* Fast path for uninitialized chaining cell */ 1659 if (cellAddr->clazz == NULL && 1660 cellAddr->branch == PREDICTED_CHAIN_BX_PAIR_INIT) { 1661 1662 UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr)); 1663 1664 cellAddr->method = newContent->method; 1665 cellAddr->branch = newContent->branch; 1666 /* 1667 * The update order matters - make sure clazz is updated last since it 1668 * will bring the uninitialized chaining cell to life. 1669 */ 1670 android_atomic_release_store((int32_t)newContent->clazz, 1671 (volatile int32_t *)(void *)&cellAddr->clazz); 1672 dvmCompilerCacheFlush((intptr_t) cellAddr, (intptr_t) (cellAddr+1), 0); 1673 UPDATE_CODE_CACHE_PATCHES(); 1674 1675 PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr)); 1676 1677 #if defined(WITH_JIT_TUNING) 1678 gDvmJit.icPatchInit++; 1679 #endif 1680 /* Check if this is a frequently missed clazz */ 1681 } else if (cellAddr->stagedClazz != newContent->clazz) { 1682 /* Not proven to be frequent yet - build up the filter cache */ 1683 UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr)); 1684 1685 cellAddr->stagedClazz = newContent->clazz; 1686 1687 UPDATE_CODE_CACHE_PATCHES(); 1688 PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr)); 1689 1690 #if defined(WITH_JIT_TUNING) 1691 gDvmJit.icPatchRejected++; 1692 #endif 1693 /* 1694 * Different classes but same method implementation - it is safe to just 1695 * patch the class value without the need to stop the world. 1696 */ 1697 } else if (cellAddr->method == newContent->method) { 1698 UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr)); 1699 1700 cellAddr->clazz = newContent->clazz; 1701 /* No need to flush the cache here since the branch is not patched */ 1702 UPDATE_CODE_CACHE_PATCHES(); 1703 1704 PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr)); 1705 1706 #if defined(WITH_JIT_TUNING) 1707 gDvmJit.icPatchLockFree++; 1708 #endif 1709 /* 1710 * Cannot patch the chaining cell inline - queue it until the next safe 1711 * point. 1712 */ 1713 } else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) { 1714 int index = gDvmJit.compilerICPatchIndex++; 1715 const ClassObject *clazz = newContent->clazz; 1716 1717 gDvmJit.compilerICPatchQueue[index].cellAddr = cellAddr; 1718 gDvmJit.compilerICPatchQueue[index].cellContent = *newContent; 1719 gDvmJit.compilerICPatchQueue[index].classDescriptor = clazz->descriptor; 1720 gDvmJit.compilerICPatchQueue[index].classLoader = clazz->classLoader; 1721 /* For verification purpose only */ 1722 gDvmJit.compilerICPatchQueue[index].serialNumber = clazz->serialNumber; 1723 #if defined(WITH_JIT_TUNING) 1724 gDvmJit.icPatchQueued++; 1725 #endif 1726 } else { 1727 /* Queue is full - just drop this patch request */ 1728 #if defined(WITH_JIT_TUNING) 1729 gDvmJit.icPatchDropped++; 1730 #endif 1731 } 1732 1733 dvmUnlockMutex(&gDvmJit.compilerICPatchLock); 1734 } 1735 #endif 1736 1737 /* 1738 * This method is called from the invoke templates for virtual and interface 1739 * methods to speculatively setup a chain to the callee. The templates are 1740 * written in assembly and have setup method, cell, and clazz at r0, r2, and 1741 * r3 respectively, so there is a unused argument in the list. Upon return one 1742 * of the following three results may happen: 1743 * 1) Chain is not setup because the callee is native. Reset the rechain 1744 * count to a big number so that it will take a long time before the next 1745 * rechain attempt to happen. 1746 * 2) Chain is not setup because the callee has not been created yet. Reset 1747 * the rechain count to a small number and retry in the near future. 1748 * 3) Enqueue the new content for the chaining cell which will be appled in 1749 * next safe point. 1750 */ 1751 const Method *dvmJitToPatchPredictedChain(const Method *method, 1752 Thread *self, 1753 PredictedChainingCell *cell, 1754 const ClassObject *clazz) 1755 { 1756 int newRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN; 1757 #if defined(WITH_SELF_VERIFICATION) 1758 newRechainCount = PREDICTED_CHAIN_COUNTER_AVOID; 1759 goto done; 1760 #else 1761 PredictedChainingCell newCell; 1762 int baseAddr, branchOffset, tgtAddr; 1763 if (dvmIsNativeMethod(method)) { 1764 UNPROTECT_CODE_CACHE(cell, sizeof(*cell)); 1765 1766 /* 1767 * Put a non-zero/bogus value in the clazz field so that it won't 1768 * trigger immediate patching and will continue to fail to match with 1769 * a real clazz pointer. 1770 */ 1771 cell->clazz = (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ; 1772 1773 UPDATE_CODE_CACHE_PATCHES(); 1774 PROTECT_CODE_CACHE(cell, sizeof(*cell)); 1775 goto done; 1776 } 1777 tgtAddr = (int) dvmJitGetTraceAddr(method->insns); 1778 1779 /* 1780 * Compilation not made yet for the callee. Reset the counter to a small 1781 * value and come back to check soon. 1782 */ 1783 if ((tgtAddr == 0) || 1784 ((void*)tgtAddr == dvmCompilerGetInterpretTemplate())) { 1785 COMPILER_TRACE_CHAINING( 1786 LOGD("Jit Runtime: predicted chain %p to method %s%s delayed", 1787 cell, method->clazz->descriptor, method->name)); 1788 goto done; 1789 } 1790 1791 if (cell->clazz == NULL) { 1792 newRechainCount = self->icRechainCount; 1793 } 1794 1795 baseAddr = (int) cell + 4; // PC is cur_addr + 4 1796 branchOffset = tgtAddr - baseAddr; 1797 1798 newCell.branch = assembleChainingBranch(branchOffset, true); 1799 newCell.clazz = clazz; 1800 newCell.method = method; 1801 newCell.stagedClazz = NULL; 1802 1803 /* 1804 * Enter the work order to the queue and the chaining cell will be patched 1805 * the next time a safe point is entered. 1806 * 1807 * If the enqueuing fails reset the rechain count to a normal value so that 1808 * it won't get indefinitely delayed. 1809 */ 1810 inlineCachePatchEnqueue(cell, &newCell); 1811 #endif 1812 done: 1813 self->icRechainCount = newRechainCount; 1814 return method; 1815 } 1816 1817 /* 1818 * Patch the inline cache content based on the content passed from the work 1819 * order. 1820 */ 1821 void dvmCompilerPatchInlineCache(void) 1822 { 1823 int i; 1824 PredictedChainingCell *minAddr, *maxAddr; 1825 1826 /* Nothing to be done */ 1827 if (gDvmJit.compilerICPatchIndex == 0) return; 1828 1829 /* 1830 * Since all threads are already stopped we don't really need to acquire 1831 * the lock. But race condition can be easily introduced in the future w/o 1832 * paying attention so we still acquire the lock here. 1833 */ 1834 dvmLockMutex(&gDvmJit.compilerICPatchLock); 1835 1836 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 1837 1838 //LOGD("Number of IC patch work orders: %d", gDvmJit.compilerICPatchIndex); 1839 1840 /* Initialize the min/max address range */ 1841 minAddr = (PredictedChainingCell *) 1842 ((char *) gDvmJit.codeCache + gDvmJit.codeCacheSize); 1843 maxAddr = (PredictedChainingCell *) gDvmJit.codeCache; 1844 1845 for (i = 0; i < gDvmJit.compilerICPatchIndex; i++) { 1846 ICPatchWorkOrder *workOrder = &gDvmJit.compilerICPatchQueue[i]; 1847 PredictedChainingCell *cellAddr = workOrder->cellAddr; 1848 PredictedChainingCell *cellContent = &workOrder->cellContent; 1849 ClassObject *clazz = dvmFindClassNoInit(workOrder->classDescriptor, 1850 workOrder->classLoader); 1851 1852 assert(clazz->serialNumber == workOrder->serialNumber); 1853 1854 /* Use the newly resolved clazz pointer */ 1855 cellContent->clazz = clazz; 1856 1857 COMPILER_TRACE_CHAINING( 1858 LOGD("Jit Runtime: predicted chain %p from %s to %s (%s) " 1859 "patched", 1860 cellAddr, 1861 cellAddr->clazz->descriptor, 1862 cellContent->clazz->descriptor, 1863 cellContent->method->name)); 1864 1865 /* Patch the chaining cell */ 1866 *cellAddr = *cellContent; 1867 minAddr = (cellAddr < minAddr) ? cellAddr : minAddr; 1868 maxAddr = (cellAddr > maxAddr) ? cellAddr : maxAddr; 1869 } 1870 1871 /* Then synchronize the I/D cache */ 1872 dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1), 0); 1873 UPDATE_CODE_CACHE_PATCHES(); 1874 1875 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 1876 1877 gDvmJit.compilerICPatchIndex = 0; 1878 dvmUnlockMutex(&gDvmJit.compilerICPatchLock); 1879 } 1880 1881 /* 1882 * Unchain a trace given the starting address of the translation 1883 * in the code cache. Refer to the diagram in dvmCompilerAssembleLIR. 1884 * Returns the address following the last cell unchained. Note that 1885 * the incoming codeAddr is a thumb code address, and therefore has 1886 * the low bit set. 1887 */ 1888 static u4* unchainSingle(JitEntry *trace) 1889 { 1890 const char *base = getTraceBase(trace); 1891 ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base); 1892 int cellSize = getChainCellSize(pChainCellCounts); 1893 u4* pChainCells; 1894 u4 newInst; 1895 int i,j; 1896 PredictedChainingCell *predChainCell; 1897 1898 if (cellSize == 0) 1899 return (u4 *) pChainCellCounts; 1900 1901 /* Locate the beginning of the chain cell region */ 1902 pChainCells = ((u4 *) pChainCellCounts) - cellSize - 1903 pChainCellCounts->u.count[kChainingCellGap]; 1904 1905 /* The cells are sorted in order - walk through them and reset */ 1906 for (i = 0; i < kChainingCellGap; i++) { 1907 int elemSize = CHAIN_CELL_NORMAL_SIZE >> 2; /* In 32-bit words */ 1908 if (i == kChainingCellInvokePredicted) { 1909 elemSize = CHAIN_CELL_PREDICTED_SIZE >> 2; 1910 } 1911 1912 for (j = 0; j < pChainCellCounts->u.count[i]; j++) { 1913 switch(i) { 1914 case kChainingCellNormal: 1915 case kChainingCellHot: 1916 case kChainingCellInvokeSingleton: 1917 case kChainingCellBackwardBranch: 1918 /* 1919 * Replace the 1st half-word of the cell with an 1920 * unconditional branch, leaving the 2nd half-word 1921 * untouched. This avoids problems with a thread 1922 * that is suspended between the two halves when 1923 * this unchaining takes place. 1924 */ 1925 newInst = *pChainCells; 1926 newInst &= 0xFFFF0000; 1927 newInst |= getSkeleton(kThumbBUncond); /* b offset is 0 */ 1928 *pChainCells = newInst; 1929 break; 1930 case kChainingCellInvokePredicted: 1931 predChainCell = (PredictedChainingCell *) pChainCells; 1932 /* 1933 * There could be a race on another mutator thread to use 1934 * this particular predicted cell and the check has passed 1935 * the clazz comparison. So we cannot safely wipe the 1936 * method and branch but it is safe to clear the clazz, 1937 * which serves as the key. 1938 */ 1939 predChainCell->clazz = PREDICTED_CHAIN_CLAZZ_INIT; 1940 break; 1941 default: 1942 LOGE("Unexpected chaining type: %d", i); 1943 dvmAbort(); // dvmAbort OK here - can't safely recover 1944 } 1945 COMPILER_TRACE_CHAINING( 1946 LOGD("Jit Runtime: unchaining %#x", (int)pChainCells)); 1947 pChainCells += elemSize; /* Advance by a fixed number of words */ 1948 } 1949 } 1950 return pChainCells; 1951 } 1952 1953 /* Unchain all translation in the cache. */ 1954 void dvmJitUnchainAll() 1955 { 1956 u4* lowAddress = NULL; 1957 u4* highAddress = NULL; 1958 unsigned int i; 1959 if (gDvmJit.pJitEntryTable != NULL) { 1960 COMPILER_TRACE_CHAINING(LOGD("Jit Runtime: unchaining all")); 1961 dvmLockMutex(&gDvmJit.tableLock); 1962 1963 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 1964 1965 for (i = 0; i < gDvmJit.jitTableSize; i++) { 1966 if (gDvmJit.pJitEntryTable[i].dPC && 1967 !gDvmJit.pJitEntryTable[i].u.info.isMethodEntry && 1968 gDvmJit.pJitEntryTable[i].codeAddress && 1969 (gDvmJit.pJitEntryTable[i].codeAddress != 1970 dvmCompilerGetInterpretTemplate())) { 1971 u4* lastAddress; 1972 lastAddress = unchainSingle(&gDvmJit.pJitEntryTable[i]); 1973 if (lowAddress == NULL || 1974 (u4*)gDvmJit.pJitEntryTable[i].codeAddress < 1975 lowAddress) 1976 lowAddress = lastAddress; 1977 if (lastAddress > highAddress) 1978 highAddress = lastAddress; 1979 } 1980 } 1981 dvmCompilerCacheFlush((long)lowAddress, (long)highAddress, 0); 1982 UPDATE_CODE_CACHE_PATCHES(); 1983 1984 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 1985 1986 dvmUnlockMutex(&gDvmJit.tableLock); 1987 gDvmJit.translationChains = 0; 1988 } 1989 gDvmJit.hasNewChain = false; 1990 } 1991 1992 typedef struct jitProfileAddrToLine { 1993 u4 lineNum; 1994 u4 bytecodeOffset; 1995 } jitProfileAddrToLine; 1996 1997 1998 /* Callback function to track the bytecode offset/line number relationiship */ 1999 static int addrToLineCb (void *cnxt, u4 bytecodeOffset, u4 lineNum) 2000 { 2001 jitProfileAddrToLine *addrToLine = (jitProfileAddrToLine *) cnxt; 2002 2003 /* Best match so far for this offset */ 2004 if (addrToLine->bytecodeOffset >= bytecodeOffset) { 2005 addrToLine->lineNum = lineNum; 2006 } 2007 return 0; 2008 } 2009 2010 /* Dumps profile info for a single trace */ 2011 static int dumpTraceProfile(JitEntry *p, bool silent, bool reset, 2012 unsigned long sum) 2013 { 2014 int idx; 2015 2016 if (p->codeAddress == NULL) { 2017 if (!silent) 2018 LOGD("TRACEPROFILE NULL"); 2019 return 0; 2020 } 2021 if (p->codeAddress == dvmCompilerGetInterpretTemplate()) { 2022 if (!silent) 2023 LOGD("TRACEPROFILE INTERPRET_ONLY"); 2024 return 0; 2025 } 2026 JitTraceCounter_t count = getProfileCount(p); 2027 if (reset) { 2028 resetProfileCount(p); 2029 } 2030 if (silent) { 2031 return count; 2032 } 2033 JitTraceDescription *desc = getTraceDescriptionPointer(getTraceBase(p)); 2034 const Method *method = desc->method; 2035 char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype); 2036 jitProfileAddrToLine addrToLine = {0, desc->trace[0].info.frag.startOffset}; 2037 2038 /* 2039 * We may end up decoding the debug information for the same method 2040 * multiple times, but the tradeoff is we don't need to allocate extra 2041 * space to store the addr/line mapping. Since this is a debugging feature 2042 * and done infrequently so the slower but simpler mechanism should work 2043 * just fine. 2044 */ 2045 dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, 2046 dvmGetMethodCode(method), 2047 method->clazz->descriptor, 2048 method->prototype.protoIdx, 2049 method->accessFlags, 2050 addrToLineCb, NULL, &addrToLine); 2051 2052 LOGD("TRACEPROFILE 0x%08x % 10d %5.2f%% [%#x(+%d), %d] %s%s;%s", 2053 (int) getTraceBase(p), 2054 count, 2055 ((float ) count) / sum * 100.0, 2056 desc->trace[0].info.frag.startOffset, 2057 desc->trace[0].info.frag.numInsts, 2058 addrToLine.lineNum, 2059 method->clazz->descriptor, method->name, methodDesc); 2060 free(methodDesc); 2061 2062 /* Find the last fragment (ie runEnd is set) */ 2063 for (idx = 0; 2064 desc->trace[idx].isCode && !desc->trace[idx].info.frag.runEnd; 2065 idx++) { 2066 } 2067 2068 /* 2069 * runEnd must comes with a JitCodeDesc frag. If isCode is false it must 2070 * be a meta info field (only used by callsite info for now). 2071 */ 2072 if (!desc->trace[idx].isCode) { 2073 const Method *method = (const Method *) 2074 desc->trace[idx+JIT_TRACE_CUR_METHOD-1].info.meta; 2075 char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype); 2076 /* Print the callee info in the trace */ 2077 LOGD(" -> %s%s;%s", method->clazz->descriptor, method->name, 2078 methodDesc); 2079 } 2080 2081 return count; 2082 } 2083 2084 /* Create a copy of the trace descriptor of an existing compilation */ 2085 JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc, 2086 const JitEntry *knownEntry) 2087 { 2088 const JitEntry *jitEntry = knownEntry ? knownEntry 2089 : dvmJitFindEntry(pc, false); 2090 if ((jitEntry == NULL) || (jitEntry->codeAddress == 0)) 2091 return NULL; 2092 2093 JitTraceDescription *desc = 2094 getTraceDescriptionPointer(getTraceBase(jitEntry)); 2095 2096 /* Now make a copy and return */ 2097 int descSize = getTraceDescriptionSize(desc); 2098 JitTraceDescription *newCopy = (JitTraceDescription *) malloc(descSize); 2099 memcpy(newCopy, desc, descSize); 2100 return newCopy; 2101 } 2102 2103 /* qsort callback function */ 2104 static int sortTraceProfileCount(const void *entry1, const void *entry2) 2105 { 2106 const JitEntry *jitEntry1 = (const JitEntry *)entry1; 2107 const JitEntry *jitEntry2 = (const JitEntry *)entry2; 2108 2109 JitTraceCounter_t count1 = getProfileCount(jitEntry1); 2110 JitTraceCounter_t count2 = getProfileCount(jitEntry2); 2111 return (count1 == count2) ? 0 : ((count1 > count2) ? -1 : 1); 2112 } 2113 2114 /* Sort the trace profile counts and dump them */ 2115 void dvmCompilerSortAndPrintTraceProfiles() 2116 { 2117 JitEntry *sortedEntries; 2118 int numTraces = 0; 2119 unsigned long sum = 0; 2120 unsigned int i; 2121 2122 /* Make sure that the table is not changing */ 2123 dvmLockMutex(&gDvmJit.tableLock); 2124 2125 /* Sort the entries by descending order */ 2126 sortedEntries = (JitEntry *)malloc(sizeof(JitEntry) * gDvmJit.jitTableSize); 2127 if (sortedEntries == NULL) 2128 goto done; 2129 memcpy(sortedEntries, gDvmJit.pJitEntryTable, 2130 sizeof(JitEntry) * gDvmJit.jitTableSize); 2131 qsort(sortedEntries, gDvmJit.jitTableSize, sizeof(JitEntry), 2132 sortTraceProfileCount); 2133 2134 /* Analyze the sorted entries */ 2135 for (i=0; i < gDvmJit.jitTableSize; i++) { 2136 if (sortedEntries[i].dPC != 0) { 2137 sum += dumpTraceProfile(&sortedEntries[i], 2138 true /* silent */, 2139 false /* reset */, 2140 0); 2141 numTraces++; 2142 } 2143 } 2144 if (numTraces == 0) 2145 numTraces = 1; 2146 if (sum == 0) { 2147 sum = 1; 2148 } 2149 2150 LOGD("JIT: Average execution count -> %d",(int)(sum / numTraces)); 2151 2152 /* Dump the sorted entries. The count of each trace will be reset to 0. */ 2153 for (i=0; i < gDvmJit.jitTableSize; i++) { 2154 if (sortedEntries[i].dPC != 0) { 2155 dumpTraceProfile(&sortedEntries[i], 2156 false /* silent */, 2157 true /* reset */, 2158 sum); 2159 } 2160 } 2161 2162 for (i=0; i < gDvmJit.jitTableSize && i < 10; i++) { 2163 /* Stip interpreter stubs */ 2164 if (sortedEntries[i].codeAddress == dvmCompilerGetInterpretTemplate()) { 2165 continue; 2166 } 2167 JitTraceDescription* desc = 2168 dvmCopyTraceDescriptor(NULL, &sortedEntries[i]); 2169 if (desc) { 2170 dvmCompilerWorkEnqueue(sortedEntries[i].dPC, 2171 kWorkOrderTraceDebug, desc); 2172 } 2173 } 2174 2175 free(sortedEntries); 2176 done: 2177 dvmUnlockMutex(&gDvmJit.tableLock); 2178 return; 2179 } 2180 2181 static void findClassPointersSingleTrace(char *base, void (*callback)(void *)) 2182 { 2183 unsigned int chainTypeIdx, chainIdx; 2184 ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base); 2185 int cellSize = getChainCellSize(pChainCellCounts); 2186 /* Scan the chaining cells */ 2187 if (cellSize) { 2188 /* Locate the beginning of the chain cell region */ 2189 u4 *pChainCells = ((u4 *) pChainCellCounts) - cellSize - 2190 pChainCellCounts->u.count[kChainingCellGap]; 2191 /* The cells are sorted in order - walk through them */ 2192 for (chainTypeIdx = 0; chainTypeIdx < kChainingCellGap; 2193 chainTypeIdx++) { 2194 if (chainTypeIdx != kChainingCellInvokePredicted) { 2195 /* In 32-bit words */ 2196 pChainCells += (CHAIN_CELL_NORMAL_SIZE >> 2) * 2197 pChainCellCounts->u.count[chainTypeIdx]; 2198 continue; 2199 } 2200 for (chainIdx = 0; 2201 chainIdx < pChainCellCounts->u.count[chainTypeIdx]; 2202 chainIdx++) { 2203 PredictedChainingCell *cell = 2204 (PredictedChainingCell *) pChainCells; 2205 /* 2206 * Report the cell if it contains a sane class 2207 * pointer. 2208 */ 2209 if (cell->clazz != NULL && 2210 cell->clazz != 2211 (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ) { 2212 callback(&cell->clazz); 2213 } 2214 pChainCells += CHAIN_CELL_PREDICTED_SIZE >> 2; 2215 } 2216 } 2217 } 2218 2219 /* Scan the class pointer pool */ 2220 JitTraceDescription *desc = getTraceDescriptionPointer(base); 2221 int descSize = getTraceDescriptionSize(desc); 2222 int *classPointerP = (int *) ((char *) desc + descSize); 2223 int numClassPointers = *classPointerP++; 2224 for (; numClassPointers; numClassPointers--, classPointerP++) { 2225 callback(classPointerP); 2226 } 2227 } 2228 2229 /* 2230 * Scan class pointers in each translation and pass its address to the callback 2231 * function. Currently such a pointers can be found in the pointer pool and the 2232 * clazz field in the predicted chaining cells. 2233 */ 2234 void dvmJitScanAllClassPointers(void (*callback)(void *)) 2235 { 2236 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 2237 2238 /* Handle the inflight compilation first */ 2239 if (gDvmJit.inflightBaseAddr) 2240 findClassPointersSingleTrace((char *) gDvmJit.inflightBaseAddr, 2241 callback); 2242 2243 if (gDvmJit.pJitEntryTable != NULL) { 2244 unsigned int traceIdx; 2245 dvmLockMutex(&gDvmJit.tableLock); 2246 for (traceIdx = 0; traceIdx < gDvmJit.jitTableSize; traceIdx++) { 2247 const JitEntry *entry = &gDvmJit.pJitEntryTable[traceIdx]; 2248 if (entry->dPC && 2249 !entry->u.info.isMethodEntry && 2250 entry->codeAddress && 2251 (entry->codeAddress != dvmCompilerGetInterpretTemplate())) { 2252 char *base = getTraceBase(entry); 2253 findClassPointersSingleTrace(base, callback); 2254 } 2255 } 2256 dvmUnlockMutex(&gDvmJit.tableLock); 2257 } 2258 UPDATE_CODE_CACHE_PATCHES(); 2259 2260 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed); 2261 } 2262 2263 /* 2264 * Provide the final touch on the class object pointer pool to install the 2265 * actual pointers. The thread has to be in the running state. 2266 */ 2267 void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, char *codeAddress) 2268 { 2269 char *base = codeAddress - cUnit->headerSize - 2270 (cUnit->instructionSet == DALVIK_JIT_ARM ? 0 : 1); 2271 2272 /* Scan the class pointer pool */ 2273 JitTraceDescription *desc = getTraceDescriptionPointer(base); 2274 int descSize = getTraceDescriptionSize(desc); 2275 intptr_t *classPointerP = (int *) ((char *) desc + descSize); 2276 int numClassPointers = *(int *)classPointerP++; 2277 intptr_t *startClassPointerP = classPointerP; 2278 2279 /* 2280 * Change the thread state to VM_RUNNING so that GC won't be happening 2281 * when the assembler looks up the class pointers. May suspend the current 2282 * thread if there is a pending request before the state is actually 2283 * changed to RUNNING. 2284 */ 2285 dvmChangeStatus(gDvmJit.compilerThread, THREAD_RUNNING); 2286 2287 /* 2288 * Unprotecting the code cache will need to acquire the code cache 2289 * protection lock first. Doing so after the state change may increase the 2290 * time spent in the RUNNING state (which may delay the next GC request 2291 * should there be contention on codeCacheProtectionLock). In practice 2292 * this is probably not going to happen often since a GC is just served. 2293 * More importantly, acquiring the lock before the state change will 2294 * cause deadlock (b/4192964). 2295 */ 2296 UNPROTECT_CODE_CACHE(startClassPointerP, 2297 numClassPointers * sizeof(intptr_t)); 2298 #if defined(WITH_JIT_TUNING) 2299 u8 startTime = dvmGetRelativeTimeUsec(); 2300 #endif 2301 for (;numClassPointers; numClassPointers--) { 2302 CallsiteInfo *callsiteInfo = (CallsiteInfo *) *classPointerP; 2303 ClassObject *clazz = dvmFindClassNoInit( 2304 callsiteInfo->classDescriptor, callsiteInfo->classLoader); 2305 assert(!strcmp(clazz->descriptor, callsiteInfo->classDescriptor)); 2306 *classPointerP++ = (intptr_t) clazz; 2307 } 2308 2309 /* 2310 * Register the base address so that if GC kicks in after the thread state 2311 * has been changed to VMWAIT and before the compiled code is registered 2312 * in the JIT table, its content can be patched if class objects are 2313 * moved. 2314 */ 2315 gDvmJit.inflightBaseAddr = base; 2316 2317 #if defined(WITH_JIT_TUNING) 2318 u8 blockTime = dvmGetRelativeTimeUsec() - startTime; 2319 gDvmJit.compilerThreadBlockGCTime += blockTime; 2320 if (blockTime > gDvmJit.maxCompilerThreadBlockGCTime) 2321 gDvmJit.maxCompilerThreadBlockGCTime = blockTime; 2322 gDvmJit.numCompilerThreadBlockGC++; 2323 #endif 2324 UPDATE_CODE_CACHE_PATCHES(); 2325 2326 PROTECT_CODE_CACHE(startClassPointerP, numClassPointers * sizeof(intptr_t)); 2327 2328 /* Change the thread state back to VMWAIT */ 2329 dvmChangeStatus(gDvmJit.compilerThread, THREAD_VMWAIT); 2330 } 2331 2332 #if defined(WITH_SELF_VERIFICATION) 2333 /* 2334 * The following are used to keep compiled loads and stores from modifying 2335 * memory during self verification mode. 2336 * 2337 * Stores do not modify memory. Instead, the address and value pair are stored 2338 * into heapSpace. Addresses within heapSpace are unique. For accesses smaller 2339 * than a word, the word containing the address is loaded first before being 2340 * updated. 2341 * 2342 * Loads check heapSpace first and return data from there if an entry exists. 2343 * Otherwise, data is loaded from memory as usual. 2344 */ 2345 2346 /* Used to specify sizes of memory operations */ 2347 enum { 2348 kSVByte, 2349 kSVSignedByte, 2350 kSVHalfword, 2351 kSVSignedHalfword, 2352 kSVWord, 2353 kSVDoubleword, 2354 kSVVariable, 2355 }; 2356 2357 /* Load the value of a decoded register from the stack */ 2358 static int selfVerificationMemRegLoad(int* sp, int reg) 2359 { 2360 return *(sp + reg); 2361 } 2362 2363 /* Load the value of a decoded doubleword register from the stack */ 2364 static s8 selfVerificationMemRegLoadDouble(int* sp, int reg) 2365 { 2366 return *((s8*)(sp + reg)); 2367 } 2368 2369 /* Store the value of a decoded register out to the stack */ 2370 static void selfVerificationMemRegStore(int* sp, int data, int reg) 2371 { 2372 *(sp + reg) = data; 2373 } 2374 2375 /* Store the value of a decoded doubleword register out to the stack */ 2376 static void selfVerificationMemRegStoreDouble(int* sp, s8 data, int reg) 2377 { 2378 *((s8*)(sp + reg)) = data; 2379 } 2380 2381 /* 2382 * Load the specified size of data from the specified address, checking 2383 * heapSpace first if Self Verification mode wrote to it previously, and 2384 * falling back to actual memory otherwise. 2385 */ 2386 static int selfVerificationLoad(int addr, int size) 2387 { 2388 Thread *self = dvmThreadSelf(); 2389 ShadowSpace *shadowSpace = self->shadowSpace; 2390 ShadowHeap *heapSpacePtr; 2391 2392 int data; 2393 int maskedAddr = addr & 0xFFFFFFFC; 2394 int alignment = addr & 0x3; 2395 2396 for (heapSpacePtr = shadowSpace->heapSpace; 2397 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) { 2398 if (heapSpacePtr->addr == maskedAddr) { 2399 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment; 2400 break; 2401 } 2402 } 2403 2404 switch (size) { 2405 case kSVByte: 2406 data = *((u1*) addr); 2407 break; 2408 case kSVSignedByte: 2409 data = *((s1*) addr); 2410 break; 2411 case kSVHalfword: 2412 data = *((u2*) addr); 2413 break; 2414 case kSVSignedHalfword: 2415 data = *((s2*) addr); 2416 break; 2417 case kSVWord: 2418 data = *((u4*) addr); 2419 break; 2420 default: 2421 LOGE("*** ERROR: BAD SIZE IN selfVerificationLoad: %d", size); 2422 data = 0; 2423 dvmAbort(); 2424 } 2425 2426 //LOGD("*** HEAP LOAD: Addr: %#x Data: %#x Size: %d", addr, data, size); 2427 return data; 2428 } 2429 2430 /* Like selfVerificationLoad, but specifically for doublewords */ 2431 static s8 selfVerificationLoadDoubleword(int addr) 2432 { 2433 Thread *self = dvmThreadSelf(); 2434 ShadowSpace* shadowSpace = self->shadowSpace; 2435 ShadowHeap* heapSpacePtr; 2436 2437 int addr2 = addr+4; 2438 unsigned int data = *((unsigned int*) addr); 2439 unsigned int data2 = *((unsigned int*) addr2); 2440 2441 for (heapSpacePtr = shadowSpace->heapSpace; 2442 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) { 2443 if (heapSpacePtr->addr == addr) { 2444 data = heapSpacePtr->data; 2445 } else if (heapSpacePtr->addr == addr2) { 2446 data2 = heapSpacePtr->data; 2447 } 2448 } 2449 2450 //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: %#x Data: %#x Data2: %#x", 2451 // addr, data, data2); 2452 return (((s8) data2) << 32) | data; 2453 } 2454 2455 /* 2456 * Handles a store of a specified size of data to a specified address. 2457 * This gets logged as an addr/data pair in heapSpace instead of modifying 2458 * memory. Addresses in heapSpace are unique, and accesses smaller than a 2459 * word pull the entire word from memory first before updating. 2460 */ 2461 static void selfVerificationStore(int addr, int data, int size) 2462 { 2463 Thread *self = dvmThreadSelf(); 2464 ShadowSpace *shadowSpace = self->shadowSpace; 2465 ShadowHeap *heapSpacePtr; 2466 2467 int maskedAddr = addr & 0xFFFFFFFC; 2468 int alignment = addr & 0x3; 2469 2470 //LOGD("*** HEAP STORE: Addr: %#x Data: %#x Size: %d", addr, data, size); 2471 2472 for (heapSpacePtr = shadowSpace->heapSpace; 2473 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) { 2474 if (heapSpacePtr->addr == maskedAddr) break; 2475 } 2476 2477 if (heapSpacePtr == shadowSpace->heapSpaceTail) { 2478 heapSpacePtr->addr = maskedAddr; 2479 heapSpacePtr->data = *((unsigned int*) maskedAddr); 2480 shadowSpace->heapSpaceTail++; 2481 } 2482 2483 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment; 2484 switch (size) { 2485 case kSVByte: 2486 *((u1*) addr) = data; 2487 break; 2488 case kSVSignedByte: 2489 *((s1*) addr) = data; 2490 break; 2491 case kSVHalfword: 2492 *((u2*) addr) = data; 2493 break; 2494 case kSVSignedHalfword: 2495 *((s2*) addr) = data; 2496 break; 2497 case kSVWord: 2498 *((u4*) addr) = data; 2499 break; 2500 default: 2501 LOGE("*** ERROR: BAD SIZE IN selfVerificationSave: %d", size); 2502 dvmAbort(); 2503 } 2504 } 2505 2506 /* Like selfVerificationStore, but specifically for doublewords */ 2507 static void selfVerificationStoreDoubleword(int addr, s8 double_data) 2508 { 2509 Thread *self = dvmThreadSelf(); 2510 ShadowSpace *shadowSpace = self->shadowSpace; 2511 ShadowHeap *heapSpacePtr; 2512 2513 int addr2 = addr+4; 2514 int data = double_data; 2515 int data2 = double_data >> 32; 2516 bool store1 = false, store2 = false; 2517 2518 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: %#x Data: %#x, Data2: %#x", 2519 // addr, data, data2); 2520 2521 for (heapSpacePtr = shadowSpace->heapSpace; 2522 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) { 2523 if (heapSpacePtr->addr == addr) { 2524 heapSpacePtr->data = data; 2525 store1 = true; 2526 } else if (heapSpacePtr->addr == addr2) { 2527 heapSpacePtr->data = data2; 2528 store2 = true; 2529 } 2530 } 2531 2532 if (!store1) { 2533 shadowSpace->heapSpaceTail->addr = addr; 2534 shadowSpace->heapSpaceTail->data = data; 2535 shadowSpace->heapSpaceTail++; 2536 } 2537 if (!store2) { 2538 shadowSpace->heapSpaceTail->addr = addr2; 2539 shadowSpace->heapSpaceTail->data = data2; 2540 shadowSpace->heapSpaceTail++; 2541 } 2542 } 2543 2544 /* 2545 * Decodes the memory instruction at the address specified in the link 2546 * register. All registers (r0-r12,lr) and fp registers (d0-d15) are stored 2547 * consecutively on the stack beginning at the specified stack pointer. 2548 * Calls the proper Self Verification handler for the memory instruction and 2549 * updates the link register to point past the decoded memory instruction. 2550 */ 2551 void dvmSelfVerificationMemOpDecode(int lr, int* sp) 2552 { 2553 enum { 2554 kMemOpLdrPcRel = 0x09, // ldr(3) [01001] rd[10..8] imm_8[7..0] 2555 kMemOpRRR = 0x0A, // Full opcode is 7 bits 2556 kMemOp2Single = 0x0A, // Used for Vstrs and Vldrs 2557 kMemOpRRR2 = 0x0B, // Full opcode is 7 bits 2558 kMemOp2Double = 0x0B, // Used for Vstrd and Vldrd 2559 kMemOpStrRRI5 = 0x0C, // str(1) [01100] imm_5[10..6] rn[5..3] rd[2..0] 2560 kMemOpLdrRRI5 = 0x0D, // ldr(1) [01101] imm_5[10..6] rn[5..3] rd[2..0] 2561 kMemOpStrbRRI5 = 0x0E, // strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0] 2562 kMemOpLdrbRRI5 = 0x0F, // ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0] 2563 kMemOpStrhRRI5 = 0x10, // strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0] 2564 kMemOpLdrhRRI5 = 0x11, // ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0] 2565 kMemOpLdrSpRel = 0x13, // ldr(4) [10011] rd[10..8] imm_8[7..0] 2566 kMemOpStmia = 0x18, // stmia [11000] rn[10..8] reglist [7..0] 2567 kMemOpLdmia = 0x19, // ldmia [11001] rn[10..8] reglist [7..0] 2568 kMemOpStrRRR = 0x28, // str(2) [0101000] rm[8..6] rn[5..3] rd[2..0] 2569 kMemOpStrhRRR = 0x29, // strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0] 2570 kMemOpStrbRRR = 0x2A, // strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0] 2571 kMemOpLdrsbRRR = 0x2B, // ldrsb [0101011] rm[8..6] rn[5..3] rd[2..0] 2572 kMemOpLdrRRR = 0x2C, // ldr(2) [0101100] rm[8..6] rn[5..3] rd[2..0] 2573 kMemOpLdrhRRR = 0x2D, // ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0] 2574 kMemOpLdrbRRR = 0x2E, // ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0] 2575 kMemOpLdrshRRR = 0x2F, // ldrsh [0101111] rm[8..6] rn[5..3] rd[2..0] 2576 kMemOp2Stmia = 0xE88, // stmia [111010001000[ rn[19..16] mask[15..0] 2577 kMemOp2Ldmia = 0xE89, // ldmia [111010001001[ rn[19..16] mask[15..0] 2578 kMemOp2Stmia2 = 0xE8A, // stmia [111010001010[ rn[19..16] mask[15..0] 2579 kMemOp2Ldmia2 = 0xE8B, // ldmia [111010001011[ rn[19..16] mask[15..0] 2580 kMemOp2Vstr = 0xED8, // Used for Vstrs and Vstrd 2581 kMemOp2Vldr = 0xED9, // Used for Vldrs and Vldrd 2582 kMemOp2Vstr2 = 0xEDC, // Used for Vstrs and Vstrd 2583 kMemOp2Vldr2 = 0xEDD, // Used for Vstrs and Vstrd 2584 kMemOp2StrbRRR = 0xF80, /* str rt,[rn,rm,LSL #imm] [111110000000] 2585 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */ 2586 kMemOp2LdrbRRR = 0xF81, /* ldrb rt,[rn,rm,LSL #imm] [111110000001] 2587 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */ 2588 kMemOp2StrhRRR = 0xF82, /* str rt,[rn,rm,LSL #imm] [111110000010] 2589 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */ 2590 kMemOp2LdrhRRR = 0xF83, /* ldrh rt,[rn,rm,LSL #imm] [111110000011] 2591 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */ 2592 kMemOp2StrRRR = 0xF84, /* str rt,[rn,rm,LSL #imm] [111110000100] 2593 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */ 2594 kMemOp2LdrRRR = 0xF85, /* ldr rt,[rn,rm,LSL #imm] [111110000101] 2595 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */ 2596 kMemOp2StrbRRI12 = 0xF88, /* strb rt,[rn,#imm12] [111110001000] 2597 rt[15..12] rn[19..16] imm12[11..0] */ 2598 kMemOp2LdrbRRI12 = 0xF89, /* ldrb rt,[rn,#imm12] [111110001001] 2599 rt[15..12] rn[19..16] imm12[11..0] */ 2600 kMemOp2StrhRRI12 = 0xF8A, /* strh rt,[rn,#imm12] [111110001010] 2601 rt[15..12] rn[19..16] imm12[11..0] */ 2602 kMemOp2LdrhRRI12 = 0xF8B, /* ldrh rt,[rn,#imm12] [111110001011] 2603 rt[15..12] rn[19..16] imm12[11..0] */ 2604 kMemOp2StrRRI12 = 0xF8C, /* str(Imm,T3) rd,[rn,#imm12] [111110001100] 2605 rn[19..16] rt[15..12] imm12[11..0] */ 2606 kMemOp2LdrRRI12 = 0xF8D, /* ldr(Imm,T3) rd,[rn,#imm12] [111110001101] 2607 rn[19..16] rt[15..12] imm12[11..0] */ 2608 kMemOp2LdrsbRRR = 0xF91, /* ldrsb rt,[rn,rm,LSL #imm] [111110010001] 2609 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */ 2610 kMemOp2LdrshRRR = 0xF93, /* ldrsh rt,[rn,rm,LSL #imm] [111110010011] 2611 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */ 2612 kMemOp2LdrsbRRI12 = 0xF99, /* ldrsb rt,[rn,#imm12] [111110011001] 2613 rt[15..12] rn[19..16] imm12[11..0] */ 2614 kMemOp2LdrshRRI12 = 0xF9B, /* ldrsh rt,[rn,#imm12] [111110011011] 2615 rt[15..12] rn[19..16] imm12[11..0] */ 2616 kMemOp2 = 0xE000, // top 3 bits set indicates Thumb2 2617 }; 2618 2619 int addr, offset, data; 2620 long long double_data; 2621 int size = kSVWord; 2622 bool store = false; 2623 unsigned int *lr_masked = (unsigned int *) (lr & 0xFFFFFFFE); 2624 unsigned int insn = *lr_masked; 2625 2626 int old_lr; 2627 old_lr = selfVerificationMemRegLoad(sp, 13); 2628 2629 if ((insn & kMemOp2) == kMemOp2) { 2630 insn = (insn << 16) | (insn >> 16); 2631 //LOGD("*** THUMB2 - Addr: %#x Insn: %#x", lr, insn); 2632 2633 int opcode12 = (insn >> 20) & 0xFFF; 2634 int opcode4 = (insn >> 8) & 0xF; 2635 int imm2 = (insn >> 4) & 0x3; 2636 int imm8 = insn & 0xFF; 2637 int imm12 = insn & 0xFFF; 2638 int rd = (insn >> 12) & 0xF; 2639 int rm = insn & 0xF; 2640 int rn = (insn >> 16) & 0xF; 2641 int rt = (insn >> 12) & 0xF; 2642 bool wBack = true; 2643 2644 // Update the link register 2645 selfVerificationMemRegStore(sp, old_lr+4, 13); 2646 2647 // Determine whether the mem op is a store or load 2648 switch (opcode12) { 2649 case kMemOp2Stmia: 2650 case kMemOp2Stmia2: 2651 case kMemOp2Vstr: 2652 case kMemOp2Vstr2: 2653 case kMemOp2StrbRRR: 2654 case kMemOp2StrhRRR: 2655 case kMemOp2StrRRR: 2656 case kMemOp2StrbRRI12: 2657 case kMemOp2StrhRRI12: 2658 case kMemOp2StrRRI12: 2659 store = true; 2660 } 2661 2662 // Determine the size of the mem access 2663 switch (opcode12) { 2664 case kMemOp2StrbRRR: 2665 case kMemOp2LdrbRRR: 2666 case kMemOp2StrbRRI12: 2667 case kMemOp2LdrbRRI12: 2668 size = kSVByte; 2669 break; 2670 case kMemOp2LdrsbRRR: 2671 case kMemOp2LdrsbRRI12: 2672 size = kSVSignedByte; 2673 break; 2674 case kMemOp2StrhRRR: 2675 case kMemOp2LdrhRRR: 2676 case kMemOp2StrhRRI12: 2677 case kMemOp2LdrhRRI12: 2678 size = kSVHalfword; 2679 break; 2680 case kMemOp2LdrshRRR: 2681 case kMemOp2LdrshRRI12: 2682 size = kSVSignedHalfword; 2683 break; 2684 case kMemOp2Vstr: 2685 case kMemOp2Vstr2: 2686 case kMemOp2Vldr: 2687 case kMemOp2Vldr2: 2688 if (opcode4 == kMemOp2Double) size = kSVDoubleword; 2689 break; 2690 case kMemOp2Stmia: 2691 case kMemOp2Ldmia: 2692 case kMemOp2Stmia2: 2693 case kMemOp2Ldmia2: 2694 size = kSVVariable; 2695 break; 2696 } 2697 2698 // Load the value of the address 2699 addr = selfVerificationMemRegLoad(sp, rn); 2700 2701 // Figure out the offset 2702 switch (opcode12) { 2703 case kMemOp2Vstr: 2704 case kMemOp2Vstr2: 2705 case kMemOp2Vldr: 2706 case kMemOp2Vldr2: 2707 offset = imm8 << 2; 2708 if (opcode4 == kMemOp2Single) { 2709 rt = rd << 1; 2710 if (insn & 0x400000) rt |= 0x1; 2711 } else if (opcode4 == kMemOp2Double) { 2712 if (insn & 0x400000) rt |= 0x10; 2713 rt = rt << 1; 2714 } else { 2715 LOGE("*** ERROR: UNRECOGNIZED VECTOR MEM OP: %x", opcode4); 2716 dvmAbort(); 2717 } 2718 rt += 14; 2719 break; 2720 case kMemOp2StrbRRR: 2721 case kMemOp2LdrbRRR: 2722 case kMemOp2StrhRRR: 2723 case kMemOp2LdrhRRR: 2724 case kMemOp2StrRRR: 2725 case kMemOp2LdrRRR: 2726 case kMemOp2LdrsbRRR: 2727 case kMemOp2LdrshRRR: 2728 offset = selfVerificationMemRegLoad(sp, rm) << imm2; 2729 break; 2730 case kMemOp2StrbRRI12: 2731 case kMemOp2LdrbRRI12: 2732 case kMemOp2StrhRRI12: 2733 case kMemOp2LdrhRRI12: 2734 case kMemOp2StrRRI12: 2735 case kMemOp2LdrRRI12: 2736 case kMemOp2LdrsbRRI12: 2737 case kMemOp2LdrshRRI12: 2738 offset = imm12; 2739 break; 2740 case kMemOp2Stmia: 2741 case kMemOp2Ldmia: 2742 wBack = false; 2743 case kMemOp2Stmia2: 2744 case kMemOp2Ldmia2: 2745 offset = 0; 2746 break; 2747 default: 2748 LOGE("*** ERROR: UNRECOGNIZED THUMB2 MEM OP: %x", opcode12); 2749 offset = 0; 2750 dvmAbort(); 2751 } 2752 2753 // Handle the decoded mem op accordingly 2754 if (store) { 2755 if (size == kSVVariable) { 2756 LOGD("*** THUMB2 STMIA CURRENTLY UNUSED (AND UNTESTED)"); 2757 int i; 2758 int regList = insn & 0xFFFF; 2759 for (i = 0; i < 16; i++) { 2760 if (regList & 0x1) { 2761 data = selfVerificationMemRegLoad(sp, i); 2762 selfVerificationStore(addr, data, kSVWord); 2763 addr += 4; 2764 } 2765 regList = regList >> 1; 2766 } 2767 if (wBack) selfVerificationMemRegStore(sp, addr, rn); 2768 } else if (size == kSVDoubleword) { 2769 double_data = selfVerificationMemRegLoadDouble(sp, rt); 2770 selfVerificationStoreDoubleword(addr+offset, double_data); 2771 } else { 2772 data = selfVerificationMemRegLoad(sp, rt); 2773 selfVerificationStore(addr+offset, data, size); 2774 } 2775 } else { 2776 if (size == kSVVariable) { 2777 LOGD("*** THUMB2 LDMIA CURRENTLY UNUSED (AND UNTESTED)"); 2778 int i; 2779 int regList = insn & 0xFFFF; 2780 for (i = 0; i < 16; i++) { 2781 if (regList & 0x1) { 2782 data = selfVerificationLoad(addr, kSVWord); 2783 selfVerificationMemRegStore(sp, data, i); 2784 addr += 4; 2785 } 2786 regList = regList >> 1; 2787 } 2788 if (wBack) selfVerificationMemRegStore(sp, addr, rn); 2789 } else if (size == kSVDoubleword) { 2790 double_data = selfVerificationLoadDoubleword(addr+offset); 2791 selfVerificationMemRegStoreDouble(sp, double_data, rt); 2792 } else { 2793 data = selfVerificationLoad(addr+offset, size); 2794 selfVerificationMemRegStore(sp, data, rt); 2795 } 2796 } 2797 } else { 2798 //LOGD("*** THUMB - Addr: %#x Insn: %#x", lr, insn); 2799 2800 // Update the link register 2801 selfVerificationMemRegStore(sp, old_lr+2, 13); 2802 2803 int opcode5 = (insn >> 11) & 0x1F; 2804 int opcode7 = (insn >> 9) & 0x7F; 2805 int imm = (insn >> 6) & 0x1F; 2806 int rd = (insn >> 8) & 0x7; 2807 int rm = (insn >> 6) & 0x7; 2808 int rn = (insn >> 3) & 0x7; 2809 int rt = insn & 0x7; 2810 2811 // Determine whether the mem op is a store or load 2812 switch (opcode5) { 2813 case kMemOpRRR: 2814 switch (opcode7) { 2815 case kMemOpStrRRR: 2816 case kMemOpStrhRRR: 2817 case kMemOpStrbRRR: 2818 store = true; 2819 } 2820 break; 2821 case kMemOpStrRRI5: 2822 case kMemOpStrbRRI5: 2823 case kMemOpStrhRRI5: 2824 case kMemOpStmia: 2825 store = true; 2826 } 2827 2828 // Determine the size of the mem access 2829 switch (opcode5) { 2830 case kMemOpRRR: 2831 case kMemOpRRR2: 2832 switch (opcode7) { 2833 case kMemOpStrbRRR: 2834 case kMemOpLdrbRRR: 2835 size = kSVByte; 2836 break; 2837 case kMemOpLdrsbRRR: 2838 size = kSVSignedByte; 2839 break; 2840 case kMemOpStrhRRR: 2841 case kMemOpLdrhRRR: 2842 size = kSVHalfword; 2843 break; 2844 case kMemOpLdrshRRR: 2845 size = kSVSignedHalfword; 2846 break; 2847 } 2848 break; 2849 case kMemOpStrbRRI5: 2850 case kMemOpLdrbRRI5: 2851 size = kSVByte; 2852 break; 2853 case kMemOpStrhRRI5: 2854 case kMemOpLdrhRRI5: 2855 size = kSVHalfword; 2856 break; 2857 case kMemOpStmia: 2858 case kMemOpLdmia: 2859 size = kSVVariable; 2860 break; 2861 } 2862 2863 // Load the value of the address 2864 if (opcode5 == kMemOpLdrPcRel) 2865 addr = selfVerificationMemRegLoad(sp, 4); 2866 else if (opcode5 == kMemOpStmia || opcode5 == kMemOpLdmia) 2867 addr = selfVerificationMemRegLoad(sp, rd); 2868 else 2869 addr = selfVerificationMemRegLoad(sp, rn); 2870 2871 // Figure out the offset 2872 switch (opcode5) { 2873 case kMemOpLdrPcRel: 2874 offset = (insn & 0xFF) << 2; 2875 rt = rd; 2876 break; 2877 case kMemOpRRR: 2878 case kMemOpRRR2: 2879 offset = selfVerificationMemRegLoad(sp, rm); 2880 break; 2881 case kMemOpStrRRI5: 2882 case kMemOpLdrRRI5: 2883 offset = imm << 2; 2884 break; 2885 case kMemOpStrhRRI5: 2886 case kMemOpLdrhRRI5: 2887 offset = imm << 1; 2888 break; 2889 case kMemOpStrbRRI5: 2890 case kMemOpLdrbRRI5: 2891 offset = imm; 2892 break; 2893 case kMemOpStmia: 2894 case kMemOpLdmia: 2895 offset = 0; 2896 break; 2897 default: 2898 LOGE("*** ERROR: UNRECOGNIZED THUMB MEM OP: %x", opcode5); 2899 offset = 0; 2900 dvmAbort(); 2901 } 2902 2903 // Handle the decoded mem op accordingly 2904 if (store) { 2905 if (size == kSVVariable) { 2906 int i; 2907 int regList = insn & 0xFF; 2908 for (i = 0; i < 8; i++) { 2909 if (regList & 0x1) { 2910 data = selfVerificationMemRegLoad(sp, i); 2911 selfVerificationStore(addr, data, kSVWord); 2912 addr += 4; 2913 } 2914 regList = regList >> 1; 2915 } 2916 selfVerificationMemRegStore(sp, addr, rd); 2917 } else { 2918 data = selfVerificationMemRegLoad(sp, rt); 2919 selfVerificationStore(addr+offset, data, size); 2920 } 2921 } else { 2922 if (size == kSVVariable) { 2923 bool wBack = true; 2924 int i; 2925 int regList = insn & 0xFF; 2926 for (i = 0; i < 8; i++) { 2927 if (regList & 0x1) { 2928 if (i == rd) wBack = false; 2929 data = selfVerificationLoad(addr, kSVWord); 2930 selfVerificationMemRegStore(sp, data, i); 2931 addr += 4; 2932 } 2933 regList = regList >> 1; 2934 } 2935 if (wBack) selfVerificationMemRegStore(sp, addr, rd); 2936 } else { 2937 data = selfVerificationLoad(addr+offset, size); 2938 selfVerificationMemRegStore(sp, data, rt); 2939 } 2940 } 2941 } 2942 } 2943 #endif 2944