• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NumArgArrayBytes(const char * shorty,uint32_t shorty_len)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:
ArgArray(const char * shorty,uint32_t shorty_len)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 
GetArray()68   uint32_t* GetArray() {
69     return arg_array_;
70   }
71 
GetNumBytes()72   uint32_t GetNumBytes() {
73     return num_bytes_;
74   }
75 
Append(uint32_t value)76   void Append(uint32_t value) {
77     arg_array_[num_bytes_ / 4] = value;
78     num_bytes_ += 4;
79   }
80 
AppendWide(uint64_t value)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 
BuildArgArray(const ScopedObjectAccess & soa,mirror::Object * receiver,va_list ap)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 
BuildArgArray(const ScopedObjectAccess & soa,mirror::Object * receiver,jvalue * args)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 
BuildArgArrayFromFrame(ShadowFrame * shadow_frame,uint32_t arg_offset)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