interpreter_common.cc revision 8ece050d85fc244c72610244e440b0e00aa618fa
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 19namespace art { 20namespace interpreter { 21 22template<InvokeType type, bool is_range, bool do_access_check> 23bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, 24 const Instruction* inst, JValue* result) { 25 uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); 26 uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); 27 Object* receiver = (type == kStatic) ? NULL : shadow_frame.GetVRegReference(vregC); 28 ArtMethod* method = FindMethodFromCode(method_idx, receiver, shadow_frame.GetMethod(), self, 29 do_access_check, type); 30 if (UNLIKELY(method == NULL)) { 31 CHECK(self->IsExceptionPending()); 32 result->SetJ(0); 33 return false; 34 } else if (UNLIKELY(method->IsAbstract())) { 35 ThrowAbstractMethodError(method); 36 result->SetJ(0); 37 return false; 38 } 39 40 MethodHelper mh(method); 41 const DexFile::CodeItem* code_item = mh.GetCodeItem(); 42 uint16_t num_regs; 43 uint16_t num_ins; 44 if (LIKELY(code_item != NULL)) { 45 num_regs = code_item->registers_size_; 46 num_ins = code_item->ins_size_; 47 } else { 48 DCHECK(method->IsNative() || method->IsProxyMethod()); 49 num_regs = num_ins = ArtMethod::NumArgRegisters(mh.GetShorty()); 50 if (!method->IsStatic()) { 51 num_regs++; 52 num_ins++; 53 } 54 } 55 56 void* memory = alloca(ShadowFrame::ComputeSize(num_regs)); 57 ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, method, 0, memory)); 58 size_t cur_reg = num_regs - num_ins; 59 if (receiver != NULL) { 60 new_shadow_frame->SetVRegReference(cur_reg, receiver); 61 ++cur_reg; 62 } 63 64 size_t arg_offset = (receiver == NULL) ? 0 : 1; 65 const char* shorty = mh.GetShorty(); 66 uint32_t arg[5]; 67 if (!is_range) { 68 inst->GetArgs(arg); 69 } 70 for (size_t shorty_pos = 0; cur_reg < num_regs; ++shorty_pos, cur_reg++, arg_offset++) { 71 DCHECK_LT(shorty_pos + 1, mh.GetShortyLength()); 72 size_t arg_pos = is_range ? vregC + arg_offset : arg[arg_offset]; 73 switch (shorty[shorty_pos + 1]) { 74 case 'L': { 75 Object* o = shadow_frame.GetVRegReference(arg_pos); 76 new_shadow_frame->SetVRegReference(cur_reg, o); 77 break; 78 } 79 case 'J': case 'D': { 80 uint64_t wide_value = (static_cast<uint64_t>(shadow_frame.GetVReg(arg_pos + 1)) << 32) | 81 static_cast<uint32_t>(shadow_frame.GetVReg(arg_pos)); 82 new_shadow_frame->SetVRegLong(cur_reg, wide_value); 83 cur_reg++; 84 arg_offset++; 85 break; 86 } 87 default: 88 new_shadow_frame->SetVReg(cur_reg, shadow_frame.GetVReg(arg_pos)); 89 break; 90 } 91 } 92 93 if (LIKELY(Runtime::Current()->IsStarted())) { 94 (method->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result); 95 } else { 96 UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins); 97 } 98 return !self->IsExceptionPending(); 99} 100 101template<bool is_range> 102bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, 103 const Instruction* inst, JValue* result) { 104 uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); 105 Object* receiver = shadow_frame.GetVRegReference(vregC); 106 if (UNLIKELY(receiver == NULL)) { 107 // We lost the reference to the method index so we cannot get a more 108 // precised exception message. 109 ThrowNullPointerExceptionFromDexPC(shadow_frame.GetCurrentLocationForThrow()); 110 return false; 111 } 112 uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); 113 // TODO: use ObjectArray<T>::GetWithoutChecks ? 114 ArtMethod* method = receiver->GetClass()->GetVTable()->Get(vtable_idx); 115 if (UNLIKELY(method == NULL)) { 116 CHECK(self->IsExceptionPending()); 117 result->SetJ(0); 118 return false; 119 } else if (UNLIKELY(method->IsAbstract())) { 120 ThrowAbstractMethodError(method); 121 result->SetJ(0); 122 return false; 123 } 124 125 MethodHelper mh(method); 126 const DexFile::CodeItem* code_item = mh.GetCodeItem(); 127 uint16_t num_regs; 128 uint16_t num_ins; 129 if (code_item != NULL) { 130 num_regs = code_item->registers_size_; 131 num_ins = code_item->ins_size_; 132 } else { 133 DCHECK(method->IsNative() || method->IsProxyMethod()); 134 num_regs = num_ins = ArtMethod::NumArgRegisters(mh.GetShorty()); 135 if (!method->IsStatic()) { 136 num_regs++; 137 num_ins++; 138 } 139 } 140 141 void* memory = alloca(ShadowFrame::ComputeSize(num_regs)); 142 ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, 143 method, 0, memory)); 144 size_t cur_reg = num_regs - num_ins; 145 if (receiver != NULL) { 146 new_shadow_frame->SetVRegReference(cur_reg, receiver); 147 ++cur_reg; 148 } 149 150 size_t arg_offset = (receiver == NULL) ? 0 : 1; 151 const char* shorty = mh.GetShorty(); 152 uint32_t arg[5]; 153 if (!is_range) { 154 inst->GetArgs(arg); 155 } 156 for (size_t shorty_pos = 0; cur_reg < num_regs; ++shorty_pos, cur_reg++, arg_offset++) { 157 DCHECK_LT(shorty_pos + 1, mh.GetShortyLength()); 158 size_t arg_pos = is_range ? vregC + arg_offset : arg[arg_offset]; 159 switch (shorty[shorty_pos + 1]) { 160 case 'L': { 161 Object* o = shadow_frame.GetVRegReference(arg_pos); 162 new_shadow_frame->SetVRegReference(cur_reg, o); 163 break; 164 } 165 case 'J': case 'D': { 166 uint64_t wide_value = (static_cast<uint64_t>(shadow_frame.GetVReg(arg_pos + 1)) << 32) | 167 static_cast<uint32_t>(shadow_frame.GetVReg(arg_pos)); 168 new_shadow_frame->SetVRegLong(cur_reg, wide_value); 169 cur_reg++; 170 arg_offset++; 171 break; 172 } 173 default: 174 new_shadow_frame->SetVReg(cur_reg, shadow_frame.GetVReg(arg_pos)); 175 break; 176 } 177 } 178 179 if (LIKELY(Runtime::Current()->IsStarted())) { 180 (method->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result); 181 } else { 182 UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins); 183 } 184 return !self->IsExceptionPending(); 185} 186 187template <bool is_range, bool do_access_check> 188bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame, 189 Thread* self, JValue* result) { 190 DCHECK(inst->Opcode() == Instruction::FILLED_NEW_ARRAY || 191 inst->Opcode() == Instruction::FILLED_NEW_ARRAY_RANGE); 192 const int32_t length = is_range ? inst->VRegA_3rc() : inst->VRegA_35c(); 193 if (!is_range) { 194 // Checks FILLED_NEW_ARRAY's length does not exceed 5 arguments. 195 CHECK_LE(length, 5); 196 } 197 if (UNLIKELY(length < 0)) { 198 ThrowNegativeArraySizeException(length); 199 return false; 200 } 201 uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); 202 Class* arrayClass = ResolveVerifyAndClinit(type_idx, shadow_frame.GetMethod(), 203 self, false, do_access_check); 204 if (UNLIKELY(arrayClass == NULL)) { 205 DCHECK(self->IsExceptionPending()); 206 return false; 207 } 208 CHECK(arrayClass->IsArrayClass()); 209 Class* componentClass = arrayClass->GetComponentType(); 210 if (UNLIKELY(componentClass->IsPrimitive() && !componentClass->IsPrimitiveInt())) { 211 if (componentClass->IsPrimitiveLong() || componentClass->IsPrimitiveDouble()) { 212 ThrowRuntimeException("Bad filled array request for type %s", 213 PrettyDescriptor(componentClass).c_str()); 214 } else { 215 self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(), 216 "Ljava/lang/InternalError;", 217 "Found type %s; filled-new-array not implemented for anything but \'int\'", 218 PrettyDescriptor(componentClass).c_str()); 219 } 220 return false; 221 } 222 Object* newArray = Array::Alloc(self, arrayClass, length); 223 if (UNLIKELY(newArray == NULL)) { 224 DCHECK(self->IsExceptionPending()); 225 return false; 226 } 227 if (is_range) { 228 uint32_t vregC = inst->VRegC_3rc(); 229 const bool is_primitive_int_component = componentClass->IsPrimitiveInt(); 230 for (int32_t i = 0; i < length; ++i) { 231 if (is_primitive_int_component) { 232 newArray->AsIntArray()->Set(i, shadow_frame.GetVReg(vregC + i)); 233 } else { 234 newArray->AsObjectArray<Object>()->Set(i, shadow_frame.GetVRegReference(vregC + i)); 235 } 236 } 237 } else { 238 uint32_t arg[5]; 239 inst->GetArgs(arg); 240 const bool is_primitive_int_component = componentClass->IsPrimitiveInt(); 241 for (int32_t i = 0; i < length; ++i) { 242 if (is_primitive_int_component) { 243 newArray->AsIntArray()->Set(i, shadow_frame.GetVReg(arg[i])); 244 } else { 245 newArray->AsObjectArray<Object>()->Set(i, shadow_frame.GetVRegReference(arg[i])); 246 } 247 } 248 } 249 250 result->SetL(newArray); 251 return true; 252} 253 254void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh, 255 const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, 256 JValue* result, size_t arg_offset) { 257 // In a runtime that's not started we intercept certain methods to avoid complicated dependency 258 // problems in core libraries. 259 std::string name(PrettyMethod(shadow_frame->GetMethod())); 260 if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") { 261 std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str())); 262 ClassLoader* class_loader = NULL; // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader(); 263 Class* found = Runtime::Current()->GetClassLinker()->FindClass(descriptor.c_str(), 264 class_loader); 265 CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: " 266 << PrettyDescriptor(descriptor); 267 result->SetL(found); 268 } else if (name == "java.lang.Object java.lang.Class.newInstance()") { 269 Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); 270 ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V"); 271 CHECK(c != NULL); 272 SirtRef<Object> obj(self, klass->AllocObject(self)); 273 CHECK(obj.get() != NULL); 274 EnterInterpreterFromInvoke(self, c, obj.get(), NULL, NULL); 275 result->SetL(obj.get()); 276 } else if (name == "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") { 277 // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail 278 // going the reflective Dex way. 279 Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); 280 String* name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString(); 281 ArtField* found = NULL; 282 FieldHelper fh; 283 ObjectArray<ArtField>* fields = klass->GetIFields(); 284 for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) { 285 ArtField* f = fields->Get(i); 286 fh.ChangeField(f); 287 if (name->Equals(fh.GetName())) { 288 found = f; 289 } 290 } 291 if (found == NULL) { 292 fields = klass->GetSFields(); 293 for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) { 294 ArtField* f = fields->Get(i); 295 fh.ChangeField(f); 296 if (name->Equals(fh.GetName())) { 297 found = f; 298 } 299 } 300 } 301 CHECK(found != NULL) 302 << "Failed to find field in Class.getDeclaredField in un-started runtime. name=" 303 << name->ToModifiedUtf8() << " class=" << PrettyDescriptor(klass); 304 // TODO: getDeclaredField calls GetType once the field is found to ensure a 305 // NoClassDefFoundError is thrown if the field's type cannot be resolved. 306 Class* jlr_Field = self->DecodeJObject(WellKnownClasses::java_lang_reflect_Field)->AsClass(); 307 SirtRef<Object> field(self, jlr_Field->AllocObject(self)); 308 CHECK(field.get() != NULL); 309 ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("<init>", "(Ljava/lang/reflect/ArtField;)V"); 310 uint32_t args[1]; 311 args[0] = reinterpret_cast<uint32_t>(found); 312 EnterInterpreterFromInvoke(self, c, field.get(), args, NULL); 313 result->SetL(field.get()); 314 } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" || 315 name == "void java.lang.System.arraycopy(char[], int, char[], int, int)") { 316 // Special case array copying without initializing System. 317 Class* ctype = shadow_frame->GetVRegReference(arg_offset)->GetClass()->GetComponentType(); 318 jint srcPos = shadow_frame->GetVReg(arg_offset + 1); 319 jint dstPos = shadow_frame->GetVReg(arg_offset + 3); 320 jint length = shadow_frame->GetVReg(arg_offset + 4); 321 if (!ctype->IsPrimitive()) { 322 ObjectArray<Object>* src = shadow_frame->GetVRegReference(arg_offset)->AsObjectArray<Object>(); 323 ObjectArray<Object>* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsObjectArray<Object>(); 324 for (jint i = 0; i < length; ++i) { 325 dst->Set(dstPos + i, src->Get(srcPos + i)); 326 } 327 } else if (ctype->IsPrimitiveChar()) { 328 CharArray* src = shadow_frame->GetVRegReference(arg_offset)->AsCharArray(); 329 CharArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsCharArray(); 330 for (jint i = 0; i < length; ++i) { 331 dst->Set(dstPos + i, src->Get(srcPos + i)); 332 } 333 } else if (ctype->IsPrimitiveInt()) { 334 IntArray* src = shadow_frame->GetVRegReference(arg_offset)->AsIntArray(); 335 IntArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsIntArray(); 336 for (jint i = 0; i < length; ++i) { 337 dst->Set(dstPos + i, src->Get(srcPos + i)); 338 } 339 } else { 340 UNIMPLEMENTED(FATAL) << "System.arraycopy of unexpected type: " << PrettyDescriptor(ctype); 341 } 342 } else { 343 // Not special, continue with regular interpreter execution. 344 artInterpreterToInterpreterBridge(self, mh, code_item, shadow_frame, result); 345 } 346} 347 348// Explicit DoInvoke template function declarations. 349#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range_, _check) \ 350 template bool DoInvoke<_type, _is_range_, _check>(Thread* self, ShadowFrame& shadow_frame, \ 351 const Instruction* inst, JValue* result) 352 353#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(_type) \ 354 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, false); \ 355 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, true); \ 356 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, false); \ 357 EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, true, true) 358 359EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kStatic); 360EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kDirect); 361EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kVirtual); 362EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kSuper); 363EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS(kInterface); 364 365#undef EXPLICIT_DO_INVOKE_TEMPLATE_DECL_VARIANTS 366#undef EXPLICIT_DO_INVOKE_TEMPLATE_DECL 367 368// Explicit DoInvokeVirtualQuick template function declarations. 369#define EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(_is_range) \ 370template bool DoInvokeVirtualQuick<_is_range>(Thread* self, ShadowFrame& shadow_frame, \ 371 const Instruction* inst, JValue* result) 372 373EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(false); 374EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(true); 375#undef EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL 376 377// Explicit DoFilledNewArray template function declarations. 378#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check) \ 379 template bool DoFilledNewArray<_is_range_, _check>(const Instruction* inst, \ 380 const ShadowFrame& shadow_frame, \ 381 Thread* self, JValue* result) 382EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false); 383EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true); 384EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false); 385EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true); 386#undef EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL 387 388} // namespace interpreter 389} // namespace art 390