1 /* 2 * Copyright (C) 2013 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_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ 18 #define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ 19 20 #include "dex_instruction-inl.h" 21 #include "entrypoints/entrypoint_utils-inl.h" 22 #include "interpreter/interpreter.h" 23 #include "mirror/art_method-inl.h" 24 #include "mirror/object-inl.h" 25 #include "scoped_thread_state_change.h" 26 27 namespace art { 28 29 // Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame. 30 class PortableArgumentVisitor { 31 public: 32 // Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame. 33 // Size of Runtime::kRefAndArgs callee save frame. 34 // Size of Method* and register parameters in out stack arguments. 35 #if defined(__arm__) 36 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8 37 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48 38 #define PORTABLE_STACK_ARG_SKIP 0 39 #elif defined(__mips__) 40 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4 41 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64 42 #define PORTABLE_STACK_ARG_SKIP 16 43 #elif defined(__i386__) 44 // For x86 there are no register arguments and the stack pointer will point directly to the called 45 // method argument passed by the caller. 46 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0 47 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0 48 #define PORTABLE_STACK_ARG_SKIP 4 49 #elif defined(__x86_64__) 50 // TODO: implement and check these. 51 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 16 52 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 96 53 #define PORTABLE_STACK_ARG_SKIP 0 54 #else 55 // TODO: portable should be disabled for aarch64 for now. 56 // #error "Unsupported architecture" 57 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0 58 #define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0 59 #define PORTABLE_STACK_ARG_SKIP 0 60 #endif 61 62 PortableArgumentVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp) 63 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : 64 caller_mh_(caller_mh), 65 args_in_regs_(ComputeArgsInRegs(caller_mh)), 66 num_params_(caller_mh.NumArgs()), 67 reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET), 68 stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 69 + PORTABLE_STACK_ARG_SKIP), 70 cur_args_(reg_args_), 71 cur_arg_index_(0), 72 param_index_(0) { 73 } 74 75 virtual ~PortableArgumentVisitor() {} 76 77 virtual void Visit() = 0; 78 79 bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 80 return caller_mh_.IsParamAReference(param_index_); 81 } 82 83 bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 84 return caller_mh_.IsParamALongOrDouble(param_index_); 85 } 86 87 Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 88 return caller_mh_.GetParamPrimitiveType(param_index_); 89 } 90 91 byte* GetParamAddress() const { 92 return cur_args_ + (cur_arg_index_ * kPointerSize); 93 } 94 95 void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 96 for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) { 97 #if (defined(__arm__) || defined(__mips__)) 98 if (IsParamALongOrDouble() && cur_arg_index_ == 2) { 99 break; 100 } 101 #endif 102 Visit(); 103 cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); 104 param_index_++; 105 } 106 cur_args_ = stack_args_; 107 cur_arg_index_ = 0; 108 while (param_index_ < num_params_) { 109 #if (defined(__arm__) || defined(__mips__)) 110 if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) { 111 cur_arg_index_++; 112 } 113 #endif 114 Visit(); 115 cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1); 116 param_index_++; 117 } 118 } 119 120 private: 121 static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 122 #if (defined(__i386__)) 123 return 0; 124 #else 125 size_t args_in_regs = 0; 126 size_t num_params = mh.NumArgs(); 127 for (size_t i = 0; i < num_params; i++) { 128 args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1); 129 if (args_in_regs > 3) { 130 args_in_regs = 3; 131 break; 132 } 133 } 134 return args_in_regs; 135 #endif 136 } 137 MethodHelper& caller_mh_; 138 const size_t args_in_regs_; 139 const size_t num_params_; 140 byte* const reg_args_; 141 byte* const stack_args_; 142 byte* cur_args_; 143 size_t cur_arg_index_; 144 size_t param_index_; 145 }; 146 147 // Visits arguments on the stack placing them into the shadow frame. 148 class BuildPortableShadowFrameVisitor : public PortableArgumentVisitor { 149 public: 150 BuildPortableShadowFrameVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp, 151 ShadowFrame& sf, size_t first_arg_reg) : 152 PortableArgumentVisitor(caller_mh, sp), sf_(sf), cur_reg_(first_arg_reg) { } 153 virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 154 Primitive::Type type = GetParamPrimitiveType(); 155 switch (type) { 156 case Primitive::kPrimLong: // Fall-through. 157 case Primitive::kPrimDouble: 158 sf_.SetVRegLong(cur_reg_, *reinterpret_cast<jlong*>(GetParamAddress())); 159 ++cur_reg_; 160 break; 161 case Primitive::kPrimNot: 162 sf_.SetVRegReference(cur_reg_, *reinterpret_cast<mirror::Object**>(GetParamAddress())); 163 break; 164 case Primitive::kPrimBoolean: // Fall-through. 165 case Primitive::kPrimByte: // Fall-through. 166 case Primitive::kPrimChar: // Fall-through. 167 case Primitive::kPrimShort: // Fall-through. 168 case Primitive::kPrimInt: // Fall-through. 169 case Primitive::kPrimFloat: 170 sf_.SetVReg(cur_reg_, *reinterpret_cast<jint*>(GetParamAddress())); 171 break; 172 case Primitive::kPrimVoid: 173 LOG(FATAL) << "UNREACHABLE"; 174 break; 175 } 176 ++cur_reg_; 177 } 178 179 private: 180 ShadowFrame& sf_; 181 size_t cur_reg_; 182 183 DISALLOW_COPY_AND_ASSIGN(BuildPortableShadowFrameVisitor); 184 }; 185 186 extern "C" uint64_t artPortableToInterpreterBridge(mirror::ArtMethod* method, Thread* self, 187 mirror::ArtMethod** sp) 188 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 189 // Ensure we don't get thread suspension until the object arguments are safely in the shadow 190 // frame. 191 // FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); 192 193 if (method->IsAbstract()) { 194 ThrowAbstractMethodError(method); 195 return 0; 196 } else { 197 const char* old_cause = self->StartAssertNoThreadSuspension("Building interpreter shadow frame"); 198 StackHandleScope<2> hs(self); 199 MethodHelper mh(hs.NewHandle(method)); 200 const DexFile::CodeItem* code_item = method->GetCodeItem(); 201 uint16_t num_regs = code_item->registers_size_; 202 void* memory = alloca(ShadowFrame::ComputeSize(num_regs)); 203 ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, NULL, // No last shadow coming from quick. 204 method, 0, memory)); 205 size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_; 206 BuildPortableShadowFrameVisitor shadow_frame_builder(mh, sp, 207 *shadow_frame, first_arg_reg); 208 shadow_frame_builder.VisitArguments(); 209 // Push a transition back into managed code onto the linked list in thread. 210 ManagedStack fragment; 211 self->PushManagedStackFragment(&fragment); 212 self->PushShadowFrame(shadow_frame); 213 self->EndAssertNoThreadSuspension(old_cause); 214 215 if (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized()) { 216 // Ensure static method's class is initialized. 217 Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass())); 218 if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) { 219 DCHECK(Thread::Current()->IsExceptionPending()); 220 self->PopManagedStackFragment(fragment); 221 return 0; 222 } 223 } 224 225 JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame); 226 // Pop transition. 227 self->PopManagedStackFragment(fragment); 228 return result.GetJ(); 229 } 230 } 231 232 // Visits arguments on the stack placing them into the args vector, Object* arguments are converted 233 // to jobjects. 234 class BuildPortableArgumentVisitor : public PortableArgumentVisitor { 235 public: 236 BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::ArtMethod** sp, 237 ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) : 238 PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {} 239 240 virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 241 jvalue val; 242 Primitive::Type type = GetParamPrimitiveType(); 243 switch (type) { 244 case Primitive::kPrimNot: { 245 mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress()); 246 val.l = soa_.AddLocalReference<jobject>(obj); 247 break; 248 } 249 case Primitive::kPrimLong: // Fall-through. 250 case Primitive::kPrimDouble: 251 val.j = *reinterpret_cast<jlong*>(GetParamAddress()); 252 break; 253 case Primitive::kPrimBoolean: // Fall-through. 254 case Primitive::kPrimByte: // Fall-through. 255 case Primitive::kPrimChar: // Fall-through. 256 case Primitive::kPrimShort: // Fall-through. 257 case Primitive::kPrimInt: // Fall-through. 258 case Primitive::kPrimFloat: 259 val.i = *reinterpret_cast<jint*>(GetParamAddress()); 260 break; 261 case Primitive::kPrimVoid: 262 LOG(FATAL) << "UNREACHABLE"; 263 val.j = 0; 264 break; 265 } 266 args_.push_back(val); 267 } 268 269 private: 270 ScopedObjectAccessUnchecked& soa_; 271 std::vector<jvalue>& args_; 272 273 DISALLOW_COPY_AND_ASSIGN(BuildPortableArgumentVisitor); 274 }; 275 276 // Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method 277 // which is responsible for recording callee save registers. We explicitly place into jobjects the 278 // incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a 279 // field within the proxy object, which will box the primitive arguments and deal with error cases. 280 extern "C" uint64_t artPortableProxyInvokeHandler(mirror::ArtMethod* proxy_method, 281 mirror::Object* receiver, 282 Thread* self, mirror::ArtMethod** sp) 283 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 284 // Ensure we don't get thread suspension until the object arguments are safely in jobjects. 285 const char* old_cause = 286 self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments"); 287 self->VerifyStack(); 288 // Start new JNI local reference state. 289 JNIEnvExt* env = self->GetJniEnv(); 290 ScopedObjectAccessUnchecked soa(env); 291 ScopedJniEnvLocalRefState env_state(env); 292 // Create local ref. copies of proxy method and the receiver. 293 jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver); 294 295 // Placing arguments into args vector and remove the receiver. 296 StackHandleScope<1> hs(self); 297 MethodHelper proxy_mh(hs.NewHandle(proxy_method)); 298 std::vector<jvalue> args; 299 BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args); 300 local_ref_visitor.VisitArguments(); 301 args.erase(args.begin()); 302 303 // Convert proxy method into expected interface method. 304 mirror::ArtMethod* interface_method = proxy_method->FindOverriddenMethod(); 305 DCHECK(interface_method != NULL); 306 DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method); 307 jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method); 308 309 // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code 310 // that performs allocations. 311 self->EndAssertNoThreadSuspension(old_cause); 312 JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(), 313 rcvr_jobj, interface_method_jobj, args); 314 return result.GetJ(); 315 } 316 317 // Lazily resolve a method for portable. Called by stub code. 318 extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called, 319 mirror::Object* receiver, 320 Thread* self, 321 mirror::ArtMethod** called_addr) 322 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 323 uint32_t dex_pc; 324 mirror::ArtMethod* caller = self->GetCurrentMethod(&dex_pc); 325 326 ClassLinker* linker = Runtime::Current()->GetClassLinker(); 327 InvokeType invoke_type; 328 bool is_range; 329 if (called->IsRuntimeMethod()) { 330 const DexFile::CodeItem* code = caller->GetCodeItem(); 331 CHECK_LT(dex_pc, code->insns_size_in_code_units_); 332 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); 333 Instruction::Code instr_code = instr->Opcode(); 334 switch (instr_code) { 335 case Instruction::INVOKE_DIRECT: 336 invoke_type = kDirect; 337 is_range = false; 338 break; 339 case Instruction::INVOKE_DIRECT_RANGE: 340 invoke_type = kDirect; 341 is_range = true; 342 break; 343 case Instruction::INVOKE_STATIC: 344 invoke_type = kStatic; 345 is_range = false; 346 break; 347 case Instruction::INVOKE_STATIC_RANGE: 348 invoke_type = kStatic; 349 is_range = true; 350 break; 351 case Instruction::INVOKE_SUPER: 352 invoke_type = kSuper; 353 is_range = false; 354 break; 355 case Instruction::INVOKE_SUPER_RANGE: 356 invoke_type = kSuper; 357 is_range = true; 358 break; 359 case Instruction::INVOKE_VIRTUAL: 360 invoke_type = kVirtual; 361 is_range = false; 362 break; 363 case Instruction::INVOKE_VIRTUAL_RANGE: 364 invoke_type = kVirtual; 365 is_range = true; 366 break; 367 case Instruction::INVOKE_INTERFACE: 368 invoke_type = kInterface; 369 is_range = false; 370 break; 371 case Instruction::INVOKE_INTERFACE_RANGE: 372 invoke_type = kInterface; 373 is_range = true; 374 break; 375 default: 376 LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL); 377 // Avoid used uninitialized warnings. 378 invoke_type = kDirect; 379 is_range = true; 380 } 381 uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c(); 382 called = linker->ResolveMethod(Thread::Current(), dex_method_idx, &caller, invoke_type); 383 // Incompatible class change should have been handled in resolve method. 384 CHECK(!called->CheckIncompatibleClassChange(invoke_type)); 385 // Refine called method based on receiver. 386 if (invoke_type == kVirtual) { 387 called = receiver->GetClass()->FindVirtualMethodForVirtual(called); 388 } else if (invoke_type == kInterface) { 389 called = receiver->GetClass()->FindVirtualMethodForInterface(called); 390 } 391 } else { 392 CHECK(called->IsStatic()) << PrettyMethod(called); 393 invoke_type = kStatic; 394 // Incompatible class change should have been handled in resolve method. 395 CHECK(!called->CheckIncompatibleClassChange(invoke_type)); 396 } 397 const void* code = nullptr; 398 if (LIKELY(!self->IsExceptionPending())) { 399 // Ensure that the called method's class is initialized. 400 StackHandleScope<1> hs(self); 401 Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass())); 402 linker->EnsureInitialized(called_class, true, true); 403 if (LIKELY(called_class->IsInitialized())) { 404 #if defined(ART_USE_PORTABLE_COMPILER) 405 code = called->GetEntryPointFromPortableCompiledCode(); 406 #else 407 code = nullptr; 408 #endif 409 // TODO: remove this after we solve the link issue. 410 if (code == nullptr) { 411 #if defined(ART_USE_PORTABLE_COMPILER) 412 bool have_portable_code; 413 code = linker->GetPortableOatCodeFor(called, &have_portable_code); 414 #endif 415 } 416 } else if (called_class->IsInitializing()) { 417 if (invoke_type == kStatic) { 418 // Class is still initializing, go to oat and grab code (trampoline must be left in place 419 // until class is initialized to stop races between threads). 420 #if defined(ART_USE_PORTABLE_COMPILER) 421 bool have_portable_code; 422 code = linker->GetPortableOatCodeFor(called, &have_portable_code); 423 #endif 424 } else { 425 // No trampoline for non-static methods. 426 #if defined(ART_USE_PORTABLE_COMPILER) 427 code = called->GetEntryPointFromPortableCompiledCode(); 428 #else 429 code = nullptr; 430 #endif 431 // TODO: remove this after we solve the link issue. 432 if (code == nullptr) { 433 #if defined(ART_USE_PORTABLE_COMPILER) 434 bool have_portable_code; 435 code = linker->GetPortableOatCodeFor(called, &have_portable_code); 436 #endif 437 } 438 } 439 } else { 440 DCHECK(called_class->IsErroneous()); 441 } 442 } 443 if (LIKELY(code != nullptr)) { 444 // Expect class to at least be initializing. 445 DCHECK(called->GetDeclaringClass()->IsInitializing()); 446 // Don't want infinite recursion. 447 DCHECK(code != linker->GetPortableResolutionTrampoline()); 448 // Set up entry into main method 449 *called_addr = called; 450 } 451 return code; 452 } 453 454 } // namespace art 455 456 #endif // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_ 457