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