blob: 4fb16e0241cf68deef07078d99e430bd4404781d [file] [log] [blame]
/*
* Copyright (C) 2013 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_OAT_RUNTIME_ARGUMENT_VISITOR_H_
#define ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_
#include "object_utils.h"
namespace art {
// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
class PortableArgumentVisitor {
public:
// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
// Size of Runtime::kRefAndArgs callee save frame.
// Size of Method* and register parameters in out stack arguments.
#if defined(__arm__)
#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
#define PORTABLE_STACK_ARG_SKIP 0
#elif defined(__mips__)
#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64
#define PORTABLE_STACK_ARG_SKIP 16
#elif defined(__i386__)
#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32
#define PORTABLE_STACK_ARG_SKIP 4
#else
#error "Unsupported architecture"
#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
#define PORTABLE_STACK_ARG_SKIP 0
#endif
PortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
caller_mh_(caller_mh),
args_in_regs_(ComputeArgsInRegs(caller_mh)),
num_params_(caller_mh.NumArgs()),
reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
+ PORTABLE_STACK_ARG_SKIP),
cur_args_(reg_args_),
cur_arg_index_(0),
param_index_(0) {
}
virtual ~PortableArgumentVisitor() {}
virtual void Visit() = 0;
bool IsParamAReference() const {
return caller_mh_.IsParamAReference(param_index_);
}
bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return caller_mh_.IsParamALongOrDouble(param_index_);
}
Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return caller_mh_.GetParamPrimitiveType(param_index_);
}
byte* GetParamAddress() const {
return cur_args_ + (cur_arg_index_ * kPointerSize);
}
void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
#if (defined(__arm__) || defined(__mips__))
if (IsParamALongOrDouble() && cur_arg_index_ == 2) {
break;
}
#endif
Visit();
cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
param_index_++;
}
cur_args_ = stack_args_;
cur_arg_index_ = 0;
while (param_index_ < num_params_) {
#if (defined(__arm__) || defined(__mips__))
if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) {
cur_arg_index_++;
}
#endif
Visit();
cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
param_index_++;
}
}
private:
static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
#if (defined(__i386__))
return 0;
#else
size_t args_in_regs = 0;
size_t num_params = mh.NumArgs();
for (size_t i = 0; i < num_params; i++) {
args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1);
if (args_in_regs > 3) {
args_in_regs = 3;
break;
}
}
return args_in_regs;
#endif
}
MethodHelper& caller_mh_;
const size_t args_in_regs_;
const size_t num_params_;
byte* const reg_args_;
byte* const stack_args_;
byte* cur_args_;
size_t cur_arg_index_;
size_t param_index_;
};
// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
class QuickArgumentVisitor {
public:
// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
// Size of Runtime::kRefAndArgs callee save frame.
// Size of Method* and register parameters in out stack arguments.
#if defined(__arm__)
#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
#define QUICK_STACK_ARG_SKIP 16
#elif defined(__mips__)
#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64
#define QUICK_STACK_ARG_SKIP 16
#elif defined(__i386__)
#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32
#define QUICK_STACK_ARG_SKIP 16
#else
#error "Unsupported architecture"
#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
#define QUICK_STACK_ARG_SKIP 0
#endif
QuickArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
caller_mh_(caller_mh),
args_in_regs_(ComputeArgsInRegs(caller_mh)),
num_params_(caller_mh.NumArgs()),
reg_args_(reinterpret_cast<byte*>(sp) + QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
stack_args_(reinterpret_cast<byte*>(sp) + QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
+ QUICK_STACK_ARG_SKIP),
cur_args_(reg_args_),
cur_arg_index_(0),
param_index_(0),
is_split_long_or_double_(false) {
}
virtual ~QuickArgumentVisitor() {}
virtual void Visit() = 0;
bool IsParamAReference() const {
return caller_mh_.IsParamAReference(param_index_);
}
bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return caller_mh_.IsParamALongOrDouble(param_index_);
}
Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return caller_mh_.GetParamPrimitiveType(param_index_);
}
byte* GetParamAddress() const {
return cur_args_ + (cur_arg_index_ * kPointerSize);
}
bool IsSplitLongOrDouble() const {
return is_split_long_or_double_;
}
uint64_t ReadSplitLongParam() const {
DCHECK(IsSplitLongOrDouble());
uint64_t low_half = *reinterpret_cast<uint32_t*>(GetParamAddress());
uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args_);
return (low_half & 0xffffffffULL) | (high_half << 32);
}
void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
is_split_long_or_double_ = (cur_arg_index_ == 2) && IsParamALongOrDouble();
Visit();
cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
param_index_++;
}
cur_args_ = stack_args_;
cur_arg_index_ = is_split_long_or_double_ ? 1 : 0;
is_split_long_or_double_ = false;
while (param_index_ < num_params_) {
Visit();
cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
param_index_++;
}
}
private:
static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
size_t args_in_regs = 0;
size_t num_params = mh.NumArgs();
for (size_t i = 0; i < num_params; i++) {
args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1);
if (args_in_regs > 3) {
args_in_regs = 3;
break;
}
}
return args_in_regs;
}
MethodHelper& caller_mh_;
const size_t args_in_regs_;
const size_t num_params_;
byte* const reg_args_;
byte* const stack_args_;
byte* cur_args_;
size_t cur_arg_index_;
size_t param_index_;
// Does a 64bit parameter straddle the register and stack arguments?
bool is_split_long_or_double_;
};
}
#endif // ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_