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-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