blob: 62594963fc935f2e59622a90f9ffec17c55f1a51 [file] [log] [blame]
buzbee2502e002012-12-31 16:05:53 -08001/*
2 * Copyright (C) 2012 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
buzbee311ca162013-02-28 15:56:43 -080017#include "local_value_numbering.h"
buzbee2502e002012-12-31 16:05:53 -080018
Vladimir Markobe0e5462014-02-26 11:24:15 +000019#include "mir_field_info.h"
Vladimir Markof59f18b2014-02-17 15:53:57 +000020#include "mir_graph.h"
21
buzbee2502e002012-12-31 16:05:53 -080022namespace art {
23
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010024namespace { // anonymous namespace
25
26// Operations used for value map keys instead of actual opcode.
27static constexpr uint16_t kInvokeMemoryVersionBumpOp = Instruction::INVOKE_DIRECT;
28static constexpr uint16_t kUnresolvedSFieldOp = Instruction::SPUT;
29static constexpr uint16_t kResolvedSFieldOp = Instruction::SGET;
30static constexpr uint16_t kUnresolvedIFieldOp = Instruction::IPUT;
31static constexpr uint16_t kNonAliasingIFieldOp = Instruction::IGET;
32static constexpr uint16_t kAliasingIFieldOp = Instruction::IGET_WIDE;
33static constexpr uint16_t kAliasingIFieldStartVersionOp = Instruction::IGET_WIDE;
34static constexpr uint16_t kAliasingIFieldBumpVersionOp = Instruction::IGET_OBJECT;
35static constexpr uint16_t kArrayAccessLocOp = Instruction::APUT;
36static constexpr uint16_t kNonAliasingArrayOp = Instruction::AGET;
37static constexpr uint16_t kNonAliasingArrayStartVersionOp = Instruction::AGET_WIDE;
38static constexpr uint16_t kAliasingArrayOp = Instruction::AGET_OBJECT;
39static constexpr uint16_t kAliasingArrayMemoryVersionOp = Instruction::AGET_BOOLEAN;
40static constexpr uint16_t kAliasingArrayBumpVersionOp = Instruction::AGET_BYTE;
41
42} // anonymous namespace
43
44LocalValueNumbering::LocalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator)
45 : cu_(cu),
46 last_value_(0u),
47 sreg_value_map_(std::less<uint16_t>(), allocator->Adapter()),
48 sreg_wide_value_map_(std::less<uint16_t>(), allocator->Adapter()),
49 value_map_(std::less<uint64_t>(), allocator->Adapter()),
50 global_memory_version_(0u),
51 aliasing_ifield_version_map_(std::less<uint16_t>(), allocator->Adapter()),
52 non_aliasing_array_version_map_(std::less<uint16_t>(), allocator->Adapter()),
53 field_index_map_(FieldReferenceComparator(), allocator->Adapter()),
54 non_aliasing_refs_(std::less<uint16_t>(), allocator->Adapter()),
55 non_aliasing_ifields_(NonAliasingIFieldKeyComparator(), allocator->Adapter()),
56 escaped_array_refs_(EscapedArrayKeyComparator(), allocator->Adapter()),
57 range_checked_(RangeCheckKeyComparator() , allocator->Adapter()),
58 null_checked_(std::less<uint16_t>(), allocator->Adapter()) {
59 std::fill_n(unresolved_sfield_version_, kFieldTypeCount, 0u);
60 std::fill_n(unresolved_ifield_version_, kFieldTypeCount, 0u);
61 std::fill_n(aliasing_array_version_, kFieldTypeCount, 0u);
62}
63
64uint16_t LocalValueNumbering::GetFieldId(const MirFieldInfo& field_info) {
65 FieldReference key = { field_info.DeclaringDexFile(), field_info.DeclaringFieldIndex() };
Vladimir Markof59f18b2014-02-17 15:53:57 +000066 auto it = field_index_map_.find(key);
67 if (it != field_index_map_.end()) {
68 return it->second;
69 }
70 uint16_t id = field_index_map_.size();
71 field_index_map_.Put(key, id);
72 return id;
73}
74
Vladimir Markof59f18b2014-02-17 15:53:57 +000075uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) {
76 uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
77 SetOperandValue(mir->ssa_rep->defs[0], res);
78 DCHECK(null_checked_.find(res) == null_checked_.end());
79 null_checked_.insert(res);
80 non_aliasing_refs_.insert(res);
81 return res;
82}
83
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010084bool LocalValueNumbering::IsNonAliasing(uint16_t reg) {
85 return non_aliasing_refs_.find(reg) != non_aliasing_refs_.end();
Vladimir Markof59f18b2014-02-17 15:53:57 +000086}
87
Vladimir Marko2ac01fc2014-05-22 12:09:08 +010088bool LocalValueNumbering::IsNonAliasingIField(uint16_t reg, uint16_t field_id, uint16_t type) {
89 if (IsNonAliasing(reg)) {
90 return true;
91 }
92 NonAliasingIFieldKey key = { reg, field_id, type };
93 return non_aliasing_ifields_.count(key) != 0u;
94}
95
96bool LocalValueNumbering::IsNonAliasingArray(uint16_t reg, uint16_t type) {
97 if (IsNonAliasing(reg)) {
98 return true;
99 }
100 EscapedArrayKey key = { reg, type };
101 return escaped_array_refs_.count(key) != 0u;
102}
103
104
Vladimir Markof59f18b2014-02-17 15:53:57 +0000105void LocalValueNumbering::HandleNullCheck(MIR* mir, uint16_t reg) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100106 auto lb = null_checked_.lower_bound(reg);
107 if (lb != null_checked_.end() && *lb == reg) {
108 if (LIKELY(Good())) {
109 if (cu_->verbose) {
110 LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
111 }
112 mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
Vladimir Markof59f18b2014-02-17 15:53:57 +0000113 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000114 } else {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100115 null_checked_.insert(lb, reg);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000116 }
117}
118
119void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100120 RangeCheckKey key = { array, index };
121 auto lb = range_checked_.lower_bound(key);
122 if (lb != range_checked_.end() && !RangeCheckKeyComparator()(key, *lb)) {
123 if (LIKELY(Good())) {
124 if (cu_->verbose) {
125 LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
126 }
127 mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
Vladimir Markof59f18b2014-02-17 15:53:57 +0000128 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100129 } else {
130 // Mark range check completed.
131 range_checked_.insert(lb, key);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000132 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000133}
134
135void LocalValueNumbering::HandlePutObject(MIR* mir) {
136 // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
137 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100138 HandleEscapingRef(base);
139}
140
141void LocalValueNumbering::HandleEscapingRef(uint16_t base) {
142 auto it = non_aliasing_refs_.find(base);
143 if (it != non_aliasing_refs_.end()) {
144 uint64_t iget_key = BuildKey(Instruction::IGET, base, 0u, 0u);
145 for (auto iget_it = value_map_.lower_bound(iget_key), iget_end = value_map_.end();
146 iget_it != iget_end && EqualOpAndOperand1(iget_it->first, iget_key); ++iget_it) {
147 uint16_t field_id = ExtractOperand2(iget_it->first);
148 uint16_t type = ExtractModifier(iget_it->first);
149 NonAliasingIFieldKey key = { base, field_id, type };
150 non_aliasing_ifields_.insert(key);
151 }
152 uint64_t aget_key = BuildKey(kNonAliasingArrayStartVersionOp, base, 0u, 0u);
153 auto aget_it = value_map_.lower_bound(aget_key);
154 if (aget_it != value_map_.end() && EqualOpAndOperand1(aget_key, aget_it->first)) {
155 DCHECK_EQ(ExtractOperand2(aget_it->first), kNoValue);
156 uint16_t type = ExtractModifier(aget_it->first);
157 EscapedArrayKey key = { base, type };
158 escaped_array_refs_.insert(key);
159 }
160 non_aliasing_refs_.erase(it);
161 }
162}
163
164uint16_t LocalValueNumbering::HandleAGet(MIR* mir, uint16_t opcode) {
165 // uint16_t type = opcode - Instruction::AGET;
166 uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
167 HandleNullCheck(mir, array);
168 uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
169 HandleRangeCheck(mir, array, index);
170 uint16_t type = opcode - Instruction::AGET;
171 // Establish value number for loaded register.
172 uint16_t res;
173 if (IsNonAliasingArray(array, type)) {
174 // Get the start version that accounts for aliasing within the array (different index names).
175 uint16_t start_version = LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, type);
176 // Find the current version from the non_aliasing_array_version_map_.
177 uint16_t memory_version = start_version;
178 auto it = non_aliasing_array_version_map_.find(start_version);
179 if (it != non_aliasing_array_version_map_.end()) {
180 memory_version = it->second;
181 } else {
182 // Just use the start_version.
183 }
184 res = LookupValue(kNonAliasingArrayOp, array, index, memory_version);
185 } else {
186 // Get the memory version of aliased array accesses of this type.
187 uint16_t memory_version = LookupValue(kAliasingArrayMemoryVersionOp, global_memory_version_,
188 aliasing_array_version_[type], kNoValue);
189 res = LookupValue(kAliasingArrayOp, array, index, memory_version);
190 }
191 if (opcode == Instruction::AGET_WIDE) {
192 SetOperandValueWide(mir->ssa_rep->defs[0], res);
193 } else {
194 SetOperandValue(mir->ssa_rep->defs[0], res);
195 }
196 return res;
197}
198
199void LocalValueNumbering::HandleAPut(MIR* mir, uint16_t opcode) {
200 int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
201 int index_idx = array_idx + 1;
202 uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]);
203 HandleNullCheck(mir, array);
204 uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
205 HandleRangeCheck(mir, array, index);
206
207 uint16_t type = opcode - Instruction::APUT;
208 uint16_t value = (opcode == Instruction::APUT_WIDE)
209 ? GetOperandValueWide(mir->ssa_rep->uses[0])
210 : GetOperandValue(mir->ssa_rep->uses[0]);
211 if (IsNonAliasing(array)) {
212 // Get the start version that accounts for aliasing within the array (different index values).
213 uint16_t start_version = LookupValue(kNonAliasingArrayStartVersionOp, array, kNoValue, type);
214 auto it = non_aliasing_array_version_map_.find(start_version);
215 uint16_t memory_version = start_version;
216 if (it != non_aliasing_array_version_map_.end()) {
217 memory_version = it->second;
218 }
219 // We need to take 4 values (array, index, memory_version, value) into account for bumping
220 // the memory version but the key can take only 3. Merge array and index into a location.
221 uint16_t array_access_location = LookupValue(kArrayAccessLocOp, array, index, kNoValue);
222 // Bump the version, adding to the chain.
223 memory_version = LookupValue(kAliasingArrayBumpVersionOp, memory_version,
224 array_access_location, value);
225 non_aliasing_array_version_map_.Overwrite(start_version, memory_version);
226 StoreValue(kNonAliasingArrayOp, array, index, memory_version, value);
227 } else {
228 // Get the memory version based on global_memory_version_ and aliasing_array_version_[type].
229 uint16_t memory_version = LookupValue(kAliasingArrayMemoryVersionOp, global_memory_version_,
230 aliasing_array_version_[type], kNoValue);
231 if (HasValue(kAliasingArrayOp, array, index, memory_version, value)) {
232 // This APUT can be eliminated, it stores the same value that's already in the field.
233 // TODO: Eliminate the APUT.
234 return;
235 }
236 // We need to take 4 values (array, index, memory_version, value) into account for bumping
237 // the memory version but the key can take only 3. Merge array and index into a location.
238 uint16_t array_access_location = LookupValue(kArrayAccessLocOp, array, index, kNoValue);
239 // Bump the version, adding to the chain.
240 uint16_t bumped_version = LookupValue(kAliasingArrayBumpVersionOp, memory_version,
241 array_access_location, value);
242 aliasing_array_version_[type] = bumped_version;
243 memory_version = LookupValue(kAliasingArrayMemoryVersionOp, global_memory_version_,
244 bumped_version, kNoValue);
245 StoreValue(kAliasingArrayOp, array, index, memory_version, value);
246
247 // Clear escaped array refs for this type.
248 EscapedArrayKey array_key = { type, 0u };
249 auto it = escaped_array_refs_.lower_bound(array_key), end = escaped_array_refs_.end();
250 while (it != end && it->type == type) {
251 it = escaped_array_refs_.erase(it);
252 }
253 }
254}
255
256uint16_t LocalValueNumbering::HandleIGet(MIR* mir, uint16_t opcode) {
257 uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
258 HandleNullCheck(mir, base);
259 const MirFieldInfo& field_info = cu_->mir_graph->GetIFieldLoweringInfo(mir);
260 uint16_t res;
261 if (!field_info.IsResolved() || field_info.IsVolatile()) {
262 // Volatile fields always get a new memory version; field id is irrelevant.
263 // Unresolved fields may be volatile, so handle them as such to be safe.
264 // Use result s_reg - will be unique.
265 res = LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
266 } else {
267 uint16_t type = opcode - Instruction::IGET;
268 uint16_t field_id = GetFieldId(field_info);
269 if (IsNonAliasingIField(base, field_id, type)) {
270 res = LookupValue(kNonAliasingIFieldOp, base, field_id, type);
271 } else {
272 // Get the start version that accounts for aliasing with unresolved fields of the same type
273 // and make it unique for the field by including the field_id.
274 uint16_t start_version = LookupValue(kAliasingIFieldStartVersionOp, global_memory_version_,
275 unresolved_ifield_version_[type], field_id);
276 // Find the current version from the aliasing_ifield_version_map_.
277 uint16_t memory_version = start_version;
278 auto version_it = aliasing_ifield_version_map_.find(start_version);
279 if (version_it != aliasing_ifield_version_map_.end()) {
280 memory_version = version_it->second;
281 } else {
282 // Just use the start_version.
283 }
284 res = LookupValue(kAliasingIFieldOp, base, field_id, memory_version);
285 }
286 }
287 if (opcode == Instruction::IGET_WIDE) {
288 SetOperandValueWide(mir->ssa_rep->defs[0], res);
289 } else {
290 SetOperandValue(mir->ssa_rep->defs[0], res);
291 }
292 return res;
293}
294
295void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) {
296 uint16_t type = opcode - Instruction::IPUT;
297 int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
298 uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
299 HandleNullCheck(mir, base);
300 const MirFieldInfo& field_info = cu_->mir_graph->GetIFieldLoweringInfo(mir);
301 if (!field_info.IsResolved()) {
302 // Unresolved fields always alias with everything of the same type.
303 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
304 unresolved_ifield_version_[type] =
305 LookupValue(kUnresolvedIFieldOp, kNoValue, kNoValue, mir->offset);
306
307 // Treat fields of escaped references of the same type as potentially modified.
308 NonAliasingIFieldKey key = { type, 0u, 0u }; // lowest possible key of this type.
309 auto it = non_aliasing_ifields_.lower_bound(key), end = non_aliasing_ifields_.end();
310 while (it != end && it->type == type) {
311 it = non_aliasing_ifields_.erase(it);
312 }
313 } else if (field_info.IsVolatile()) {
314 // Nothing to do, resolved volatile fields always get a new memory version anyway and
315 // can't alias with resolved non-volatile fields.
316 } else {
317 uint16_t field_id = GetFieldId(field_info);
318 uint16_t value = (opcode == Instruction::IPUT_WIDE)
319 ? GetOperandValueWide(mir->ssa_rep->uses[0])
320 : GetOperandValue(mir->ssa_rep->uses[0]);
321 if (IsNonAliasing(base)) {
322 StoreValue(kNonAliasingIFieldOp, base, field_id, type, value);
323 } else {
324 // Get the start version that accounts for aliasing with unresolved fields of the same type
325 // and make it unique for the field by including the field_id.
326 uint16_t start_version = LookupValue(kAliasingIFieldStartVersionOp, global_memory_version_,
327 unresolved_ifield_version_[type], field_id);
328 // Find the old version from the aliasing_ifield_version_map_.
329 uint16_t old_version = start_version;
330 auto version_it = aliasing_ifield_version_map_.find(start_version);
331 if (version_it != aliasing_ifield_version_map_.end()) {
332 old_version = version_it->second;
333 }
334 // Check if the field currently contains the value, making this a NOP.
335 if (HasValue(kAliasingIFieldOp, base, field_id, old_version, value)) {
336 // This IPUT can be eliminated, it stores the same value that's already in the field.
337 // TODO: Eliminate the IPUT.
338 return;
339 }
340 // Bump the version, adding to the chain started by start_version.
341 uint16_t memory_version = LookupValue(kAliasingIFieldBumpVersionOp, old_version, base, value);
342 // Update the aliasing_ifield_version_map_ so that HandleIGet() can get the memory_version
343 // without knowing the values used to build the chain.
344 aliasing_ifield_version_map_.Overwrite(start_version, memory_version);
345 StoreValue(kAliasingIFieldOp, base, field_id, memory_version, value);
346
347 // Clear non-aliasing fields for this field_id.
348 NonAliasingIFieldKey field_key = { type, field_id, 0u };
349 auto it = non_aliasing_ifields_.lower_bound(field_key), end = non_aliasing_ifields_.end();
350 while (it != end && it->field_id == field_id) {
351 DCHECK_EQ(type, it->type);
352 it = non_aliasing_ifields_.erase(it);
353 }
354 }
355 }
356}
357
358uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) {
359 const MirFieldInfo& field_info = cu_->mir_graph->GetSFieldLoweringInfo(mir);
360 uint16_t res;
361 if (!field_info.IsResolved() || field_info.IsVolatile()) {
362 // Volatile fields always get a new memory version; field id is irrelevant.
363 // Unresolved fields may be volatile, so handle them as such to be safe.
364 // Use result s_reg - will be unique.
365 res = LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue);
366 } else {
367 uint16_t field_id = GetFieldId(field_info);
368 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
369 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
370 // to determine the version of the field.
371 uint16_t type = opcode - Instruction::SGET;
372 res = LookupValue(kResolvedSFieldOp, field_id,
373 unresolved_sfield_version_[type], global_memory_version_);
374 }
375 if (opcode == Instruction::SGET_WIDE) {
376 SetOperandValueWide(mir->ssa_rep->defs[0], res);
377 } else {
378 SetOperandValue(mir->ssa_rep->defs[0], res);
379 }
380 return res;
381}
382
383void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) {
384 uint16_t type = opcode - Instruction::SPUT;
385 const MirFieldInfo& field_info = cu_->mir_graph->GetSFieldLoweringInfo(mir);
386 if (!field_info.IsResolved()) {
387 // Unresolved fields always alias with everything of the same type.
388 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
389 unresolved_sfield_version_[type] =
390 LookupValue(kUnresolvedSFieldOp, kNoValue, kNoValue, mir->offset);
391 } else if (field_info.IsVolatile()) {
392 // Nothing to do, resolved volatile fields always get a new memory version anyway and
393 // can't alias with resolved non-volatile fields.
394 } else {
395 uint16_t field_id = GetFieldId(field_info);
396 uint16_t value = (opcode == Instruction::SPUT_WIDE)
397 ? GetOperandValueWide(mir->ssa_rep->uses[0])
398 : GetOperandValue(mir->ssa_rep->uses[0]);
399 // Resolved non-volatile static fields can alias with non-resolved fields of the same type,
400 // so we need to use unresolved_sfield_version_[type] in addition to global_memory_version_
401 // to determine the version of the field.
402 uint16_t type = opcode - Instruction::SGET;
403 StoreValue(kResolvedSFieldOp, field_id,
404 unresolved_sfield_version_[type], global_memory_version_, value);
405 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000406}
buzbee2502e002012-12-31 16:05:53 -0800407
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700408uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100409 uint16_t res = kNoValue;
buzbee2502e002012-12-31 16:05:53 -0800410 uint16_t opcode = mir->dalvikInsn.opcode;
411 switch (opcode) {
412 case Instruction::NOP:
413 case Instruction::RETURN_VOID:
414 case Instruction::RETURN:
415 case Instruction::RETURN_OBJECT:
416 case Instruction::RETURN_WIDE:
417 case Instruction::MONITOR_ENTER:
418 case Instruction::MONITOR_EXIT:
419 case Instruction::GOTO:
420 case Instruction::GOTO_16:
421 case Instruction::GOTO_32:
422 case Instruction::CHECK_CAST:
423 case Instruction::THROW:
424 case Instruction::FILL_ARRAY_DATA:
buzbee2502e002012-12-31 16:05:53 -0800425 case Instruction::PACKED_SWITCH:
426 case Instruction::SPARSE_SWITCH:
427 case Instruction::IF_EQ:
428 case Instruction::IF_NE:
429 case Instruction::IF_LT:
430 case Instruction::IF_GE:
431 case Instruction::IF_GT:
432 case Instruction::IF_LE:
433 case Instruction::IF_EQZ:
434 case Instruction::IF_NEZ:
435 case Instruction::IF_LTZ:
436 case Instruction::IF_GEZ:
437 case Instruction::IF_GTZ:
438 case Instruction::IF_LEZ:
buzbee2502e002012-12-31 16:05:53 -0800439 case kMirOpFusedCmplFloat:
440 case kMirOpFusedCmpgFloat:
441 case kMirOpFusedCmplDouble:
442 case kMirOpFusedCmpgDouble:
443 case kMirOpFusedCmpLong:
444 // Nothing defined - take no action.
445 break;
446
Vladimir Markof59f18b2014-02-17 15:53:57 +0000447 case Instruction::FILLED_NEW_ARRAY:
448 case Instruction::FILLED_NEW_ARRAY_RANGE:
449 // Nothing defined but the result will be unique and non-null.
450 if (mir->next != nullptr && mir->next->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
451 MarkNonAliasingNonNull(mir->next);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100452 // TUNING: We could track value names stored in the array.
Vladimir Markof59f18b2014-02-17 15:53:57 +0000453 // The MOVE_RESULT_OBJECT will be processed next and we'll return the value name then.
454 }
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100455 // All args escaped (if references).
456 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
457 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
458 HandleEscapingRef(reg);
459 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000460 break;
461
462 case Instruction::INVOKE_DIRECT:
463 case Instruction::INVOKE_DIRECT_RANGE:
464 case Instruction::INVOKE_VIRTUAL:
465 case Instruction::INVOKE_VIRTUAL_RANGE:
466 case Instruction::INVOKE_SUPER:
467 case Instruction::INVOKE_SUPER_RANGE:
468 case Instruction::INVOKE_INTERFACE:
469 case Instruction::INVOKE_INTERFACE_RANGE: {
470 // Nothing defined but handle the null check.
471 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
472 HandleNullCheck(mir, reg);
473 }
474 // Intentional fall-through.
475 case Instruction::INVOKE_STATIC:
476 case Instruction::INVOKE_STATIC_RANGE:
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000477 if ((mir->optimization_flags & MIR_INLINED) == 0) {
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100478 // Use mir->offset as modifier; without elaborate inlining, it will be unique.
479 global_memory_version_ = LookupValue(kInvokeMemoryVersionBumpOp, 0u, 0u, mir->offset);
480 // Make ref args aliasing.
481 for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
482 uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
483 non_aliasing_refs_.erase(reg);
484 }
485 // All fields of escaped references need to be treated as potentially modified.
486 non_aliasing_ifields_.clear();
487 // Array elements may also have been modified via escaped array refs.
488 escaped_array_refs_.clear();
Vladimir Marko9820b7c2014-01-02 16:40:37 +0000489 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000490 break;
491
buzbee2502e002012-12-31 16:05:53 -0800492 case Instruction::MOVE_RESULT:
493 case Instruction::MOVE_RESULT_OBJECT:
494 case Instruction::INSTANCE_OF:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000495 // 1 result, treat as unique each time, use result s_reg - will be unique.
496 res = GetOperandValue(mir->ssa_rep->defs[0]);
497 SetOperandValue(mir->ssa_rep->defs[0], res);
498 break;
499 case Instruction::MOVE_EXCEPTION:
buzbee2502e002012-12-31 16:05:53 -0800500 case Instruction::NEW_INSTANCE:
buzbee2502e002012-12-31 16:05:53 -0800501 case Instruction::CONST_CLASS:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000502 case Instruction::NEW_ARRAY:
Vladimir Markob3e527b2014-04-04 12:37:07 +0100503 // 1 result, treat as unique each time, use result s_reg - will be unique.
504 res = MarkNonAliasingNonNull(mir);
buzbee2502e002012-12-31 16:05:53 -0800505 break;
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100506 case Instruction::CONST_STRING:
507 case Instruction::CONST_STRING_JUMBO:
508 // These strings are internalized, so assign value based on the string pool index.
509 res = LookupValue(Instruction::CONST_STRING, Low16Bits(mir->dalvikInsn.vB),
510 High16Bits(mir->dalvikInsn.vB), 0);
511 SetOperandValue(mir->ssa_rep->defs[0], res);
512 null_checked_.insert(res); // May already be there.
513 // NOTE: Hacking the contents of an internalized string via reflection is possible
514 // but the behavior is undefined. Therefore, we consider the string constant and
515 // the reference non-aliasing.
516 // TUNING: We could keep this property even if the reference "escapes".
517 non_aliasing_refs_.insert(res); // May already be there.
518 break;
Vladimir Markof59f18b2014-02-17 15:53:57 +0000519 case Instruction::MOVE_RESULT_WIDE:
Vladimir Markob3e527b2014-04-04 12:37:07 +0100520 // 1 wide result, treat as unique each time, use result s_reg - will be unique.
521 res = GetOperandValueWide(mir->ssa_rep->defs[0]);
522 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -0800523 break;
524
525 case kMirOpPhi:
526 /*
527 * Because we'll only see phi nodes at the beginning of an extended basic block,
528 * we can ignore them. Revisit if we shift to global value numbering.
529 */
530 break;
531
532 case Instruction::MOVE:
533 case Instruction::MOVE_OBJECT:
534 case Instruction::MOVE_16:
535 case Instruction::MOVE_OBJECT_16:
536 case Instruction::MOVE_FROM16:
537 case Instruction::MOVE_OBJECT_FROM16:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000538 case kMirOpCopy:
539 // Just copy value number of source to value number of result.
540 res = GetOperandValue(mir->ssa_rep->uses[0]);
541 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -0800542 break;
543
544 case Instruction::MOVE_WIDE:
545 case Instruction::MOVE_WIDE_16:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000546 case Instruction::MOVE_WIDE_FROM16:
547 // Just copy value number of source to value number of result.
548 res = GetOperandValueWide(mir->ssa_rep->uses[0]);
549 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -0800550 break;
551
552 case Instruction::CONST:
553 case Instruction::CONST_4:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000554 case Instruction::CONST_16:
555 res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100556 High16Bits(mir->dalvikInsn.vB), 0);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000557 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -0800558 break;
559
Vladimir Markof59f18b2014-02-17 15:53:57 +0000560 case Instruction::CONST_HIGH16:
561 res = LookupValue(Instruction::CONST, 0, mir->dalvikInsn.vB, 0);
562 SetOperandValue(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -0800563 break;
564
565 case Instruction::CONST_WIDE_16:
566 case Instruction::CONST_WIDE_32: {
567 uint16_t low_res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
568 High16Bits(mir->dalvikInsn.vB >> 16), 1);
569 uint16_t high_res;
570 if (mir->dalvikInsn.vB & 0x80000000) {
571 high_res = LookupValue(Instruction::CONST, 0xffff, 0xffff, 2);
572 } else {
573 high_res = LookupValue(Instruction::CONST, 0, 0, 2);
574 }
Vladimir Markof59f18b2014-02-17 15:53:57 +0000575 res = LookupValue(Instruction::CONST, low_res, high_res, 3);
576 SetOperandValueWide(mir->ssa_rep->defs[0], res);
buzbee2502e002012-12-31 16:05:53 -0800577 }
578 break;
579
580 case Instruction::CONST_WIDE: {
581 uint32_t low_word = Low32Bits(mir->dalvikInsn.vB_wide);
582 uint32_t high_word = High32Bits(mir->dalvikInsn.vB_wide);
583 uint16_t low_res = LookupValue(Instruction::CONST, Low16Bits(low_word),
584 High16Bits(low_word), 1);
585 uint16_t high_res = LookupValue(Instruction::CONST, Low16Bits(high_word),
586 High16Bits(high_word), 2);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000587 res = LookupValue(Instruction::CONST, low_res, high_res, 3);
buzbee2502e002012-12-31 16:05:53 -0800588 SetOperandValueWide(mir->ssa_rep->defs[0], res);
589 }
590 break;
591
592 case Instruction::CONST_WIDE_HIGH16: {
593 uint16_t low_res = LookupValue(Instruction::CONST, 0, 0, 1);
594 uint16_t high_res = LookupValue(Instruction::CONST, 0, Low16Bits(mir->dalvikInsn.vB), 2);
Vladimir Markof59f18b2014-02-17 15:53:57 +0000595 res = LookupValue(Instruction::CONST, low_res, high_res, 3);
buzbee2502e002012-12-31 16:05:53 -0800596 SetOperandValueWide(mir->ssa_rep->defs[0], res);
597 }
598 break;
599
600 case Instruction::ARRAY_LENGTH:
601 case Instruction::NEG_INT:
602 case Instruction::NOT_INT:
603 case Instruction::NEG_FLOAT:
604 case Instruction::INT_TO_BYTE:
605 case Instruction::INT_TO_SHORT:
606 case Instruction::INT_TO_CHAR:
607 case Instruction::INT_TO_FLOAT:
608 case Instruction::FLOAT_TO_INT: {
609 // res = op + 1 operand
610 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100611 res = LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800612 SetOperandValue(mir->ssa_rep->defs[0], res);
613 }
614 break;
615
616 case Instruction::LONG_TO_FLOAT:
617 case Instruction::LONG_TO_INT:
618 case Instruction::DOUBLE_TO_FLOAT:
619 case Instruction::DOUBLE_TO_INT: {
620 // res = op + 1 wide operand
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100621 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
622 res = LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800623 SetOperandValue(mir->ssa_rep->defs[0], res);
624 }
625 break;
626
627
628 case Instruction::DOUBLE_TO_LONG:
629 case Instruction::LONG_TO_DOUBLE:
630 case Instruction::NEG_LONG:
631 case Instruction::NOT_LONG:
632 case Instruction::NEG_DOUBLE: {
633 // wide res = op + 1 wide operand
634 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100635 res = LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800636 SetOperandValueWide(mir->ssa_rep->defs[0], res);
637 }
638 break;
639
640 case Instruction::FLOAT_TO_DOUBLE:
641 case Instruction::FLOAT_TO_LONG:
642 case Instruction::INT_TO_DOUBLE:
643 case Instruction::INT_TO_LONG: {
644 // wide res = op + 1 operand
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100645 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
646 res = LookupValue(opcode, operand1, kNoValue, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800647 SetOperandValueWide(mir->ssa_rep->defs[0], res);
648 }
649 break;
650
651 case Instruction::CMPL_DOUBLE:
652 case Instruction::CMPG_DOUBLE:
653 case Instruction::CMP_LONG: {
654 // res = op + 2 wide operands
655 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
656 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100657 res = LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800658 SetOperandValue(mir->ssa_rep->defs[0], res);
659 }
660 break;
661
662 case Instruction::CMPG_FLOAT:
663 case Instruction::CMPL_FLOAT:
664 case Instruction::ADD_INT:
665 case Instruction::ADD_INT_2ADDR:
666 case Instruction::MUL_INT:
667 case Instruction::MUL_INT_2ADDR:
668 case Instruction::AND_INT:
669 case Instruction::AND_INT_2ADDR:
670 case Instruction::OR_INT:
671 case Instruction::OR_INT_2ADDR:
672 case Instruction::XOR_INT:
673 case Instruction::XOR_INT_2ADDR:
674 case Instruction::SUB_INT:
675 case Instruction::SUB_INT_2ADDR:
676 case Instruction::DIV_INT:
677 case Instruction::DIV_INT_2ADDR:
678 case Instruction::REM_INT:
679 case Instruction::REM_INT_2ADDR:
680 case Instruction::SHL_INT:
681 case Instruction::SHL_INT_2ADDR:
682 case Instruction::SHR_INT:
683 case Instruction::SHR_INT_2ADDR:
684 case Instruction::USHR_INT:
685 case Instruction::USHR_INT_2ADDR: {
686 // res = op + 2 operands
687 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
688 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100689 res = LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800690 SetOperandValue(mir->ssa_rep->defs[0], res);
691 }
692 break;
693
694 case Instruction::ADD_LONG:
695 case Instruction::SUB_LONG:
696 case Instruction::MUL_LONG:
697 case Instruction::DIV_LONG:
698 case Instruction::REM_LONG:
699 case Instruction::AND_LONG:
700 case Instruction::OR_LONG:
701 case Instruction::XOR_LONG:
702 case Instruction::ADD_LONG_2ADDR:
703 case Instruction::SUB_LONG_2ADDR:
704 case Instruction::MUL_LONG_2ADDR:
705 case Instruction::DIV_LONG_2ADDR:
706 case Instruction::REM_LONG_2ADDR:
707 case Instruction::AND_LONG_2ADDR:
708 case Instruction::OR_LONG_2ADDR:
709 case Instruction::XOR_LONG_2ADDR:
710 case Instruction::ADD_DOUBLE:
711 case Instruction::SUB_DOUBLE:
712 case Instruction::MUL_DOUBLE:
713 case Instruction::DIV_DOUBLE:
714 case Instruction::REM_DOUBLE:
715 case Instruction::ADD_DOUBLE_2ADDR:
716 case Instruction::SUB_DOUBLE_2ADDR:
717 case Instruction::MUL_DOUBLE_2ADDR:
718 case Instruction::DIV_DOUBLE_2ADDR:
719 case Instruction::REM_DOUBLE_2ADDR: {
720 // wide res = op + 2 wide operands
721 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
722 uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100723 res = LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800724 SetOperandValueWide(mir->ssa_rep->defs[0], res);
725 }
726 break;
727
728 case Instruction::SHL_LONG:
729 case Instruction::SHR_LONG:
730 case Instruction::USHR_LONG:
731 case Instruction::SHL_LONG_2ADDR:
732 case Instruction::SHR_LONG_2ADDR:
733 case Instruction::USHR_LONG_2ADDR: {
734 // wide res = op + 1 wide operand + 1 operand
735 uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100736 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[2]);
737 res = LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800738 SetOperandValueWide(mir->ssa_rep->defs[0], res);
739 }
740 break;
741
742 case Instruction::ADD_FLOAT:
743 case Instruction::SUB_FLOAT:
744 case Instruction::MUL_FLOAT:
745 case Instruction::DIV_FLOAT:
746 case Instruction::REM_FLOAT:
747 case Instruction::ADD_FLOAT_2ADDR:
748 case Instruction::SUB_FLOAT_2ADDR:
749 case Instruction::MUL_FLOAT_2ADDR:
750 case Instruction::DIV_FLOAT_2ADDR:
751 case Instruction::REM_FLOAT_2ADDR: {
752 // res = op + 2 operands
753 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
754 uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100755 res = LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800756 SetOperandValue(mir->ssa_rep->defs[0], res);
757 }
758 break;
759
760 case Instruction::RSUB_INT:
761 case Instruction::ADD_INT_LIT16:
762 case Instruction::MUL_INT_LIT16:
763 case Instruction::DIV_INT_LIT16:
764 case Instruction::REM_INT_LIT16:
765 case Instruction::AND_INT_LIT16:
766 case Instruction::OR_INT_LIT16:
767 case Instruction::XOR_INT_LIT16:
768 case Instruction::ADD_INT_LIT8:
769 case Instruction::RSUB_INT_LIT8:
770 case Instruction::MUL_INT_LIT8:
771 case Instruction::DIV_INT_LIT8:
772 case Instruction::REM_INT_LIT8:
773 case Instruction::AND_INT_LIT8:
774 case Instruction::OR_INT_LIT8:
775 case Instruction::XOR_INT_LIT8:
776 case Instruction::SHL_INT_LIT8:
777 case Instruction::SHR_INT_LIT8:
778 case Instruction::USHR_INT_LIT8: {
nikolay serdjukee40aa42014-03-25 12:21:29 +0700779 // Same as res = op + 2 operands, except use vC as operand 2
buzbee2502e002012-12-31 16:05:53 -0800780 uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
nikolay serdjukee40aa42014-03-25 12:21:29 +0700781 uint16_t operand2 = LookupValue(Instruction::CONST, mir->dalvikInsn.vC, 0, 0);
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100782 res = LookupValue(opcode, operand1, operand2, kNoValue);
buzbee2502e002012-12-31 16:05:53 -0800783 SetOperandValue(mir->ssa_rep->defs[0], res);
784 }
785 break;
786
buzbee2502e002012-12-31 16:05:53 -0800787 case Instruction::AGET_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000788 case Instruction::AGET:
789 case Instruction::AGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -0800790 case Instruction::AGET_BOOLEAN:
791 case Instruction::AGET_BYTE:
792 case Instruction::AGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100793 case Instruction::AGET_SHORT:
794 res = HandleAGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -0800795 break;
796
buzbee2502e002012-12-31 16:05:53 -0800797 case Instruction::APUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000798 HandlePutObject(mir);
799 // Intentional fall-through.
800 case Instruction::APUT:
801 case Instruction::APUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -0800802 case Instruction::APUT_BYTE:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000803 case Instruction::APUT_BOOLEAN:
804 case Instruction::APUT_SHORT:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100805 case Instruction::APUT_CHAR:
806 HandleAPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -0800807 break;
808
809 case Instruction::IGET_OBJECT:
buzbee2502e002012-12-31 16:05:53 -0800810 case Instruction::IGET:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000811 case Instruction::IGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -0800812 case Instruction::IGET_BOOLEAN:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000813 case Instruction::IGET_BYTE:
814 case Instruction::IGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100815 case Instruction::IGET_SHORT:
816 res = HandleIGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -0800817 break;
818
buzbee2502e002012-12-31 16:05:53 -0800819 case Instruction::IPUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000820 HandlePutObject(mir);
821 // Intentional fall-through.
buzbee2502e002012-12-31 16:05:53 -0800822 case Instruction::IPUT:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000823 case Instruction::IPUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -0800824 case Instruction::IPUT_BOOLEAN:
825 case Instruction::IPUT_BYTE:
826 case Instruction::IPUT_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100827 case Instruction::IPUT_SHORT:
828 HandleIPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -0800829 break;
830
831 case Instruction::SGET_OBJECT:
832 case Instruction::SGET:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000833 case Instruction::SGET_WIDE:
buzbee2502e002012-12-31 16:05:53 -0800834 case Instruction::SGET_BOOLEAN:
835 case Instruction::SGET_BYTE:
836 case Instruction::SGET_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100837 case Instruction::SGET_SHORT:
838 res = HandleSGet(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -0800839 break;
840
841 case Instruction::SPUT_OBJECT:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000842 HandlePutObject(mir);
843 // Intentional fall-through.
buzbee2502e002012-12-31 16:05:53 -0800844 case Instruction::SPUT:
Vladimir Markof59f18b2014-02-17 15:53:57 +0000845 case Instruction::SPUT_WIDE:
buzbee2502e002012-12-31 16:05:53 -0800846 case Instruction::SPUT_BOOLEAN:
847 case Instruction::SPUT_BYTE:
848 case Instruction::SPUT_CHAR:
Vladimir Marko2ac01fc2014-05-22 12:09:08 +0100849 case Instruction::SPUT_SHORT:
850 HandleSPut(mir, opcode);
buzbee2502e002012-12-31 16:05:53 -0800851 break;
buzbee2502e002012-12-31 16:05:53 -0800852 }
853 return res;
854}
855
856} // namespace art