diff options
Diffstat (limited to 'src/invoke_arg_array_builder.h')
-rw-r--r-- | src/invoke_arg_array_builder.h | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/invoke_arg_array_builder.h b/src/invoke_arg_array_builder.h new file mode 100644 index 0000000000..e965a1ad18 --- /dev/null +++ b/src/invoke_arg_array_builder.h @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_INVOKE_ARG_ARRAY_BUILDER_H_ +#define ART_SRC_INVOKE_ARG_ARRAY_BUILDER_H_ + +#include "object.h" +#include "scoped_thread_state_change.h" + +namespace art { + +static inline size_t NumArgArrayBytes(const char* shorty, uint32_t shorty_len) { + size_t num_bytes = 0; + for (size_t i = 1; i < shorty_len; ++i) { + char ch = shorty[i]; + if (ch == 'D' || ch == 'J') { + num_bytes += 8; + } else if (ch == 'L') { + // Argument is a reference or an array. The shorty descriptor + // does not distinguish between these types. + num_bytes += sizeof(Object*); + } else { + num_bytes += 4; + } + } + return num_bytes; +} + +class ArgArray { + public: + explicit ArgArray(const char* shorty, uint32_t shorty_len) + : shorty_(shorty), shorty_len_(shorty_len) { + if (shorty_len - 1 < kSmallArgArraySize) { + arg_array_ = small_arg_array_; + } else { + large_arg_array_.reset(new JValue[shorty_len_ - 1]); + arg_array_ = large_arg_array_.get(); + } + } + + JValue* get() { + return arg_array_; + } + + void BuildArgArray(const ScopedObjectAccess& soa, va_list ap) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) { + switch (shorty_[i]) { + case 'Z': + arg_array_[offset].SetZ(va_arg(ap, jint)); + break; + case 'B': + arg_array_[offset].SetB(va_arg(ap, jint)); + break; + case 'C': + arg_array_[offset].SetC(va_arg(ap, jint)); + break; + case 'S': + arg_array_[offset].SetS(va_arg(ap, jint)); + break; + case 'I': + arg_array_[offset].SetI(va_arg(ap, jint)); + break; + case 'F': + arg_array_[offset].SetF(va_arg(ap, jdouble)); + break; + case 'L': + arg_array_[offset].SetL(soa.Decode<Object*>(va_arg(ap, jobject))); + break; + case 'D': + arg_array_[offset].SetD(va_arg(ap, jdouble)); + break; + case 'J': + arg_array_[offset].SetJ(va_arg(ap, jlong)); + break; + } + } + } + + void BuildArgArray(const ScopedObjectAccess& soa, jvalue* args) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) { + switch (shorty_[i]) { + case 'Z': + arg_array_[offset].SetZ(args[offset].z); + break; + case 'B': + arg_array_[offset].SetB(args[offset].b); + break; + case 'C': + arg_array_[offset].SetC(args[offset].c); + break; + case 'S': + arg_array_[offset].SetS(args[offset].s); + break; + case 'I': + arg_array_[offset].SetI(args[offset].i); + break; + case 'F': + arg_array_[offset].SetF(args[offset].f); + break; + case 'L': + arg_array_[offset].SetL(soa.Decode<Object*>(args[offset].l)); + break; + case 'D': + arg_array_[offset].SetD(args[offset].d); + break; + case 'J': + arg_array_[offset].SetJ(args[offset].j); + break; + } + } + } + + void BuildArgArray(const ShadowFrame& shadow_frame, uint32_t range_start) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (size_t i = 1, offset = range_start; i < shorty_len_; ++i, ++offset) { + switch (shorty_[i]) { + case 'Z': + arg_array_[offset].SetZ(shadow_frame.GetVReg(offset)); + break; + case 'B': + arg_array_[offset].SetB(shadow_frame.GetVReg(offset)); + break; + case 'C': + arg_array_[offset].SetC(shadow_frame.GetVReg(offset)); + break; + case 'S': + arg_array_[offset].SetS(shadow_frame.GetVReg(offset)); + break; + case 'I': + arg_array_[offset].SetI(shadow_frame.GetVReg(offset)); + break; + case 'F': + arg_array_[offset].SetF(shadow_frame.GetVRegFloat(offset)); + break; + case 'L': + arg_array_[offset].SetL(shadow_frame.GetReference(offset)); + break; + case 'D': + arg_array_[offset].SetD(shadow_frame.GetVRegDouble(offset)); + offset++; + break; + case 'J': + arg_array_[offset].SetJ(shadow_frame.GetVRegLong(offset)); + offset++; + break; + } + } + } + + void BuildArgArray(const ShadowFrame& shadow_frame, const uint32_t* arg_regs) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) { + switch (shorty_[i]) { + case 'Z': + arg_array_[offset].SetZ(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'B': + arg_array_[offset].SetB(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'C': + arg_array_[offset].SetC(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'S': + arg_array_[offset].SetS(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'I': + arg_array_[offset].SetI(shadow_frame.GetVReg(arg_regs[offset])); + break; + case 'F': + arg_array_[offset].SetF(shadow_frame.GetVRegFloat(arg_regs[offset])); + break; + case 'L': + arg_array_[offset].SetL(shadow_frame.GetReference(arg_regs[offset])); + break; + case 'D': + arg_array_[offset].SetD(shadow_frame.GetVRegDouble(arg_regs[offset])); + offset++; + break; + case 'J': + arg_array_[offset].SetJ(shadow_frame.GetVRegLong(arg_regs[offset])); + offset++; + break; + } + } + } + + private: + enum { kSmallArgArraySize = 16 }; + const char* const shorty_; + const uint32_t shorty_len_; + JValue* arg_array_; + JValue small_arg_array_[kSmallArgArraySize]; + UniquePtr<JValue[]> large_arg_array_; +}; + +} // namespace art + +#endif // ART_SRC_INVOKE_ARG_ARRAY_BUILDER_H_ |