<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This is really Posix minus Mac. Mac code is in base_paths_mac.mm.

#include "base/base_paths.h"

#include <unistd.h>

#include "base/env_var.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/sys_string_conversions.h"
#include "base/xdg_util.h"

namespace base {

#if defined(OS_LINUX)
const char kSelfExe[] = "/proc/self/exe";
#elif defined(OS_SOLARIS)
const char kSelfExe[] = getexecname();
#elif defined(OS_FREEBSD)
const char kSelfExe[] = "/proc/curproc/file";
#endif

bool PathProviderPosix(int key, FilePath* result) {
  FilePath path;
  switch (key) {
    case base::FILE_EXE:
    case base::FILE_MODULE: {  // TODO(evanm): is this correct?
      char bin_dir[PATH_MAX + 1];
      int bin_dir_size = readlink(kSelfExe, bin_dir, PATH_MAX);
      if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
        NOTREACHED() << "Unable to resolve " << kSelfExe << ".";
        return false;
      }
      bin_dir[bin_dir_size] = 0;
      *result = FilePath(bin_dir);
      return true;
    }
    case base::DIR_SOURCE_ROOT: {
      // Allow passing this in the environment, for more flexibility in build
      // tree configurations (sub-project builds, gyp --output_dir, etc.)
      scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
      std::string cr_source_root;
      if (env->GetEnv("CR_SOURCE_ROOT", &cr_source_root)) {
        path = FilePath(cr_source_root);
        if (file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
          *result = path;
          return true;
        } else {
          LOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not "
                       << "point to the correct source root directory.";
        }
      }
      // On POSIX, unit tests execute two levels deep from the source root.
      // For example:  sconsbuild/{Debug|Release}/net_unittest
      if (PathService::Get(base::DIR_EXE, &path)) {
        path = path.DirName().DirName();
        if (file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
          *result = path;
          return true;
        }
      }
      // If that failed (maybe the build output is symlinked to a different
      // drive) try assuming the current directory is the source root.
      if (file_util::GetCurrentDirectory(&path) &&
          file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
        *result = path;
        return true;
      }
      LOG(ERROR) << "Couldn't find your source root.  "
                 << "Try running from your chromium/src directory.";
      return false;
    }
    case base::DIR_USER_CACHE:
      scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
      FilePath cache_dir(base::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
                                               ".cache"));
      *result = cache_dir;
      return true;
  }
  return false;
}

}  // namespace base
<commit_msg>use sysctl instead of /proc on FreeBSD (unfortunately this approach is not available on OpenBSD though) patch from sprewell Review URL: http://codereview.chromium.org/1979006<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This is really Posix minus Mac. Mac code is in base_paths_mac.mm.

#include "base/base_paths.h"

#include <unistd.h>
#if defined(OS_FREEBSD)
#include <sys/param.h>
#include <sys/sysctl.h>
#endif

#include "base/env_var.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/sys_string_conversions.h"
#include "base/xdg_util.h"

namespace base {

#if defined(OS_LINUX)
const char kSelfExe[] = "/proc/self/exe";
#elif defined(OS_SOLARIS)
const char kSelfExe[] = getexecname();
#endif

bool PathProviderPosix(int key, FilePath* result) {
  FilePath path;
  switch (key) {
    case base::FILE_EXE:
    case base::FILE_MODULE: {  // TODO(evanm): is this correct?
#if defined(OS_LINUX)
      char bin_dir[PATH_MAX + 1];
      int bin_dir_size = readlink(kSelfExe, bin_dir, PATH_MAX);
      if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
        NOTREACHED() << "Unable to resolve " << kSelfExe << ".";
        return false;
      }
      bin_dir[bin_dir_size] = 0;
      *result = FilePath(bin_dir);
      return true;
#elif defined(OS_FREEBSD)
      int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
      char bin_dir[PATH_MAX + 1];
      size_t length = sizeof(bin_dir);
      int error = sysctl(name, 4, bin_dir, &length, NULL, 0);
      if (error < 0 || length == 0 || strlen(bin_dir) == 0) {
        NOTREACHED() << "Unable to resolve path.";
        return false;
      }
      bin_dir[strlen(bin_dir)] = 0;
      *result = FilePath(bin_dir);
      return true;
#endif
    }
    case base::DIR_SOURCE_ROOT: {
      // Allow passing this in the environment, for more flexibility in build
      // tree configurations (sub-project builds, gyp --output_dir, etc.)
      scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
      std::string cr_source_root;
      if (env->GetEnv("CR_SOURCE_ROOT", &cr_source_root)) {
        path = FilePath(cr_source_root);
        if (file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
          *result = path;
          return true;
        } else {
          LOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not "
                       << "point to the correct source root directory.";
        }
      }
      // On POSIX, unit tests execute two levels deep from the source root.
      // For example:  sconsbuild/{Debug|Release}/net_unittest
      if (PathService::Get(base::DIR_EXE, &path)) {
        path = path.DirName().DirName();
        if (file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
          *result = path;
          return true;
        }
      }
      // If that failed (maybe the build output is symlinked to a different
      // drive) try assuming the current directory is the source root.
      if (file_util::GetCurrentDirectory(&path) &&
          file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
        *result = path;
        return true;
      }
      LOG(ERROR) << "Couldn't find your source root.  "
                 << "Try running from your chromium/src directory.";
      return false;
    }
    case base::DIR_USER_CACHE:
      scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
      FilePath cache_dir(base::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
                                               ".cache"));
      *result = cache_dir;
      return true;
  }
  return false;
}

}  // namespace base
<|endoftext|>


<commit_before>#include "robot_interface/arm_perception_ctrl.h"

#include <tf/transform_datatypes.h>

using namespace std;
using namespace human_robot_collaboration_msgs;

ArmPerceptionCtrl::ArmPerceptionCtrl(std::string _name, std::string _limb, bool _use_robot) :
                     ArmCtrl(_name,_limb, _use_robot), PerceptionClientImpl(_name, _limb)
{
    setHomeConfiguration();
    setState(START);

    insertAction(ACTION_GET,       static_cast<f_action>(&ArmPerceptionCtrl::getObject));
    insertAction(ACTION_PASS,      static_cast<f_action>(&ArmPerceptionCtrl::passObject));
    insertAction(ACTION_GET_PASS,  static_cast<f_action>(&ArmPerceptionCtrl::getPassObject));

    if (not _use_robot) return;

    // moveArm("up",0.2,"strict");
    // moveArm("down",0.2,"strict");
    // moveArm("right",0.2,"strict");
    // moveArm("left",0.2,"strict");
    // moveArm("forward",0.1,"strict");
    // moveArm("backward",0.2,"strict");
    // moveArm("forward",0.1,"strict");
}

bool ArmPerceptionCtrl::selectObject4PickUp()
{
    if (getObjectIDs().size() >  1)
    {
        setSubState(CHECK_OBJ_IDS);
        int id = chooseObjectID(getObjectIDs());

        if (id == -1)      { return false; };

        setObjectID(id);
        ROS_INFO_COND(print_level>=1, "[%s] Chosen object with name %s", getLimb().c_str(),
                          getObjectNameFromDB(ClientTemplate<int>::getObjectID()).c_str());
    }

    return true;
}

bool ArmPerceptionCtrl::recoverRelease()
{
    if (getPrevAction() != ACTION_RELEASE)  return false;
    if(!homePoseStrict())                   return false;
    ros::Duration(0.05).sleep();
    if (!pickUpObject())                    return false;
    if (!close())                           return false;
    if (!moveArm("up", 0.2))                return false;
    if (!homePoseStrict())                  return false;

    return true;
}

bool ArmPerceptionCtrl::recoverGet()
{
    if (!hoverAbovePool())          return false;
    if (!open())                    return false;
    if (!homePoseStrict())          return false;

    return true;
}

bool ArmPerceptionCtrl::pickUpObject()
{
    ROS_INFO_COND(print_level>=0, "[%s] Start Picking up object %s..", getLimb().c_str(),
                        getObjectNameFromDB(ClientTemplate<int>::getObjectID()).c_str());

    if (!isIRok())
    {
        ROS_ERROR("No callback from the IR sensor! Stopping.");
        setSubState(NO_IR_SENSOR);
        return false;
    }

    if (!waitForData())
    {
        setSubState(NO_OBJ);
        return false;
    }

    double offs_x = 0.0;
    double offs_y = 0.0;

    if (not computeOffsets(offs_x, offs_y))  { return false; }

    // Let's compute a first estimation of the joint position
    // (we reduce the z by 15 cm to start picking up from a
    // closer position)
    double x = getObjectPos().x + offs_x;
    double y = getObjectPos().y + offs_y;
    double z =       getPos().z -   0.15;

    geometry_msgs::Quaternion q;
    if (not computeOrientation(q))           { return false; }

    ROS_INFO_COND(print_level>=1, "Going to: %g %g %g", x, y, z);

    if (not goToPose(x, y, z, q.x, q.y, q.z, q.w, "loose"))
    {
        return false;
    }

    if (!waitForData())
    {
        setSubState(NO_OBJ);
        return false;
    }

    ros::Time start_time = ros::Time::now();
    double z_start       =       getPos().z;
    int cnt_ik_fail      =                0;

    ros::Rate r(THREAD_FREQ);
    while(RobotInterface::ok())
    {
        double elap_time = (ros::Time::now() - start_time).toSec();

        double x = getObjectPos().x + offs_x;
        double y = getObjectPos().y + offs_y;
        double z = z_start - getArmSpeed() * elap_time;

        ROS_INFO_COND(print_level>=3, "Time %g Going to: %g %g %g Position: %g %g %g",
                              elap_time, x, y, z, getPos().x, getPos().y, getPos().z);

        if (goToPoseNoCheck(x, y, z, q.x, q.y, q.z, q.w))
        {
            cnt_ik_fail = 0;
            // if (elap_time - old_elap_time > 0.02)
            // {
            //     ROS_WARN("\t\t\t\t\tTime elapsed: %g", elap_time - old_elap_time);
            // }
            // old_elap_time = elap_time;

            if (determineContactCondition()) { return true; }

            r.sleep();
        }
        else
        {
            ++cnt_ik_fail;
        }

        if (cnt_ik_fail == 10)      { return false; }
    }

    return false;
}

bool ArmPerceptionCtrl::determineContactCondition()
{
    if (hasCollidedIR("strict") || hasCollidedCD())
    {
        if (hasCollidedCD())
        {
            moveArm("up", 0.002);
        }
        ROS_INFO("Collision!");
        return true;
    }
    else
    {
        if (getAction() == ACTION_GET      ||
            getAction() == ACTION_GET_PASS)
        {
            if (getPos().z < -0.28)
            {
                ROS_INFO("Object reached!");
                return true;
            }
        }
    }

    return false;
}

bool ArmPerceptionCtrl::computeOffsets(double &_x_offs, double &_y_offs)
{
    return true;
}

int ArmPerceptionCtrl::chooseObjectID(vector<int> _objs)
{
    if (getSubState() != CHECK_OBJ_IDS)
    {
        return ArmCtrl::chooseObjectID(_objs);
    }

    ROS_INFO_COND(print_level>=3, "[%s] Choosing object IDs", getLimb().c_str());

    if (!waitForOK())
    {
        setSubState(NO_OBJ);
        return -1;
    }

    if (!waitForObjsFound())
    {
        setSubState(NO_OBJ);
        return -1;
    }

    std::vector<int> av_objects = ClientTemplate<int>::getAvailableObjects(_objs);

    if (av_objects.size() == 0)
    {
        setSubState(NO_OBJ);
        return -1;
    }

    srand(time(0)); //use current time as seed

    return av_objects[rand() % av_objects.size()];
}

bool ArmPerceptionCtrl::computeOrientation(geometry_msgs::Quaternion &_ori)
{
    if (getLimb() == "left")
    {
        if (getAction() == ACTION_GET || getAction() == ACTION_GET_PASS)
        {
            if      (ClientTemplate<int>::getObjectID() == 24)
            {
                // Get the rotation matrix for the object, as retrieved from
                tf::Quaternion mrk_q;
                tf::quaternionMsgToTF(getObjectOri(), mrk_q);
                tf::Matrix3x3 mrk_rot(mrk_q);

                // printf("Object Orientation\n");
                // for (int j = 0; j < 3; ++j)
                // {
                //     printf("%g\t%g\t%g\n", mrk_rot[j][0], mrk_rot[j][1], mrk_rot[j][2]);
                // }

                // Compute the transform matrix between the object's orientation
                // and the end-effector's orientation
                tf::Matrix3x3 mrk2ee;
                mrk2ee[0][0] =  1;  mrk2ee[0][1] =  0;   mrk2ee[0][2] =  0;
                mrk2ee[1][0] =  0;  mrk2ee[1][1] =  0;   mrk2ee[1][2] = -1;
                mrk2ee[2][0] =  0;  mrk2ee[2][1] =  1;   mrk2ee[2][2] =  0;

                // printf("Rotation\n");
                // for (int j = 0; j < 3; ++j)
                // {
                //     printf("%g\t%g\t%g\n", mrk2ee[j][0], mrk2ee[j][1], mrk2ee[j][2]);
                // }

                // Compute the final end-effector orientation, and convert it to a msg
                mrk2ee = mrk_rot * mrk2ee;

                tf::Quaternion ee_q;
                mrk2ee.getRotation(ee_q);
                geometry_msgs::Quaternion ee_q_msg;
                tf::quaternionTFToMsg(ee_q,ee_q_msg);

                // printf("Desired Orientation\n");
                // for (int j = 0; j < 3; ++j)
                // {
                //     printf("%g\t%g\t%g\n", mrk2ee[j][0], mrk2ee[j][1], mrk2ee[j][2]);
                // }

                _ori = ee_q_msg;
            }
            else
            {
                quaternionFromDoubles(_ori, POOL_ORI_L);
            }
        }
        else if (getAction() == ACTION_CLEANUP)
        {
            quaternionFromDoubles(_ori, VERTICAL_ORI_L);
        }
        else
        {
            ROS_ERROR("State is neither ACTION_GET, ACTION_GET_PASS or ACTION_CLEANUP!");
            return false;
        }
    }
    else if (getLimb() == "right")
    {
        if (getAction() == ACTION_GET || getAction() == ACTION_GET_PASS)
        {
            quaternionFromDoubles(_ori, POOL_ORI_L);
        }
        else if (getAction() == ACTION_CLEANUP)
        {
            quaternionFromDoubles(_ori, VERTICAL_ORI_R);
        }
        else
        {
            ROS_ERROR("State is neither ACTION_GET, ACTION_GET_PASS or ACTION_CLEANUP!");
            return false;
        }
    }

    return true;
}

void ArmPerceptionCtrl::setHomeConfiguration()
{
    ArmCtrl::setHomeConfiguration("pool");
}

void ArmPerceptionCtrl::setObjectID(int _obj)
{
    ArmCtrl::setObjectID(_obj);
    PerceptionClientImpl::setObjectID(_obj);
}

ArmPerceptionCtrl::~ArmPerceptionCtrl()
{

}
<commit_msg>[arm_perception_ctrl] Fixed bug in pickup of objects.<commit_after>#include "robot_interface/arm_perception_ctrl.h"

#include <tf/transform_datatypes.h>

using namespace std;
using namespace human_robot_collaboration_msgs;

ArmPerceptionCtrl::ArmPerceptionCtrl(std::string _name, std::string _limb, bool _use_robot) :
                     ArmCtrl(_name,_limb, _use_robot), PerceptionClientImpl(_name, _limb)
{
    setHomeConfiguration();
    setState(START);

    insertAction(ACTION_GET,       static_cast<f_action>(&ArmPerceptionCtrl::getObject));
    insertAction(ACTION_PASS,      static_cast<f_action>(&ArmPerceptionCtrl::passObject));
    insertAction(ACTION_GET_PASS,  static_cast<f_action>(&ArmPerceptionCtrl::getPassObject));

    if (not _use_robot) return;

    // moveArm("up",0.2,"strict");
    // moveArm("down",0.2,"strict");
    // moveArm("right",0.2,"strict");
    // moveArm("left",0.2,"strict");
    // moveArm("forward",0.1,"strict");
    // moveArm("backward",0.2,"strict");
    // moveArm("forward",0.1,"strict");
}

bool ArmPerceptionCtrl::selectObject4PickUp()
{
    if (getObjectIDs().size() >  1)
    {
        setSubState(CHECK_OBJ_IDS);
        int id = chooseObjectID(getObjectIDs());

        if (id == -1)      { return false; };

        setObjectID(id);
        ROS_INFO_COND(print_level>=1, "[%s] Chosen object with name %s", getLimb().c_str(),
                          getObjectNameFromDB(ClientTemplate<int>::getObjectID()).c_str());
    }

    return true;
}

bool ArmPerceptionCtrl::recoverRelease()
{
    if (getPrevAction() != ACTION_RELEASE)  return false;
    if(!homePoseStrict())                   return false;
    ros::Duration(0.05).sleep();
    if (!pickUpObject())                    return false;
    if (!close())                           return false;
    if (!moveArm("up", 0.2))                return false;
    if (!homePoseStrict())                  return false;

    return true;
}

bool ArmPerceptionCtrl::recoverGet()
{
    if (!hoverAbovePool())          return false;
    if (!open())                    return false;
    if (!homePoseStrict())          return false;

    return true;
}

bool ArmPerceptionCtrl::pickUpObject()
{
    ROS_INFO_COND(print_level>=0, "[%s] Start Picking up object %s..", getLimb().c_str(),
                        getObjectNameFromDB(ClientTemplate<int>::getObjectID()).c_str());

    if (!isIRok())
    {
        ROS_ERROR("No callback from the IR sensor! Stopping.");
        setSubState(NO_IR_SENSOR);
        return false;
    }

    if (!waitForData())
    {
        setSubState(NO_OBJ);
        return false;
    }

    double offs_x = 0.0;
    double offs_y = 0.0;

    if (not computeOffsets(offs_x, offs_y))  { return false; }

    // Let's compute a first estimation of the joint position
    // (we reduce the z by 15 cm to start picking up from a
    // closer position)
    double x = getObjectPos().x + offs_x;
    double y = getObjectPos().y + offs_y;
    double z =       getPos().z -   0.15;

    geometry_msgs::Quaternion q;
    if (not computeOrientation(q))           { return false; }

    ROS_INFO_COND(print_level>=1, "Going to: %g %g %g", x, y, z);

    if (not goToPose(x, y, z, q.x, q.y, q.z, q.w, "loose"))
    {
        return false;
    }

    if (!waitForData())
    {
        setSubState(NO_OBJ);
        return false;
    }

    ros::Time start_time = ros::Time::now();
    double z_start       =       getPos().z;
    int cnt_ik_fail      =                0;

    ros::Rate r(THREAD_FREQ);
    while(RobotInterface::ok())
    {
        double elap_time = (ros::Time::now() - start_time).toSec();

        double x = getObjectPos().x + offs_x;
        double y = getObjectPos().y + offs_y;
        double z = z_start - getArmSpeed() * elap_time;

        ROS_INFO_COND(print_level>=3, "Time %g Going to: %g %g %g Position: %g %g %g",
                              elap_time, x, y, z, getPos().x, getPos().y, getPos().z);

        if (goToPoseNoCheck(x, y, z, q.x, q.y, q.z, q.w))
        {
            cnt_ik_fail = 0;
            // if (elap_time - old_elap_time > 0.02)
            // {
            //     ROS_WARN("\t\t\t\t\tTime elapsed: %g", elap_time - old_elap_time);
            // }
            // old_elap_time = elap_time;

            if (determineContactCondition()) { return true; }

            r.sleep();
        }
        else
        {
            ++cnt_ik_fail;
        }

        if (cnt_ik_fail == 10)      { return false; }
    }

    return false;
}

bool ArmPerceptionCtrl::determineContactCondition()
{
    if (hasCollidedIR("strict") || hasCollidedCD())
    {
        if (hasCollidedCD())
        {
            moveArm("up", 0.002);
        }
        ROS_INFO("Collision!");
        return true;
    }
    else
    {
        if (getAction() == ACTION_GET      ||
            getAction() == ACTION_GET_PASS)
        {
            if (getPos().z < -0.28)
            {
                ROS_INFO("Object reached!");
                return true;
            }
        }
    }

    return false;
}

bool ArmPerceptionCtrl::computeOffsets(double &_x_offs, double &_y_offs)
{
    return true;
}

int ArmPerceptionCtrl::chooseObjectID(vector<int> _objs)
{
    if (getSubState() != CHECK_OBJ_IDS)
    {
        return ArmCtrl::chooseObjectID(_objs);
    }

    ROS_INFO_COND(print_level>=3, "[%s] Choosing object IDs", getLimb().c_str());

    if (!waitForOK())
    {
        setSubState(NO_OBJ);
        return -1;
    }

    if (!waitForObjsFound())
    {
        setSubState(NO_OBJ);
        return -1;
    }

    std::vector<int> av_objects = ClientTemplate<int>::getAvailableObjects(_objs);

    if (av_objects.size() == 0)
    {
        setSubState(NO_OBJ);
        return -1;
    }

    srand(time(0)); //use current time as seed

    return av_objects[rand() % av_objects.size()];
}

bool ArmPerceptionCtrl::computeOrientation(geometry_msgs::Quaternion &_ori)
{
    if (getLimb() == "left")
    {
        if (getAction() == ACTION_GET || getAction() == ACTION_GET_PASS)
        {
            if      (ClientTemplate<int>::getObjectID() == 24)
            {
                // Get the rotation matrix for the object, as retrieved from
                tf::Quaternion mrk_q;
                tf::quaternionMsgToTF(getObjectOri(), mrk_q);
                tf::Matrix3x3 mrk_rot(mrk_q);

                // printf("Object Orientation\n");
                // for (int j = 0; j < 3; ++j)
                // {
                //     printf("%g\t%g\t%g\n", mrk_rot[j][0], mrk_rot[j][1], mrk_rot[j][2]);
                // }

                // Compute the transform matrix between the object's orientation
                // and the end-effector's orientation
                tf::Matrix3x3 mrk2ee;
                mrk2ee[0][0] =  1;  mrk2ee[0][1] =  0;   mrk2ee[0][2] =  0;
                mrk2ee[1][0] =  0;  mrk2ee[1][1] =  0;   mrk2ee[1][2] = -1;
                mrk2ee[2][0] =  0;  mrk2ee[2][1] =  1;   mrk2ee[2][2] =  0;

                // printf("Rotation\n");
                // for (int j = 0; j < 3; ++j)
                // {
                //     printf("%g\t%g\t%g\n", mrk2ee[j][0], mrk2ee[j][1], mrk2ee[j][2]);
                // }

                // Compute the final end-effector orientation, and convert it to a msg
                mrk2ee = mrk_rot * mrk2ee;

                tf::Quaternion ee_q;
                mrk2ee.getRotation(ee_q);
                geometry_msgs::Quaternion ee_q_msg;
                tf::quaternionTFToMsg(ee_q,ee_q_msg);

                // printf("Desired Orientation\n");
                // for (int j = 0; j < 3; ++j)
                // {
                //     printf("%g\t%g\t%g\n", mrk2ee[j][0], mrk2ee[j][1], mrk2ee[j][2]);
                // }

                _ori = ee_q_msg;
            }
            else
            {
                quaternionFromDoubles(_ori, POOL_ORI_L);
            }
        }
        else if (getAction() == ACTION_CLEANUP)
        {
            quaternionFromDoubles(_ori, VERTICAL_ORI_L);
        }
        else
        {
            ROS_ERROR("State is neither ACTION_GET, ACTION_GET_PASS or ACTION_CLEANUP!");
            return false;
        }
    }
    else if (getLimb() == "right")
    {
        if (getAction() == ACTION_GET || getAction() == ACTION_GET_PASS)
        {
            quaternionFromDoubles(_ori, POOL_ORI_R);
        }
        else if (getAction() == ACTION_CLEANUP)
        {
            quaternionFromDoubles(_ori, VERTICAL_ORI_R);
        }
        else
        {
            ROS_ERROR("State is neither ACTION_GET, ACTION_GET_PASS or ACTION_CLEANUP!");
            return false;
        }
    }

    return true;
}

void ArmPerceptionCtrl::setHomeConfiguration()
{
    ArmCtrl::setHomeConfiguration("pool");
}

void ArmPerceptionCtrl::setObjectID(int _obj)
{
    ArmCtrl::setObjectID(_obj);
    PerceptionClientImpl::setObjectID(_obj);
}

ArmPerceptionCtrl::~ArmPerceptionCtrl()
{

}
<|endoftext|>


<commit_before>
#pragma once

// This code comes from:
// https://code.google.com/p/or-tools/source/browse/trunk/src/base/fingerprint2011.h
// and was adapted to Visual Studio 2013 and to the needs of this project.

// Copyright 2010-2014 Google
// 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.

#include <cstdint>

namespace principia {
namespace base {

inline std::uint64_t FingerprintCat2011(std::uint64_t fp1, std::uint64_t fp2) {
  // Two big prime numbers.
  const std::uint64_t kMul1 = 0xc6a4a7935bd1e995ULL;
  const std::uint64_t kMul2 = 0x228876a7198b743ULL;
  std::uint64_t a = fp1 * kMul1 + fp2 * kMul2;
  // Note: The following line also makes sure we never return 0 or 1, because we
  // will only add something to 'a' if there are any MSBs (the remaining bits
  // after the shift) being 0, in which case wrapping around would not happen.
  return a + (~a >> 47);
}

// This should be better (collision-wise) than the default hash<std::string>,
// without being much slower. It never returns 0 or 1.
inline std::uint64_t Fingerprint2011(const char* bytes, size_t len) {
  // Some big prime numer.
  std::uint64_t fp = 0xa5b85c5e198ed849ULL;
  const char* end = bytes + len;
  while (bytes + 8 <= end) {
    fp = FingerprintCat2011(
             fp, *(reinterpret_cast<const std::uint64_t*>(bytes)));
    bytes += 8;
  }
  // Note: we don't care about "consistency" (little or big endian) between
  // the bulk and the suffix of the message.
  std::uint64_t last_bytes = 0;
  while (bytes < end) {
    last_bytes += *bytes;
    last_bytes <<= 8;
    bytes++;
  }
  return FingerprintCat2011(fp, last_bytes);
}

}  // namespace base
}  // namespace principia
<commit_msg>Hex digits.<commit_after>
#pragma once

// This code comes from:
// https://code.google.com/p/or-tools/source/browse/trunk/src/base/fingerprint2011.h
// and was adapted to Visual Studio 2013 and to the needs of this project.

// Copyright 2010-2014 Google
// 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.

#include <cstdint>

namespace principia {
namespace base {

inline std::uint64_t FingerprintCat2011(std::uint64_t fp1, std::uint64_t fp2) {
  // Two big prime numbers.
  const std::uint64_t kMul1 = 0xC6A4A7935BD1E995u;
  const std::uint64_t kMul2 = 0x228876A7198B743u;
  std::uint64_t a = fp1 * kMul1 + fp2 * kMul2;
  // Note: The following line also makes sure we never return 0 or 1, because we
  // will only add something to 'a' if there are any MSBs (the remaining bits
  // after the shift) being 0, in which case wrapping around would not happen.
  return a + (~a >> 47);
}

// This should be better (collision-wise) than the default hash<std::string>,
// without being much slower. It never returns 0 or 1.
inline std::uint64_t Fingerprint2011(const char* bytes, size_t len) {
  // Some big prime numer.
  std::uint64_t fp = 0xA5B85C5E198ED849u;
  const char* end = bytes + len;
  while (bytes + 8 <= end) {
    fp = FingerprintCat2011(
             fp, *(reinterpret_cast<const std::uint64_t*>(bytes)));
    bytes += 8;
  }
  // Note: we don't care about "consistency" (little or big endian) between
  // the bulk and the suffix of the message.
  std::uint64_t last_bytes = 0;
  while (bytes < end) {
    last_bytes += *bytes;
    last_bytes <<= 8;
    bytes++;
  }
  return FingerprintCat2011(fp, last_bytes);
}

}  // namespace base
}  // namespace principia
<|endoftext|>


<commit_before>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include <hspp/Cards/Entity.h>

namespace Hearthstonepp
{
Entity::Entity(Card& _card) : card(new Card(_card))
{
    for (auto& mechanic : card->mechanics)
    {
        gameTags.insert(std::make_pair(mechanic, 1));
    }
}

Entity::Entity(const Entity& ent)
{
    FreeMemory();

    card = ent.card;
    gameTags = ent.gameTags;
}

Entity::~Entity()
{
    FreeMemory();
}

Entity& Entity::operator=(const Entity& ent)
{
    if (this == &ent)
    {
        return *this;
    }

    FreeMemory();

    card = ent.card;
    gameTags = ent.gameTags;

    return *this;
}

Entity* Entity::Clone() const
{
    return new Entity(*this);
}

void Entity::SetAbility(GameTag tag, bool flag)
{
    gameTags.insert_or_assign(tag, flag);
}

void Entity::FreeMemory()
{
    gameTags.clear();

    delete card;
}
}  // namespace Hearthstonepp<commit_msg>[ci skip] feat(improve-tool): Change SetAbility() method logic<commit_after>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include <hspp/Cards/Entity.h>

namespace Hearthstonepp
{
Entity::Entity(Card& _card) : card(new Card(_card))
{
    for (auto& mechanic : card->mechanics)
    {
        gameTags.insert(std::make_pair(mechanic, 1));
    }
}

Entity::Entity(const Entity& ent)
{
    FreeMemory();

    card = ent.card;
    gameTags = ent.gameTags;
}

Entity::~Entity()
{
    FreeMemory();
}

Entity& Entity::operator=(const Entity& ent)
{
    if (this == &ent)
    {
        return *this;
    }

    FreeMemory();

    card = ent.card;
    gameTags = ent.gameTags;

    return *this;
}

Entity* Entity::Clone() const
{
    return new Entity(*this);
}

void Entity::SetAbility(GameTag tag, bool flag)
{
    const bool isExistAbility = (gameTags.find(tag) != gameTags.end()) &&
                                (static_cast<bool>(gameTags[tag]));
    if (isExistAbility ^ flag)
    {
        gameTags.insert_or_assign(tag, flag);
    }
}

void Entity::FreeMemory()
{
    gameTags.clear();

    delete card;
}
}  // namespace Hearthstonepp<|endoftext|>


<commit_before>// Copyright 2012-2019 Richard Copley
//
// 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.

#include "mswin.h"
#include "bump.h"
#include <limits>

void step_t::initialize (float t0, float t1)
{
  // Precompute the coefficents c of the cubic polynomial f
  // such that f(t0)=0, f(t1)=1, f'(t0)=0 and f'(t0)=1.
  float d = t1 - t0;
  float a = t1 + t0;
  c [0] = t0 * t0 * (a + d + d);
  c [1] = -6 * t0 * t1;
  c [2] = 3 * a;
  c [3] = -2;

  // Divide c [] by d^3.
  v4f dt = _mm_set1_ps (d);
  store4f (c, load4f (c) / (dt * dt * dt));

  T [0] = t0;
  T [1] = t1;
  T [2] = t1;
  T [3] = std::numeric_limits <float>::infinity ();
}

v4f step_t::operator () (float t) const
{
  // Evaluate the polynomial f by Estrin's method. Return
  //   (0 0 0 0)  if t < t0,
  //   (f f f f)  if t0 <= t < t1,
  //   (1 1 1 1)  if t > t1.
  v4f c4 = load4f (c);
  v4f one = { 1.0f, 1.0f, 1.0f, 1.0f, };
  v4f tttt = _mm_set1_ps (t);           // t t t t
  v4f tt = _mm_unpacklo_ps (one, tttt); // 1 t 1 t
  v4f f0 = c4 * tt;                     // c0 c1*t c2 c3*t
  v4f ha = _mm_hadd_ps (f0, f0) * tt * tt;
  v4f f = _mm_hadd_ps (ha, ha);         // f f f f
  v4f f1 = _mm_unpacklo_ps (f, one);    // f 1 f 1
  v4f tx = load4f (T);                  // t0   t1  t1  inf
  v4f lo = _mm_movelh_ps (tx, tx);      // t0   t1  t0   t1
  v4f hi = _mm_movehl_ps (tx, tx);      // t1  inf  t1  inf
  v4f sel = _mm_and_ps (_mm_cmpge_ps (tttt, lo), _mm_cmplt_ps (tttt, hi));
  v4f val = _mm_and_ps (sel, f1);       // f? 1? f? 1?
  return _mm_hadd_ps (val, val);
}

void bumps_t::initialize (const bump_specifier_t & b0, const bump_specifier_t & b1)
{
  // Precompute the coefficients of four cubic polynomials in t, giving
  // the two smoothstep regions of the each of the two bump functions.
  v4f b0t = _mm_load_ps (& b0.t0); // b0.t0 b0.t1 b0.t2 b0.t2
  v4f b1t = _mm_load_ps (& b1.t0); // b1.t0 b1.t1 b1.t2 b1.t2
  v4f b0v = _mm_movelh_ps (_mm_load_ps (& b0.v0), _mm_setzero_ps ()); // b0.v0 b0.v1 0 0
  v4f b1v = _mm_movelh_ps (_mm_load_ps (& b1.v0), _mm_setzero_ps ()); // b1.v0 b1.v1 0 0
  v4f S = _mm_shuffle_ps (b0t, b1t, SHUFFLE (0, 2, 0, 2)); // b0.t0 b0.t2 b1.t0 b1.t2
  v4f T = _mm_shuffle_ps (b0t, b1t, SHUFFLE (1, 3, 1, 3)); // b0.t1 b0.t3 b1.t1 b1.t3
  v4f U = _mm_shuffle_ps (b0v, b1v, SHUFFLE (0, 2, 0, 2)); // b0.v0 0 b1.v0 0
  v4f V1 = _mm_shuffle_ps (b0v, b1v, SHUFFLE (1, 0, 1, 0)); // b0.v1 b0.v0 b1.v1 b1.v0
  v4f V2 = _mm_shuffle_ps (b0v, b1v, SHUFFLE (2, 1, 2, 1)); // 0 b0.v1 0 b1.v1
  v4f V = V1 - V2;
  v4f d = T - S;
  v4f a = T + S;
  v4f m = (V - U) / (d * d * d);
  store4f (c [0], U + m * S * S * (a + d + d));
  store4f (c [1], _mm_set1_ps (-6.0f) * m * S * T);
  store4f (c [2], _mm_set1_ps (+3.0f) * m * a);
  store4f (c [3], _mm_set1_ps (-2.0f) * m);
  store4f (S0, S);
  store4f (T0, T);
  store4f (U0, U);
  store4f (V0, V);
}

// Returns {f,g,f,g}, where f = bump0 (t), g = bump1 (t).
v4f bumps_t::operator () (float t) const
{
  // Compute all four polynomials by Estrin's method, and mask
  // and combine the values according to the region of the graph
  // to which t belongs.
  v4f s = _mm_set1_ps (t);
  v4f S = load4f (S0);
  v4f T = load4f (T0);
  v4f U = load4f (U0);
  v4f V = load4f (V0);
  v4f f01 = load4f (c [0]) + load4f (c [1]) * s;
  v4f f12 = load4f (c [2]) + load4f (c [3]) * s;
  v4f f = f01 + f12 * s * s;
  v4f ltS = _mm_cmplt_ps (s, S);
  v4f geT = _mm_cmpge_ps (s, T);
  v4f x1 = _mm_andnot_ps (_mm_or_ps (ltS, geT), f);
  v4f x2 = _mm_and_ps (ltS, U);
  v4f x3 = _mm_and_ps (geT, V);
  v4f val = _mm_or_ps (_mm_or_ps (x1, x2), x3);
  return _mm_hadd_ps (val, val);
}
<commit_msg>bump.cpp: Refill to 80 columns.<commit_after>// Copyright 2012-2019 Richard Copley
//
// 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.

#include "mswin.h"
#include "bump.h"
#include <limits>

void step_t::initialize (float t0, float t1)
{
  // Precompute the coefficents c of the cubic polynomial f
  // such that f(t0)=0, f(t1)=1, f'(t0)=0 and f'(t0)=1.
  float d = t1 - t0;
  float a = t1 + t0;
  c [0] = t0 * t0 * (a + d + d);
  c [1] = -6 * t0 * t1;
  c [2] = 3 * a;
  c [3] = -2;

  // Divide c [] by d^3.
  v4f dt = _mm_set1_ps (d);
  store4f (c, load4f (c) / (dt * dt * dt));

  T [0] = t0;
  T [1] = t1;
  T [2] = t1;
  T [3] = std::numeric_limits <float>::infinity ();
}

v4f step_t::operator () (float t) const
{
  // Evaluate the polynomial f by Estrin's method. Return
  //   (0 0 0 0)  if t < t0,
  //   (f f f f)  if t0 <= t < t1,
  //   (1 1 1 1)  if t > t1.
  v4f c4 = load4f (c);
  v4f one = { 1.0f, 1.0f, 1.0f, 1.0f, };
  v4f tttt = _mm_set1_ps (t);           // t t t t
  v4f tt = _mm_unpacklo_ps (one, tttt); // 1 t 1 t
  v4f f0 = c4 * tt;                     // c0 c1*t c2 c3*t
  v4f ha = _mm_hadd_ps (f0, f0) * tt * tt;
  v4f f = _mm_hadd_ps (ha, ha);         // f f f f
  v4f f1 = _mm_unpacklo_ps (f, one);    // f 1 f 1
  v4f tx = load4f (T);                  // t0  t1 t1 inf
  v4f lo = _mm_movelh_ps (tx, tx);      // t0  t1 t0  t1
  v4f hi = _mm_movehl_ps (tx, tx);      // t1 inf t1 inf
  v4f sel = _mm_and_ps (_mm_cmpge_ps (tttt, lo), _mm_cmplt_ps (tttt, hi));
  v4f val = _mm_and_ps (sel, f1);       // f? 1? f? 1?
  return _mm_hadd_ps (val, val);
}

#define SHUFPS(u, v, shuffle) _mm_shuffle_ps (u, v, SHUFFLE shuffle)

void bumps_t::initialize (
  const bump_specifier_t & b0, const bump_specifier_t & b1)
{
  // Precompute the coefficients of four cubic polynomials in t, giving
  // the two smoothstep regions of the each of the two bump functions.
  v4f b0t = load4f (& b0.t0); // b0.t0 b0.t1 b0.t2 b0.t2
  v4f b1t = load4f (& b1.t0); // b1.t0 b1.t1 b1.t2 b1.t2
  v4f b0v = _mm_movelh_ps (load4f (& b0.v0), _mm_setzero_ps ()); // b0.v0 b0.v1
  v4f b1v = _mm_movelh_ps (load4f (& b1.v0), _mm_setzero_ps ()); // b1.v0 b1.v1
  v4f S = SHUFPS (b0t, b1t, (0, 2, 0, 2)); // b0.t0 b0.t2 b1.t0 b1.t2
  v4f T = SHUFPS (b0t, b1t, (1, 3, 1, 3)); // b0.t1 b0.t3 b1.t1 b1.t3
  v4f U = SHUFPS (b0v, b1v, (0, 2, 0, 2)); // b0.v0   0   b1.v0   0
  v4f V1 = SHUFPS (b0v, b1v, (1, 0, 1, 0)); // b0.v1 b0.v0 b1.v1 b1.v0
  v4f V2 = SHUFPS (b0v, b1v, (2, 1, 2, 1)); //   0   b0.v1   0   b1.v1
  v4f V = V1 - V2;
  v4f d = T - S;
  v4f a = T + S;
  v4f m = (V - U) / (d * d * d);
  store4f (c [0], U + m * S * S * (a + d + d));
  store4f (c [1], _mm_set1_ps (-6.0f) * m * S * T);
  store4f (c [2], _mm_set1_ps (+3.0f) * m * a);
  store4f (c [3], _mm_set1_ps (-2.0f) * m);
  store4f (S0, S);
  store4f (T0, T);
  store4f (U0, U);
  store4f (V0, V);
}

// Returns {f,g,f,g}, where f = bump0 (t), g = bump1 (t).
v4f bumps_t::operator () (float t) const
{
  // Compute all four polynomials by Estrin's method, and mask and combine the
  // values according to the region of the graph to which t belongs.
  v4f s = _mm_set1_ps (t);
  v4f S = load4f (S0);
  v4f T = load4f (T0);
  v4f U = load4f (U0);
  v4f V = load4f (V0);
  v4f f01 = load4f (c [0]) + load4f (c [1]) * s;
  v4f f12 = load4f (c [2]) + load4f (c [3]) * s;
  v4f f = f01 + f12 * s * s;
  v4f ltS = _mm_cmplt_ps (s, S);
  v4f geT = _mm_cmpge_ps (s, T);
  v4f x1 = _mm_andnot_ps (_mm_or_ps (ltS, geT), f);
  v4f x2 = _mm_and_ps (ltS, U);
  v4f x3 = _mm_and_ps (geT, V);
  v4f val = _mm_or_ps (_mm_or_ps (x1, x2), x3);
  return _mm_hadd_ps (val, val);
}
<|endoftext|>


<commit_before>#include <ph.h>
#include <chef.h>
#include <phstream.h>
#include <phAttrib.h>
#include <phInput.h>
#include <phBC.h>
#include <phRestart.h>
#include <phAdapt.h>
#include <phOutput.h>
#include <phPartition.h>
#include <phFilterMatching.h>
#include <apfMDS.h>
#include <apfMesh2.h>
#include <apfPartition.h>
#include <apf.h>
#include <gmi_mesh.h>
#include <PCU.h>
#include <pcu_io.h>
#include <string>
#include <stdlib.h>
#include <assert.h>
#include <iostream>

#define SIZET(a) static_cast<size_t>(a)

namespace {

void balanceAndReorder(apf::Mesh2* m, ph::Input& in, int numMasters)
{
  /* check if the mesh changed at all */
  if ((PCU_Comm_Peers()!=numMasters) || in.adaptFlag || in.tetrahedronize) {
    if (in.parmaPtn && PCU_Comm_Peers() > 1)
      ph::balance(in,m);
    apf::reorderMdsMesh(m);
  }
}

void switchToMasters(int splitFactor)
{
  int self = PCU_Comm_Self();
  int groupRank = self / splitFactor;
  int group = self % splitFactor;
  MPI_Comm groupComm;
  MPI_Comm_split(MPI_COMM_WORLD, group, groupRank, &groupComm);
  PCU_Switch_Comm(groupComm);
}

void switchToAll()
{
  MPI_Comm prevComm = PCU_Get_Comm();
  PCU_Switch_Comm(MPI_COMM_WORLD);
  MPI_Comm_free(&prevComm);
  PCU_Barrier();
}

void loadCommon(ph::Input& in, ph::BCs& bcs, gmi_model*& g)
{
  ph::loadModelAndBCs(in, g, bcs);
}

void originalMain(apf::Mesh2*& m, ph::Input& in,
    gmi_model* g, apf::Migration*& plan)
{
  if(!m)
    m = apf::loadMdsMesh(g, in.meshFileName.c_str());
  else
    apf::printStats(m);
  m->verify();
  if (in.solutionMigration)
    ph::readAndAttachFields(in, m);
  else
    ph::attachZeroSolution(in, m);
  if (in.buildMapping)
    ph::buildMapping(m);
  apf::setMigrationLimit(SIZET(in.elementsPerMigration));
  if (in.adaptFlag)
    ph::adapt(in, m);
  if (in.tetrahedronize)
    ph::tetrahedronize(in, m);
  plan = ph::split(in, m);
}

}//end namespace

namespace ph {
  void preprocess(apf::Mesh2* m, Input& in, Output& out, BCs& bcs) {
//    if (in.adaptFlag)
//      ph::goToStepDir(in.timeStepNumber);
    std::string path = ph::setupOutputDir();
    ph::setupOutputSubdir(path);
    ph::enterFilteredMatching(m, in, bcs);
    ph::generateOutput(in, bcs, m, out);
    ph::exitFilteredMatching(m);
    // a path is not needed for inmem
    ph::detachAndWriteSolution(in,out,m,path); //write restart
    if (in.adaptFlag && (in.timeStepNumber % in.writeVizFiles == 0) ) {
      // store the value of the function pointer
      FILE (*fn)(out, path) = out.openfile_write;
      // set function pointer for file writing
      out.openfile_write = openfile_write; // as defined in phCook.cc
      writeGeomBC(out, path, in.timeStepNumber); //write geombc for viz only
      // reset the function pointer to the original value
      out.openfile_write = fn;
    }
    ph::writeGeomBC(out, path); //write geombc
    ph::writeAuxiliaryFiles(path, in.timeStepNumber);
//    if ( ! in.outMeshFileName.empty() )
//      m->writeNative(in.outMeshFileName.c_str());
    m->verify();
    gmi_model* g = m->getModel();
    ph::clearAttAssociation(g,in);
    if (in.adaptFlag)
      ph::goToParentDir();
  }
  void preprocess(apf::Mesh2* m, Input& in, Output& out) {
    gmi_model* g = m->getModel();
    assert(g);
    BCs bcs;
    ph::readBCs(g, in.attributeFileName.c_str(), in.axisymmetry, bcs);
    preprocess(m,in,out,bcs);
  }
}

namespace chef {
  static FILE* openfile_read(ph::Input&, const char* path) {
    return pcu_group_open(path, false);
  }

  static FILE* openfile_write(ph::Output&, const char* path) {
    return pcu_group_open(path, true);
  }

  static FILE* openstream_write(ph::Output& out, const char* path) {
    return openGRStreamWrite(out.grs, path);
  }

  static FILE* openstream_read(ph::Input& in, const char* path) {
    std::string fname(path);
    std::string restartStr("restart");
    FILE* f = NULL;
    if( fname.find(restartStr) != std::string::npos )
      f = openRStreamRead(in.rs);
    else {
      fprintf(stderr,
        "ERROR %s type of stream %s is unknown... exiting\n",
        __func__, fname.c_str());
      exit(1);
    }
    return f;
  }
  void bake(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& in, ph::Output& out) {
    apf::Migration* plan = 0;
    ph::BCs bcs;
    loadCommon(in, bcs, g);
    const int worldRank = PCU_Comm_Self();
    switchToMasters(in.splitFactor);
    const int numMasters = PCU_Comm_Peers();
    if ((worldRank % in.splitFactor) == 0)
      originalMain(m, in, g, plan);
    switchToAll();
    m = repeatMdsMesh(m, g, plan, in.splitFactor);
    balanceAndReorder(m,in,numMasters);
    ph::preprocess(m,in,out,bcs);
  }
  void cook(gmi_model*& g, apf::Mesh2*& m) {
    ph::Input in;
    in.load("adapt.inp");
    in.openfile_read = openfile_read;
    ph::Output out;
    out.openfile_write = openfile_write;
    bake(g,m,in,out);
  }
  void cook(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& ctrl) {
    ctrl.openfile_read = openfile_read;
    ph::Output out;
    out.openfile_write = openfile_write;
    bake(g,m,ctrl,out);
  }
  void cook(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& ctrl, GRStream* grs) {
    ctrl.openfile_read = openfile_read;
    ph::Output out;
    out.openfile_write = openstream_write;
    out.grs = grs;
    bake(g,m,ctrl,out);
  }
  void cook(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& ctrl, RStream* rs) {
    ctrl.openfile_read = openstream_read;
    ctrl.rs = rs;
    ph::Output out;
    out.openfile_write = openfile_write;
    bake(g,m,ctrl,out);
    return;
  }
  void cook(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& ctrl, RStream* rs, GRStream* grs) {
    ctrl.openfile_read = openstream_read;
    ctrl.rs = rs;
    ph::Output out;
    out.openfile_write = openstream_write;
    out.grs = grs;
    bake(g,m,ctrl,out);
    return;
  }

  void readAndAttachFields(ph::Input& ctrl, apf::Mesh2*& m) {
    ph::readAndAttachFields(ctrl, m);
  }

  void preprocess(apf::Mesh2*& m, ph::Input& in) {
    ph::Output out;
    out.openfile_write = chef::openfile_write;
    ph::preprocess(m,in,out);
  }

  void preprocess(apf::Mesh2*& m, ph::Input& in, GRStream* grs) {
    ph::Output out;
    out.openfile_write = chef::openstream_write;
    out.grs = grs;
    ph::preprocess(m,in,out);
  }
}

<commit_msg>write geombc for viz onluy<commit_after>#include <ph.h>
#include <chef.h>
#include <phstream.h>
#include <phAttrib.h>
#include <phInput.h>
#include <phBC.h>
#include <phRestart.h>
#include <phAdapt.h>
#include <phOutput.h>
#include <phPartition.h>
#include <phFilterMatching.h>
#include <apfMDS.h>
#include <apfMesh2.h>
#include <apfPartition.h>
#include <apf.h>
#include <gmi_mesh.h>
#include <PCU.h>
#include <pcu_io.h>
#include <string>
#include <stdlib.h>
#include <assert.h>
#include <iostream>

#define SIZET(a) static_cast<size_t>(a)

namespace {

void balanceAndReorder(apf::Mesh2* m, ph::Input& in, int numMasters)
{
  /* check if the mesh changed at all */
  if ((PCU_Comm_Peers()!=numMasters) || in.adaptFlag || in.tetrahedronize) {
    if (in.parmaPtn && PCU_Comm_Peers() > 1)
      ph::balance(in,m);
    apf::reorderMdsMesh(m);
  }
}

void switchToMasters(int splitFactor)
{
  int self = PCU_Comm_Self();
  int groupRank = self / splitFactor;
  int group = self % splitFactor;
  MPI_Comm groupComm;
  MPI_Comm_split(MPI_COMM_WORLD, group, groupRank, &groupComm);
  PCU_Switch_Comm(groupComm);
}

void switchToAll()
{
  MPI_Comm prevComm = PCU_Get_Comm();
  PCU_Switch_Comm(MPI_COMM_WORLD);
  MPI_Comm_free(&prevComm);
  PCU_Barrier();
}

void loadCommon(ph::Input& in, ph::BCs& bcs, gmi_model*& g)
{
  ph::loadModelAndBCs(in, g, bcs);
}

void originalMain(apf::Mesh2*& m, ph::Input& in,
    gmi_model* g, apf::Migration*& plan)
{
  if(!m)
    m = apf::loadMdsMesh(g, in.meshFileName.c_str());
  else
    apf::printStats(m);
  m->verify();
  if (in.solutionMigration)
    ph::readAndAttachFields(in, m);
  else
    ph::attachZeroSolution(in, m);
  if (in.buildMapping)
    ph::buildMapping(m);
  apf::setMigrationLimit(SIZET(in.elementsPerMigration));
  if (in.adaptFlag)
    ph::adapt(in, m);
  if (in.tetrahedronize)
    ph::tetrahedronize(in, m);
  plan = ph::split(in, m);
}

}//end namespace

namespace ph {
  void preprocess(apf::Mesh2* m, Input& in, Output& out, BCs& bcs) {
//    if (in.adaptFlag)
//      ph::goToStepDir(in.timeStepNumber);
    std::string path = ph::setupOutputDir();
    ph::setupOutputSubdir(path);
    ph::enterFilteredMatching(m, in, bcs);
    ph::generateOutput(in, bcs, m, out);
    ph::exitFilteredMatching(m);
    // a path is not needed for inmem
    ph::detachAndWriteSolution(in,out,m,path); //write restart
    if (in.adaptFlag && (in.timeStepNumber % in.writeVizFiles == 0) ) {
      // store the value of the function pointer
      FILE* (*fn)(Output& out, const char* path) = out.openfile_write;
      // set function pointer for file writing
      out.openfile_write = openfile_write;
      writeGeomBC(out, path, in.timeStepNumber); //write geombc for viz only
      // reset the function pointer to the original value
      out.openfile_write = fn;
    }
    ph::writeGeomBC(out, path); //write geombc
    ph::writeAuxiliaryFiles(path, in.timeStepNumber);
//    if ( ! in.outMeshFileName.empty() )
//      m->writeNative(in.outMeshFileName.c_str());
    m->verify();
    gmi_model* g = m->getModel();
    ph::clearAttAssociation(g,in);
    if (in.adaptFlag)
      ph::goToParentDir();
  }
  void preprocess(apf::Mesh2* m, Input& in, Output& out) {
    gmi_model* g = m->getModel();
    assert(g);
    BCs bcs;
    ph::readBCs(g, in.attributeFileName.c_str(), in.axisymmetry, bcs);
    preprocess(m,in,out,bcs);
  }
}

namespace chef {
  static FILE* openfile_read(ph::Input&, const char* path) {
    return pcu_group_open(path, false);
  }

  static FILE* openfile_write(ph::Output&, const char* path) {
    return pcu_group_open(path, true);
  }

  static FILE* openstream_write(ph::Output& out, const char* path) {
    return openGRStreamWrite(out.grs, path);
  }

  static FILE* openstream_read(ph::Input& in, const char* path) {
    std::string fname(path);
    std::string restartStr("restart");
    FILE* f = NULL;
    if( fname.find(restartStr) != std::string::npos )
      f = openRStreamRead(in.rs);
    else {
      fprintf(stderr,
        "ERROR %s type of stream %s is unknown... exiting\n",
        __func__, fname.c_str());
      exit(1);
    }
    return f;
  }
  void bake(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& in, ph::Output& out) {
    apf::Migration* plan = 0;
    ph::BCs bcs;
    loadCommon(in, bcs, g);
    const int worldRank = PCU_Comm_Self();
    switchToMasters(in.splitFactor);
    const int numMasters = PCU_Comm_Peers();
    if ((worldRank % in.splitFactor) == 0)
      originalMain(m, in, g, plan);
    switchToAll();
    m = repeatMdsMesh(m, g, plan, in.splitFactor);
    balanceAndReorder(m,in,numMasters);
    ph::preprocess(m,in,out,bcs);
  }
  void cook(gmi_model*& g, apf::Mesh2*& m) {
    ph::Input in;
    in.load("adapt.inp");
    in.openfile_read = openfile_read;
    ph::Output out;
    out.openfile_write = openfile_write;
    bake(g,m,in,out);
  }
  void cook(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& ctrl) {
    ctrl.openfile_read = openfile_read;
    ph::Output out;
    out.openfile_write = openfile_write;
    bake(g,m,ctrl,out);
  }
  void cook(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& ctrl, GRStream* grs) {
    ctrl.openfile_read = openfile_read;
    ph::Output out;
    out.openfile_write = openstream_write;
    out.grs = grs;
    bake(g,m,ctrl,out);
  }
  void cook(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& ctrl, RStream* rs) {
    ctrl.openfile_read = openstream_read;
    ctrl.rs = rs;
    ph::Output out;
    out.openfile_write = openfile_write;
    bake(g,m,ctrl,out);
    return;
  }
  void cook(gmi_model*& g, apf::Mesh2*& m,
      ph::Input& ctrl, RStream* rs, GRStream* grs) {
    ctrl.openfile_read = openstream_read;
    ctrl.rs = rs;
    ph::Output out;
    out.openfile_write = openstream_write;
    out.grs = grs;
    bake(g,m,ctrl,out);
    return;
  }

  void readAndAttachFields(ph::Input& ctrl, apf::Mesh2*& m) {
    ph::readAndAttachFields(ctrl, m);
  }

  void preprocess(apf::Mesh2*& m, ph::Input& in) {
    ph::Output out;
    out.openfile_write = chef::openfile_write;
    ph::preprocess(m,in,out);
  }

  void preprocess(apf::Mesh2*& m, ph::Input& in, GRStream* grs) {
    ph::Output out;
    out.openfile_write = chef::openstream_write;
    out.grs = grs;
    ph::preprocess(m,in,out);
  }
}

<|endoftext|>


<commit_before><commit_msg>PLANNING TEST: unit test timeout so add todo to fix<commit_after><|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ClassAssemblingUtils.h"

#include <boost/algorithm/string.hpp>

#include "Creators.h"
#include "DexStoreUtil.h"
#include "DexUtil.h"
#include "Model.h"

namespace {

void patch_iget_for_int_like_types(DexMethod* meth,
                                   IRList::iterator it,
                                   IRInstruction* convert) {
  auto insn = it->insn;
  auto move_result_it = std::next(it);
  auto src_dest = move_result_it->insn->dest();
  convert->set_src(0, src_dest)->set_dest(src_dest);
  meth->get_code()->insert_after(move_result_it, convert);
  insn->set_opcode(OPCODE_IGET);
}

/**
 * Change the super class of a given class. The assumption is the new super
 * class has only one ctor and it shares the same signature with the old super
 * ctor.
 */
void change_super_class(DexClass* cls, DexType* super_type) {
  always_assert(cls);
  DexClass* super_cls = type_class(super_type);
  DexClass* old_super_cls = type_class(cls->get_super_class());
  always_assert(super_cls);
  always_assert(old_super_cls);
  auto super_ctors = super_cls->get_ctors();
  auto old_super_ctors = old_super_cls->get_ctors();
  // Assume that both the old and the new super only have one ctor
  always_assert(super_ctors.size() == 1);
  always_assert(old_super_ctors.size() == 1);

  // Fix calls to super_ctor in its ctors.
  // NOTE: we are not parallelizing this since the ctor is very short.
  size_t num_insn_fixed = 0;
  for (auto ctor : cls->get_ctors()) {
    TRACE(TERA, 5, "Fixing ctor: %s\n", SHOW(ctor));
    auto code = ctor->get_code();
    for (auto& mie : InstructionIterable(code)) {
      auto insn = mie.insn;
      if (!is_invoke_direct(insn->opcode()) || !insn->has_method()) {
        continue;
      }
      // Replace "invoke_direct v0, old_super_type;.<init>:()V" with
      // "invoke_direct v0, super_type;.<init>:()V"
      if (insn->get_method() == old_super_ctors[0]) {
        TRACE(TERA, 9, "  - Replacing call: %s with", SHOW(insn));
        insn->set_method(super_ctors[0]);
        TRACE(TERA, 9, " %s\n", SHOW(insn));
        num_insn_fixed++;
      }
    }
  }
  TRACE(TERA, 5, "Fixed %ld instructions\n", num_insn_fixed);

  cls->set_super_class(super_type);
  TRACE(TERA, 5, "Added super class %s to %s\n", SHOW(super_type), SHOW(cls));
}

} // namespace

DexClass* create_class(const DexType* type,
                       const DexType* super_type,
                       const std::string& pkg_name,
                       std::vector<DexField*> fields,
                       const TypeSet& interfaces,
                       bool with_default_ctor,
                       DexAccessFlags access) {
  DexType* t = const_cast<DexType*>(type);
  always_assert(!pkg_name.empty());
  auto name = std::string(type->get_name()->c_str());
  name = pkg_name + "/" + name.substr(1);
  t->assign_name_alias(DexString::make_string(name));
  // Create class.
  ClassCreator creator(t);
  creator.set_access(access);
  always_assert(super_type != nullptr);
  creator.set_super(const_cast<DexType*>(super_type));
  for (const auto& itf : interfaces) {
    creator.add_interface(const_cast<DexType*>(itf));
  }
  for (const auto& field : fields) {
    creator.add_field(field);
  }
  auto cls = creator.create();
  // Keeping type-erasure generated classes from being renamed.
  cls->rstate.set_keep_name();

  if (!with_default_ctor) {
    return cls;
  }
  // Create ctor.
  auto super_ctors = type_class(super_type)->get_ctors();
  for (auto super_ctor : super_ctors) {
    auto mc = new MethodCreator(t,
                                DexString::make_string("<init>"),
                                super_ctor->get_proto(),
                                ACC_PUBLIC | ACC_CONSTRUCTOR);
    // Call to super.<init>
    std::vector<Location> args;
    size_t args_size = super_ctor->get_proto()->get_args()->size();
    for (size_t arg_loc = 0; arg_loc < args_size + 1; ++arg_loc) {
      args.push_back(mc->get_local(arg_loc));
    }
    auto mb = mc->get_main_block();
    mb->invoke(OPCODE_INVOKE_DIRECT, super_ctor, args);
    mb->ret_void();
    auto ctor = mc->create();
    TRACE(TERA, 4, " default ctor created %s\n", SHOW(ctor));
    cls->add_method(ctor);
  }
  return cls;
}

std::vector<DexField*> create_merger_fields(
    const DexType* owner, const std::vector<DexField*>& mergeable_fields) {
  std::vector<DexField*> res;
  size_t cnt = 0;
  for (const auto f : mergeable_fields) {
    auto type = f->get_type();
    std::string name;
    if (type == get_byte_type() || type == get_char_type() ||
        type == get_short_type() || type == get_int_type()) {
      type = get_int_type();
      name = "i";
    } else if (type == get_boolean_type()) {
      type = get_boolean_type();
      name = "z";
    } else if (type == get_long_type()) {
      type = get_long_type();
      name = "j";
    } else if (type == get_float_type()) {
      type = get_float_type();
      name = "f";
    } else if (type == get_double_type()) {
      type = get_double_type();
      name = "d";
    } else {
      static DexType* string_type = DexType::make_type("Ljava/lang/String;");
      if (type == string_type) {
        type = string_type;
        name = "s";
      } else {
        char t = type_shorty(type);
        always_assert(t == 'L' || t == '[');
        type = get_object_type();
        name = "l";
      }
    }

    name = name + std::to_string(cnt);
    auto field = static_cast<DexField*>(
        DexField::make_field(owner, DexString::make_string(name), type));
    field->make_concrete(ACC_PUBLIC);
    res.push_back(field);
    cnt++;
  }

  TRACE(TERA, 8, "  created merger fields %d \n", res.size());
  return res;
}

void cook_merger_fields_lookup(
    const std::vector<DexField*>& new_fields,
    const FieldsMap& fields_map,
    std::unordered_map<DexField*, DexField*>& merger_fields_lookup) {
  for (const auto& fmap : fields_map) {
    const auto& old_fields = fmap.second;
    always_assert(new_fields.size() == old_fields.size());
    for (size_t i = 0; i < new_fields.size(); i++) {
      if (old_fields.at(i) != nullptr) {
        merger_fields_lookup[old_fields.at(i)] = new_fields.at(i);
      }
    }
  }
}

std::string get_merger_package_name(const DexType* type) {
  auto pkg_name = get_package_name(type);
  // Avoid an Android OS like package name, which might confuse the custom class
  // loader.
  if (boost::starts_with(pkg_name, "Landroid") ||
      boost::starts_with(pkg_name, "Ldalvik")) {
    return "Lcom/facebook";
  }
  return pkg_name;
}

DexClass* create_merger_class(const DexType* type,
                              const DexType* super_type,
                              const std::vector<DexField*>& merger_fields,
                              const TypeSet& interfaces,
                              bool add_type_tag_field,
                              bool with_default_ctor /* false */) {
  always_assert(type && super_type);
  std::vector<DexField*> fields;

  if (add_type_tag_field) {
    auto type_tag_field = static_cast<DexField*>(DexField::make_field(
        type, DexString::make_string(INTERNAL_TYPE_TAG_FIELD_NAME),
        get_int_type()));
    type_tag_field->make_concrete(ACC_PUBLIC | ACC_FINAL);
    fields.push_back(type_tag_field);
  }

  for (auto f : merger_fields) {
    fields.push_back(f);
  }
  // Put merger class in the same package as super_type.
  auto pkg_name = get_merger_package_name(super_type);
  auto cls = create_class(type, super_type, pkg_name, fields, interfaces,
                          with_default_ctor);
  TRACE(TERA, 3, "  created merger class w/ fields %s \n", SHOW(cls));
  return cls;
}

void patch_iput(IRList::iterator it) {
  auto insn = it->insn;
  const auto op = insn->opcode();
  always_assert(is_iput(op));
  switch (op) {
  case OPCODE_IPUT_BYTE:
  case OPCODE_IPUT_CHAR:
  case OPCODE_IPUT_SHORT:
    insn->set_opcode(OPCODE_IPUT);
    break;
  default:
    break;
  }
};

void patch_iget(DexMethod* meth,
                IRList::iterator it,
                DexType* original_field_type) {
  auto insn = it->insn;
  const auto op = insn->opcode();
  always_assert(is_iget(op));
  switch (op) {
  case OPCODE_IGET_OBJECT: {
    auto dest = std::next(it)->insn->dest();
    auto cast = MethodMerger::make_check_cast(original_field_type, dest);
    meth->get_code()->insert_after(insn, cast);
    break;
  }
  case OPCODE_IGET_BYTE: {
    always_assert(original_field_type == get_byte_type());
    auto int_to_byte = new IRInstruction(OPCODE_INT_TO_BYTE);
    patch_iget_for_int_like_types(meth, it, int_to_byte);
    break;
  }
  case OPCODE_IGET_CHAR: {
    always_assert(original_field_type == get_char_type());
    auto int_to_char = new IRInstruction(OPCODE_INT_TO_CHAR);
    patch_iget_for_int_like_types(meth, it, int_to_char);
    break;
  }
  case OPCODE_IGET_SHORT: {
    always_assert(original_field_type == get_short_type());
    auto int_to_short = new IRInstruction(OPCODE_INT_TO_SHORT);
    patch_iget_for_int_like_types(meth, it, int_to_short);
    break;
  }
  default:
    break;
  }
};

void add_class(DexClass* new_cls, Scope& scope, DexStoresVector& stores) {
  always_assert(new_cls != nullptr);

  scope.push_back(new_cls);
  TRACE(TERA,
        4,
        " TERA Adding class %s to scope %d \n",
        SHOW(new_cls),
        scope.size());

  // TODO(emmasevastian): Handle this case in a better way.
  if (!stores.empty()) {
    DexClassesVector& root_store = stores.front().get_dexen();
    DexClasses dc = {new_cls};
    root_store.emplace_back(std::move(dc));
  }
}

/**
 * In some limited cases we can do type erasure on an interface when
 * implementors of the interface only implement that interface and have no
 * parent class other than java.lang.Object. We create a base class for those
 * implementors and use the new base class as root, and proceed with type
 * erasure as usual.
 */
void handle_interface_as_root(ModelSpec& spec,
                              Scope& scope,
                              DexStoresVector& stores) {
  auto cls = type_class(spec.root);
  if (cls == nullptr) {
    return;
  }
  if (!is_interface(cls)) {
    TRACE(TERA, 1, "root %s is not an interface!\n", SHOW(spec.root));
    return;
  }

  // Build a temporary type system.
  TypeSystem type_system(scope);

  // Create an empty base and add to the scope. Put the base class in the same
  // package as the root interface.
  auto base_type = DexType::make_type(
      DexString::make_string("L" + spec.class_name_prefix + "EmptyBase;"));
  auto base_class = create_class(base_type,
                                 get_object_type(),
                                 get_merger_package_name(spec.root),
                                 std::vector<DexField*>(),
                                 TypeSet(),
                                 true);

  TRACE(TERA, 1, "Created an empty base class %s for interface %s.\n",
        SHOW(cls), SHOW(spec.root));

  // Set it as the super class of implementors.
  size_t num = 0;
  XStoreRefs xstores(stores);

  for (auto impl_type : type_system.get_implementors(spec.root)) {
    auto& ifcs = type_system.get_implemented_interfaces(impl_type);
    // Add an empty base class to qualified implementors
    auto impl_cls = type_class(impl_type);
    if (ifcs.size() == 1 && impl_cls &&
        impl_cls->get_super_class() == get_object_type() &&
        !is_in_non_root_store(impl_type, stores, xstores,
                              spec.include_primary_dex)) {
      change_super_class(impl_cls, base_type);
      num++;
    }
  }

  // Change the root from the interface to the added base class.
  if (num > 0) {
    TRACE(TERA, 3, "Changing the root from %s to %s.\n", SHOW(spec.root),
          SHOW(base_type));
    spec.root = base_type;
    add_class(base_class, scope, stores);
  }
}
<commit_msg>Add one more directory level in default merger type package name<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ClassAssemblingUtils.h"

#include <boost/algorithm/string.hpp>

#include "Creators.h"
#include "DexStoreUtil.h"
#include "DexUtil.h"
#include "Model.h"

namespace {

void patch_iget_for_int_like_types(DexMethod* meth,
                                   IRList::iterator it,
                                   IRInstruction* convert) {
  auto insn = it->insn;
  auto move_result_it = std::next(it);
  auto src_dest = move_result_it->insn->dest();
  convert->set_src(0, src_dest)->set_dest(src_dest);
  meth->get_code()->insert_after(move_result_it, convert);
  insn->set_opcode(OPCODE_IGET);
}

/**
 * Change the super class of a given class. The assumption is the new super
 * class has only one ctor and it shares the same signature with the old super
 * ctor.
 */
void change_super_class(DexClass* cls, DexType* super_type) {
  always_assert(cls);
  DexClass* super_cls = type_class(super_type);
  DexClass* old_super_cls = type_class(cls->get_super_class());
  always_assert(super_cls);
  always_assert(old_super_cls);
  auto super_ctors = super_cls->get_ctors();
  auto old_super_ctors = old_super_cls->get_ctors();
  // Assume that both the old and the new super only have one ctor
  always_assert(super_ctors.size() == 1);
  always_assert(old_super_ctors.size() == 1);

  // Fix calls to super_ctor in its ctors.
  // NOTE: we are not parallelizing this since the ctor is very short.
  size_t num_insn_fixed = 0;
  for (auto ctor : cls->get_ctors()) {
    TRACE(TERA, 5, "Fixing ctor: %s\n", SHOW(ctor));
    auto code = ctor->get_code();
    for (auto& mie : InstructionIterable(code)) {
      auto insn = mie.insn;
      if (!is_invoke_direct(insn->opcode()) || !insn->has_method()) {
        continue;
      }
      // Replace "invoke_direct v0, old_super_type;.<init>:()V" with
      // "invoke_direct v0, super_type;.<init>:()V"
      if (insn->get_method() == old_super_ctors[0]) {
        TRACE(TERA, 9, "  - Replacing call: %s with", SHOW(insn));
        insn->set_method(super_ctors[0]);
        TRACE(TERA, 9, " %s\n", SHOW(insn));
        num_insn_fixed++;
      }
    }
  }
  TRACE(TERA, 5, "Fixed %ld instructions\n", num_insn_fixed);

  cls->set_super_class(super_type);
  TRACE(TERA, 5, "Added super class %s to %s\n", SHOW(super_type), SHOW(cls));
}

} // namespace

DexClass* create_class(const DexType* type,
                       const DexType* super_type,
                       const std::string& pkg_name,
                       std::vector<DexField*> fields,
                       const TypeSet& interfaces,
                       bool with_default_ctor,
                       DexAccessFlags access) {
  DexType* t = const_cast<DexType*>(type);
  always_assert(!pkg_name.empty());
  auto name = std::string(type->get_name()->c_str());
  name = pkg_name + "/" + name.substr(1);
  t->assign_name_alias(DexString::make_string(name));
  // Create class.
  ClassCreator creator(t);
  creator.set_access(access);
  always_assert(super_type != nullptr);
  creator.set_super(const_cast<DexType*>(super_type));
  for (const auto& itf : interfaces) {
    creator.add_interface(const_cast<DexType*>(itf));
  }
  for (const auto& field : fields) {
    creator.add_field(field);
  }
  auto cls = creator.create();
  // Keeping type-erasure generated classes from being renamed.
  cls->rstate.set_keep_name();

  if (!with_default_ctor) {
    return cls;
  }
  // Create ctor.
  auto super_ctors = type_class(super_type)->get_ctors();
  for (auto super_ctor : super_ctors) {
    auto mc = new MethodCreator(t,
                                DexString::make_string("<init>"),
                                super_ctor->get_proto(),
                                ACC_PUBLIC | ACC_CONSTRUCTOR);
    // Call to super.<init>
    std::vector<Location> args;
    size_t args_size = super_ctor->get_proto()->get_args()->size();
    for (size_t arg_loc = 0; arg_loc < args_size + 1; ++arg_loc) {
      args.push_back(mc->get_local(arg_loc));
    }
    auto mb = mc->get_main_block();
    mb->invoke(OPCODE_INVOKE_DIRECT, super_ctor, args);
    mb->ret_void();
    auto ctor = mc->create();
    TRACE(TERA, 4, " default ctor created %s\n", SHOW(ctor));
    cls->add_method(ctor);
  }
  return cls;
}

std::vector<DexField*> create_merger_fields(
    const DexType* owner, const std::vector<DexField*>& mergeable_fields) {
  std::vector<DexField*> res;
  size_t cnt = 0;
  for (const auto f : mergeable_fields) {
    auto type = f->get_type();
    std::string name;
    if (type == get_byte_type() || type == get_char_type() ||
        type == get_short_type() || type == get_int_type()) {
      type = get_int_type();
      name = "i";
    } else if (type == get_boolean_type()) {
      type = get_boolean_type();
      name = "z";
    } else if (type == get_long_type()) {
      type = get_long_type();
      name = "j";
    } else if (type == get_float_type()) {
      type = get_float_type();
      name = "f";
    } else if (type == get_double_type()) {
      type = get_double_type();
      name = "d";
    } else {
      static DexType* string_type = DexType::make_type("Ljava/lang/String;");
      if (type == string_type) {
        type = string_type;
        name = "s";
      } else {
        char t = type_shorty(type);
        always_assert(t == 'L' || t == '[');
        type = get_object_type();
        name = "l";
      }
    }

    name = name + std::to_string(cnt);
    auto field = static_cast<DexField*>(
        DexField::make_field(owner, DexString::make_string(name), type));
    field->make_concrete(ACC_PUBLIC);
    res.push_back(field);
    cnt++;
  }

  TRACE(TERA, 8, "  created merger fields %d \n", res.size());
  return res;
}

void cook_merger_fields_lookup(
    const std::vector<DexField*>& new_fields,
    const FieldsMap& fields_map,
    std::unordered_map<DexField*, DexField*>& merger_fields_lookup) {
  for (const auto& fmap : fields_map) {
    const auto& old_fields = fmap.second;
    always_assert(new_fields.size() == old_fields.size());
    for (size_t i = 0; i < new_fields.size(); i++) {
      if (old_fields.at(i) != nullptr) {
        merger_fields_lookup[old_fields.at(i)] = new_fields.at(i);
      }
    }
  }
}

std::string get_merger_package_name(const DexType* type) {
  auto pkg_name = get_package_name(type);
  // Avoid an Android OS like package name, which might confuse the custom class
  // loader.
  if (boost::starts_with(pkg_name, "Landroid") ||
      boost::starts_with(pkg_name, "Ldalvik")) {
    return "Lcom/facebook/redex";
  }
  return pkg_name;
}

DexClass* create_merger_class(const DexType* type,
                              const DexType* super_type,
                              const std::vector<DexField*>& merger_fields,
                              const TypeSet& interfaces,
                              bool add_type_tag_field,
                              bool with_default_ctor /* false */) {
  always_assert(type && super_type);
  std::vector<DexField*> fields;

  if (add_type_tag_field) {
    auto type_tag_field = static_cast<DexField*>(DexField::make_field(
        type, DexString::make_string(INTERNAL_TYPE_TAG_FIELD_NAME),
        get_int_type()));
    type_tag_field->make_concrete(ACC_PUBLIC | ACC_FINAL);
    fields.push_back(type_tag_field);
  }

  for (auto f : merger_fields) {
    fields.push_back(f);
  }
  // Put merger class in the same package as super_type.
  auto pkg_name = get_merger_package_name(super_type);
  auto cls = create_class(type, super_type, pkg_name, fields, interfaces,
                          with_default_ctor);
  TRACE(TERA, 3, "  created merger class w/ fields %s \n", SHOW(cls));
  return cls;
}

void patch_iput(IRList::iterator it) {
  auto insn = it->insn;
  const auto op = insn->opcode();
  always_assert(is_iput(op));
  switch (op) {
  case OPCODE_IPUT_BYTE:
  case OPCODE_IPUT_CHAR:
  case OPCODE_IPUT_SHORT:
    insn->set_opcode(OPCODE_IPUT);
    break;
  default:
    break;
  }
};

void patch_iget(DexMethod* meth,
                IRList::iterator it,
                DexType* original_field_type) {
  auto insn = it->insn;
  const auto op = insn->opcode();
  always_assert(is_iget(op));
  switch (op) {
  case OPCODE_IGET_OBJECT: {
    auto dest = std::next(it)->insn->dest();
    auto cast = MethodMerger::make_check_cast(original_field_type, dest);
    meth->get_code()->insert_after(insn, cast);
    break;
  }
  case OPCODE_IGET_BYTE: {
    always_assert(original_field_type == get_byte_type());
    auto int_to_byte = new IRInstruction(OPCODE_INT_TO_BYTE);
    patch_iget_for_int_like_types(meth, it, int_to_byte);
    break;
  }
  case OPCODE_IGET_CHAR: {
    always_assert(original_field_type == get_char_type());
    auto int_to_char = new IRInstruction(OPCODE_INT_TO_CHAR);
    patch_iget_for_int_like_types(meth, it, int_to_char);
    break;
  }
  case OPCODE_IGET_SHORT: {
    always_assert(original_field_type == get_short_type());
    auto int_to_short = new IRInstruction(OPCODE_INT_TO_SHORT);
    patch_iget_for_int_like_types(meth, it, int_to_short);
    break;
  }
  default:
    break;
  }
};

void add_class(DexClass* new_cls, Scope& scope, DexStoresVector& stores) {
  always_assert(new_cls != nullptr);

  scope.push_back(new_cls);
  TRACE(TERA,
        4,
        " TERA Adding class %s to scope %d \n",
        SHOW(new_cls),
        scope.size());

  // TODO(emmasevastian): Handle this case in a better way.
  if (!stores.empty()) {
    DexClassesVector& root_store = stores.front().get_dexen();
    DexClasses dc = {new_cls};
    root_store.emplace_back(std::move(dc));
  }
}

/**
 * In some limited cases we can do type erasure on an interface when
 * implementors of the interface only implement that interface and have no
 * parent class other than java.lang.Object. We create a base class for those
 * implementors and use the new base class as root, and proceed with type
 * erasure as usual.
 */
void handle_interface_as_root(ModelSpec& spec,
                              Scope& scope,
                              DexStoresVector& stores) {
  auto cls = type_class(spec.root);
  if (cls == nullptr) {
    return;
  }
  if (!is_interface(cls)) {
    TRACE(TERA, 1, "root %s is not an interface!\n", SHOW(spec.root));
    return;
  }

  // Build a temporary type system.
  TypeSystem type_system(scope);

  // Create an empty base and add to the scope. Put the base class in the same
  // package as the root interface.
  auto base_type = DexType::make_type(
      DexString::make_string("L" + spec.class_name_prefix + "EmptyBase;"));
  auto base_class = create_class(base_type,
                                 get_object_type(),
                                 get_merger_package_name(spec.root),
                                 std::vector<DexField*>(),
                                 TypeSet(),
                                 true);

  TRACE(TERA, 1, "Created an empty base class %s for interface %s.\n",
        SHOW(cls), SHOW(spec.root));

  // Set it as the super class of implementors.
  size_t num = 0;
  XStoreRefs xstores(stores);

  for (auto impl_type : type_system.get_implementors(spec.root)) {
    auto& ifcs = type_system.get_implemented_interfaces(impl_type);
    // Add an empty base class to qualified implementors
    auto impl_cls = type_class(impl_type);
    if (ifcs.size() == 1 && impl_cls &&
        impl_cls->get_super_class() == get_object_type() &&
        !is_in_non_root_store(impl_type, stores, xstores,
                              spec.include_primary_dex)) {
      change_super_class(impl_cls, base_type);
      num++;
    }
  }

  // Change the root from the interface to the added base class.
  if (num > 0) {
    TRACE(TERA, 3, "Changing the root from %s to %s.\n", SHOW(spec.root),
          SHOW(base_type));
    spec.root = base_type;
    add_class(base_class, scope, stores);
  }
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/**
 * @author Pavel N. Vyssotski
 * @version $Revision: 1.10 $
 */
// AgentEventRequest.cpp

#include "AgentEventRequest.h"
#include "RequestManager.h"
#include "Log.h"

using namespace jdwp;

AgentEventRequest::AgentEventRequest(jdwpEventKind kind,
        jdwpSuspendPolicy suspend, jint modCount)
    throw(AgentException)
{
    m_requestId = 0;
    m_eventKind = kind;
    m_suspendPolicy = suspend;
    m_modifierCount = modCount;
    m_modifiers = 0;
    m_isExpired = false;
    if (modCount != 0) {
        m_modifiers = reinterpret_cast<RequestModifier**>
            (GetMemoryManager().Allocate(sizeof(RequestModifier*)*modCount JDWP_FILE_LINE));
        memset(m_modifiers, 0, sizeof(RequestModifier*)*modCount);
    }
}

AgentEventRequest::~AgentEventRequest() throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        delete m_modifiers[i];
    }
    if (m_modifiers != 0) {
        GetMemoryManager().Free(m_modifiers JDWP_FILE_LINE);
    }
}

bool AgentEventRequest::ApplyModifiers(JNIEnv *jni, EventInfo &eInfo)
    throw(AgentException)
{
    for (jint i = 0; i < m_modifierCount; i++) {
        if (!m_modifiers[i]->Apply(jni, eInfo)) {
            return false;
        }
        if ((m_modifiers[i])->GetKind() == JDWP_MODIFIER_COUNT) {
            // once the count reaches 0, the event becomes expired
            m_isExpired = true;
        }
    }
    return true;
}

jthread AgentEventRequest::GetThread() const throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        if ((m_modifiers[i])->GetKind() == JDWP_MODIFIER_THREAD_ONLY) {
            return (reinterpret_cast<ThreadOnlyModifier*>
                (m_modifiers[i]))->GetThread();
        }
    }
    return 0;
}

FieldOnlyModifier* AgentEventRequest::GetField() const throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        if ((m_modifiers[i])->GetKind() == JDWP_MODIFIER_FIELD_ONLY) {
            return reinterpret_cast<FieldOnlyModifier*>(m_modifiers[i]);
        }
    }
    return 0;
}

LocationOnlyModifier* AgentEventRequest::GetLocation() const throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        if ((m_modifiers[i])->GetKind() == JDWP_MODIFIER_LOCATION_ONLY) {
            return reinterpret_cast<LocationOnlyModifier*>(m_modifiers[i]);
        }
    }
    return 0;
}

//-----------------------------------------------------------------------------
// StepRequest
//-----------------------------------------------------------------------------

StepRequest::~StepRequest() throw()
{
    ControlSingleStep(false);
    JNIEnv *jni = GetJniEnv();
    if (m_framePopRequest != 0) {
        GetRequestManager().DeleteRequest(jni, m_framePopRequest);
    }
    if (m_methodEntryRequest != 0) {
        GetRequestManager().DeleteRequest(jni, m_methodEntryRequest);
    }
    jni->DeleteGlobalRef(m_thread);
}

jint StepRequest::GetCurrentLine() throw()
{
    jint lineNumber = -1;
    if (m_size == JDWP_STEP_LINE) {
        jmethodID method;
        jlocation location;
        jvmtiError err;
        JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameLocation(m_thread, 0,
            &method, &location));
        if (err == JVMTI_ERROR_NONE && location != -1) {
            jint cnt;
            jvmtiLineNumberEntry* table = 0;
            JVMTI_TRACE(err, GetJvmtiEnv()->GetLineNumberTable(method,
                &cnt, &table));
            JvmtiAutoFree jafTable(table);
            if (err == JVMTI_ERROR_NONE && cnt > 0) {
                jint i = 1;
                while (i < cnt && location >= table[i].start_location) {
                    i++;
                }
                lineNumber = table[i-1].line_number;
            }
        }
    }
    return lineNumber;
}

void StepRequest::ControlSingleStep(bool enable) throw()
{
    JDWP_TRACE_EVENT("control Step: "<< (enable ? "on" : "off")
        << ", thread=" << m_thread);
    jvmtiError err;
    JVMTI_TRACE(err, GetJvmtiEnv()->SetEventNotificationMode(
        (enable) ? JVMTI_ENABLE : JVMTI_DISABLE,
        JVMTI_EVENT_SINGLE_STEP, m_thread));
    m_isActive = enable;
}

void StepRequest::Restore() throw(AgentException) {
    JDWP_TRACE_EVENT("Restore stepRequest: " << (m_isActive ? "on" : "off"));
    jvmtiError err;
    JVMTI_TRACE(err, GetJvmtiEnv()->SetEventNotificationMode(
        (m_isActive) ? JVMTI_ENABLE : JVMTI_DISABLE,
        JVMTI_EVENT_SINGLE_STEP, m_thread));
    if (err != JVMTI_ERROR_NONE) {
        throw AgentException(err);
    }
}

bool StepRequest::IsClassApplicable(JNIEnv* jni, EventInfo &eInfo) throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        switch ((m_modifiers[i])->GetKind()) {
        case JDWP_MODIFIER_CLASS_ONLY:
        case JDWP_MODIFIER_CLASS_MATCH:
        case JDWP_MODIFIER_CLASS_EXCLUDE:
            if (!m_modifiers[i]->Apply(jni, eInfo)) {
                return false;
            }
            break;
        case JDWP_MODIFIER_COUNT:
            return true;
        default:
            break;
        }
    }
    return true;
}

void StepRequest::OnFramePop(JNIEnv *jni)
    throw(AgentException)
{
    JDWP_ASSERT(m_framePopRequest != 0);

    jint currentCount;
    jvmtiError err;
    JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameCount(m_thread, &currentCount));
    if (err != JVMTI_ERROR_NONE) {
        currentCount = -1;
    }

    if (m_depth == JDWP_STEP_OVER ||
        (m_depth == JDWP_STEP_OUT && currentCount <= m_frameCount) ||
        (m_methodEntryRequest != 0 && currentCount-1 <= m_frameCount))
    {
        ControlSingleStep(true);
        if (m_methodEntryRequest != 0) {
            GetRequestManager().DeleteRequest(jni, m_methodEntryRequest);
            m_methodEntryRequest = 0;
        }
    }
}

void StepRequest::OnMethodEntry(JNIEnv *jni, EventInfo &eInfo)
    throw(AgentException)
{
    JDWP_ASSERT(m_methodEntryRequest != 0);
    JDWP_ASSERT(m_depth == JDWP_STEP_INTO);

    if ((m_size == JDWP_STEP_MIN || GetCurrentLine() != -1) &&
        IsClassApplicable(jni, eInfo))
    {
        ControlSingleStep(true);
        m_methodEntryRequest->SetExpired(true);
        m_methodEntryRequest = 0;
    }
}

void StepRequest::Init(JNIEnv *jni, jthread thread, jint size, jint depth)
    throw(AgentException)
{
    m_thread = jni->NewGlobalRef(thread);
    if (m_thread == 0) {
        throw OutOfMemoryException();
    }
    m_size = size;
    m_depth = depth;

    if (m_depth != JDWP_STEP_INTO || m_size != JDWP_STEP_MIN) {
        jvmtiError err;
        JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameCount(m_thread, &m_frameCount));
        if (err != JVMTI_ERROR_NONE) {
            m_frameCount = -1;
        }
        if (m_size == JDWP_STEP_LINE) {
            m_lineNumber = GetCurrentLine();
        }
    }

    if (m_depth == JDWP_STEP_INTO || m_frameCount > 0) {
        // add internal FramePop event request for the thread
        m_framePopRequest =
            new AgentEventRequest(JDWP_EVENT_FRAME_POP, JDWP_SUSPEND_NONE, 1);
        m_framePopRequest->AddModifier(new ThreadOnlyModifier(jni, thread), 0);
        GetRequestManager().AddInternalRequest(jni, m_framePopRequest);
        jvmtiError err;
        JVMTI_TRACE(err, GetJvmtiEnv()->NotifyFramePop(m_thread, 0));
        if (err == JVMTI_ERROR_OPAQUE_FRAME) {
            m_isNative = true;
        }
    }

    if (m_depth == JDWP_STEP_INTO ||
        (m_depth == JDWP_STEP_OUT && m_frameCount > 0 && m_isNative) ||
        (m_depth == JDWP_STEP_OVER && m_frameCount > 0 &&
         (m_size == JDWP_STEP_MIN || m_isNative || m_lineNumber != -1)))
    {
        ControlSingleStep(true);
    }

    JDWP_TRACE_EVENT("step start: size=" << m_size << ", depth=" << m_depth
        << ", frame=" << m_frameCount << ", line=" << m_lineNumber);
}

bool StepRequest::ApplyModifiers(JNIEnv *jni, EventInfo &eInfo)
    throw(AgentException)
{
    JDWP_ASSERT(eInfo.thread != 0);

    if (JNI_FALSE == jni->IsSameObject(eInfo.thread, m_thread)) {
        return false;
    }

    jint currentCount = 0;
    jvmtiError err;
    JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameCount(m_thread, &currentCount));
    if (err != JVMTI_ERROR_NONE) {
        return false;
    }

    jint currentLine = 0;
    if (m_size == JDWP_STEP_LINE) {
        currentLine = GetCurrentLine();
    }

    if (currentCount < m_frameCount) {
        // method exit
    } else if (currentCount > m_frameCount) {
        // method entry
        if (m_depth != JDWP_STEP_INTO || !IsClassApplicable(jni, eInfo)) {
            ControlSingleStep(false);
            if (m_depth == JDWP_STEP_INTO) {
                // add internal MethodEntry event request for the thread
                m_methodEntryRequest = new AgentEventRequest(
                    JDWP_EVENT_METHOD_ENTRY, JDWP_SUSPEND_NONE, 1);
                m_methodEntryRequest->AddModifier(
                    new ThreadOnlyModifier(jni, m_thread), 0);
                GetRequestManager().AddInternalRequest(
                    jni, m_methodEntryRequest);
            }
            JVMTI_TRACE(err, GetJvmtiEnv()->NotifyFramePop(m_thread, 0));
            if (err == JVMTI_ERROR_OPAQUE_FRAME) {
                m_isNative = true;
            }
            return false;
        }
    } else { // currentCount == m_frameCount
        // check against line
        if (m_size == JDWP_STEP_LINE && currentLine == m_lineNumber) {
            return false;
        }
    }

    if (m_size == JDWP_STEP_LINE && currentLine == -1) {
        return false;
    }

    m_frameCount = currentCount;
    m_lineNumber = currentLine;

    JDWP_TRACE_EVENT("step: frame=" << m_frameCount << ", line=" << m_lineNumber);
    return AgentEventRequest::ApplyModifiers(jni, eInfo);
}
<commit_msg>Applied fix for HARMONY-4823 [jdktools][jdwp] 2 jdtdebug tests fail with similar messages in EUT 3.2<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/**
 * @author Pavel N. Vyssotski
 * @version $Revision: 1.10 $
 */
// AgentEventRequest.cpp

#include "AgentEventRequest.h"
#include "RequestManager.h"
#include "Log.h"

using namespace jdwp;

AgentEventRequest::AgentEventRequest(jdwpEventKind kind,
        jdwpSuspendPolicy suspend, jint modCount)
    throw(AgentException)
{
    m_requestId = 0;
    m_eventKind = kind;
    m_suspendPolicy = suspend;
    m_modifierCount = modCount;
    m_modifiers = 0;
    m_isExpired = false;
    if (modCount != 0) {
        m_modifiers = reinterpret_cast<RequestModifier**>
            (GetMemoryManager().Allocate(sizeof(RequestModifier*)*modCount JDWP_FILE_LINE));
        memset(m_modifiers, 0, sizeof(RequestModifier*)*modCount);
    }
}

AgentEventRequest::~AgentEventRequest() throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        delete m_modifiers[i];
    }
    if (m_modifiers != 0) {
        GetMemoryManager().Free(m_modifiers JDWP_FILE_LINE);
    }
}

bool AgentEventRequest::ApplyModifiers(JNIEnv *jni, EventInfo &eInfo)
    throw(AgentException)
{
    for (jint i = 0; i < m_modifierCount; i++) {
        if (!m_modifiers[i]->Apply(jni, eInfo)) {
            return false;
        }
        if ((m_modifiers[i])->GetKind() == JDWP_MODIFIER_COUNT) {
            // once the count reaches 0, the event becomes expired
            m_isExpired = true;
        }
    }
    return true;
}

jthread AgentEventRequest::GetThread() const throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        if ((m_modifiers[i])->GetKind() == JDWP_MODIFIER_THREAD_ONLY) {
            return (reinterpret_cast<ThreadOnlyModifier*>
                (m_modifiers[i]))->GetThread();
        }
    }
    return 0;
}

FieldOnlyModifier* AgentEventRequest::GetField() const throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        if ((m_modifiers[i])->GetKind() == JDWP_MODIFIER_FIELD_ONLY) {
            return reinterpret_cast<FieldOnlyModifier*>(m_modifiers[i]);
        }
    }
    return 0;
}

LocationOnlyModifier* AgentEventRequest::GetLocation() const throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        if ((m_modifiers[i])->GetKind() == JDWP_MODIFIER_LOCATION_ONLY) {
            return reinterpret_cast<LocationOnlyModifier*>(m_modifiers[i]);
        }
    }
    return 0;
}

//-----------------------------------------------------------------------------
// StepRequest
//-----------------------------------------------------------------------------

StepRequest::~StepRequest() throw()
{
    ControlSingleStep(false);
    JNIEnv *jni = GetJniEnv();
    if (m_framePopRequest != 0) {
        GetRequestManager().DeleteRequest(jni, m_framePopRequest);
    }
    if (m_methodEntryRequest != 0) {
        GetRequestManager().DeleteRequest(jni, m_methodEntryRequest);
    }
    jni->DeleteGlobalRef(m_thread);
}

jint StepRequest::GetCurrentLine() throw()
{
    jint lineNumber = -1;
    if (m_size == JDWP_STEP_LINE) {
        jmethodID method;
        jlocation location;
        jvmtiError err;
        JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameLocation(m_thread, 0,
            &method, &location));
        if (err == JVMTI_ERROR_NONE && location != -1) {
            jint cnt;
            jvmtiLineNumberEntry* table = 0;
            JVMTI_TRACE(err, GetJvmtiEnv()->GetLineNumberTable(method,
                &cnt, &table));
            JvmtiAutoFree jafTable(table);
            if (err == JVMTI_ERROR_NONE && cnt > 0) {
                jint i = 1;
                while (i < cnt && location >= table[i].start_location) {
                    i++;
                }
                lineNumber = table[i-1].line_number;
            }
        }
    }
    return lineNumber;
}

void StepRequest::ControlSingleStep(bool enable) throw()
{
    JDWP_TRACE_EVENT("control Step: "<< (enable ? "on" : "off")
        << ", thread=" << m_thread);
    jvmtiError err;
    JVMTI_TRACE(err, GetJvmtiEnv()->SetEventNotificationMode(
        (enable) ? JVMTI_ENABLE : JVMTI_DISABLE,
        JVMTI_EVENT_SINGLE_STEP, m_thread));
    m_isActive = enable;
}

void StepRequest::Restore() throw(AgentException) {
    JDWP_TRACE_EVENT("Restore stepRequest: " << (m_isActive ? "on" : "off"));
    jvmtiError err;
    JVMTI_TRACE(err, GetJvmtiEnv()->SetEventNotificationMode(
        (m_isActive) ? JVMTI_ENABLE : JVMTI_DISABLE,
        JVMTI_EVENT_SINGLE_STEP, m_thread));
    if (err != JVMTI_ERROR_NONE) {
        throw AgentException(err);
    }
}

bool StepRequest::IsClassApplicable(JNIEnv* jni, EventInfo &eInfo) throw()
{
    for (jint i = 0; i < m_modifierCount; i++) {
        switch ((m_modifiers[i])->GetKind()) {
        case JDWP_MODIFIER_CLASS_ONLY:
        case JDWP_MODIFIER_CLASS_MATCH:
        case JDWP_MODIFIER_CLASS_EXCLUDE:
            if (!m_modifiers[i]->Apply(jni, eInfo)) {
                return false;
            }
            break;
        case JDWP_MODIFIER_COUNT:
            return true;
        default:
            break;
        }
    }
    return true;
}

void StepRequest::OnFramePop(JNIEnv *jni)
    throw(AgentException)
{
    JDWP_ASSERT(m_framePopRequest != 0);

    jint currentCount;
    jvmtiError err;
    JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameCount(m_thread, &currentCount));
    if (err != JVMTI_ERROR_NONE) {
        currentCount = -1;
    }

    if (m_depth == JDWP_STEP_OVER ||
        (m_depth == JDWP_STEP_OUT && currentCount <= m_frameCount) ||
        (m_methodEntryRequest != 0 && currentCount-1 <= m_frameCount))
    {
        ControlSingleStep(true);
        if (m_methodEntryRequest != 0) {
            GetRequestManager().DeleteRequest(jni, m_methodEntryRequest);
            m_methodEntryRequest = 0;
        }
    }
}

void StepRequest::OnMethodEntry(JNIEnv *jni, EventInfo &eInfo)
    throw(AgentException)
{
    JDWP_ASSERT(m_methodEntryRequest != 0);
    JDWP_ASSERT(m_depth == JDWP_STEP_INTO);

    if ((m_size == JDWP_STEP_MIN || GetCurrentLine() != -1) &&
        IsClassApplicable(jni, eInfo))
    {
        ControlSingleStep(true);
        m_methodEntryRequest->SetExpired(true);
        m_methodEntryRequest = 0;
    }
}

void StepRequest::Init(JNIEnv *jni, jthread thread, jint size, jint depth)
    throw(AgentException)
{
    m_thread = jni->NewGlobalRef(thread);
    if (m_thread == 0) {
        throw OutOfMemoryException();
    }
    m_size = size;
    m_depth = depth;

    if (m_depth != JDWP_STEP_INTO || m_size != JDWP_STEP_MIN) {
        jvmtiError err;
        JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameCount(m_thread, &m_frameCount));
        if (err != JVMTI_ERROR_NONE) {
            m_frameCount = -1;
        }
        if (m_size == JDWP_STEP_LINE) {
            m_lineNumber = GetCurrentLine();
        }
    }

    if (m_depth == JDWP_STEP_INTO || m_frameCount > 0) {
        // add internal FramePop event request for the thread
        m_framePopRequest =
            new AgentEventRequest(JDWP_EVENT_FRAME_POP, JDWP_SUSPEND_NONE, 1);
        m_framePopRequest->AddModifier(new ThreadOnlyModifier(jni, thread), 0);
        GetRequestManager().AddInternalRequest(jni, m_framePopRequest);
        jvmtiError err;
        JVMTI_TRACE(err, GetJvmtiEnv()->NotifyFramePop(m_thread, 0));
        if (err == JVMTI_ERROR_OPAQUE_FRAME) {
            m_isNative = true;
        }
    }

    if (m_depth == JDWP_STEP_INTO ||
        (m_depth == JDWP_STEP_OUT && m_frameCount > 0 && m_isNative) ||
        (m_depth == JDWP_STEP_OVER && m_frameCount > 0 &&
         (m_size == JDWP_STEP_MIN || m_isNative || m_lineNumber != -1)))
    {
        ControlSingleStep(true);
    }

    JDWP_TRACE_EVENT("step start: size=" << m_size << ", depth=" << m_depth
        << ", frame=" << m_frameCount << ", line=" << m_lineNumber);
}

bool StepRequest::ApplyModifiers(JNIEnv *jni, EventInfo &eInfo)
    throw(AgentException)
{
    JDWP_ASSERT(eInfo.thread != 0);

    if (JNI_FALSE == jni->IsSameObject(eInfo.thread, m_thread)) {
        return false;
    }

    jint currentCount = 0;
    jvmtiError err;
    JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameCount(m_thread, &currentCount));
    if (err != JVMTI_ERROR_NONE) {
        return false;
    }

    jint currentLine = 0;
    if (m_size == JDWP_STEP_LINE) {
        currentLine = GetCurrentLine();
    }

    if (currentCount < m_frameCount) {
        // method exit
    } else if (currentCount > m_frameCount) {
        // method entry
        if (m_depth != JDWP_STEP_INTO || !IsClassApplicable(jni, eInfo)) {
            ControlSingleStep(false);
            if (m_depth == JDWP_STEP_INTO) {
                // add internal MethodEntry event request for the thread
                m_methodEntryRequest = new AgentEventRequest(
                    JDWP_EVENT_METHOD_ENTRY, JDWP_SUSPEND_NONE, 1);
                m_methodEntryRequest->AddModifier(
                    new ThreadOnlyModifier(jni, m_thread), 0);
                GetRequestManager().AddInternalRequest(
                    jni, m_methodEntryRequest);
            }
            JVMTI_TRACE(err, GetJvmtiEnv()->NotifyFramePop(m_thread, 0));
            if (err == JVMTI_ERROR_OPAQUE_FRAME) {
                m_isNative = true;
            }
            return false;
        }
    } else { // currentCount == m_frameCount
        // check against line
        if (m_size == JDWP_STEP_LINE && currentLine == m_lineNumber && currentLine != -1) {
            return false;
        }
    }

    m_frameCount = currentCount;
    m_lineNumber = currentLine;

    JDWP_TRACE_EVENT("step: frame=" << m_frameCount << ", line=" << m_lineNumber);
    return AgentEventRequest::ApplyModifiers(jni, eInfo);
}
<|endoftext|>


<commit_before><commit_msg>planning: fix a bug in Standby stage<commit_after><|endoftext|>