/* * 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(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(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 = 0; i < shorty_len_; ++i, ++offset) { switch (shorty_[i]) { case 'Z': arg_array_[offset].SetZ(shadow_frame.GetVReg(range_start + offset)); break; case 'B': arg_array_[offset].SetB(shadow_frame.GetVReg(range_start + offset)); break; case 'C': arg_array_[offset].SetC(shadow_frame.GetVReg(range_start + offset)); break; case 'S': arg_array_[offset].SetS(shadow_frame.GetVReg(range_start + offset)); break; case 'I': arg_array_[offset].SetI(shadow_frame.GetVReg(range_start + offset)); break; case 'F': arg_array_[offset].SetF(shadow_frame.GetVRegFloat(range_start + offset)); break; case 'L': arg_array_[offset].SetL(shadow_frame.GetReference(range_start + offset)); break; case 'D': arg_array_[offset].SetD(shadow_frame.GetVRegDouble(range_start + offset)); offset++; break; case 'J': arg_array_[offset].SetJ(shadow_frame.GetVRegLong(range_start + 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 large_arg_array_; }; } // namespace art #endif // ART_SRC_INVOKE_ARG_ARRAY_BUILDER_H_