interpreter_common.cc revision d16363a93053de0f32252c7897d839a46aff14ae
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#include "interpreter_common.h" 18 19#include <cmath> 20 21#include "base/enums.h" 22#include "debugger.h" 23#include "entrypoints/runtime_asm_entrypoints.h" 24#include "jit/jit.h" 25#include "jvalue.h" 26#include "method_handles.h" 27#include "method_handles-inl.h" 28#include "mirror/array-inl.h" 29#include "mirror/class.h" 30#include "mirror/emulated_stack_frame.h" 31#include "mirror/method_handle_impl.h" 32#include "reflection.h" 33#include "reflection-inl.h" 34#include "stack.h" 35#include "verifier/method_verifier.h" 36#include "well_known_classes.h" 37 38namespace art { 39namespace interpreter { 40 41void ThrowNullPointerExceptionFromInterpreter() { 42 ThrowNullPointerExceptionFromDexPC(); 43} 44 45template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> 46bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, 47 uint16_t inst_data) { 48 const bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead); 49 const uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c(); 50 ArtField* f = 51 FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self, 52 Primitive::ComponentSize(field_type)); 53 if (UNLIKELY(f == nullptr)) { 54 CHECK(self->IsExceptionPending()); 55 return false; 56 } 57 ObjPtr<mirror::Object> obj; 58 if (is_static) { 59 obj = f->GetDeclaringClass(); 60 } else { 61 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); 62 if (UNLIKELY(obj == nullptr)) { 63 ThrowNullPointerExceptionForFieldAccess(f, true); 64 return false; 65 } 66 } 67 68 JValue result; 69 DoFieldGetCommon<field_type>(self, shadow_frame, obj, f, &result); 70 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data); 71 switch (field_type) { 72 case Primitive::kPrimBoolean: 73 shadow_frame.SetVReg(vregA, result.GetZ()); 74 break; 75 case Primitive::kPrimByte: 76 shadow_frame.SetVReg(vregA, result.GetB()); 77 break; 78 case Primitive::kPrimChar: 79 shadow_frame.SetVReg(vregA, result.GetC()); 80 break; 81 case Primitive::kPrimShort: 82 shadow_frame.SetVReg(vregA, result.GetS()); 83 break; 84 case Primitive::kPrimInt: 85 shadow_frame.SetVReg(vregA, result.GetI()); 86 break; 87 case Primitive::kPrimLong: 88 shadow_frame.SetVRegLong(vregA, result.GetJ()); 89 break; 90 case Primitive::kPrimNot: 91 shadow_frame.SetVRegReference(vregA, result.GetL()); 92 break; 93 default: 94 LOG(FATAL) << "Unreachable: " << field_type; 95 UNREACHABLE(); 96 } 97 return true; 98} 99 100// Explicitly instantiate all DoFieldGet functions. 101#define EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, _do_check) \ 102 template bool DoFieldGet<_find_type, _field_type, _do_check>(Thread* self, \ 103 ShadowFrame& shadow_frame, \ 104 const Instruction* inst, \ 105 uint16_t inst_data) 106 107#define EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(_find_type, _field_type) \ 108 EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, false); \ 109 EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, true); 110 111// iget-XXX 112EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimBoolean) 113EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimByte) 114EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimChar) 115EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimShort) 116EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimInt) 117EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstancePrimitiveRead, Primitive::kPrimLong) 118EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(InstanceObjectRead, Primitive::kPrimNot) 119 120// sget-XXX 121EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimBoolean) 122EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimByte) 123EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimChar) 124EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimShort) 125EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimInt) 126EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticPrimitiveRead, Primitive::kPrimLong) 127EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticObjectRead, Primitive::kPrimNot) 128 129#undef EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL 130#undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL 131 132// Handles iget-quick, iget-wide-quick and iget-object-quick instructions. 133// Returns true on success, otherwise throws an exception and returns false. 134template<Primitive::Type field_type> 135bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) { 136 ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); 137 if (UNLIKELY(obj == nullptr)) { 138 // We lost the reference to the field index so we cannot get a more 139 // precised exception message. 140 ThrowNullPointerExceptionFromDexPC(); 141 return false; 142 } 143 MemberOffset field_offset(inst->VRegC_22c()); 144 // Report this field access to instrumentation if needed. Since we only have the offset of 145 // the field from the base of the object, we need to look for it first. 146 instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); 147 if (UNLIKELY(instrumentation->HasFieldReadListeners())) { 148 ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(), 149 field_offset.Uint32Value()); 150 DCHECK(f != nullptr); 151 DCHECK(!f->IsStatic()); 152 StackHandleScope<1> hs(Thread::Current()); 153 // Save obj in case the instrumentation event has thread suspension. 154 HandleWrapperObjPtr<mirror::Object> h = hs.NewHandleWrapper(&obj); 155 instrumentation->FieldReadEvent(Thread::Current(), 156 obj.Ptr(), 157 shadow_frame.GetMethod(), 158 shadow_frame.GetDexPC(), 159 f); 160 } 161 // Note: iget-x-quick instructions are only for non-volatile fields. 162 const uint32_t vregA = inst->VRegA_22c(inst_data); 163 switch (field_type) { 164 case Primitive::kPrimInt: 165 shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetField32(field_offset))); 166 break; 167 case Primitive::kPrimBoolean: 168 shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldBoolean(field_offset))); 169 break; 170 case Primitive::kPrimByte: 171 shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldByte(field_offset))); 172 break; 173 case Primitive::kPrimChar: 174 shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldChar(field_offset))); 175 break; 176 case Primitive::kPrimShort: 177 shadow_frame.SetVReg(vregA, static_cast<int32_t>(obj->GetFieldShort(field_offset))); 178 break; 179 case Primitive::kPrimLong: 180 shadow_frame.SetVRegLong(vregA, static_cast<int64_t>(obj->GetField64(field_offset))); 181 break; 182 case Primitive::kPrimNot: 183 shadow_frame.SetVRegReference(vregA, obj->GetFieldObject<mirror::Object>(field_offset)); 184 break; 185 default: 186 LOG(FATAL) << "Unreachable: " << field_type; 187 UNREACHABLE(); 188 } 189 return true; 190} 191 192// Explicitly instantiate all DoIGetQuick functions. 193#define EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(_field_type) \ 194 template bool DoIGetQuick<_field_type>(ShadowFrame& shadow_frame, const Instruction* inst, \ 195 uint16_t inst_data) 196 197EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimInt); // iget-quick. 198EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimBoolean); // iget-boolean-quick. 199EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimByte); // iget-byte-quick. 200EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimChar); // iget-char-quick. 201EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimShort); // iget-short-quick. 202EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimLong); // iget-wide-quick. 203EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimNot); // iget-object-quick. 204#undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL 205 206template<Primitive::Type field_type> 207static JValue GetFieldValue(const ShadowFrame& shadow_frame, uint32_t vreg) 208 REQUIRES_SHARED(Locks::mutator_lock_) { 209 JValue field_value; 210 switch (field_type) { 211 case Primitive::kPrimBoolean: 212 field_value.SetZ(static_cast<uint8_t>(shadow_frame.GetVReg(vreg))); 213 break; 214 case Primitive::kPrimByte: 215 field_value.SetB(static_cast<int8_t>(shadow_frame.GetVReg(vreg))); 216 break; 217 case Primitive::kPrimChar: 218 field_value.SetC(static_cast<uint16_t>(shadow_frame.GetVReg(vreg))); 219 break; 220 case Primitive::kPrimShort: 221 field_value.SetS(static_cast<int16_t>(shadow_frame.GetVReg(vreg))); 222 break; 223 case Primitive::kPrimInt: 224 field_value.SetI(shadow_frame.GetVReg(vreg)); 225 break; 226 case Primitive::kPrimLong: 227 field_value.SetJ(shadow_frame.GetVRegLong(vreg)); 228 break; 229 case Primitive::kPrimNot: 230 field_value.SetL(shadow_frame.GetVRegReference(vreg)); 231 break; 232 default: 233 LOG(FATAL) << "Unreachable: " << field_type; 234 UNREACHABLE(); 235 } 236 return field_value; 237} 238 239template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, 240 bool transaction_active> 241bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst, 242 uint16_t inst_data) { 243 const bool do_assignability_check = do_access_check; 244 bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite); 245 uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c(); 246 ArtField* f = 247 FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self, 248 Primitive::ComponentSize(field_type)); 249 if (UNLIKELY(f == nullptr)) { 250 CHECK(self->IsExceptionPending()); 251 return false; 252 } 253 ObjPtr<mirror::Object> obj; 254 if (is_static) { 255 obj = f->GetDeclaringClass(); 256 } else { 257 obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); 258 if (UNLIKELY(obj == nullptr)) { 259 ThrowNullPointerExceptionForFieldAccess(f, false); 260 return false; 261 } 262 } 263 264 uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data); 265 JValue value = GetFieldValue<field_type>(shadow_frame, vregA); 266 return DoFieldPutCommon<field_type, do_assignability_check, transaction_active>(self, 267 shadow_frame, 268 obj, 269 f, 270 value); 271} 272 273// Explicitly instantiate all DoFieldPut functions. 274#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check, _transaction_active) \ 275 template bool DoFieldPut<_find_type, _field_type, _do_check, _transaction_active>(Thread* self, \ 276 const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) 277 278#define EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(_find_type, _field_type) \ 279 EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, false); \ 280 EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, false); \ 281 EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, true); \ 282 EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, true); 283 284// iput-XXX 285EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimBoolean) 286EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimByte) 287EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimChar) 288EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimShort) 289EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimInt) 290EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimLong) 291EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstanceObjectWrite, Primitive::kPrimNot) 292 293// sput-XXX 294EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimBoolean) 295EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimByte) 296EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimChar) 297EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimShort) 298EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimInt) 299EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticPrimitiveWrite, Primitive::kPrimLong) 300EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticObjectWrite, Primitive::kPrimNot) 301 302#undef EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL 303#undef EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL 304 305template<Primitive::Type field_type, bool transaction_active> 306bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) { 307 ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); 308 if (UNLIKELY(obj == nullptr)) { 309 // We lost the reference to the field index so we cannot get a more 310 // precised exception message. 311 ThrowNullPointerExceptionFromDexPC(); 312 return false; 313 } 314 MemberOffset field_offset(inst->VRegC_22c()); 315 const uint32_t vregA = inst->VRegA_22c(inst_data); 316 // Report this field modification to instrumentation if needed. Since we only have the offset of 317 // the field from the base of the object, we need to look for it first. 318 instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); 319 if (UNLIKELY(instrumentation->HasFieldWriteListeners())) { 320 ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(), 321 field_offset.Uint32Value()); 322 DCHECK(f != nullptr); 323 DCHECK(!f->IsStatic()); 324 JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA); 325 StackHandleScope<1> hs(Thread::Current()); 326 // Save obj in case the instrumentation event has thread suspension. 327 HandleWrapperObjPtr<mirror::Object> h = hs.NewHandleWrapper(&obj); 328 instrumentation->FieldWriteEvent(Thread::Current(), 329 obj.Ptr(), 330 shadow_frame.GetMethod(), 331 shadow_frame.GetDexPC(), 332 f, 333 field_value); 334 } 335 // Note: iput-x-quick instructions are only for non-volatile fields. 336 switch (field_type) { 337 case Primitive::kPrimBoolean: 338 obj->SetFieldBoolean<transaction_active>(field_offset, shadow_frame.GetVReg(vregA)); 339 break; 340 case Primitive::kPrimByte: 341 obj->SetFieldByte<transaction_active>(field_offset, shadow_frame.GetVReg(vregA)); 342 break; 343 case Primitive::kPrimChar: 344 obj->SetFieldChar<transaction_active>(field_offset, shadow_frame.GetVReg(vregA)); 345 break; 346 case Primitive::kPrimShort: 347 obj->SetFieldShort<transaction_active>(field_offset, shadow_frame.GetVReg(vregA)); 348 break; 349 case Primitive::kPrimInt: 350 obj->SetField32<transaction_active>(field_offset, shadow_frame.GetVReg(vregA)); 351 break; 352 case Primitive::kPrimLong: 353 obj->SetField64<transaction_active>(field_offset, shadow_frame.GetVRegLong(vregA)); 354 break; 355 case Primitive::kPrimNot: 356 obj->SetFieldObject<transaction_active>(field_offset, shadow_frame.GetVRegReference(vregA)); 357 break; 358 default: 359 LOG(FATAL) << "Unreachable: " << field_type; 360 UNREACHABLE(); 361 } 362 return true; 363} 364 365// Explicitly instantiate all DoIPutQuick functions. 366#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, _transaction_active) \ 367 template bool DoIPutQuick<_field_type, _transaction_active>(const ShadowFrame& shadow_frame, \ 368 const Instruction* inst, \ 369 uint16_t inst_data) 370 371#define EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(_field_type) \ 372 EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, false); \ 373 EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, true); 374 375EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimInt) // iput-quick. 376EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimBoolean) // iput-boolean-quick. 377EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimByte) // iput-byte-quick. 378EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimChar) // iput-char-quick. 379EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimShort) // iput-short-quick. 380EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimLong) // iput-wide-quick. 381EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimNot) // iput-object-quick. 382#undef EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL 383#undef EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL 384 385// We accept a null Instrumentation* meaning we must not report anything to the instrumentation. 386uint32_t FindNextInstructionFollowingException( 387 Thread* self, ShadowFrame& shadow_frame, uint32_t dex_pc, 388 const instrumentation::Instrumentation* instrumentation) { 389 self->VerifyStack(); 390 StackHandleScope<2> hs(self); 391 Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException())); 392 if (instrumentation != nullptr && instrumentation->HasExceptionCaughtListeners() 393 && self->IsExceptionThrownByCurrentMethod(exception.Get())) { 394 instrumentation->ExceptionCaughtEvent(self, exception.Get()); 395 } 396 bool clear_exception = false; 397 uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock( 398 hs.NewHandle(exception->GetClass()), dex_pc, &clear_exception); 399 if (found_dex_pc == DexFile::kDexNoIndex && instrumentation != nullptr) { 400 // Exception is not caught by the current method. We will unwind to the 401 // caller. Notify any instrumentation listener. 402 instrumentation->MethodUnwindEvent(self, shadow_frame.GetThisObject(), 403 shadow_frame.GetMethod(), dex_pc); 404 } else { 405 // Exception is caught in the current method. We will jump to the found_dex_pc. 406 if (clear_exception) { 407 self->ClearException(); 408 } 409 } 410 return found_dex_pc; 411} 412 413void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame) { 414 LOG(FATAL) << "Unexpected instruction: " 415 << inst->DumpString(shadow_frame.GetMethod()->GetDexFile()); 416 UNREACHABLE(); 417} 418 419void AbortTransactionF(Thread* self, const char* fmt, ...) { 420 va_list args; 421 va_start(args, fmt); 422 AbortTransactionV(self, fmt, args); 423 va_end(args); 424} 425 426void AbortTransactionV(Thread* self, const char* fmt, va_list args) { 427 CHECK(Runtime::Current()->IsActiveTransaction()); 428 // Constructs abort message. 429 std::string abort_msg; 430 android::base::StringAppendV(&abort_msg, fmt, args); 431 // Throws an exception so we can abort the transaction and rollback every change. 432 Runtime::Current()->AbortTransactionAndThrowAbortError(self, abort_msg); 433} 434 435// START DECLARATIONS : 436// 437// These additional declarations are required because clang complains 438// about ALWAYS_INLINE (-Werror, -Wgcc-compat) in definitions. 439// 440 441template <bool is_range, bool do_assignability_check> 442static ALWAYS_INLINE bool DoCallCommon(ArtMethod* called_method, 443 Thread* self, 444 ShadowFrame& shadow_frame, 445 JValue* result, 446 uint16_t number_of_inputs, 447 uint32_t (&arg)[Instruction::kMaxVarArgRegs], 448 uint32_t vregC) REQUIRES_SHARED(Locks::mutator_lock_); 449 450template <bool is_range> 451ALWAYS_INLINE void CopyRegisters(ShadowFrame& caller_frame, 452 ShadowFrame* callee_frame, 453 const uint32_t (&arg)[Instruction::kMaxVarArgRegs], 454 const size_t first_src_reg, 455 const size_t first_dest_reg, 456 const size_t num_regs) REQUIRES_SHARED(Locks::mutator_lock_); 457 458// END DECLARATIONS. 459 460void ArtInterpreterToCompiledCodeBridge(Thread* self, 461 ArtMethod* caller, 462 const DexFile::CodeItem* code_item, 463 ShadowFrame* shadow_frame, 464 JValue* result) 465 REQUIRES_SHARED(Locks::mutator_lock_) { 466 ArtMethod* method = shadow_frame->GetMethod(); 467 // Ensure static methods are initialized. 468 if (method->IsStatic()) { 469 ObjPtr<mirror::Class> declaringClass = method->GetDeclaringClass(); 470 if (UNLIKELY(!declaringClass->IsInitialized())) { 471 self->PushShadowFrame(shadow_frame); 472 StackHandleScope<1> hs(self); 473 Handle<mirror::Class> h_class(hs.NewHandle(declaringClass)); 474 if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, 475 true))) { 476 self->PopShadowFrame(); 477 DCHECK(self->IsExceptionPending()); 478 return; 479 } 480 self->PopShadowFrame(); 481 CHECK(h_class->IsInitializing()); 482 // Reload from shadow frame in case the method moved, this is faster than adding a handle. 483 method = shadow_frame->GetMethod(); 484 } 485 } 486 uint16_t arg_offset = (code_item == nullptr) 487 ? 0 488 : code_item->registers_size_ - code_item->ins_size_; 489 jit::Jit* jit = Runtime::Current()->GetJit(); 490 if (jit != nullptr && caller != nullptr) { 491 jit->NotifyInterpreterToCompiledCodeTransition(self, caller); 492 } 493 method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset), 494 (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t), 495 result, method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()); 496} 497 498void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame, 499 uint16_t this_obj_vreg, 500 JValue result) 501 REQUIRES_SHARED(Locks::mutator_lock_) { 502 ObjPtr<mirror::Object> existing = shadow_frame->GetVRegReference(this_obj_vreg); 503 if (existing == nullptr) { 504 // If it's null, we come from compiled code that was deoptimized. Nothing to do, 505 // as the compiler verified there was no alias. 506 // Set the new string result of the StringFactory. 507 shadow_frame->SetVRegReference(this_obj_vreg, result.GetL()); 508 return; 509 } 510 // Set the string init result into all aliases. 511 for (uint32_t i = 0, e = shadow_frame->NumberOfVRegs(); i < e; ++i) { 512 if (shadow_frame->GetVRegReference(i) == existing) { 513 DCHECK_EQ(shadow_frame->GetVRegReference(i), 514 reinterpret_cast<mirror::Object*>(shadow_frame->GetVReg(i))); 515 shadow_frame->SetVRegReference(i, result.GetL()); 516 DCHECK_EQ(shadow_frame->GetVRegReference(i), 517 reinterpret_cast<mirror::Object*>(shadow_frame->GetVReg(i))); 518 } 519 } 520} 521 522template<bool is_range, bool do_access_check> 523bool DoInvokePolymorphic(Thread* self, 524 ShadowFrame& shadow_frame, 525 const Instruction* inst, 526 uint16_t inst_data, 527 JValue* result) 528 REQUIRES_SHARED(Locks::mutator_lock_) { 529 // Invoke-polymorphic instructions always take a receiver. i.e, they are never static. 530 const uint32_t vRegC = (is_range) ? inst->VRegC_4rcc() : inst->VRegC_45cc(); 531 const int invoke_method_idx = (is_range) ? inst->VRegB_4rcc() : inst->VRegB_45cc(); 532 533 // Initialize |result| to 0 as this is the default return value for 534 // polymorphic invocations of method handle types with void return 535 // and provides sane return result in error cases. 536 result->SetJ(0); 537 538 // The invoke_method_idx here is the name of the signature polymorphic method that 539 // was symbolically invoked in bytecode (say MethodHandle.invoke or MethodHandle.invokeExact) 540 // and not the method that we'll dispatch to in the end. 541 StackHandleScope<5> hs(self); 542 Handle<mirror::MethodHandleImpl> method_handle(hs.NewHandle( 543 ObjPtr<mirror::MethodHandleImpl>::DownCast( 544 MakeObjPtr(shadow_frame.GetVRegReference(vRegC))))); 545 if (UNLIKELY(method_handle.Get() == nullptr)) { 546 // Note that the invoke type is kVirtual here because a call to a signature 547 // polymorphic method is shaped like a virtual call at the bytecode level. 548 ThrowNullPointerExceptionForMethodAccess(invoke_method_idx, InvokeType::kVirtual); 549 return false; 550 } 551 552 // The vRegH value gives the index of the proto_id associated with this 553 // signature polymorphic call site. 554 const uint32_t callsite_proto_id = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc(); 555 556 // Call through to the classlinker and ask it to resolve the static type associated 557 // with the callsite. This information is stored in the dex cache so it's 558 // guaranteed to be fast after the first resolution. 559 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 560 Handle<mirror::Class> caller_class(hs.NewHandle(shadow_frame.GetMethod()->GetDeclaringClass())); 561 Handle<mirror::MethodType> callsite_type(hs.NewHandle(class_linker->ResolveMethodType( 562 caller_class->GetDexFile(), callsite_proto_id, 563 hs.NewHandle<mirror::DexCache>(caller_class->GetDexCache()), 564 hs.NewHandle<mirror::ClassLoader>(caller_class->GetClassLoader())))); 565 566 // This implies we couldn't resolve one or more types in this method handle. 567 if (UNLIKELY(callsite_type.Get() == nullptr)) { 568 CHECK(self->IsExceptionPending()); 569 return false; 570 } 571 572 ArtMethod* invoke_method = 573 class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(self, 574 invoke_method_idx, 575 shadow_frame.GetMethod(), 576 kVirtual); 577 578 // There is a common dispatch method for method handles that takes 579 // arguments either from a range or an array of arguments depending 580 // on whether the DEX instruction is invoke-polymorphic/range or 581 // invoke-polymorphic. The array here is for the latter. 582 uint32_t args[Instruction::kMaxVarArgRegs] = {}; 583 if (is_range) { 584 // VRegC is the register holding the method handle. Arguments passed 585 // to the method handle's target do not include the method handle. 586 uint32_t first_arg = inst->VRegC_4rcc() + 1; 587 return DoInvokePolymorphic<is_range, do_access_check>(self, 588 invoke_method, 589 shadow_frame, 590 method_handle, 591 callsite_type, 592 args /* unused */, 593 first_arg, 594 result); 595 } else { 596 // Get the register arguments for the invoke. 597 inst->GetVarArgs(args, inst_data); 598 // Drop the first register which is the method handle performing the invoke. 599 memmove(args, args + 1, sizeof(args[0]) * (Instruction::kMaxVarArgRegs - 1)); 600 args[Instruction::kMaxVarArgRegs - 1] = 0; 601 return DoInvokePolymorphic<is_range, do_access_check>(self, 602 invoke_method, 603 shadow_frame, 604 method_handle, 605 callsite_type, 606 args, 607 args[0], 608 result); 609 } 610} 611 612template <bool is_range> 613inline void CopyRegisters(ShadowFrame& caller_frame, 614 ShadowFrame* callee_frame, 615 const uint32_t (&arg)[Instruction::kMaxVarArgRegs], 616 const size_t first_src_reg, 617 const size_t first_dest_reg, 618 const size_t num_regs) { 619 if (is_range) { 620 const size_t dest_reg_bound = first_dest_reg + num_regs; 621 for (size_t src_reg = first_src_reg, dest_reg = first_dest_reg; dest_reg < dest_reg_bound; 622 ++dest_reg, ++src_reg) { 623 AssignRegister(callee_frame, caller_frame, dest_reg, src_reg); 624 } 625 } else { 626 DCHECK_LE(num_regs, arraysize(arg)); 627 628 for (size_t arg_index = 0; arg_index < num_regs; ++arg_index) { 629 AssignRegister(callee_frame, caller_frame, first_dest_reg + arg_index, arg[arg_index]); 630 } 631 } 632} 633 634template <bool is_range, 635 bool do_assignability_check> 636static inline bool DoCallCommon(ArtMethod* called_method, 637 Thread* self, 638 ShadowFrame& shadow_frame, 639 JValue* result, 640 uint16_t number_of_inputs, 641 uint32_t (&arg)[Instruction::kMaxVarArgRegs], 642 uint32_t vregC) { 643 bool string_init = false; 644 // Replace calls to String.<init> with equivalent StringFactory call. 645 if (UNLIKELY(called_method->GetDeclaringClass()->IsStringClass() 646 && called_method->IsConstructor())) { 647 called_method = WellKnownClasses::StringInitToStringFactory(called_method); 648 string_init = true; 649 } 650 651 // Compute method information. 652 const DexFile::CodeItem* code_item = called_method->GetCodeItem(); 653 654 // Number of registers for the callee's call frame. 655 uint16_t num_regs; 656 if (LIKELY(code_item != nullptr)) { 657 num_regs = code_item->registers_size_; 658 DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_); 659 } else { 660 DCHECK(called_method->IsNative() || called_method->IsProxyMethod()); 661 num_regs = number_of_inputs; 662 } 663 664 // Hack for String init: 665 // 666 // Rewrite invoke-x java.lang.String.<init>(this, a, b, c, ...) into: 667 // invoke-x StringFactory(a, b, c, ...) 668 // by effectively dropping the first virtual register from the invoke. 669 // 670 // (at this point the ArtMethod has already been replaced, 671 // so we just need to fix-up the arguments) 672 // 673 // Note that FindMethodFromCode in entrypoint_utils-inl.h was also special-cased 674 // to handle the compiler optimization of replacing `this` with null without 675 // throwing NullPointerException. 676 uint32_t string_init_vreg_this = is_range ? vregC : arg[0]; 677 if (UNLIKELY(string_init)) { 678 DCHECK_GT(num_regs, 0u); // As the method is an instance method, there should be at least 1. 679 680 // The new StringFactory call is static and has one fewer argument. 681 if (code_item == nullptr) { 682 DCHECK(called_method->IsNative() || called_method->IsProxyMethod()); 683 num_regs--; 684 } // else ... don't need to change num_regs since it comes up from the string_init's code item 685 number_of_inputs--; 686 687 // Rewrite the var-args, dropping the 0th argument ("this") 688 for (uint32_t i = 1; i < arraysize(arg); ++i) { 689 arg[i - 1] = arg[i]; 690 } 691 arg[arraysize(arg) - 1] = 0; 692 693 // Rewrite the non-var-arg case 694 vregC++; // Skips the 0th vreg in the range ("this"). 695 } 696 697 // Parameter registers go at the end of the shadow frame. 698 DCHECK_GE(num_regs, number_of_inputs); 699 size_t first_dest_reg = num_regs - number_of_inputs; 700 DCHECK_NE(first_dest_reg, (size_t)-1); 701 702 // Allocate shadow frame on the stack. 703 const char* old_cause = self->StartAssertNoThreadSuspension("DoCallCommon"); 704 ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr = 705 CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0); 706 ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get(); 707 708 // Initialize new shadow frame by copying the registers from the callee shadow frame. 709 if (do_assignability_check) { 710 // Slow path. 711 // We might need to do class loading, which incurs a thread state change to kNative. So 712 // register the shadow frame as under construction and allow suspension again. 713 ScopedStackedShadowFramePusher pusher( 714 self, new_shadow_frame, StackedShadowFrameType::kShadowFrameUnderConstruction); 715 self->EndAssertNoThreadSuspension(old_cause); 716 717 // ArtMethod here is needed to check type information of the call site against the callee. 718 // Type information is retrieved from a DexFile/DexCache for that respective declared method. 719 // 720 // As a special case for proxy methods, which are not dex-backed, 721 // we have to retrieve type information from the proxy's method 722 // interface method instead (which is dex backed since proxies are never interfaces). 723 ArtMethod* method = 724 new_shadow_frame->GetMethod()->GetInterfaceMethodIfProxy(kRuntimePointerSize); 725 726 // We need to do runtime check on reference assignment. We need to load the shorty 727 // to get the exact type of each reference argument. 728 const DexFile::TypeList* params = method->GetParameterTypeList(); 729 uint32_t shorty_len = 0; 730 const char* shorty = method->GetShorty(&shorty_len); 731 732 // Handle receiver apart since it's not part of the shorty. 733 size_t dest_reg = first_dest_reg; 734 size_t arg_offset = 0; 735 736 if (!method->IsStatic()) { 737 size_t receiver_reg = is_range ? vregC : arg[0]; 738 new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg)); 739 ++dest_reg; 740 ++arg_offset; 741 DCHECK(!string_init); // All StringFactory methods are static. 742 } 743 744 // Copy the caller's invoke-* arguments into the callee's parameter registers. 745 for (uint32_t shorty_pos = 0; dest_reg < num_regs; ++shorty_pos, ++dest_reg, ++arg_offset) { 746 // Skip the 0th 'shorty' type since it represents the return type. 747 DCHECK_LT(shorty_pos + 1, shorty_len) << "for shorty '" << shorty << "'"; 748 const size_t src_reg = (is_range) ? vregC + arg_offset : arg[arg_offset]; 749 switch (shorty[shorty_pos + 1]) { 750 // Handle Object references. 1 virtual register slot. 751 case 'L': { 752 ObjPtr<mirror::Object> o = shadow_frame.GetVRegReference(src_reg); 753 if (do_assignability_check && o != nullptr) { 754 const dex::TypeIndex type_idx = params->GetTypeItem(shorty_pos).type_idx_; 755 ObjPtr<mirror::Class> arg_type = method->GetDexCache()->GetResolvedType(type_idx); 756 if (arg_type == nullptr) { 757 StackHandleScope<1> hs(self); 758 // Preserve o since it is used below and GetClassFromTypeIndex may cause thread 759 // suspension. 760 HandleWrapperObjPtr<mirror::Object> h = hs.NewHandleWrapper(&o); 761 arg_type = method->GetClassFromTypeIndex(type_idx, true /* resolve */); 762 if (arg_type == nullptr) { 763 CHECK(self->IsExceptionPending()); 764 return false; 765 } 766 } 767 if (!o->VerifierInstanceOf(arg_type)) { 768 // This should never happen. 769 std::string temp1, temp2; 770 self->ThrowNewExceptionF("Ljava/lang/InternalError;", 771 "Invoking %s with bad arg %d, type '%s' not instance of '%s'", 772 new_shadow_frame->GetMethod()->GetName(), shorty_pos, 773 o->GetClass()->GetDescriptor(&temp1), 774 arg_type->GetDescriptor(&temp2)); 775 return false; 776 } 777 } 778 new_shadow_frame->SetVRegReference(dest_reg, o.Ptr()); 779 break; 780 } 781 // Handle doubles and longs. 2 consecutive virtual register slots. 782 case 'J': case 'D': { 783 uint64_t wide_value = 784 (static_cast<uint64_t>(shadow_frame.GetVReg(src_reg + 1)) << BitSizeOf<uint32_t>()) | 785 static_cast<uint32_t>(shadow_frame.GetVReg(src_reg)); 786 new_shadow_frame->SetVRegLong(dest_reg, wide_value); 787 // Skip the next virtual register slot since we already used it. 788 ++dest_reg; 789 ++arg_offset; 790 break; 791 } 792 // Handle all other primitives that are always 1 virtual register slot. 793 default: 794 new_shadow_frame->SetVReg(dest_reg, shadow_frame.GetVReg(src_reg)); 795 break; 796 } 797 } 798 } else { 799 if (is_range) { 800 DCHECK_EQ(num_regs, first_dest_reg + number_of_inputs); 801 } 802 803 CopyRegisters<is_range>(shadow_frame, 804 new_shadow_frame, 805 arg, 806 vregC, 807 first_dest_reg, 808 number_of_inputs); 809 self->EndAssertNoThreadSuspension(old_cause); 810 } 811 812 PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result); 813 814 if (string_init && !self->IsExceptionPending()) { 815 SetStringInitValueToAllAliases(&shadow_frame, string_init_vreg_this, *result); 816 } 817 818 return !self->IsExceptionPending(); 819} 820 821template<bool is_range, bool do_assignability_check> 822bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame, 823 const Instruction* inst, uint16_t inst_data, JValue* result) { 824 // Argument word count. 825 const uint16_t number_of_inputs = 826 (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data); 827 828 // TODO: find a cleaner way to separate non-range and range information without duplicating 829 // code. 830 uint32_t arg[Instruction::kMaxVarArgRegs] = {}; // only used in invoke-XXX. 831 uint32_t vregC = 0; 832 if (is_range) { 833 vregC = inst->VRegC_3rc(); 834 } else { 835 vregC = inst->VRegC_35c(); 836 inst->GetVarArgs(arg, inst_data); 837 } 838 839 return DoCallCommon<is_range, do_assignability_check>( 840 called_method, self, shadow_frame, 841 result, number_of_inputs, arg, vregC); 842} 843 844template <bool is_range, bool do_access_check, bool transaction_active> 845bool DoFilledNewArray(const Instruction* inst, 846 const ShadowFrame& shadow_frame, 847 Thread* self, 848 JValue* result) { 849 DCHECK(inst->Opcode() == Instruction::FILLED_NEW_ARRAY || 850 inst->Opcode() == Instruction::FILLED_NEW_ARRAY_RANGE); 851 const int32_t length = is_range ? inst->VRegA_3rc() : inst->VRegA_35c(); 852 if (!is_range) { 853 // Checks FILLED_NEW_ARRAY's length does not exceed 5 arguments. 854 CHECK_LE(length, 5); 855 } 856 if (UNLIKELY(length < 0)) { 857 ThrowNegativeArraySizeException(length); 858 return false; 859 } 860 uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); 861 ObjPtr<mirror::Class> array_class = ResolveVerifyAndClinit(dex::TypeIndex(type_idx), 862 shadow_frame.GetMethod(), 863 self, 864 false, 865 do_access_check); 866 if (UNLIKELY(array_class == nullptr)) { 867 DCHECK(self->IsExceptionPending()); 868 return false; 869 } 870 CHECK(array_class->IsArrayClass()); 871 ObjPtr<mirror::Class> component_class = array_class->GetComponentType(); 872 const bool is_primitive_int_component = component_class->IsPrimitiveInt(); 873 if (UNLIKELY(component_class->IsPrimitive() && !is_primitive_int_component)) { 874 if (component_class->IsPrimitiveLong() || component_class->IsPrimitiveDouble()) { 875 ThrowRuntimeException("Bad filled array request for type %s", 876 component_class->PrettyDescriptor().c_str()); 877 } else { 878 self->ThrowNewExceptionF("Ljava/lang/InternalError;", 879 "Found type %s; filled-new-array not implemented for anything but 'int'", 880 component_class->PrettyDescriptor().c_str()); 881 } 882 return false; 883 } 884 ObjPtr<mirror::Object> new_array = mirror::Array::Alloc<true>( 885 self, 886 array_class, 887 length, 888 array_class->GetComponentSizeShift(), 889 Runtime::Current()->GetHeap()->GetCurrentAllocator()); 890 if (UNLIKELY(new_array == nullptr)) { 891 self->AssertPendingOOMException(); 892 return false; 893 } 894 uint32_t arg[Instruction::kMaxVarArgRegs]; // only used in filled-new-array. 895 uint32_t vregC = 0; // only used in filled-new-array-range. 896 if (is_range) { 897 vregC = inst->VRegC_3rc(); 898 } else { 899 inst->GetVarArgs(arg); 900 } 901 for (int32_t i = 0; i < length; ++i) { 902 size_t src_reg = is_range ? vregC + i : arg[i]; 903 if (is_primitive_int_component) { 904 new_array->AsIntArray()->SetWithoutChecks<transaction_active>( 905 i, shadow_frame.GetVReg(src_reg)); 906 } else { 907 new_array->AsObjectArray<mirror::Object>()->SetWithoutChecks<transaction_active>( 908 i, shadow_frame.GetVRegReference(src_reg)); 909 } 910 } 911 912 result->SetL(new_array); 913 return true; 914} 915 916// TODO: Use ObjPtr here. 917template<typename T> 918static void RecordArrayElementsInTransactionImpl(mirror::PrimitiveArray<T>* array, 919 int32_t count) 920 REQUIRES_SHARED(Locks::mutator_lock_) { 921 Runtime* runtime = Runtime::Current(); 922 for (int32_t i = 0; i < count; ++i) { 923 runtime->RecordWriteArray(array, i, array->GetWithoutChecks(i)); 924 } 925} 926 927void RecordArrayElementsInTransaction(ObjPtr<mirror::Array> array, int32_t count) 928 REQUIRES_SHARED(Locks::mutator_lock_) { 929 DCHECK(Runtime::Current()->IsActiveTransaction()); 930 DCHECK(array != nullptr); 931 DCHECK_LE(count, array->GetLength()); 932 Primitive::Type primitive_component_type = array->GetClass()->GetComponentType()->GetPrimitiveType(); 933 switch (primitive_component_type) { 934 case Primitive::kPrimBoolean: 935 RecordArrayElementsInTransactionImpl(array->AsBooleanArray(), count); 936 break; 937 case Primitive::kPrimByte: 938 RecordArrayElementsInTransactionImpl(array->AsByteArray(), count); 939 break; 940 case Primitive::kPrimChar: 941 RecordArrayElementsInTransactionImpl(array->AsCharArray(), count); 942 break; 943 case Primitive::kPrimShort: 944 RecordArrayElementsInTransactionImpl(array->AsShortArray(), count); 945 break; 946 case Primitive::kPrimInt: 947 RecordArrayElementsInTransactionImpl(array->AsIntArray(), count); 948 break; 949 case Primitive::kPrimFloat: 950 RecordArrayElementsInTransactionImpl(array->AsFloatArray(), count); 951 break; 952 case Primitive::kPrimLong: 953 RecordArrayElementsInTransactionImpl(array->AsLongArray(), count); 954 break; 955 case Primitive::kPrimDouble: 956 RecordArrayElementsInTransactionImpl(array->AsDoubleArray(), count); 957 break; 958 default: 959 LOG(FATAL) << "Unsupported primitive type " << primitive_component_type 960 << " in fill-array-data"; 961 break; 962 } 963} 964 965// Explicit DoCall template function declarations. 966#define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check) \ 967 template REQUIRES_SHARED(Locks::mutator_lock_) \ 968 bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method, Thread* self, \ 969 ShadowFrame& shadow_frame, \ 970 const Instruction* inst, uint16_t inst_data, \ 971 JValue* result) 972EXPLICIT_DO_CALL_TEMPLATE_DECL(false, false); 973EXPLICIT_DO_CALL_TEMPLATE_DECL(false, true); 974EXPLICIT_DO_CALL_TEMPLATE_DECL(true, false); 975EXPLICIT_DO_CALL_TEMPLATE_DECL(true, true); 976#undef EXPLICIT_DO_CALL_TEMPLATE_DECL 977 978// Explicit DoInvokePolymorphic template function declarations. 979#define EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(_is_range, _do_assignability_check) \ 980 template REQUIRES_SHARED(Locks::mutator_lock_) \ 981 bool DoInvokePolymorphic<_is_range, _do_assignability_check>( \ 982 Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, \ 983 uint16_t inst_data, JValue* result) 984 985EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(false, false); 986EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(false, true); 987EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(true, false); 988EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(true, true); 989#undef EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL 990 991// Explicit DoFilledNewArray template function declarations. 992#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check, _transaction_active) \ 993 template REQUIRES_SHARED(Locks::mutator_lock_) \ 994 bool DoFilledNewArray<_is_range_, _check, _transaction_active>(const Instruction* inst, \ 995 const ShadowFrame& shadow_frame, \ 996 Thread* self, JValue* result) 997#define EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(_transaction_active) \ 998 EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false, _transaction_active); \ 999 EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true, _transaction_active); \ 1000 EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false, _transaction_active); \ 1001 EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true, _transaction_active) 1002EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(false); 1003EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(true); 1004#undef EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL 1005#undef EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL 1006 1007} // namespace interpreter 1008} // namespace art 1009