interpreter_common.h revision 3d21bdf8894e780d349c481e5c9e29fe1556051c
1/* 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 17#ifndef ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_ 18#define ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_ 19 20#include "interpreter.h" 21 22#include <math.h> 23 24#include <iostream> 25#include <sstream> 26 27#include "art_field-inl.h" 28#include "art_method-inl.h" 29#include "base/logging.h" 30#include "base/macros.h" 31#include "class_linker-inl.h" 32#include "common_throws.h" 33#include "dex_file-inl.h" 34#include "dex_instruction-inl.h" 35#include "entrypoints/entrypoint_utils-inl.h" 36#include "handle_scope-inl.h" 37#include "mirror/class-inl.h" 38#include "mirror/object-inl.h" 39#include "mirror/object_array-inl.h" 40#include "mirror/string-inl.h" 41#include "thread.h" 42#include "well_known_classes.h" 43 44using ::art::ArtMethod; 45using ::art::mirror::Array; 46using ::art::mirror::BooleanArray; 47using ::art::mirror::ByteArray; 48using ::art::mirror::CharArray; 49using ::art::mirror::Class; 50using ::art::mirror::ClassLoader; 51using ::art::mirror::IntArray; 52using ::art::mirror::LongArray; 53using ::art::mirror::Object; 54using ::art::mirror::ObjectArray; 55using ::art::mirror::ShortArray; 56using ::art::mirror::String; 57using ::art::mirror::Throwable; 58 59namespace art { 60namespace interpreter { 61 62// External references to both interpreter implementations. 63 64template<bool do_access_check, bool transaction_active> 65extern JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, 66 ShadowFrame& shadow_frame, JValue result_register); 67 68template<bool do_access_check, bool transaction_active> 69extern JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, 70 ShadowFrame& shadow_frame, JValue result_register); 71 72void ThrowNullPointerExceptionFromInterpreter() 73 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 74 75static inline void DoMonitorEnter(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS { 76 ref->MonitorEnter(self); 77} 78 79static inline void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS { 80 ref->MonitorExit(self); 81} 82 83void AbortTransactionF(Thread* self, const char* fmt, ...) 84 __attribute__((__format__(__printf__, 2, 3))) 85 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 86 87void AbortTransactionV(Thread* self, const char* fmt, va_list args) 88 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 89 90void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count) 91 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 92 93// Invokes the given method. This is part of the invocation support and is used by DoInvoke and 94// DoInvokeVirtualQuick functions. 95// Returns true on success, otherwise throws an exception and returns false. 96template<bool is_range, bool do_assignability_check> 97bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame, 98 const Instruction* inst, uint16_t inst_data, JValue* result); 99 100// Handles invoke-XXX/range instructions. 101// Returns true on success, otherwise throws an exception and returns false. 102template<InvokeType type, bool is_range, bool do_access_check> 103static inline bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, 104 uint16_t inst_data, JValue* result) { 105 const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); 106 const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); 107 Object* receiver = (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC); 108 ArtMethod* sf_method = shadow_frame.GetMethod(); 109 ArtMethod* const called_method = FindMethodFromCode<type, do_access_check>( 110 method_idx, &receiver, &sf_method, self); 111 // The shadow frame should already be pushed, so we don't need to update it. 112 if (UNLIKELY(called_method == nullptr)) { 113 CHECK(self->IsExceptionPending()); 114 result->SetJ(0); 115 return false; 116 } else if (UNLIKELY(called_method->IsAbstract())) { 117 ThrowAbstractMethodError(called_method); 118 result->SetJ(0); 119 return false; 120 } else { 121 return DoCall<is_range, do_access_check>(called_method, self, shadow_frame, inst, inst_data, 122 result); 123 } 124} 125 126// Handles invoke-virtual-quick and invoke-virtual-quick-range instructions. 127// Returns true on success, otherwise throws an exception and returns false. 128template<bool is_range> 129static inline bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, 130 const Instruction* inst, uint16_t inst_data, 131 JValue* result) { 132 const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); 133 Object* const receiver = shadow_frame.GetVRegReference(vregC); 134 if (UNLIKELY(receiver == nullptr)) { 135 // We lost the reference to the method index so we cannot get a more 136 // precised exception message. 137 ThrowNullPointerExceptionFromDexPC(); 138 return false; 139 } 140 const uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); 141 CHECK(receiver->GetClass()->ShouldHaveEmbeddedImtAndVTable()); 142 ArtMethod* const called_method = receiver->GetClass()->GetEmbeddedVTableEntry( 143 vtable_idx, sizeof(void*)); 144 if (UNLIKELY(called_method == nullptr)) { 145 CHECK(self->IsExceptionPending()); 146 result->SetJ(0); 147 return false; 148 } else if (UNLIKELY(called_method->IsAbstract())) { 149 ThrowAbstractMethodError(called_method); 150 result->SetJ(0); 151 return false; 152 } else { 153 // No need to check since we've been quickened. 154 return DoCall<is_range, false>(called_method, self, shadow_frame, inst, inst_data, result); 155 } 156} 157 158// Handles iget-XXX and sget-XXX instructions. 159// Returns true on success, otherwise throws an exception and returns false. 160template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> 161bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, 162 uint16_t inst_data) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 163 164// Handles iget-quick, iget-wide-quick and iget-object-quick instructions. 165// Returns true on success, otherwise throws an exception and returns false. 166template<Primitive::Type field_type> 167bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) 168 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 169 170// Handles iput-XXX and sput-XXX instructions. 171// Returns true on success, otherwise throws an exception and returns false. 172template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, 173 bool transaction_active> 174bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst, 175 uint16_t inst_data) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 176 177// Handles iput-quick, iput-wide-quick and iput-object-quick instructions. 178// Returns true on success, otherwise throws an exception and returns false. 179template<Primitive::Type field_type, bool transaction_active> 180bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) 181 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 182 183 184// Handles string resolution for const-string and const-string-jumbo instructions. Also ensures the 185// java.lang.String class is initialized. 186static inline String* ResolveString(Thread* self, ShadowFrame& shadow_frame, uint32_t string_idx) 187 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 188 Class* java_lang_string_class = String::GetJavaLangString(); 189 if (UNLIKELY(!java_lang_string_class->IsInitialized())) { 190 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 191 StackHandleScope<1> hs(self); 192 Handle<mirror::Class> h_class(hs.NewHandle(java_lang_string_class)); 193 if (UNLIKELY(!class_linker->EnsureInitialized(self, h_class, true, true))) { 194 DCHECK(self->IsExceptionPending()); 195 return nullptr; 196 } 197 } 198 ArtMethod* method = shadow_frame.GetMethod(); 199 mirror::Class* declaring_class = method->GetDeclaringClass(); 200 mirror::String* s = declaring_class->GetDexCacheStrings()->Get(string_idx); 201 if (UNLIKELY(s == nullptr)) { 202 StackHandleScope<1> hs(self); 203 Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache())); 204 s = Runtime::Current()->GetClassLinker()->ResolveString(*method->GetDexFile(), string_idx, 205 dex_cache); 206 } 207 return s; 208} 209 210// Handles div-int, div-int/2addr, div-int/li16 and div-int/lit8 instructions. 211// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false. 212static inline bool DoIntDivide(ShadowFrame& shadow_frame, size_t result_reg, 213 int32_t dividend, int32_t divisor) 214 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 215 constexpr int32_t kMinInt = std::numeric_limits<int32_t>::min(); 216 if (UNLIKELY(divisor == 0)) { 217 ThrowArithmeticExceptionDivideByZero(); 218 return false; 219 } 220 if (UNLIKELY(dividend == kMinInt && divisor == -1)) { 221 shadow_frame.SetVReg(result_reg, kMinInt); 222 } else { 223 shadow_frame.SetVReg(result_reg, dividend / divisor); 224 } 225 return true; 226} 227 228// Handles rem-int, rem-int/2addr, rem-int/li16 and rem-int/lit8 instructions. 229// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false. 230static inline bool DoIntRemainder(ShadowFrame& shadow_frame, size_t result_reg, 231 int32_t dividend, int32_t divisor) 232 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 233 constexpr int32_t kMinInt = std::numeric_limits<int32_t>::min(); 234 if (UNLIKELY(divisor == 0)) { 235 ThrowArithmeticExceptionDivideByZero(); 236 return false; 237 } 238 if (UNLIKELY(dividend == kMinInt && divisor == -1)) { 239 shadow_frame.SetVReg(result_reg, 0); 240 } else { 241 shadow_frame.SetVReg(result_reg, dividend % divisor); 242 } 243 return true; 244} 245 246// Handles div-long and div-long-2addr instructions. 247// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false. 248static inline bool DoLongDivide(ShadowFrame& shadow_frame, size_t result_reg, 249 int64_t dividend, int64_t divisor) 250 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 251 const int64_t kMinLong = std::numeric_limits<int64_t>::min(); 252 if (UNLIKELY(divisor == 0)) { 253 ThrowArithmeticExceptionDivideByZero(); 254 return false; 255 } 256 if (UNLIKELY(dividend == kMinLong && divisor == -1)) { 257 shadow_frame.SetVRegLong(result_reg, kMinLong); 258 } else { 259 shadow_frame.SetVRegLong(result_reg, dividend / divisor); 260 } 261 return true; 262} 263 264// Handles rem-long and rem-long-2addr instructions. 265// Returns true on success, otherwise throws a java.lang.ArithmeticException and return false. 266static inline bool DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg, 267 int64_t dividend, int64_t divisor) 268 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 269 const int64_t kMinLong = std::numeric_limits<int64_t>::min(); 270 if (UNLIKELY(divisor == 0)) { 271 ThrowArithmeticExceptionDivideByZero(); 272 return false; 273 } 274 if (UNLIKELY(dividend == kMinLong && divisor == -1)) { 275 shadow_frame.SetVRegLong(result_reg, 0); 276 } else { 277 shadow_frame.SetVRegLong(result_reg, dividend % divisor); 278 } 279 return true; 280} 281 282// Handles filled-new-array and filled-new-array-range instructions. 283// Returns true on success, otherwise throws an exception and returns false. 284template <bool is_range, bool do_access_check, bool transaction_active> 285bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame, 286 Thread* self, JValue* result); 287 288// Handles packed-switch instruction. 289// Returns the branch offset to the next instruction to execute. 290static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame, 291 uint16_t inst_data) 292 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 293 DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH); 294 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t(); 295 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data)); 296 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature)); 297 uint16_t size = switch_data[1]; 298 DCHECK_GT(size, 0); 299 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]); 300 DCHECK(IsAligned<4>(keys)); 301 int32_t first_key = keys[0]; 302 const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]); 303 DCHECK(IsAligned<4>(targets)); 304 int32_t index = test_val - first_key; 305 if (index >= 0 && index < size) { 306 return targets[index]; 307 } else { 308 // No corresponding value: move forward by 3 (size of PACKED_SWITCH). 309 return 3; 310 } 311} 312 313// Handles sparse-switch instruction. 314// Returns the branch offset to the next instruction to execute. 315static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame, 316 uint16_t inst_data) 317 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 318 DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH); 319 const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t(); 320 int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data)); 321 DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature)); 322 uint16_t size = switch_data[1]; 323 // Return length of SPARSE_SWITCH if size is 0. 324 if (size == 0) { 325 return 3; 326 } 327 const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]); 328 DCHECK(IsAligned<4>(keys)); 329 const int32_t* entries = keys + size; 330 DCHECK(IsAligned<4>(entries)); 331 int lo = 0; 332 int hi = size - 1; 333 while (lo <= hi) { 334 int mid = (lo + hi) / 2; 335 int32_t foundVal = keys[mid]; 336 if (test_val < foundVal) { 337 hi = mid - 1; 338 } else if (test_val > foundVal) { 339 lo = mid + 1; 340 } else { 341 return entries[mid]; 342 } 343 } 344 // No corresponding value: move forward by 3 (size of SPARSE_SWITCH). 345 return 3; 346} 347 348uint32_t FindNextInstructionFollowingException(Thread* self, ShadowFrame& shadow_frame, 349 uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation) 350 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 351 352NO_RETURN void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame) 353 __attribute__((cold)) 354 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 355 356static inline void TraceExecution(const ShadowFrame& shadow_frame, const Instruction* inst, 357 const uint32_t dex_pc) 358 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 359 constexpr bool kTracing = false; 360 if (kTracing) { 361#define TRACE_LOG std::cerr 362 std::ostringstream oss; 363 oss << PrettyMethod(shadow_frame.GetMethod()) 364 << StringPrintf("\n0x%x: ", dex_pc) 365 << inst->DumpString(shadow_frame.GetMethod()->GetDexFile()) << "\n"; 366 for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) { 367 uint32_t raw_value = shadow_frame.GetVReg(i); 368 Object* ref_value = shadow_frame.GetVRegReference(i); 369 oss << StringPrintf(" vreg%u=0x%08X", i, raw_value); 370 if (ref_value != nullptr) { 371 if (ref_value->GetClass()->IsStringClass() && 372 ref_value->AsString()->GetValue() != nullptr) { 373 oss << "/java.lang.String \"" << ref_value->AsString()->ToModifiedUtf8() << "\""; 374 } else { 375 oss << "/" << PrettyTypeOf(ref_value); 376 } 377 } 378 } 379 TRACE_LOG << oss.str() << "\n"; 380#undef TRACE_LOG 381 } 382} 383 384static inline bool IsBackwardBranch(int32_t branch_offset) { 385 return branch_offset <= 0; 386} 387 388// Explicitly instantiate all DoInvoke functions. 389#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check) \ 390 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) \ 391 bool DoInvoke<_type, _is_range, _do_check>(Thread* self, ShadowFrame& shadow_frame, \ 392 const Instruction* inst, uint16_t inst_data, \ 393 JValue* result) 394 395#define EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(_type) \ 396 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, false); \ 397 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, true); \ 398 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, false); \ 399 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, true); 400 401EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kStatic) // invoke-static/range. 402EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kDirect) // invoke-direct/range. 403EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kVirtual) // invoke-virtual/range. 404EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kSuper) // invoke-super/range. 405EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(kInterface) // invoke-interface/range. 406#undef EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL 407#undef EXPLICIT_DO_INVOKE_TEMPLATE_DECL 408 409// Explicitly instantiate all DoInvokeVirtualQuick functions. 410#define EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(_is_range) \ 411 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) \ 412 bool DoInvokeVirtualQuick<_is_range>(Thread* self, ShadowFrame& shadow_frame, \ 413 const Instruction* inst, uint16_t inst_data, \ 414 JValue* result) 415 416EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(false); // invoke-virtual-quick. 417EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(true); // invoke-virtual-quick-range. 418#undef EXPLICIT_INSTANTIATION_DO_INVOKE_VIRTUAL_QUICK 419 420 421} // namespace interpreter 422} // namespace art 423 424#endif // ART_RUNTIME_INTERPRETER_INTERPRETER_COMMON_H_ 425