blob: 19c42ac9b83ea580e2478536a75098604bd491d9 [file] [log] [blame]
/*
* 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 "mirror/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(mirror::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<mirror::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<mirror::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 = 0; i < shorty_len_; ++i, ++offset) {
switch (shorty_[i]) {
case 'Z':
arg_array_[i - 1].SetZ(shadow_frame.GetVReg(range_start + offset));
break;
case 'B':
arg_array_[i - 1].SetB(shadow_frame.GetVReg(range_start + offset));
break;
case 'C':
arg_array_[i - 1].SetC(shadow_frame.GetVReg(range_start + offset));
break;
case 'S':
arg_array_[i - 1].SetS(shadow_frame.GetVReg(range_start + offset));
break;
case 'I':
arg_array_[i - 1].SetI(shadow_frame.GetVReg(range_start + offset));
break;
case 'F':
arg_array_[i - 1].SetF(shadow_frame.GetVRegFloat(range_start + offset));
break;
case 'L':
arg_array_[i - 1].SetL(shadow_frame.GetVRegReference(range_start + offset));
break;
case 'D':
arg_array_[i - 1].SetD(shadow_frame.GetVRegDouble(range_start + offset));
offset++;
break;
case 'J':
arg_array_[i - 1].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_[i - 1].SetZ(shadow_frame.GetVReg(arg_regs[offset]));
break;
case 'B':
arg_array_[i - 1].SetB(shadow_frame.GetVReg(arg_regs[offset]));
break;
case 'C':
arg_array_[i - 1].SetC(shadow_frame.GetVReg(arg_regs[offset]));
break;
case 'S':
arg_array_[i - 1].SetS(shadow_frame.GetVReg(arg_regs[offset]));
break;
case 'I':
arg_array_[i - 1].SetI(shadow_frame.GetVReg(arg_regs[offset]));
break;
case 'F':
arg_array_[i - 1].SetF(shadow_frame.GetVRegFloat(arg_regs[offset]));
break;
case 'L':
arg_array_[i - 1].SetL(shadow_frame.GetVRegReference(arg_regs[offset]));
break;
case 'D':
arg_array_[i - 1].SetD(shadow_frame.GetVRegDouble(arg_regs[offset]));
offset++;
break;
case 'J':
arg_array_[i - 1].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_