<commit_before>#pragma once

#define DEF_REGMEMBER(n, clazz, elem, getter)	::rs::LuaImport::RegisterMember<getter,clazz>(lsc, BOOST_PP_STRINGIZE(elem), &clazz::elem);
#define DEF_REGMEMBER_HDL(n, data, elem)	DEF_REGMEMBER(n, BOOST_PP_SEQ_ELEM(1,data), elem, ::rs::LI_GetHandle<BOOST_PP_SEQ_ELEM(0,data)>)
#define DEF_REGMEMBER_PTR(n, clazz, elem)	DEF_REGMEMBER(n, clazz, elem, ::rs::LI_GetPtr<clazz>)

#define DEF_LUAIMPORT_BASE namespace rs{ \
	class LuaState; \
	namespace lua{ \
		template <class T> \
		void LuaExport(LuaState& lsc, T*); \
		template <class T> \
		const char* LuaName(T*); \
	}}
#define DEF_LUAIMPORT(clazz) \
	DEF_LUAIMPORT_BASE \
	namespace rs { \
		namespace lua { \
		template <> \
		const char* LuaName(clazz*); \
		template <> \
		void LuaExport(LuaState& lsc, clazz*); \
	}}

#define DEF_LUAIMPLEMENT_HDL_IMPL(mgr, clazz, class_name, base, seq_member, seq_method, seq_ctor, makeobj) \
		namespace rs{ namespace lua{ \
			template <> \
			const char* LuaName(clazz*) { return #class_name; } \
			template <> \
			void LuaExport(LuaState& lsc, clazz*) { \
				lsc.getGlobal(::rs::luaNS::DerivedHandle); \
				lsc.getGlobal(base); \
				lsc.push(#class_name); \
				lsc.call(2,1); \
				lsc.push(::rs::luaNS::objBase::_New); \
				lsc.push(makeobj<BOOST_PP_SEQ_ENUM((mgr)(clazz)seq_ctor)>); \
				lsc.setTable(-3); \
				\
				lsc.getField(-1, ::rs::luaNS::objBase::ValueR); \
				lsc.getField(-2, ::rs::luaNS::objBase::ValueW); \
				BOOST_PP_SEQ_FOR_EACH(DEF_REGMEMBER_HDL, (typename mgr::data_type)(clazz), seq_member) \
				lsc.pop(2); \
				\
				lsc.getField(-1, ::rs::luaNS::objBase::Func); \
				BOOST_PP_SEQ_FOR_EACH(DEF_REGMEMBER_HDL, (typename mgr::data_type)(clazz), seq_method) \
				lsc.pop(1); \
				\
				lsc.setGlobal(#class_name); \
			} \
		}}
#define DEF_LUAIMPLEMENT_HDL(mgr, clazz, class_name, base, seq_member, seq_method, seq_ctor) \
	DEF_LUAIMPLEMENT_HDL_IMPL(mgr, clazz, class_name, base, seq_member, seq_method,  seq_ctor, ::rs::MakeHandle)
#define DEF_LUAIMPLEMENT_HDL_NOBASE(mgr, clazz, class_name, seq_member, seq_method, seq_ctor) \
	DEF_LUAIMPLEMENT_HDL(mgr, clazz, class_name, ::rs::luaNS::ObjectBase, seq_member, seq_method, seq_ctor)
#define DEF_LUAIMPLEMENT_HDL_NOCTOR(mgr, clazz, class_name, base, seq_member, seq_method) \
	DEF_LUAIMPLEMENT_HDL_IMPL(mgr, clazz, class_name, base, seq_member, seq_method, NOTHING, ::rs::MakeHandle_Fake)
#define DEF_LUAIMPLEMENT_HDL_NOBASE_NOCTOR(mgr, clazz, class_name, seq_member, seq_method) \
	DEF_LUAIMPLEMENT_HDL_IMPL(mgr, clazz, class_name, ::rs::luaNS::ObjectBase, seq_member, seq_method, NOTHING, ::rs::MakeHandle_Fake)

#define DEF_LUAIMPLEMENT_PTR(clazz, class_name, seq_member, seq_method) \
		namespace rs{ namespace lua{ \
			template <> \
			const char* LuaName(clazz*) { return #class_name; } \
			template <> \
			void LuaExport(LuaState& lsc, clazz*) { \
				lsc.getGlobal(::rs::luaNS::DerivedHandle); \
				lsc.getGlobal(::rs::luaNS::ObjectBase); \
				lsc.push(#class_name); \
				lsc.call(2,1); \
				\
				lsc.getField(-1, ::rs::luaNS::objBase::ValueR); \
				lsc.getField(-2, ::rs::luaNS::objBase::ValueW); \
				BOOST_PP_SEQ_FOR_EACH(DEF_REGMEMBER_PTR, clazz, seq_member) \
				lsc.pop(2); \
				\
				lsc.getField(-1, ::rs::luaNS::objBase::Func); \
				BOOST_PP_SEQ_FOR_EACH(DEF_REGMEMBER_PTR, clazz, seq_method) \
				lsc.pop(1); \
				\
				lsc.setGlobal(#class_name); \
			} \
		}}

<commit_msg>LuaExport: クラスがLuaExport()というstaticメソッドを持っていればエクスポート時にそれを呼ぶ仕様とした<commit_after>#pragma once

#define DEF_REGMEMBER(n, clazz, elem, getter)	::rs::LuaImport::RegisterMember<getter,clazz>(lsc, BOOST_PP_STRINGIZE(elem), &clazz::elem);
#define DEF_REGMEMBER_HDL(n, data, elem)	DEF_REGMEMBER(n, BOOST_PP_SEQ_ELEM(1,data), elem, ::rs::LI_GetHandle<BOOST_PP_SEQ_ELEM(0,data)>)
#define DEF_REGMEMBER_PTR(n, clazz, elem)	DEF_REGMEMBER(n, clazz, elem, ::rs::LI_GetPtr<clazz>)

#define DEF_LUAIMPORT_BASE namespace rs{ \
	class LuaState; \
	namespace lua{ \
		template <class T> \
		void LuaExport(LuaState& lsc, T*); \
		template <class T> \
		const char* LuaName(T*); \
	}}
#define DEF_LUAIMPORT(clazz) \
	DEF_LUAIMPORT_BASE \
	namespace rs { \
		namespace lua { \
		template <> \
		const char* LuaName(clazz*); \
		template <> \
		void LuaExport(LuaState& lsc, clazz*); \
	}}
#include "spinner/check_macro.hpp"
namespace rs {
	DEF_HASMETHOD(LuaExport)
	class LuaState;
	template <class T>
	void CallLuaExport(LuaState& lsc, std::true_type) {
		T::LuaExport(lsc);
	}
	template <class T>
	void CallLuaExport(LuaState&, std::false_type) {}
}
#define DEF_LUAIMPLEMENT_HDL_IMPL(mgr, clazz, class_name, base, seq_member, seq_method, seq_ctor, makeobj) \
		namespace rs{ namespace lua{ \
			template <> \
			const char* LuaName(clazz*) { return #class_name; } \
			template <> \
			void LuaExport(LuaState& lsc, clazz*) { \
				lsc.getGlobal(::rs::luaNS::DerivedHandle); \
				lsc.getGlobal(base); \
				lsc.push(#class_name); \
				lsc.call(2,1); \
				lsc.push(::rs::luaNS::objBase::_New); \
				lsc.push(makeobj<BOOST_PP_SEQ_ENUM((mgr)(clazz)seq_ctor)>); \
				lsc.setTable(-3); \
				\
				lsc.getField(-1, ::rs::luaNS::objBase::ValueR); \
				lsc.getField(-2, ::rs::luaNS::objBase::ValueW); \
				BOOST_PP_SEQ_FOR_EACH(DEF_REGMEMBER_HDL, (typename mgr::data_type)(clazz), seq_member) \
				lsc.pop(2); \
				\
				lsc.getField(-1, ::rs::luaNS::objBase::Func); \
				BOOST_PP_SEQ_FOR_EACH(DEF_REGMEMBER_HDL, (typename mgr::data_type)(clazz), seq_method) \
				lsc.pop(1); \
				\
				CallLuaExport<clazz>(lsc, rs::HasMethod_LuaExport_t<clazz>()); \
				lsc.setGlobal(#class_name); \
			} \
		}}
#define DEF_LUAIMPLEMENT_HDL(mgr, clazz, class_name, base, seq_member, seq_method, seq_ctor) \
	DEF_LUAIMPLEMENT_HDL_IMPL(mgr, clazz, class_name, base, seq_member, seq_method,  seq_ctor, ::rs::MakeHandle)
#define DEF_LUAIMPLEMENT_HDL_NOBASE(mgr, clazz, class_name, seq_member, seq_method, seq_ctor) \
	DEF_LUAIMPLEMENT_HDL(mgr, clazz, class_name, ::rs::luaNS::ObjectBase, seq_member, seq_method, seq_ctor)
#define DEF_LUAIMPLEMENT_HDL_NOCTOR(mgr, clazz, class_name, base, seq_member, seq_method) \
	DEF_LUAIMPLEMENT_HDL_IMPL(mgr, clazz, class_name, base, seq_member, seq_method, NOTHING, ::rs::MakeHandle_Fake)
#define DEF_LUAIMPLEMENT_HDL_NOBASE_NOCTOR(mgr, clazz, class_name, seq_member, seq_method) \
	DEF_LUAIMPLEMENT_HDL_IMPL(mgr, clazz, class_name, ::rs::luaNS::ObjectBase, seq_member, seq_method, NOTHING, ::rs::MakeHandle_Fake)

#define DEF_LUAIMPLEMENT_PTR(clazz, class_name, seq_member, seq_method) \
		namespace rs{ namespace lua{ \
			template <> \
			const char* LuaName(clazz*) { return #class_name; } \
			template <> \
			void LuaExport(LuaState& lsc, clazz*) { \
				lsc.getGlobal(::rs::luaNS::DerivedHandle); \
				lsc.getGlobal(::rs::luaNS::ObjectBase); \
				lsc.push(#class_name); \
				lsc.call(2,1); \
				\
				lsc.getField(-1, ::rs::luaNS::objBase::ValueR); \
				lsc.getField(-2, ::rs::luaNS::objBase::ValueW); \
				BOOST_PP_SEQ_FOR_EACH(DEF_REGMEMBER_PTR, clazz, seq_member) \
				lsc.pop(2); \
				\
				lsc.getField(-1, ::rs::luaNS::objBase::Func); \
				BOOST_PP_SEQ_FOR_EACH(DEF_REGMEMBER_PTR, clazz, seq_method) \
				lsc.pop(1); \
				\
				CallLuaExport<clazz>(lsc, rs::HasMethod_LuaExport_t<clazz>()); \
				lsc.setGlobal(#class_name); \
			} \
		}}

<|endoftext|>


<commit_before>#include <iostream>
#include <string>

#include "Cutie.hpp"

//#include "Main.hpp"

enum Move {ROCK, PAPER, SCISSORS};

// void getPlayerTurn(enum Move & temp);
// void outputScore(int myScore, int theirScore);
// void updateScore(bool winner, int & myScore, int & theirScore);

void getPlayerTurn(Move & temp)
{
	int choice = 1;
	std::cout << "Please enter your move!" << std::endl;
	std::cout << "1: ROCK" << std::endl;
	std::cout << "2: PAPER" << std::endl;
	std::cout << "3: SCISSORS!" << std::endl;
	std::cin >> choice;

	if (choice == 1) {
		temp = ROCK;
	}
	else if (choice == 2) {
		temp =  PAPER;
	}
	else {
		temp = SCISSORS;
	}
}

void outputScore(int myScore, int theirScore)
{
	std::cout << "YOU: " << myScore << std::endl;
	std::cout << "OPPONENT: " << theirScore << std:: endl;
}

void updateScore(bool winner, int & myScore, int & theirScore)
{
	if (winner) {
		myScore++;
		return;
	}
	theirScore++;
	return;
}
// bool compareTurn(Move player){

// }

int main(int argc, char *argv[])
{
	//cutie::connect();

	//if(cutie::connect(address, timeout)) {

		bool gameStarted = true;//gameInit(0,0);
		bool gameActive = true;

		if (gameStarted) {
			int myScore = 0;
			int theirScore = 0;
			bool winner = false;
			Move myTurn = ROCK;
			Move theirTurn = ROCK;

			while (gameActive) {

				outputScore(myScore, theirScore);
				getPlayerTurn(myTurn);

				//theirTurn =  cutie::doTurn(myTurn);

				if (myTurn == theirTurn) {
					winner = false;
				}
				else if (myTurn == ROCK) {
					winner = (theirTurn == SCISSORS)? true : false;
				}
				else if (myTurn == PAPER) {
					winner = (theirTurn == ROCK)? true : false;
				}
				else {
					winner = (theirTurn == PAPER)? true : false;
				}

				updateScore(winner, myScore, theirScore);

			}

		}
	//}
    return 0;
}

<commit_msg>Added choice menu<commit_after>#include <iostream>
#include <string>

#include "Cutie.hpp"

//#include "Main.hpp"

enum Move {
	ROCK,
	PAPER,
	SCISSORS
};

enum SessionType {
	JOIN,
	CREATE
};

// void getPlayerTurn(enum Move & temp);
// void outputScore(int myScore, int theirScore);
// void updateScore(bool winner, int & myScore, int & theirScore);

//
int choice()
{
	int res = 0;

	std::cout << "Would you like to create a game or join a game?" << endl;
	std::cout << "1: Join\n2:Create\n> ";
	std::cin >> res;

	cin >> res;

	cin.clear();
	cin.ignore(256, '\n');
	switch (res) {
		case 1:
			return JOIN;
		case 2:
			return CREATE;
		default:
			return -1;
	}
}

void getPlayerTurn(Move& temp)
{
	int choice = 1;
	std::cout << "Please enter your move!" << std::endl;
	std::cout << "1: ROCK" << std::endl;
	std::cout << "2: PAPER" << std::endl;
	std::cout << "3: SCISSORS!" << std::endl;
	std::cin >> choice;

	if (choice == 1) {
		temp = ROCK;
	}
	else if (choice == 2) {
		temp =  PAPER;
	}
	else {
		temp = SCISSORS;
	}
}

void outputScore(int myScore, int theirScore)
{
	std::cout << "YOU: " << myScore << std::endl;
	std::cout << "OPPONENT: " << theirScore << std:: endl;
}

void updateScore(bool winner, int & myScore, int & theirScore)
{
	if (winner) {
		myScore++;
		return;
	}
	theirScore++;
	return;
}
// bool compareTurn(Move player){

// }

int main(int argc, char *argv[])
{
	SessionType type = choice();

	//cutie::connect();

	//if(cutie::connect(address, timeout)) {

		bool gameStarted = true;//gameInit(0,0);
		bool gameActive = true;

		if (gameStarted) {
			int myScore = 0;
			int theirScore = 0;
			bool winner = false;
			Move myTurn = ROCK;
			Move theirTurn = ROCK;

			while (gameActive) {

				outputScore(myScore, theirScore);
				getPlayerTurn(myTurn);

				//theirTurn =  cutie::doTurn(myTurn);

				if (myTurn == theirTurn) {
					winner = false;
				}
				else if (myTurn == ROCK) {
					winner = (theirTurn == SCISSORS)? true : false;
				}
				else if (myTurn == PAPER) {
					winner = (theirTurn == ROCK)? true : false;
				}
				else {
					winner = (theirTurn == PAPER)? true : false;
				}

				updateScore(winner, myScore, theirScore);

			}

		}
	//}
    return 0;
}

<|endoftext|>


<commit_before>/****************************************************************
Purpose:
	Look for a "core" file at a given location.  Return TRUE if it
	exists and appears complete and correct, and FALSE otherwise.
	The SUN core consists of a header, the data and stack segments
	and finally the uarea.  We check the magic number in the header
	first.  If that's OK we then calculate what the size of the
	core should be using the size of the header, the sizes of the
	data and stack areas recorded in the header and the size of the
	uarea as defined in "sys/param.h".  We then compare this
	calculation with the actual size of the file.
Portability:
	This code depends upon the core format for SUNOS4.1 systems,
	and is not portable to other systems.

Modified for Solaris by : Dhaval N. Shah
							 University of Wisconsin, Madison
**                           Computer Sciences Department
******************************************************************/

#define _ALL_SOURCE

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_constants.h"
#include "condor_jobqueue.h"
#include <sys/file.h>
#include <sys/core.h>
#include <sys/param.h>
#include "proto.h"

static char *_FileName_ = __FILE__;     /* Used by EXCEPT (see except.h)     */
#if defined(Solaris)
  #define UPAGES 4
  #define NBPG 0x1000   /*couldnt get this val from header files. Rough
		        estimate from Suns header files - Raghu */
  #undef CORE_MAGIC
  #if defined(X86)
  #define CORE_MAGIC 0x7f454c46  /* at least, this is the magic for my
									core file - Jim B. */
  #else
  #define CORE_MAGIC 0x464c457f
  #endif
#endif

const int       UAREA_SIZE = UPAGES * NBPG;
const int	HEADER_SIZE = sizeof(struct core);

int
core_is_valid( char *name )
{
	struct core header;

	int		fd;
	int		total_size;
	off_t	file_size;

	dprintf( D_ALWAYS,
		"Analyzing core file \"%s\" for existence and completeness\n", name
	);

	if( (fd=open(name,O_RDONLY)) < 0 ) {
		dprintf( D_ALWAYS, "Can't open core file \"%s\"", name );
		return FALSE;
	}

	if( read(fd,(char *)&header,HEADER_SIZE) != HEADER_SIZE ) {
		dprintf( D_ALWAYS, "Can't read header from core file\n" );
		(void)close( fd );
		return FALSE;
	}

	file_size = lseek( fd, (off_t)0, SEEK_END );
	(void)close( fd );

	if( header.c_magic != CORE_MAGIC ) {
		dprintf( D_ALWAYS,
			"Core file - bad magic number (0x%x)\n", header.c_magic
		);
		return FALSE;
	}

	dprintf( D_ALWAYS,
		"Core file - magic number OK\n"
	);

	/* the size test is bogus on Solaris -- there is something wrong
	   with the header information -- I'm taking it out.  -Jim B. */

/*	total_size = header.c_len + header.c_dsize + header.c_ssize + UAREA_SIZE;

	if( file_size != total_size ) {
		dprintf( D_ALWAYS,
			"file_size should be %d, but is %d\n", total_size, file_size
		);
		return FALSE;
	} else {
		dprintf( D_ALWAYS,
			"Core file_size of %d is correct\n", file_size
		); */
		return TRUE;
/*	} */

#if 0
	dprintf( D_ALWAYS, "c_len = %d bytes\n", header.c_len );
	dprintf( D_ALWAYS, "c_dsize = %d bytes\n", header.c_dsize );
	dprintf( D_ALWAYS, "c_ssize = %d bytes\n", header.c_ssize );
	dprintf( D_ALWAYS, "UAREA_SIZE = %d bytes\n", UAREA_SIZE );
	dprintf( D_ALWAYS, "total_size = %d bytes\n", total_size );
#endif

}
<commit_msg>I had the corefile magic numbers exactly backwards for x86 Solaris vs. sparc Solaris.  This update should set the numbers straight.<commit_after>/****************************************************************
Purpose:
	Look for a "core" file at a given location.  Return TRUE if it
	exists and appears complete and correct, and FALSE otherwise.
	The SUN core consists of a header, the data and stack segments
	and finally the uarea.  We check the magic number in the header
	first.  If that's OK we then calculate what the size of the
	core should be using the size of the header, the sizes of the
	data and stack areas recorded in the header and the size of the
	uarea as defined in "sys/param.h".  We then compare this
	calculation with the actual size of the file.
Portability:
	This code depends upon the core format for SUNOS4.1 systems,
	and is not portable to other systems.

Modified for Solaris by : Dhaval N. Shah
							 University of Wisconsin, Madison
**                           Computer Sciences Department
******************************************************************/

#define _ALL_SOURCE

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_constants.h"
#include "condor_jobqueue.h"
#include <sys/file.h>
#include <sys/core.h>
#include <sys/param.h>
#include "proto.h"

static char *_FileName_ = __FILE__;     /* Used by EXCEPT (see except.h)     */
#if defined(Solaris)
  #define UPAGES 4
  #define NBPG 0x1000   /*couldnt get this val from header files. Rough
		        estimate from Suns header files - Raghu */
  #undef CORE_MAGIC
  #if defined(X86)
  #define CORE_MAGIC 0x464c457f  /* at least, this is the magic for my
									core file - Jim B. */
  #else
  #define CORE_MAGIC 0x7f454c46
  #endif
#endif

const int       UAREA_SIZE = UPAGES * NBPG;
const int	HEADER_SIZE = sizeof(struct core);

int
core_is_valid( char *name )
{
	struct core header;

	int		fd;
	int		total_size;
	off_t	file_size;

	dprintf( D_ALWAYS,
		"Analyzing core file \"%s\" for existence and completeness\n", name
	);

	if( (fd=open(name,O_RDONLY)) < 0 ) {
		dprintf( D_ALWAYS, "Can't open core file \"%s\"", name );
		return FALSE;
	}

	if( read(fd,(char *)&header,HEADER_SIZE) != HEADER_SIZE ) {
		dprintf( D_ALWAYS, "Can't read header from core file\n" );
		(void)close( fd );
		return FALSE;
	}

	file_size = lseek( fd, (off_t)0, SEEK_END );
	(void)close( fd );

	if( header.c_magic != CORE_MAGIC ) {
		dprintf( D_ALWAYS,
			"Core file - bad magic number (0x%x)\n", header.c_magic
		);
		return FALSE;
	}

	dprintf( D_ALWAYS,
		"Core file - magic number OK\n"
	);

	/* the size test is bogus on Solaris -- there is something wrong
	   with the header information -- I'm taking it out.  -Jim B. */

/*	total_size = header.c_len + header.c_dsize + header.c_ssize + UAREA_SIZE;

	if( file_size != total_size ) {
		dprintf( D_ALWAYS,
			"file_size should be %d, but is %d\n", total_size, file_size
		);
		return FALSE;
	} else {
		dprintf( D_ALWAYS,
			"Core file_size of %d is correct\n", file_size
		); */
		return TRUE;
/*	} */

#if 0
	dprintf( D_ALWAYS, "c_len = %d bytes\n", header.c_len );
	dprintf( D_ALWAYS, "c_dsize = %d bytes\n", header.c_dsize );
	dprintf( D_ALWAYS, "c_ssize = %d bytes\n", header.c_ssize );
	dprintf( D_ALWAYS, "UAREA_SIZE = %d bytes\n", UAREA_SIZE );
	dprintf( D_ALWAYS, "total_size = %d bytes\n", total_size );
#endif

}
<|endoftext|>


<commit_before>// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Copyright (c) 2015-2016 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder.  You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Copyright 2009-2014 Sandia Coporation.  Under the terms
// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
// Government retains certain rights in this software.
//
// Copyright (c) 2009-2014, Sandia Corporation
// All rights reserved.
//
// For license information, see the LICENSE file in the current directory.

#include <sst/core/sst_config.h>
#include <sst/core/componentInfo.h>
#include <sst/core/interfaces/simpleMem.h>
#include <sst/elements/memHierarchy/memEvent.h>
#include <sst/elements/memHierarchy/memTypes.h>
#include <sst/elements/memHierarchy/util.h>

#include <Python.h>  // Before serialization to prevent spurious warnings

#include "gem5.hh"

#include "util.hh"

// System headers
#include <algorithm>
#include <fstream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

#include <pybind11/embed.h>
#include <pybind11/pybind11.h>

// gem5 Headers
#include <sim/core.hh>
#include <sim/init.hh>
#include <sim/init_signals.hh>
#include <sim/root.hh>
#include <sim/system.hh>
#include <sim/sim_events.hh>
#include <sim/sim_object.hh>
#include <base/logging.hh>
#include <base/debug.hh>

#include <base/pollevent.hh>
#include <base/types.hh>
#include <sim/async.hh>
#include <sim/eventq.hh>
#include <sim/sim_exit.hh>
#include <sim/stat_control.hh>

#include <sst/outgoing_request_bridge.hh>

#include <cassert>

#ifdef fatal  // gem5 sets this
#undef fatal
#endif

// More SST Headers
#include <core/timeConverter.h>

namespace py = pybind11;

gem5Component::gem5Component(SST::ComponentId_t id, SST::Params& params):
    SST::Component(id), threadInitialized(false)
{
    output.init("gem5Component-" + getName() + "->", 1, 0,
                SST::Output::STDOUT);

    std::string cpu_frequency = params.find<std::string>("frequency", "");
    if (cpu_frequency.empty()) {
        output.fatal(
            CALL_INFO, -1, "The frequency of the CPU must be specified.\n"
        );
    }

    // Register a handler to be called on a set frequency.
    timeConverter = registerClock(
        cpu_frequency,
        new SST::Clock::Handler<gem5Component>(this, &gem5Component::clockTick)
    );

    // "cmd" -> gem5's Python
    std::string cmd = params.find<std::string>("cmd", "");
    if (cmd.empty()) {
        output.fatal(
            CALL_INFO, -1, "Component %s must have a 'cmd' parameter.\n",
            getName().c_str()
        );
    }

    // Telling SST the command line call to gem5
    args.push_back(const_cast<char*>("sst.x"));
    splitCommandArgs(cmd, args);
    output.output(CALL_INFO, "Command string:  [sst.x %s]\n", cmd.c_str());
    for (size_t i = 0; i < args.size(); ++i) {
        output.output(CALL_INFO, "  Arg [%02zu] = %s\n", i, args[i]);
    }

    // Parsing and setting gem5 debug flags
    std::string gem5_debug_flags = params.find<std::string>("debug_flags", "");
    for (auto const debug_flag: tokenizeString(gem5_debug_flags, {' ', ','})) {
        output.output(CALL_INFO, "Debug flag += %s\n", debug_flag.c_str());
        gem5::setDebugFlag(debug_flag.c_str());
    }

    registerAsPrimaryComponent();
    primaryComponentDoNotEndSim();

    systemPort = \
        loadUserSubComponent<SSTResponderSubComponent>("system_port",0);
    cachePort = \
        loadUserSubComponent<SSTResponderSubComponent>("cache_port", 0);

    systemPort->setTimeConverter(timeConverter);
    systemPort->setOutputStream(&(output));
    cachePort->setTimeConverter(timeConverter);
    cachePort->setOutputStream(&(output));

}

gem5Component::~gem5Component()
{
}

void
gem5Component::init(unsigned phase)
{
    output.output(CALL_INFO," init phase: %u\n", phase);

    if (phase == 0) {
        initPython(args.size(), &args[0]);

        const std::vector<std::string> m5_instantiate_commands = {
            "m5.instantiate()"
        };
        execPythonCommands(m5_instantiate_commands);

        // calling SimObject.startup()
        const std::vector<std::string> simobject_setup_commands = {
            "import atexit",
            "import _m5",
            "root = m5.objects.Root.getInstance()",
            "for obj in root.descendants(): obj.startup()",
            "atexit.register(m5.stats.dump)",
            "atexit.register(_m5.core.doExitCleanup)",
            "m5.stats.reset()"
        };
        execPythonCommands(simobject_setup_commands);

        // find the corresponding SimObject for each SSTResponderSubComponent
        gem5::Root* gem5_root = gem5::Root::root();
        systemPort->findCorrespondingSimObject(gem5_root);
        cachePort->findCorrespondingSimObject(gem5_root);

        // initialize the gem5 event queue
        if (!(threadInitialized)) {
            threadInitialized = true;
            gem5::simulate_limit_event = new gem5::GlobalSimLoopExitEvent(
                gem5::mainEventQueue[0]->getCurTick(),
                "simulate() limit reached",
                0
            );
        }

    }

    systemPort->init(phase);
    cachePort->init(phase);
}

void
gem5Component::setup()
{
    output.verbose(CALL_INFO, 1, 0, "Component is being setup.\n");
    systemPort->setup();
    cachePort->setup();
}

void
gem5Component::finish()
{
    output.verbose(CALL_INFO, 1, 0, "Component is being finished.\n");
}

bool
gem5Component::clockTick(SST::Cycle_t currentCycle)
{
    // what to do in a SST's cycle
    gem5::GlobalSimLoopExitEvent *event = simulateGem5(currentCycle);
    clocksProcessed++;
    // gem5 exits due to reasons other than reaching simulation limit
    if (event != gem5::simulate_limit_event) {
        output.output("exiting: curTick()=%lu cause=`%s` code=%d\n",
            gem5::curTick(), event->getCause().c_str(), event->getCode()
        );
        // output gem5 stats
        const std::vector<std::string> output_stats_commands = {
            "m5.stats.dump()"
        };
        execPythonCommands(output_stats_commands);

        primaryComponentOKToEndSim();
        return true;
    }

    // returning False means the simulation should go on
    return false;

}

#define PyCC(x) (const_cast<char *>(x))

gem5::GlobalSimLoopExitEvent*
gem5Component::simulateGem5(uint64_t current_cycle)
{
    // This function should be similar to simulate() of src/sim/simulate.cc
    // with synchronization barriers removed.

    inform_once("Entering event queue @ %d.  Starting simulation...\n",
                gem5::curTick());

    // Tick conversion
    // The main logic for synchronize SST Tick and gem5 Tick is here.
    // next_end_tick = current_cycle * timeConverter->getFactor()
    uint64_t next_end_tick = \
        timeConverter->convertToCoreTime(current_cycle);

    // Here, if the next event in gem5's queue is not executed within the next
    // cycle, there's no need to enter the gem5's sim loop.
    if (gem5::mainEventQueue[0]->empty() ||
        next_end_tick < gem5::mainEventQueue[0]->getHead()->when()) {
        return gem5::simulate_limit_event;
    }
    gem5::simulate_limit_event->reschedule(next_end_tick);
    gem5::Event *local_event = doSimLoop(gem5::mainEventQueue[0]);
    gem5::BaseGlobalEvent *global_event = local_event->globalEvent();
    gem5::GlobalSimLoopExitEvent *global_exit_event =
        dynamic_cast<gem5::GlobalSimLoopExitEvent *>(global_event);
    return global_exit_event;
}

gem5::Event*
gem5Component::doSimLoop(gem5::EventQueue* eventq)
{
    // This function should be similar to doSimLoop() in src/sim/simulate.cc
    // with synchronization barriers removed.
    gem5::curEventQueue(eventq);
    eventq->handleAsyncInsertions();

    while (true)
    {
        // there should always be at least one event (the SimLoopExitEvent
        // we just scheduled) in the queue

        assert(!eventq->empty());
        assert(gem5::curTick() <= eventq->nextTick() &&
               "event scheduled in the past");

        if (gem5::async_event) {
            // Take the event queue lock in case any of the service
            // routines want to schedule new events.
            if (gem5::async_statdump || gem5::async_statreset) {
                gem5::statistics::schedStatEvent(gem5::async_statdump,
                                                 gem5::async_statreset);
                gem5::async_statdump = false;
                gem5::async_statreset = false;
            }

            if (gem5::async_io) {
                gem5::async_io = false;
                gem5::pollQueue.service();
            }

            if (gem5::async_exit) {
                gem5::async_exit = false;
                gem5::exitSimLoop("user interrupt received");
            }

            if (gem5::async_exception) {
                gem5::async_exception = false;
                return NULL;
            }
        }

        gem5::Event *exit_event = eventq->serviceOne();
        if (exit_event != NULL) {
            return exit_event;
        }
    }
}

int
gem5Component::execPythonCommands(const std::vector<std::string>& commands)
{
    static PyObject *dict =
        py::module_::import("__main__").attr("__dict__").ptr();

    PyObject *result;

    for (auto const command: commands) {
        result = PyRun_String(command.c_str(), Py_file_input, dict, dict);
        if (!result) {
            PyErr_Print();
            return 1;
        }
        Py_DECREF(result);
    }
    return 0;
}

void
gem5Component::initPython(int argc, char *_argv[])
{
    // Initialize gem5 special signal handling.
    gem5::initSignals();

    if (!Py_IsInitialized())
        py::initialize_interpreter(false, argc, _argv);

    auto importer = py::module_::import("importer");
    importer.attr("install")();

    try {
        py::module_::import("m5").attr("main")();
    } catch (py::error_already_set &e) {
        if (!e.matches(PyExc_SystemExit)) {
            std::cerr << e.what();
            output.output(CALL_INFO, "Calling m5.main(...) failed.\n");
        }
    }
}

void
gem5Component::splitCommandArgs(std::string &cmd, std::vector<char*> &args)
{
    std::vector<std::string> parsed_args = tokenizeString(
        cmd, {'\\', ' ', '\'', '\"'}
    );

    for (auto part: parsed_args)
        args.push_back(strdup(part.c_str()));
}
<commit_msg>ext: In sst, don't assume existing imports in python blobs.<commit_after>// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Copyright (c) 2015-2016 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder.  You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Copyright 2009-2014 Sandia Coporation.  Under the terms
// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
// Government retains certain rights in this software.
//
// Copyright (c) 2009-2014, Sandia Corporation
// All rights reserved.
//
// For license information, see the LICENSE file in the current directory.

#include <sst/core/sst_config.h>
#include <sst/core/componentInfo.h>
#include <sst/core/interfaces/simpleMem.h>
#include <sst/elements/memHierarchy/memEvent.h>
#include <sst/elements/memHierarchy/memTypes.h>
#include <sst/elements/memHierarchy/util.h>

#include <Python.h>  // Before serialization to prevent spurious warnings

#include "gem5.hh"

#include "util.hh"

// System headers
#include <algorithm>
#include <fstream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

#include <pybind11/embed.h>
#include <pybind11/pybind11.h>

// gem5 Headers
#include <sim/core.hh>
#include <sim/init.hh>
#include <sim/init_signals.hh>
#include <sim/root.hh>
#include <sim/system.hh>
#include <sim/sim_events.hh>
#include <sim/sim_object.hh>
#include <base/logging.hh>
#include <base/debug.hh>

#include <base/pollevent.hh>
#include <base/types.hh>
#include <sim/async.hh>
#include <sim/eventq.hh>
#include <sim/sim_exit.hh>
#include <sim/stat_control.hh>

#include <sst/outgoing_request_bridge.hh>

#include <cassert>

#ifdef fatal  // gem5 sets this
#undef fatal
#endif

// More SST Headers
#include <core/timeConverter.h>

namespace py = pybind11;

gem5Component::gem5Component(SST::ComponentId_t id, SST::Params& params):
    SST::Component(id), threadInitialized(false)
{
    output.init("gem5Component-" + getName() + "->", 1, 0,
                SST::Output::STDOUT);

    std::string cpu_frequency = params.find<std::string>("frequency", "");
    if (cpu_frequency.empty()) {
        output.fatal(
            CALL_INFO, -1, "The frequency of the CPU must be specified.\n"
        );
    }

    // Register a handler to be called on a set frequency.
    timeConverter = registerClock(
        cpu_frequency,
        new SST::Clock::Handler<gem5Component>(this, &gem5Component::clockTick)
    );

    // "cmd" -> gem5's Python
    std::string cmd = params.find<std::string>("cmd", "");
    if (cmd.empty()) {
        output.fatal(
            CALL_INFO, -1, "Component %s must have a 'cmd' parameter.\n",
            getName().c_str()
        );
    }

    // Telling SST the command line call to gem5
    args.push_back(const_cast<char*>("sst.x"));
    splitCommandArgs(cmd, args);
    output.output(CALL_INFO, "Command string:  [sst.x %s]\n", cmd.c_str());
    for (size_t i = 0; i < args.size(); ++i) {
        output.output(CALL_INFO, "  Arg [%02zu] = %s\n", i, args[i]);
    }

    // Parsing and setting gem5 debug flags
    std::string gem5_debug_flags = params.find<std::string>("debug_flags", "");
    for (auto const debug_flag: tokenizeString(gem5_debug_flags, {' ', ','})) {
        output.output(CALL_INFO, "Debug flag += %s\n", debug_flag.c_str());
        gem5::setDebugFlag(debug_flag.c_str());
    }

    registerAsPrimaryComponent();
    primaryComponentDoNotEndSim();

    systemPort = \
        loadUserSubComponent<SSTResponderSubComponent>("system_port",0);
    cachePort = \
        loadUserSubComponent<SSTResponderSubComponent>("cache_port", 0);

    systemPort->setTimeConverter(timeConverter);
    systemPort->setOutputStream(&(output));
    cachePort->setTimeConverter(timeConverter);
    cachePort->setOutputStream(&(output));

}

gem5Component::~gem5Component()
{
}

void
gem5Component::init(unsigned phase)
{
    output.output(CALL_INFO," init phase: %u\n", phase);

    if (phase == 0) {
        initPython(args.size(), &args[0]);

        const std::vector<std::string> m5_instantiate_commands = {
            "import m5",
            "m5.instantiate()"
        };
        execPythonCommands(m5_instantiate_commands);

        // calling SimObject.startup()
        const std::vector<std::string> simobject_setup_commands = {
            "import atexit",
            "import _m5.core",
            "import m5",
            "import m5.stats",
            "import m5.objects.Root",
            "root = m5.objects.Root.getInstance()",
            "for obj in root.descendants(): obj.startup()",
            "atexit.register(m5.stats.dump)",
            "atexit.register(_m5.core.doExitCleanup)",
            "m5.stats.reset()"
        };
        execPythonCommands(simobject_setup_commands);

        // find the corresponding SimObject for each SSTResponderSubComponent
        gem5::Root* gem5_root = gem5::Root::root();
        systemPort->findCorrespondingSimObject(gem5_root);
        cachePort->findCorrespondingSimObject(gem5_root);

        // initialize the gem5 event queue
        if (!(threadInitialized)) {
            threadInitialized = true;
            gem5::simulate_limit_event = new gem5::GlobalSimLoopExitEvent(
                gem5::mainEventQueue[0]->getCurTick(),
                "simulate() limit reached",
                0
            );
        }

    }

    systemPort->init(phase);
    cachePort->init(phase);
}

void
gem5Component::setup()
{
    output.verbose(CALL_INFO, 1, 0, "Component is being setup.\n");
    systemPort->setup();
    cachePort->setup();
}

void
gem5Component::finish()
{
    output.verbose(CALL_INFO, 1, 0, "Component is being finished.\n");
}

bool
gem5Component::clockTick(SST::Cycle_t currentCycle)
{
    // what to do in a SST's cycle
    gem5::GlobalSimLoopExitEvent *event = simulateGem5(currentCycle);
    clocksProcessed++;
    // gem5 exits due to reasons other than reaching simulation limit
    if (event != gem5::simulate_limit_event) {
        output.output("exiting: curTick()=%lu cause=`%s` code=%d\n",
            gem5::curTick(), event->getCause().c_str(), event->getCode()
        );
        // output gem5 stats
        const std::vector<std::string> output_stats_commands = {
            "import m5.stats"
            "m5.stats.dump()"
        };
        execPythonCommands(output_stats_commands);

        primaryComponentOKToEndSim();
        return true;
    }

    // returning False means the simulation should go on
    return false;

}

#define PyCC(x) (const_cast<char *>(x))

gem5::GlobalSimLoopExitEvent*
gem5Component::simulateGem5(uint64_t current_cycle)
{
    // This function should be similar to simulate() of src/sim/simulate.cc
    // with synchronization barriers removed.

    inform_once("Entering event queue @ %d.  Starting simulation...\n",
                gem5::curTick());

    // Tick conversion
    // The main logic for synchronize SST Tick and gem5 Tick is here.
    // next_end_tick = current_cycle * timeConverter->getFactor()
    uint64_t next_end_tick = \
        timeConverter->convertToCoreTime(current_cycle);

    // Here, if the next event in gem5's queue is not executed within the next
    // cycle, there's no need to enter the gem5's sim loop.
    if (gem5::mainEventQueue[0]->empty() ||
        next_end_tick < gem5::mainEventQueue[0]->getHead()->when()) {
        return gem5::simulate_limit_event;
    }
    gem5::simulate_limit_event->reschedule(next_end_tick);
    gem5::Event *local_event = doSimLoop(gem5::mainEventQueue[0]);
    gem5::BaseGlobalEvent *global_event = local_event->globalEvent();
    gem5::GlobalSimLoopExitEvent *global_exit_event =
        dynamic_cast<gem5::GlobalSimLoopExitEvent *>(global_event);
    return global_exit_event;
}

gem5::Event*
gem5Component::doSimLoop(gem5::EventQueue* eventq)
{
    // This function should be similar to doSimLoop() in src/sim/simulate.cc
    // with synchronization barriers removed.
    gem5::curEventQueue(eventq);
    eventq->handleAsyncInsertions();

    while (true)
    {
        // there should always be at least one event (the SimLoopExitEvent
        // we just scheduled) in the queue

        assert(!eventq->empty());
        assert(gem5::curTick() <= eventq->nextTick() &&
               "event scheduled in the past");

        if (gem5::async_event) {
            // Take the event queue lock in case any of the service
            // routines want to schedule new events.
            if (gem5::async_statdump || gem5::async_statreset) {
                gem5::statistics::schedStatEvent(gem5::async_statdump,
                                                 gem5::async_statreset);
                gem5::async_statdump = false;
                gem5::async_statreset = false;
            }

            if (gem5::async_io) {
                gem5::async_io = false;
                gem5::pollQueue.service();
            }

            if (gem5::async_exit) {
                gem5::async_exit = false;
                gem5::exitSimLoop("user interrupt received");
            }

            if (gem5::async_exception) {
                gem5::async_exception = false;
                return NULL;
            }
        }

        gem5::Event *exit_event = eventq->serviceOne();
        if (exit_event != NULL) {
            return exit_event;
        }
    }
}

int
gem5Component::execPythonCommands(const std::vector<std::string>& commands)
{
    static PyObject *dict =
        py::module_::import("__main__").attr("__dict__").ptr();

    PyObject *result;

    for (auto const command: commands) {
        result = PyRun_String(command.c_str(), Py_file_input, dict, dict);
        if (!result) {
            PyErr_Print();
            return 1;
        }
        Py_DECREF(result);
    }
    return 0;
}

void
gem5Component::initPython(int argc, char *_argv[])
{
    // Initialize gem5 special signal handling.
    gem5::initSignals();

    if (!Py_IsInitialized())
        py::initialize_interpreter(false, argc, _argv);

    auto importer = py::module_::import("importer");
    importer.attr("install")();

    try {
        py::module_::import("m5").attr("main")();
    } catch (py::error_already_set &e) {
        if (!e.matches(PyExc_SystemExit)) {
            std::cerr << e.what();
            output.output(CALL_INFO, "Calling m5.main(...) failed.\n");
        }
    }
}

void
gem5Component::splitCommandArgs(std::string &cmd, std::vector<char*> &args)
{
    std::vector<std::string> parsed_args = tokenizeString(
        cmd, {'\\', ' ', '\'', '\"'}
    );

    for (auto part: parsed_args)
        args.push_back(strdup(part.c_str()));
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \class QPropertyAnimation
    \brief The QPropertyAnimation class animates Qt properties
    \since 4.6

    \ingroup animation

    QPropertyAnimation interpolates over \l{Qt's Property System}{Qt
    properties}. As property values are stored in \l{QVariant}s, the
    class inherits QVariantAnimation, and supports animation of the
    same \l{QVariant::Type}{variant types} as its super class.

    A class declaring properties must be a QObject. To make it
    possible to animate a property, it must provide a setter (so that
    QPropertyAnimation can set the property's value). Note that this
    makes it possible to animate many of Qt's widgets. Let's look at
    an example:

    \code
        QPropertyAnimation animation(myWidget, "geometry");
        animation.setDuration(10000);
        animation.setStartValue(QRect(0, 0, 100, 30));
        animation.setEndValue(QRect(250, 250, 100, 30));

        animation.start();
    \endcode

    The property name and the QObject instance of which property
    should be animated are passed to the constructor. You can then
    specify the start and end value of the property. The procedure is
    equal for properties in classes you have implemented
    yourself--just check with QVariantAnimation that your QVariant
    type is supported.

    The QVariantAnimation class description explains how to set up the
    animation in detail. Note, however, that if a start value is not
    set, the property will start at the value it had when the
    QPropertyAnimation instance was created.

    QPropertyAnimation works like a charm on its own. For complex
    animations that, for instance, contain several objects,
    QAnimationGroup is provided. An animation group is an animation
    that can contain other animations, and that can manage when its
    animations are played. Look at QParallelAnimationGroup for an
    example.

    \sa QVariantAnimation, QAnimationGroup, {The Animation Framework}
*/

#include "qpropertyanimation.h"
#include "qanimationgroup.h"
#include "qpropertyanimation_p.h"

#include <private/qmutexpool_p.h>

#ifndef QT_NO_ANIMATION

QT_BEGIN_NAMESPACE

void QPropertyAnimationPrivate::updateMetaProperty()
{
    if (!target || propertyName.isEmpty()) {
        propertyType = QVariant::Invalid;
        propertyIndex = -1;
        return;
    }

    //propertyType will be set to a valid type only if there is a Q_PROPERTY
    //otherwise it will be set to QVariant::Invalid at the end of this function
    propertyType = targetValue->property(propertyName).userType();
    propertyIndex = targetValue->metaObject()->indexOfProperty(propertyName);

    if (propertyType != QVariant::Invalid)
        convertValues(propertyType);
    if (propertyIndex == -1) {
        //there is no Q_PROPERTY on the object
        propertyType = QVariant::Invalid;
        if (!targetValue->dynamicPropertyNames().contains(propertyName))
            qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of your QObject", propertyName.constData());
    }
}

void QPropertyAnimationPrivate::updateProperty(const QVariant &newValue)
{
    if (state == QAbstractAnimation::Stopped)
        return;

    if (!target) {
        q_func()->stop(); //the target was destroyed we need to stop the animation
        return;
    }

    if (newValue.userType() == propertyType) {
        //no conversion is needed, we directly call the QObject::qt_metacall
        void *data = const_cast<void*>(newValue.constData());
        targetValue->qt_metacall(QMetaObject::WriteProperty, propertyIndex, &data);
    } else {
        targetValue->setProperty(propertyName.constData(), newValue);
    }
}

/*!
    Construct a QPropertyAnimation object. \a parent is passed to QObject's
    constructor.
*/
QPropertyAnimation::QPropertyAnimation(QObject *parent)
    : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
{
}

/*!
    Construct a QPropertyAnimation object. \a parent is passed to QObject's
    constructor. The animation changes the property \a propertyName on \a
    target. The default duration is 250ms.

    \sa targetObject, propertyName
*/
QPropertyAnimation::QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent)
    : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
{
    setTargetObject(target);
    setPropertyName(propertyName);
}

/*!
    Destroys the QPropertyAnimation instance.
 */
QPropertyAnimation::~QPropertyAnimation()
{
    stop();
}

/*!
    \property QPropertyAnimation::targetObject
    \brief the target QObject for this animation.

    This property defines the target QObject for this animation.
 */
QObject *QPropertyAnimation::targetObject() const
{
    return d_func()->target.data();
}

void QPropertyAnimation::setTargetObject(QObject *target)
{
    Q_D(QPropertyAnimation);
    if (d->targetValue == target)
        return;

    if (d->state != QAbstractAnimation::Stopped) {
        qWarning("QPropertyAnimation::setTargetObject: you can't change the target of a running animation");
        return;
    }

    d->target = d->targetValue = target;
    d->updateMetaProperty();
}

/*!
    \property QPropertyAnimation::propertyName
    \brief the target property name for this animation

    This property defines the target property name for this animation. The
    property name is required for the animation to operate.
 */
QByteArray QPropertyAnimation::propertyName() const
{
    Q_D(const QPropertyAnimation);
    return d->propertyName;
}

void QPropertyAnimation::setPropertyName(const QByteArray &propertyName)
{
    Q_D(QPropertyAnimation);
    if (d->state != QAbstractAnimation::Stopped) {
        qWarning("QPropertyAnimation::setPropertyName: you can't change the property name of a running animation");
        return;
    }

    d->propertyName = propertyName;
    d->updateMetaProperty();
}

/*!
    \reimp
 */
bool QPropertyAnimation::event(QEvent *event)
{
    return QVariantAnimation::event(event);
}

/*!
    This virtual function is called by QVariantAnimation whenever the current value
    changes. \a value is the new, updated value. It updates the current value
    of the property on the target object.

    \sa currentValue, currentTime
 */
void QPropertyAnimation::updateCurrentValue(const QVariant &value)
{
    Q_D(QPropertyAnimation);
    d->updateProperty(value);
}

/*!
    \reimp

    If the startValue is not defined when the state of the animation changes from Stopped to Running,
    the current property value is used as the initial value for the animation.
*/
void QPropertyAnimation::updateState(QAbstractAnimation::State oldState,
                                     QAbstractAnimation::State newState)
{
    Q_D(QPropertyAnimation);

    if (!d->target && oldState == Stopped) {
        qWarning("QPropertyAnimation::updateState: Changing state of an animation without target");
        return;
    }

    QVariantAnimation::updateState(oldState, newState);

    QPropertyAnimation *animToStop = 0;
    {
        QMutexLocker locker(QMutexPool::globalInstanceGet(&staticMetaObject));
        typedef QPair<QObject *, QByteArray> QPropertyAnimationPair;
        typedef QHash<QPropertyAnimationPair, QPropertyAnimation*> QPropertyAnimationHash;
        static QPropertyAnimationHash hash;
        //here we need to use value because we need to know to which pointer
        //the animation was referring in case stopped because the target was destroyed
        QPropertyAnimationPair key(d->targetValue, d->propertyName);
        if (newState == Running) {
            d->updateMetaProperty();
            animToStop = hash.value(key, 0);
            hash.insert(key, this);
            // update the default start value
            if (oldState == Stopped) {
                d->setDefaultStartEndValue(d->targetValue->property(d->propertyName.constData()));
                //let's check if we have a start value and an end value
                if (!startValue().isValid() && (d->direction == Backward || !d->defaultStartEndValue.isValid()))
                    qWarning("QPropertyAnimation::updateState: starting an animation without start value");
                if (!endValue().isValid() && (d->direction == Forward || !d->defaultStartEndValue.isValid()))
                    qWarning("QPropertyAnimation::updateState: starting an animation without end value");
            }
        } else if (hash.value(key) == this) {
            hash.remove(key);
        }
    }

    //we need to do that after the mutex was unlocked
    if (animToStop) {
        // try to stop the top level group
        QAbstractAnimation *current = animToStop;
        while (current->group() && current->state() != Stopped)
            current = current->group();
        current->stop();
    }
}

#include "moc_qpropertyanimation.cpp"

QT_END_NAMESPACE

#endif //QT_NO_ANIMATION
<commit_msg>QPropertyAnimation now uses QMetaObject::metacall instead of qt_metacall<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \class QPropertyAnimation
    \brief The QPropertyAnimation class animates Qt properties
    \since 4.6

    \ingroup animation

    QPropertyAnimation interpolates over \l{Qt's Property System}{Qt
    properties}. As property values are stored in \l{QVariant}s, the
    class inherits QVariantAnimation, and supports animation of the
    same \l{QVariant::Type}{variant types} as its super class.

    A class declaring properties must be a QObject. To make it
    possible to animate a property, it must provide a setter (so that
    QPropertyAnimation can set the property's value). Note that this
    makes it possible to animate many of Qt's widgets. Let's look at
    an example:

    \code
        QPropertyAnimation animation(myWidget, "geometry");
        animation.setDuration(10000);
        animation.setStartValue(QRect(0, 0, 100, 30));
        animation.setEndValue(QRect(250, 250, 100, 30));

        animation.start();
    \endcode

    The property name and the QObject instance of which property
    should be animated are passed to the constructor. You can then
    specify the start and end value of the property. The procedure is
    equal for properties in classes you have implemented
    yourself--just check with QVariantAnimation that your QVariant
    type is supported.

    The QVariantAnimation class description explains how to set up the
    animation in detail. Note, however, that if a start value is not
    set, the property will start at the value it had when the
    QPropertyAnimation instance was created.

    QPropertyAnimation works like a charm on its own. For complex
    animations that, for instance, contain several objects,
    QAnimationGroup is provided. An animation group is an animation
    that can contain other animations, and that can manage when its
    animations are played. Look at QParallelAnimationGroup for an
    example.

    \sa QVariantAnimation, QAnimationGroup, {The Animation Framework}
*/

#include "qpropertyanimation.h"
#include "qanimationgroup.h"
#include "qpropertyanimation_p.h"

#include <private/qmutexpool_p.h>

#ifndef QT_NO_ANIMATION

QT_BEGIN_NAMESPACE

void QPropertyAnimationPrivate::updateMetaProperty()
{
    if (!target || propertyName.isEmpty()) {
        propertyType = QVariant::Invalid;
        propertyIndex = -1;
        return;
    }

    //propertyType will be set to a valid type only if there is a Q_PROPERTY
    //otherwise it will be set to QVariant::Invalid at the end of this function
    propertyType = targetValue->property(propertyName).userType();
    propertyIndex = targetValue->metaObject()->indexOfProperty(propertyName);

    if (propertyType != QVariant::Invalid)
        convertValues(propertyType);
    if (propertyIndex == -1) {
        //there is no Q_PROPERTY on the object
        propertyType = QVariant::Invalid;
        if (!targetValue->dynamicPropertyNames().contains(propertyName))
            qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of your QObject", propertyName.constData());
    }
}

void QPropertyAnimationPrivate::updateProperty(const QVariant &newValue)
{
    if (state == QAbstractAnimation::Stopped)
        return;

    if (!target) {
        q_func()->stop(); //the target was destroyed we need to stop the animation
        return;
    }

    if (newValue.userType() == propertyType) {
        //no conversion is needed, we directly call the QMetaObject::metacall
        void *data = const_cast<void*>(newValue.constData());
        QMetaObject::metacall(targetValue, QMetaObject::WriteProperty, propertyIndex, &data);
    } else {
        targetValue->setProperty(propertyName.constData(), newValue);
    }
}

/*!
    Construct a QPropertyAnimation object. \a parent is passed to QObject's
    constructor.
*/
QPropertyAnimation::QPropertyAnimation(QObject *parent)
    : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
{
}

/*!
    Construct a QPropertyAnimation object. \a parent is passed to QObject's
    constructor. The animation changes the property \a propertyName on \a
    target. The default duration is 250ms.

    \sa targetObject, propertyName
*/
QPropertyAnimation::QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent)
    : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
{
    setTargetObject(target);
    setPropertyName(propertyName);
}

/*!
    Destroys the QPropertyAnimation instance.
 */
QPropertyAnimation::~QPropertyAnimation()
{
    stop();
}

/*!
    \property QPropertyAnimation::targetObject
    \brief the target QObject for this animation.

    This property defines the target QObject for this animation.
 */
QObject *QPropertyAnimation::targetObject() const
{
    return d_func()->target.data();
}

void QPropertyAnimation::setTargetObject(QObject *target)
{
    Q_D(QPropertyAnimation);
    if (d->targetValue == target)
        return;

    if (d->state != QAbstractAnimation::Stopped) {
        qWarning("QPropertyAnimation::setTargetObject: you can't change the target of a running animation");
        return;
    }

    d->target = d->targetValue = target;
    d->updateMetaProperty();
}

/*!
    \property QPropertyAnimation::propertyName
    \brief the target property name for this animation

    This property defines the target property name for this animation. The
    property name is required for the animation to operate.
 */
QByteArray QPropertyAnimation::propertyName() const
{
    Q_D(const QPropertyAnimation);
    return d->propertyName;
}

void QPropertyAnimation::setPropertyName(const QByteArray &propertyName)
{
    Q_D(QPropertyAnimation);
    if (d->state != QAbstractAnimation::Stopped) {
        qWarning("QPropertyAnimation::setPropertyName: you can't change the property name of a running animation");
        return;
    }

    d->propertyName = propertyName;
    d->updateMetaProperty();
}

/*!
    \reimp
 */
bool QPropertyAnimation::event(QEvent *event)
{
    return QVariantAnimation::event(event);
}

/*!
    This virtual function is called by QVariantAnimation whenever the current value
    changes. \a value is the new, updated value. It updates the current value
    of the property on the target object.

    \sa currentValue, currentTime
 */
void QPropertyAnimation::updateCurrentValue(const QVariant &value)
{
    Q_D(QPropertyAnimation);
    d->updateProperty(value);
}

/*!
    \reimp

    If the startValue is not defined when the state of the animation changes from Stopped to Running,
    the current property value is used as the initial value for the animation.
*/
void QPropertyAnimation::updateState(QAbstractAnimation::State oldState,
                                     QAbstractAnimation::State newState)
{
    Q_D(QPropertyAnimation);

    if (!d->target && oldState == Stopped) {
        qWarning("QPropertyAnimation::updateState: Changing state of an animation without target");
        return;
    }

    QVariantAnimation::updateState(oldState, newState);

    QPropertyAnimation *animToStop = 0;
    {
        QMutexLocker locker(QMutexPool::globalInstanceGet(&staticMetaObject));
        typedef QPair<QObject *, QByteArray> QPropertyAnimationPair;
        typedef QHash<QPropertyAnimationPair, QPropertyAnimation*> QPropertyAnimationHash;
        static QPropertyAnimationHash hash;
        //here we need to use value because we need to know to which pointer
        //the animation was referring in case stopped because the target was destroyed
        QPropertyAnimationPair key(d->targetValue, d->propertyName);
        if (newState == Running) {
            d->updateMetaProperty();
            animToStop = hash.value(key, 0);
            hash.insert(key, this);
            // update the default start value
            if (oldState == Stopped) {
                d->setDefaultStartEndValue(d->targetValue->property(d->propertyName.constData()));
                //let's check if we have a start value and an end value
                if (!startValue().isValid() && (d->direction == Backward || !d->defaultStartEndValue.isValid()))
                    qWarning("QPropertyAnimation::updateState: starting an animation without start value");
                if (!endValue().isValid() && (d->direction == Forward || !d->defaultStartEndValue.isValid()))
                    qWarning("QPropertyAnimation::updateState: starting an animation without end value");
            }
        } else if (hash.value(key) == this) {
            hash.remove(key);
        }
    }

    //we need to do that after the mutex was unlocked
    if (animToStop) {
        // try to stop the top level group
        QAbstractAnimation *current = animToStop;
        while (current->group() && current->state() != Stopped)
            current = current->group();
        current->stop();
    }
}

#include "moc_qpropertyanimation.cpp"

QT_END_NAMESPACE

#endif //QT_NO_ANIMATION
<|endoftext|>


<commit_before>//===-- asan_asm_test.cc --------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
//===----------------------------------------------------------------------===//
#include "asan_test_utils.h"

#if defined(__linux__)

// Assembly instrumentation is broken on x86 Android (x86 + PIC + shared runtime
// library). See https://github.com/google/sanitizers/issues/353
#if defined(__x86_64__) ||                                                     \
    (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))

#include <emmintrin.h>

namespace {

template<typename T> void asm_write(T *ptr, T val);
template<typename T> T asm_read(T *ptr);
template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);

} // End of anonymous namespace

#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))

#if defined(__x86_64__)

namespace {

#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg)        \
template<> void asm_write<Type>(Type *ptr, Type val) { \
  __asm__(                                             \
    Mov " %[val], (%[ptr])  \n\t"                      \
    :                                                  \
    : [ptr] "r" (ptr), [val] Reg (val)                 \
    : "memory"                                         \
  );                                                   \
}

#define DECLARE_ASM_READ(Type, Size, Mov, Reg)     \
template<> Type asm_read<Type>(Type *ptr) {        \
  Type res;                                        \
  __asm__(                                         \
    Mov " (%[ptr]), %[res]  \n\t"                  \
    : [res] Reg (res)                              \
    : [ptr] "r" (ptr)                              \
    : "memory"                                     \
  );                                               \
  return res;                                      \
}

#define DECLARE_ASM_REP_MOVS(Type, Movs)                                       \
  template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) {   \
    __asm__("rep " Movs " \n\t"                                                \
            :                                                                  \
            : "D"(dst), "S"(src), "c"(size)                                    \
            : "memory");                                  \
  }

DECLARE_ASM_WRITE(U8, "8", "movq", "r");
DECLARE_ASM_READ(U8, "8", "movq", "=r");
DECLARE_ASM_REP_MOVS(U8, "movsq");

} // End of anonymous namespace

#endif // defined(__x86_64__)

#if defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__)

namespace {

#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg)        \
template<> void asm_write<Type>(Type *ptr, Type val) { \
  __asm__(                                             \
    Mov " %[val], (%[ptr])  \n\t"                      \
    :                                                  \
    : [ptr] "r" (ptr), [val] Reg (val)                 \
    : "memory"                                         \
  );                                                   \
}

#define DECLARE_ASM_READ(Type, Size, Mov, Reg)     \
template<> Type asm_read<Type>(Type *ptr) {        \
  Type res;                                        \
  __asm__(                                         \
    Mov " (%[ptr]), %[res]  \n\t"                  \
    : [res] Reg (res)                              \
    : [ptr] "r" (ptr)                              \
    : "memory"                                     \
  );                                               \
  return res;                                      \
}

#define DECLARE_ASM_REP_MOVS(Type, Movs)                                       \
  template <> void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) {   \
    __asm__("rep " Movs " \n\t"                                                \
            :                                                                  \
            : "D"(dst), "S"(src), "c"(size)                                    \
            : "memory");                                  \
  }

} // End of anonymous namespace

#endif  // defined(__i386__) && defined(__SSE2__)

#if defined(__x86_64__) ||                                                     \
    (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))

namespace {

DECLARE_ASM_WRITE(U1, "1", "movb", "r");
DECLARE_ASM_WRITE(U2, "2", "movw", "r");
DECLARE_ASM_WRITE(U4, "4", "movl", "r");
DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x");

DECLARE_ASM_READ(U1, "1", "movb", "=r");
DECLARE_ASM_READ(U2, "2", "movw", "=r");
DECLARE_ASM_READ(U4, "4", "movl", "=r");
DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");

DECLARE_ASM_REP_MOVS(U1, "movsb");
DECLARE_ASM_REP_MOVS(U2, "movsw");
DECLARE_ASM_REP_MOVS(U4, "movsl");

template<typename T> void TestAsmWrite(const char *DeathPattern) {
  T *buf = new T;
  EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
  T var = 0x12;
  asm_write(&var, static_cast<T>(0x21));
  ASSERT_EQ(static_cast<T>(0x21), var);
  delete buf;
}

template<> void TestAsmWrite<__m128i>(const char *DeathPattern) {
  char *buf = new char[16];
  char *p = buf + 16;
  if (((uintptr_t) p % 16) != 0)
    p = buf + 8;
  assert(((uintptr_t) p % 16) == 0);
  __m128i val = _mm_set1_epi16(0x1234);
  EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern);
  __m128i var = _mm_set1_epi16(0x4321);
  asm_write(&var, val);
  ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0));
  delete [] buf;
}

template<typename T> void TestAsmRead(const char *DeathPattern) {
  T *buf = new T;
  EXPECT_DEATH(asm_read(&buf[1]), DeathPattern);
  T var = 0x12;
  ASSERT_EQ(static_cast<T>(0x12), asm_read(&var));
  delete buf;
}

template<> void TestAsmRead<__m128i>(const char *DeathPattern) {
  char *buf = new char[16];
  char *p = buf + 16;
  if (((uintptr_t) p % 16) != 0)
    p = buf + 8;
  assert(((uintptr_t) p % 16) == 0);
  EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern);
  __m128i val = _mm_set1_epi16(0x1234);
  ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0));
  delete [] buf;
}

U4 AsmLoad(U4 *a) {
  U4 r;
  __asm__("movl (%[a]), %[r]  \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory");
  return r;
}

void AsmStore(U4 r, U4 *a) {
  __asm__("movl %[r], (%[a])  \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
}

template <typename T>
void TestAsmRepMovs(const char *DeathPatternRead,
                    const char *DeathPatternWrite) {
  T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
  T dst_good[4] = {};
  asm_rep_movs(dst_good, src_good, 4);
  ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
  ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
  ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
  ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);

  T dst_bad[3];
  EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);

  T src_bad[3] = { 0x0, 0x1, 0x2 };
  EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);

  T* dp = dst_bad + 4;
  T* sp = src_bad + 4;
  asm_rep_movs(dp, sp, 0);
}

} // End of anonymous namespace

TEST(AddressSanitizer, asm_load_store) {
  U4* buf = new U4[2];
  EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4");
  EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4");
  delete [] buf;
}

TEST(AddressSanitizer, asm_rw) {
  TestAsmWrite<U1>("WRITE of size 1");
  TestAsmWrite<U2>("WRITE of size 2");
  TestAsmWrite<U4>("WRITE of size 4");
#if defined(__x86_64__)
  TestAsmWrite<U8>("WRITE of size 8");
#endif // defined(__x86_64__)
  TestAsmWrite<__m128i>("WRITE of size 16");

  TestAsmRead<U1>("READ of size 1");
  TestAsmRead<U2>("READ of size 2");
  TestAsmRead<U4>("READ of size 4");
#if defined(__x86_64__)
  TestAsmRead<U8>("READ of size 8");
#endif // defined(__x86_64__)
  TestAsmRead<__m128i>("READ of size 16");
}

TEST(AddressSanitizer, asm_flags) {
  long magic = 0x1234;
  long r = 0x0;

#if defined(__x86_64__) && !defined(__ILP32__)
  __asm__("xorq %%rax, %%rax  \n\t"
          "movq (%[p]), %%rax \n\t"
          "sete %%al          \n\t"
          "movzbq %%al, %[r]  \n\t"
          : [r] "=r"(r)
          : [p] "r"(&magic)
          : "rax", "memory");
#else
  __asm__("xorl %%eax, %%eax  \n\t"
          "movl (%[p]), %%eax \n\t"
          "sete %%al          \n\t"
          "movzbl %%al, %[r]  \n\t"
          : [r] "=r"(r)
          : [p] "r"(&magic)
          : "eax", "memory");
#endif // defined(__x86_64__) && !defined(__ILP32__)

  ASSERT_EQ(0x1, r);
}

TEST(AddressSanitizer, asm_rep_movs) {
  TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
  TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
  TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
#if defined(__x86_64__)
  TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
#endif  // defined(__x86_64__)
}

#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))

#endif // defined(__linux__)
<commit_msg>[asan] Fix test broken by r290540<commit_after>//===-- asan_asm_test.cc --------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
//===----------------------------------------------------------------------===//
#include "asan_test_utils.h"

#if defined(__linux__)

// Assembly instrumentation is broken on x86 Android (x86 + PIC + shared runtime
// library). See https://github.com/google/sanitizers/issues/353
#if defined(__x86_64__) ||                                                     \
    (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))

#include <emmintrin.h>

namespace {

template<typename T> void asm_write(T *ptr, T val);
template<typename T> T asm_read(T *ptr);
template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);

} // End of anonymous namespace

#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))

#if defined(__x86_64__)

namespace {

#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg)        \
template<> void asm_write<Type>(Type *ptr, Type val) { \
  __asm__(                                             \
    Mov " %[val], (%[ptr])  \n\t"                      \
    :                                                  \
    : [ptr] "r" (ptr), [val] Reg (val)                 \
    : "memory"                                         \
  );                                                   \
}

#define DECLARE_ASM_READ(Type, Size, Mov, Reg)     \
template<> Type asm_read<Type>(Type *ptr) {        \
  Type res;                                        \
  __asm__(                                         \
    Mov " (%[ptr]), %[res]  \n\t"                  \
    : [res] Reg (res)                              \
    : [ptr] "r" (ptr)                              \
    : "memory"                                     \
  );                                               \
  return res;                                      \
}

#define DECLARE_ASM_REP_MOVS(Type, Movs)                         \
  template <>                                                    \
  void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
    __asm__("rep " Movs " \n\t"                                  \
            : "+D"(dst), "+S"(src), "+c"(size)                   \
            :                                                    \
            : "memory");                                         \
  }

DECLARE_ASM_WRITE(U8, "8", "movq", "r");
DECLARE_ASM_READ(U8, "8", "movq", "=r");
DECLARE_ASM_REP_MOVS(U8, "movsq");

} // End of anonymous namespace

#endif // defined(__x86_64__)

#if defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__)

namespace {

#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg)        \
template<> void asm_write<Type>(Type *ptr, Type val) { \
  __asm__(                                             \
    Mov " %[val], (%[ptr])  \n\t"                      \
    :                                                  \
    : [ptr] "r" (ptr), [val] Reg (val)                 \
    : "memory"                                         \
  );                                                   \
}

#define DECLARE_ASM_READ(Type, Size, Mov, Reg)     \
template<> Type asm_read<Type>(Type *ptr) {        \
  Type res;                                        \
  __asm__(                                         \
    Mov " (%[ptr]), %[res]  \n\t"                  \
    : [res] Reg (res)                              \
    : [ptr] "r" (ptr)                              \
    : "memory"                                     \
  );                                               \
  return res;                                      \
}

#define DECLARE_ASM_REP_MOVS(Type, Movs)                         \
  template <>                                                    \
  void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
    __asm__("rep " Movs " \n\t"                                  \
            : "+D"(dst), "+S"(src), "+c"(size)                   \
            :                                                    \
            : "memory");                                         \
  }

} // End of anonymous namespace

#endif  // defined(__i386__) && defined(__SSE2__)

#if defined(__x86_64__) ||                                                     \
    (defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))

namespace {

DECLARE_ASM_WRITE(U1, "1", "movb", "r");
DECLARE_ASM_WRITE(U2, "2", "movw", "r");
DECLARE_ASM_WRITE(U4, "4", "movl", "r");
DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x");

DECLARE_ASM_READ(U1, "1", "movb", "=r");
DECLARE_ASM_READ(U2, "2", "movw", "=r");
DECLARE_ASM_READ(U4, "4", "movl", "=r");
DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");

DECLARE_ASM_REP_MOVS(U1, "movsb");
DECLARE_ASM_REP_MOVS(U2, "movsw");
DECLARE_ASM_REP_MOVS(U4, "movsl");

template<typename T> void TestAsmWrite(const char *DeathPattern) {
  T *buf = new T;
  EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
  T var = 0x12;
  asm_write(&var, static_cast<T>(0x21));
  ASSERT_EQ(static_cast<T>(0x21), var);
  delete buf;
}

template<> void TestAsmWrite<__m128i>(const char *DeathPattern) {
  char *buf = new char[16];
  char *p = buf + 16;
  if (((uintptr_t) p % 16) != 0)
    p = buf + 8;
  assert(((uintptr_t) p % 16) == 0);
  __m128i val = _mm_set1_epi16(0x1234);
  EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern);
  __m128i var = _mm_set1_epi16(0x4321);
  asm_write(&var, val);
  ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0));
  delete [] buf;
}

template<typename T> void TestAsmRead(const char *DeathPattern) {
  T *buf = new T;
  EXPECT_DEATH(asm_read(&buf[1]), DeathPattern);
  T var = 0x12;
  ASSERT_EQ(static_cast<T>(0x12), asm_read(&var));
  delete buf;
}

template<> void TestAsmRead<__m128i>(const char *DeathPattern) {
  char *buf = new char[16];
  char *p = buf + 16;
  if (((uintptr_t) p % 16) != 0)
    p = buf + 8;
  assert(((uintptr_t) p % 16) == 0);
  EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern);
  __m128i val = _mm_set1_epi16(0x1234);
  ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0));
  delete [] buf;
}

U4 AsmLoad(U4 *a) {
  U4 r;
  __asm__("movl (%[a]), %[r]  \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory");
  return r;
}

void AsmStore(U4 r, U4 *a) {
  __asm__("movl %[r], (%[a])  \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
}

template <typename T>
void TestAsmRepMovs(const char *DeathPatternRead,
                    const char *DeathPatternWrite) {
  T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
  T dst_good[4] = {};
  asm_rep_movs(dst_good, src_good, 4);
  ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
  ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
  ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
  ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);

  T dst_bad[3];
  EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);

  T src_bad[3] = { 0x0, 0x1, 0x2 };
  EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);

  T* dp = dst_bad + 4;
  T* sp = src_bad + 4;
  asm_rep_movs(dp, sp, 0);
}

} // End of anonymous namespace

TEST(AddressSanitizer, asm_load_store) {
  U4* buf = new U4[2];
  EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4");
  EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4");
  delete [] buf;
}

TEST(AddressSanitizer, asm_rw) {
  TestAsmWrite<U1>("WRITE of size 1");
  TestAsmWrite<U2>("WRITE of size 2");
  TestAsmWrite<U4>("WRITE of size 4");
#if defined(__x86_64__)
  TestAsmWrite<U8>("WRITE of size 8");
#endif // defined(__x86_64__)
  TestAsmWrite<__m128i>("WRITE of size 16");

  TestAsmRead<U1>("READ of size 1");
  TestAsmRead<U2>("READ of size 2");
  TestAsmRead<U4>("READ of size 4");
#if defined(__x86_64__)
  TestAsmRead<U8>("READ of size 8");
#endif // defined(__x86_64__)
  TestAsmRead<__m128i>("READ of size 16");
}

TEST(AddressSanitizer, asm_flags) {
  long magic = 0x1234;
  long r = 0x0;

#if defined(__x86_64__) && !defined(__ILP32__)
  __asm__("xorq %%rax, %%rax  \n\t"
          "movq (%[p]), %%rax \n\t"
          "sete %%al          \n\t"
          "movzbq %%al, %[r]  \n\t"
          : [r] "=r"(r)
          : [p] "r"(&magic)
          : "rax", "memory");
#else
  __asm__("xorl %%eax, %%eax  \n\t"
          "movl (%[p]), %%eax \n\t"
          "sete %%al          \n\t"
          "movzbl %%al, %[r]  \n\t"
          : [r] "=r"(r)
          : [p] "r"(&magic)
          : "eax", "memory");
#endif // defined(__x86_64__) && !defined(__ILP32__)

  ASSERT_EQ(0x1, r);
}

TEST(AddressSanitizer, asm_rep_movs) {
  TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
  TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
  TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
#if defined(__x86_64__)
  TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
#endif  // defined(__x86_64__)
}

#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))

#endif // defined(__linux__)
<|endoftext|>


<commit_before>/*
* Copyright © 2012, United States Government, as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All rights reserved.
*
* The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is 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.
*/
/**
* @file AppObstacleTest.cpp
* @brief Contains the definition function main() for testing new obstacles
* @author Brian Mirletz
* $Id$
*/
// This application
#include "tgBlockField.h"
#include "tgStairs.h"
// This library
#include "core/terrain/tgBoxGround.h"
#include "core/terrain/tgEmptyGround.h"
#include "core/terrain/tgHillyGround.h"
#include "core/tgModel.h"
#include "core/tgSimViewGraphics.h"
#include "core/tgSimulation.h"
#include "core/tgWorld.h"
#include "tgcreator/tgUtil.h"

// The Bullet Physics Library
#include "LinearMath/btVector3.h"
#include "LinearMath/btQuaternion.h"
// The C++ Standard Library
#include <iostream>
/**
* The entry point.
* @param[in] argc the number of command-line arguments
* @param[in] argv argv[0] is the executable name
* @return 0
*/
int main(int argc, char** argv)
{

	std::cout << "AppObstacleTest" << std::endl;

	// First create the ground and world. Specify ground rotation in radians
	const double yaw = 0.0;
	const double pitch = 0.0;
	const double roll = 0.0;
	const tgBoxGround::Config groundConfig(btVector3(yaw, pitch, roll));

	// the world will delete this
	tgBoxGround* ground = new tgBoxGround(groundConfig);

    btVector3 eulerAngles = btVector3(0.0, 0.0, 0.0);
   btScalar friction = 0.5;
   btScalar restitution = 0.0;
   // Size doesn't affect hilly terrain
   btVector3 size = btVector3(0.0, 0.1, 0.0);
   btVector3 origin = btVector3(0.0, 0.0, 0.0);
   size_t nx = 100;
   size_t ny = 100;
   double margin = 0.5;
   double triangleSize = 5.0;
   double waveHeight = 3.0;
   double offset = 0.0;
    tgHillyGround::Config hillGroundConfig(eulerAngles, friction, restitution,
                                    size, origin, nx, ny, margin, triangleSize,
                                    waveHeight, offset);

	const tgWorld::Config config(98.1); // gravity, cm/sec^2
	tgWorld world(config, ground);

	// Second create the view
	const double timestep_physics = 1.0/1000.0; // seconds
	const double timestep_graphics = 1.f/60.f; // seconds
	tgSimViewGraphics view(world, timestep_physics, timestep_graphics);

	// Third create the simulation
	tgSimulation simulation(view);

    btVector3 position(0.0, 0.0, 0.0);

	// Fourth create the models with their controllers and add the models to the
	// simulation
    tgBlockField* myObstacle = new tgBlockField();
    // Add the model to the world
    simulation.addModel(myObstacle);

	tgStairs* bigStairs = new tgStairs();
	// Add the stairs to the world
	simulation.addModel(bigStairs);

    for (int i = 0; i < 3; i++)
    {

        simulation.run(10);

        if (i %2 == 0)
        {
            // World will delete prior pointer, so make a new one each time
            tgHillyGround* hillGround = new tgHillyGround(hillGroundConfig);
            world.reset(hillGround);
        }
        else
        {
            ground = new tgBoxGround(groundConfig);
            world.reset(ground);
        }

        simulation.reset();

    }
	return 0;
}
<commit_msg>Example of obstacle use<commit_after>/*
* Copyright © 2012, United States Government, as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All rights reserved.
*
* The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is 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.
*/
/**
* @file AppObstacleTest.cpp
* @brief Contains the definition function main() for testing new obstacles
* @author Brian Mirletz
* $Id$
*/
// This application
#include "tgBlockField.h"
#include "tgStairs.h"
// This library
#include "core/terrain/tgBoxGround.h"
#include "core/terrain/tgEmptyGround.h"
#include "core/terrain/tgHillyGround.h"
#include "core/tgModel.h"
#include "core/tgSimViewGraphics.h"
#include "core/tgSimulation.h"
#include "core/tgWorld.h"
#include "tgcreator/tgUtil.h"

// The Bullet Physics Library
#include "LinearMath/btVector3.h"
#include "LinearMath/btQuaternion.h"
// The C++ Standard Library
#include <iostream>
/**
* The entry point.
* @param[in] argc the number of command-line arguments
* @param[in] argv argv[0] is the executable name
* @return 0
*/
int main(int argc, char** argv)
{

	std::cout << "AppObstacleTest" << std::endl;

	// First create the ground and world. Specify ground rotation in radians
	const double yaw = 0.0;
	const double pitch = 0.0;
	const double roll = 0.0;
	const tgBoxGround::Config groundConfig(btVector3(yaw, pitch, roll));

	// the world will delete this
	tgBoxGround* ground = new tgBoxGround(groundConfig);

    btVector3 eulerAngles = btVector3(0.0, 0.0, 0.0);
   btScalar friction = 0.5;
   btScalar restitution = 0.0;
   // Size doesn't affect hilly terrain
   btVector3 size = btVector3(0.0, 0.1, 0.0);
   btVector3 origin = btVector3(0.0, 0.0, 0.0);
   size_t nx = 100;
   size_t ny = 100;
   double margin = 0.5;
   double triangleSize = 5.0;
   double waveHeight = 3.0;
   double offset = 0.0;
    tgHillyGround::Config hillGroundConfig(eulerAngles, friction, restitution,
                                    size, origin, nx, ny, margin, triangleSize,
                                    waveHeight, offset);

	const tgWorld::Config config(98.1); // gravity, cm/sec^2
	tgWorld world(config, ground);

	// Second create the view
	const double timestep_physics = 1.0/1000.0; // seconds
	const double timestep_graphics = 1.f/60.f; // seconds
	tgSimViewGraphics view(world, timestep_physics, timestep_graphics);

	// Third create the simulation
	tgSimulation simulation(view);

    btVector3 position(0.0, 0.0, 0.0);

	// Fourth create the models with their controllers and add the models to the
	// simulation
    tgBlockField* myObstacle = new tgBlockField();
    // Add the model to the world
    simulation.addModel(myObstacle);

	tgStairs* bigStairs = new tgStairs();
	// Add the stairs to the world
	simulation.addObstacle(bigStairs);

    for (int i = 0; i < 3; i++)
    {

        simulation.run(10);

        if (i %2 == 0)
        {
            // World will delete prior pointer, so make a new one each time
            tgHillyGround* hillGround = new tgHillyGround(hillGroundConfig);
            world.reset(hillGround);
        }
        else
        {
            ground = new tgBoxGround(groundConfig);
            world.reset(ground);
        }

        simulation.reset();

    }
	return 0;
}
<|endoftext|>