Home | History | Annotate | Download | only in runtime
      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 #ifndef ART_RUNTIME_INVOKE_ARG_ARRAY_BUILDER_H_
     18 #define ART_RUNTIME_INVOKE_ARG_ARRAY_BUILDER_H_
     19 
     20 #include "mirror/art_method.h"
     21 #include "mirror/object.h"
     22 #include "scoped_thread_state_change.h"
     23 
     24 namespace art {
     25 
     26 static inline size_t NumArgArrayBytes(const char* shorty, uint32_t shorty_len) {
     27   size_t num_bytes = 0;
     28   for (size_t i = 1; i < shorty_len; ++i) {
     29     char ch = shorty[i];
     30     if (ch == 'D' || ch == 'J') {
     31       num_bytes += 8;
     32     } else if (ch == 'L') {
     33       // Argument is a reference or an array.  The shorty descriptor
     34       // does not distinguish between these types.
     35       num_bytes += sizeof(mirror::Object*);
     36     } else {
     37       num_bytes += 4;
     38     }
     39   }
     40   return num_bytes;
     41 }
     42 
     43 class ArgArray {
     44  public:
     45   explicit ArgArray(const char* shorty, uint32_t shorty_len)
     46       : shorty_(shorty), shorty_len_(shorty_len), num_bytes_(0) {
     47     size_t num_slots = shorty_len + 1;  // +1 in case of receiver.
     48     if (LIKELY((num_slots * 2) < kSmallArgArraySize)) {
     49       // We can trivially use the small arg array.
     50       arg_array_ = small_arg_array_;
     51     } else {
     52       // Analyze shorty to see if we need the large arg array.
     53       for (size_t i = 1; i < shorty_len; ++i) {
     54         char c = shorty[i];
     55         if (c == 'J' || c == 'D') {
     56           num_slots++;
     57         }
     58       }
     59       if (num_slots <= kSmallArgArraySize) {
     60         arg_array_ = small_arg_array_;
     61       } else {
     62         large_arg_array_.reset(new uint32_t[num_slots]);
     63         arg_array_ = large_arg_array_.get();
     64       }
     65     }
     66   }
     67 
     68   uint32_t* GetArray() {
     69     return arg_array_;
     70   }
     71 
     72   uint32_t GetNumBytes() {
     73     return num_bytes_;
     74   }
     75 
     76   void Append(uint32_t value) {
     77     arg_array_[num_bytes_ / 4] = value;
     78     num_bytes_ += 4;
     79   }
     80 
     81   void AppendWide(uint64_t value) {
     82     // For ARM and MIPS portable, align wide values to 8 bytes (ArgArray starts at offset of 4).
     83 #if defined(ART_USE_PORTABLE_COMPILER) && (defined(__arm__) || defined(__mips__))
     84     if (num_bytes_ % 8 == 0) {
     85       num_bytes_ += 4;
     86     }
     87 #endif
     88     arg_array_[num_bytes_ / 4] = value;
     89     arg_array_[(num_bytes_ / 4) + 1] = value >> 32;
     90     num_bytes_ += 8;
     91   }
     92 
     93   void BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver, va_list ap)
     94       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     95     // Set receiver if non-null (method is not static)
     96     if (receiver != NULL) {
     97       Append(reinterpret_cast<int32_t>(receiver));
     98     }
     99     for (size_t i = 1; i < shorty_len_; ++i) {
    100       switch (shorty_[i]) {
    101         case 'Z':
    102         case 'B':
    103         case 'C':
    104         case 'S':
    105         case 'I':
    106           Append(va_arg(ap, jint));
    107           break;
    108         case 'F': {
    109           JValue value;
    110           value.SetF(va_arg(ap, jdouble));
    111           Append(value.GetI());
    112           break;
    113         }
    114         case 'L':
    115           Append(reinterpret_cast<int32_t>(soa.Decode<mirror::Object*>(va_arg(ap, jobject))));
    116           break;
    117         case 'D': {
    118           JValue value;
    119           value.SetD(va_arg(ap, jdouble));
    120           AppendWide(value.GetJ());
    121           break;
    122         }
    123         case 'J': {
    124           AppendWide(va_arg(ap, jlong));
    125           break;
    126         }
    127       }
    128     }
    129   }
    130 
    131   void BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver, jvalue* args)
    132       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    133     // Set receiver if non-null (method is not static)
    134     if (receiver != NULL) {
    135       Append(reinterpret_cast<int32_t>(receiver));
    136     }
    137     for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++args_offset) {
    138       switch (shorty_[i]) {
    139         case 'Z':
    140           Append(args[args_offset].z);
    141           break;
    142         case 'B':
    143           Append(args[args_offset].b);
    144           break;
    145         case 'C':
    146           Append(args[args_offset].c);
    147           break;
    148         case 'S':
    149           Append(args[args_offset].s);
    150           break;
    151         case 'I':
    152         case 'F':
    153           Append(args[args_offset].i);
    154           break;
    155         case 'L':
    156           Append(reinterpret_cast<int32_t>(soa.Decode<mirror::Object*>(args[args_offset].l)));
    157           break;
    158         case 'D':
    159         case 'J':
    160           AppendWide(args[args_offset].j);
    161           break;
    162       }
    163     }
    164   }
    165 
    166 
    167   void BuildArgArrayFromFrame(ShadowFrame* shadow_frame, uint32_t arg_offset)
    168       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    169     // Set receiver if non-null (method is not static)
    170     size_t cur_arg = arg_offset;
    171     if (!shadow_frame->GetMethod()->IsStatic()) {
    172       Append(shadow_frame->GetVReg(cur_arg));
    173       cur_arg++;
    174     }
    175     for (size_t i = 1; i < shorty_len_; ++i) {
    176       switch (shorty_[i]) {
    177         case 'Z':
    178         case 'B':
    179         case 'C':
    180         case 'S':
    181         case 'I':
    182         case 'F':
    183         case 'L':
    184           Append(shadow_frame->GetVReg(cur_arg));
    185           cur_arg++;
    186           break;
    187         case 'D':
    188         case 'J':
    189           AppendWide(shadow_frame->GetVRegLong(cur_arg));
    190           cur_arg++;
    191           cur_arg++;
    192           break;
    193       }
    194     }
    195   }
    196 
    197  private:
    198   enum { kSmallArgArraySize = 16 };
    199   const char* const shorty_;
    200   const uint32_t shorty_len_;
    201   uint32_t num_bytes_;
    202   uint32_t* arg_array_;
    203   uint32_t small_arg_array_[kSmallArgArraySize];
    204   UniquePtr<uint32_t[]> large_arg_array_;
    205 };
    206 
    207 }  // namespace art
    208 
    209 #endif  // ART_RUNTIME_INVOKE_ARG_ARRAY_BUILDER_H_
    210