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