<commit_before>/*
 * Stateplex - A server-side actor model library.
 *
 * core/dispatcher.cpp
 *
 * (c) 2013 Henrik Hedberg <henrik.hedberg@innologies.fi>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * Authors: Henrik Hedberg
 */

#include <sys/time.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <stdio.h>

#include "dispatcher.h"
#include "actor.h"
#include "allocator.h"

/* TODO: Parametrise this */
#define MAX_EVENTS 10

namespace Stateplex {

Spinlock Dispatcher::sDispatchLock;
Allocator *Dispatcher::sRecycledAllocator;
__thread Dispatcher *Dispatcher::sCurrentDispatcher;

/**
 * Default constructor for dispatcher.
 * Also creates the epoll file discriptor.
 */

Dispatcher::Dispatcher()
	: mRunning(true), mMilliseconds(0)
{
	if (sCurrentDispatcher)
		abort();
	sCurrentDispatcher = this;

	mEpollFd = epoll_create(1024);
	mAllocator = new Allocator();

	sDispatchLock.lock();
	if (!sRecycledAllocator)
		sRecycledAllocator = new Allocator();
	sDispatchLock.unlock();
}

void Dispatcher::activateActor(Actor *actor)
{
	if (!actor->mActive) {
		mActiveActors.addTail(actor);
		actor->mActive = 1;
	}
}

/**
 * Function that dispatch incoming and outgoing messages with the lock hold,handles time out for active actors.
 * Dispatch outgoing messages with the lock hold
 * Dispatch incoming messages with the lock hold
 * Release the lock if it was acquired in dispatching
 * Handle timeouts for waiting actors
 * Handle active actors i.e. actors that have incoming messages
 */

void Dispatcher::run()
{
	bool locked;
	struct epoll_event events[MAX_EVENTS];
	int n_events;
	struct timeval tv;
	List<Actor> actors;
	int timeout;

	while (mRunning) {
		locked = false;
		actors.spliceTail(&mActiveActors);

		/* Dispatch outgoing messages with the lock hold */
		if (!mOutgoingMessages.isEmpty()) {
			sDispatchLock.lock();
			locked = true;
			for (ListIterator<Message> iterator(&mOutgoingMessages); iterator.hasCurrent(); iterator.subsequent()) {
				Message *message = iterator.current();
				Actor *receiver = message->mReceiver;
				receiver->mQueuedMessages.addTail(message);
				activateActor(receiver);
			}
		}

		/* Dispatch incoming messages with the lock hold */
		if (!actors.isEmpty()) {
			if (!locked) {
				sDispatchLock.lock();
				locked = true;
			}
			for (ListIterator<Actor> iterator(&actors); iterator.hasCurrent(); iterator.subsequent()) {
				Actor *actor = iterator.current();
				actor->mIncomingMessages.spliceTail(&actor->mQueuedMessages);
			}
		}

		/* Recycle allocators and release the lock if the lock was acquired in dispatching */
		if (locked) {
			Allocator *allocator = sRecycledAllocator;
			sRecycledAllocator = mAllocator;
			mAllocator = allocator;

			sDispatchLock.unlock();
		}

		/* Start a new cycle */
		gettimeofday(&tv, 0);
		mMilliseconds = tv.tv_sec * 1000 + tv.tv_usec / 1000;

		/* Do not block, if there are active actors, check when the next waiting actor timeouts, or wait indefinitely */
		if (!actors.isEmpty())
			timeout = 0;
		else if(!mWaitingActors.isEmpty()) {
			timeout = mWaitingActors.first()->nextTimeoutMilliseconds() - mMilliseconds;
			if (timeout < 0)
				timeout = 0;
		} else
			timeout = -1;

		/* Receive external events i.e. poll sources */
		n_events = epoll_wait(mEpollFd, events, MAX_EVENTS, timeout);
		if (n_events == -1) {
			perror("epoll_wait");
			abort();
		}
		for (int i = 0; i < n_events; i++) {
			Source *source = reinterpret_cast<Source *>(events[i].data.ptr);
			source->handleReady(events[i].events & EPOLLIN, events[i].events & EPOLLOUT);
		}

		/* Handle timeouts for waiting actors */
		for (ListIterator<Actor> iterator(&mWaitingActors); iterator.hasCurrent(); iterator.subsequent()) {
			Actor *actor = iterator.current();

			if (actor->nextTimeoutMilliseconds() > mMilliseconds) {
				break;
			}

			bool alive = actor->handleTimeouts(mMilliseconds);
			if (alive) {
				if (!actor->nextTimeoutMilliseconds())
					mPassiveActors.addTail(actor);
				else
					waitTimeout(actor);
			} else
				delete actor;

		}

		/* Handle active actors i.e. actors that have incoming messages */
		for (ListIterator<Actor> iterator(&actors); iterator.hasCurrent(); iterator.subsequent()) {
			Actor *actor = iterator.current();

			bool alive = actor->handleMessages(mMilliseconds);
			if (alive) {
				if (!actor->mIncomingMessages.isEmpty())
					mActiveActors.addTail(actor);
				else if (!actor->nextTimeoutMilliseconds()) {
					actor->mActive = 0;
					mPassiveActors.addTail(actor);
				} else {
					actor->mActive = 0;
					waitTimeout(actor);
				}
			} else
				delete actor;
		}
	}
}

/**
 * Function that queues message, activates message receiver actor if
 * message sender is set and message senders dispatcher is the same as the receivers,
 * otherwise adds to outgoing messages list.
 */

void Dispatcher::queueMessage(Message *message)
{
	if (message->actor() && message->actor()->mDispatcher == message->mReceiver->mDispatcher) {
		message->mReceiver->mIncomingMessages.addTail(message);
		activateActor(message->mReceiver);
	} else
		mOutgoingMessages.addTail(message);
}

/**
 * Function that handles timeout for waiting actors.
 *
 * @return		void if existing timeout is larger that the specified actor's timeout.
 */

void Dispatcher::waitTimeout(Actor *actor)
{
	for (ListIterator<Actor> iterator(&mWaitingActors); iterator.hasCurrent(); iterator.subsequent()) {
		Actor *existing = iterator.current();
		if (actor->nextTimeoutMilliseconds() < existing->nextTimeoutMilliseconds()) {
			actor->addBefore(existing);
			return;
		}
	}
	mWaitingActors.addTail(actor);
}

}
<commit_msg>Dispatcher: fixed an active actor list splicing bug<commit_after>/*
 * Stateplex - A server-side actor model library.
 *
 * core/dispatcher.cpp
 *
 * (c) 2013 Henrik Hedberg <henrik.hedberg@innologies.fi>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * Authors: Henrik Hedberg
 */

#include <sys/time.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <stdio.h>

#include "dispatcher.h"
#include "actor.h"
#include "allocator.h"

/* TODO: Parametrise this */
#define MAX_EVENTS 10

namespace Stateplex {

Spinlock Dispatcher::sDispatchLock;
Allocator *Dispatcher::sRecycledAllocator;
__thread Dispatcher *Dispatcher::sCurrentDispatcher;

/**
 * Default constructor for dispatcher.
 * Also creates the epoll file discriptor.
 */

Dispatcher::Dispatcher()
	: mRunning(true), mMilliseconds(0)
{
	if (sCurrentDispatcher)
		abort();
	sCurrentDispatcher = this;

	mEpollFd = epoll_create(1024);
	mAllocator = new Allocator();

	sDispatchLock.lock();
	if (!sRecycledAllocator)
		sRecycledAllocator = new Allocator();
	sDispatchLock.unlock();
}

void Dispatcher::activateActor(Actor *actor)
{
	if (!actor->mActive) {
		mActiveActors.addTail(actor);
		actor->mActive = 1;
	}
}

/**
 * Function that dispatch incoming and outgoing messages with the lock hold,handles time out for active actors.
 * Dispatch outgoing messages with the lock hold
 * Dispatch incoming messages with the lock hold
 * Release the lock if it was acquired in dispatching
 * Handle timeouts for waiting actors
 * Handle active actors i.e. actors that have incoming messages
 */

void Dispatcher::run()
{
	bool locked;
	struct epoll_event events[MAX_EVENTS];
	int n_events;
	struct timeval tv;
	List<Actor> actors;
	int timeout;

	while (mRunning) {
		locked = false;

		/* Dispatch outgoing messages with the lock hold */
		if (!mOutgoingMessages.isEmpty()) {
			sDispatchLock.lock();
			locked = true;
			for (ListIterator<Message> iterator(&mOutgoingMessages); iterator.hasCurrent(); iterator.subsequent()) {
				Message *message = iterator.current();
				Actor *receiver = message->mReceiver;
				receiver->mQueuedMessages.addTail(message);
				activateActor(receiver);
			}
		}

		/* Dispatch incoming messages with the lock hold */
		actors.spliceTail(&mActiveActors);
		if (!actors.isEmpty()) {
			if (!locked) {
				sDispatchLock.lock();
				locked = true;
			}
			for (ListIterator<Actor> iterator(&actors); iterator.hasCurrent(); iterator.subsequent()) {
				Actor *actor = iterator.current();
				actor->mIncomingMessages.spliceTail(&actor->mQueuedMessages);
			}
		}

		/* Recycle allocators and release the lock if the lock was acquired in dispatching */
		if (locked) {
			Allocator *allocator = sRecycledAllocator;
			sRecycledAllocator = mAllocator;
			mAllocator = allocator;

			sDispatchLock.unlock();
		}

		/* Start a new cycle */
		gettimeofday(&tv, 0);
		mMilliseconds = tv.tv_sec * 1000 + tv.tv_usec / 1000;

		/* Do not block, if there are active actors, check when the next waiting actor timeouts, or wait indefinitely */
		if (!actors.isEmpty())
			timeout = 0;
		else if(!mWaitingActors.isEmpty()) {
			timeout = mWaitingActors.first()->nextTimeoutMilliseconds() - mMilliseconds;
			if (timeout < 0)
				timeout = 0;
		} else
			timeout = -1;

		/* Receive external events i.e. poll sources */
		n_events = epoll_wait(mEpollFd, events, MAX_EVENTS, timeout);
		if (n_events == -1) {
			perror("epoll_wait");
			abort();
		}
		for (int i = 0; i < n_events; i++) {
			Source *source = reinterpret_cast<Source *>(events[i].data.ptr);
			source->handleReady(events[i].events & EPOLLIN, events[i].events & EPOLLOUT);
		}

		/* Handle timeouts for waiting actors */
		for (ListIterator<Actor> iterator(&mWaitingActors); iterator.hasCurrent(); iterator.subsequent()) {
			Actor *actor = iterator.current();

			if (actor->nextTimeoutMilliseconds() > mMilliseconds) {
				break;
			}

			bool alive = actor->handleTimeouts(mMilliseconds);
			if (alive) {
				if (!actor->nextTimeoutMilliseconds())
					mPassiveActors.addTail(actor);
				else
					waitTimeout(actor);
			} else
				delete actor;

		}

		/* Handle active actors i.e. actors that have incoming messages */
		for (ListIterator<Actor> iterator(&actors); iterator.hasCurrent(); iterator.subsequent()) {
			Actor *actor = iterator.current();

			bool alive = actor->handleMessages(mMilliseconds);
			if (alive) {
				if (!actor->mIncomingMessages.isEmpty())
					mActiveActors.addTail(actor);
				else if (!actor->nextTimeoutMilliseconds()) {
					actor->mActive = 0;
					mPassiveActors.addTail(actor);
				} else {
					actor->mActive = 0;
					waitTimeout(actor);
				}
			} else
				delete actor;
		}
	}
}

/**
 * Function that queues message, activates message receiver actor if
 * message sender is set and message senders dispatcher is the same as the receivers,
 * otherwise adds to outgoing messages list.
 */

void Dispatcher::queueMessage(Message *message)
{
	if (message->actor() && message->actor()->mDispatcher == message->mReceiver->mDispatcher) {
		message->mReceiver->mIncomingMessages.addTail(message);
		activateActor(message->mReceiver);
	} else
		mOutgoingMessages.addTail(message);
}

/**
 * Function that handles timeout for waiting actors.
 *
 * @return		void if existing timeout is larger that the specified actor's timeout.
 */

void Dispatcher::waitTimeout(Actor *actor)
{
	for (ListIterator<Actor> iterator(&mWaitingActors); iterator.hasCurrent(); iterator.subsequent()) {
		Actor *existing = iterator.current();
		if (actor->nextTimeoutMilliseconds() < existing->nextTimeoutMilliseconds()) {
			actor->addBefore(existing);
			return;
		}
	}
	mWaitingActors.addTail(actor);
}

}
<|endoftext|>


<commit_before>/* KPilot
**
** Copyright (C) 2004 by Adriaan de Groot, Joern Ahrens
**
** The code for NotepadActionThread::unpackNotePad was taken from
** Angus Ainslies read-notepad.c, which is part of pilot-link.
** NotepadActionThread::saveImage is also based on read-notepad.c.
**
** This file is part of the Notepad conduit, a conduit for KPilot that
** stores the notepad drawings to files.
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
** MA 02111-1307, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

#ifdef DEBUG
#undef DEBUG
#define DEBUG (1)
#else
#define DEBUG (1)
#endif

#define DEBUG (1)

#include "options.h"
#include "pilotUser.h"
#include "pilotSerialDatabase.h"

#include "notepad-conduit.h"  // The Conduit action
#include "notepadconduit.h"   // The settings class

#include <pi-notepad.h>

#include <qthread.h>
#include <qapplication.h>
#include <qvaluelist.h>
#include <qimage.h>
#include <qdir.h>

extern "C"
{
long version_conduit_notepad = KPILOT_PLUGIN_API;
const char *id_conduit_notepad =
	"$Id$";
}

NotepadConduit::NotepadConduit(KPilotDeviceLink *d,	const char *n,
	const QStringList &args) :	ConduitAction(d, n, args)
{
	FUNCTIONSETUP;
#ifdef DEBUG
	DEBUGCONDUIT << id_conduit_notepad << endl;
#endif
	fConduitName=i18n("Notepad");
	thread = 0L;

	(void) id_conduit_notepad;
}

NotepadConduit::~NotepadConduit()
{
	FUNCTIONSETUP;
}

/* virtual */ bool NotepadConduit::exec()
{
	FUNCTIONSETUP;

#ifdef DEBUG
	DEBUGCONDUIT << fname << ": In exec() @" << (unsigned long) this << endl;
#endif

	QDir dir(NotepadConduitSettings::outputDirectory());
	if(!dir.exists() && !dir.mkdir(dir.path())) {
		emit logError(i18n("Unable to open %1").arg(dir.path()));
		delayDone();
		return false;
	}
	else {
		thread = new NotepadActionThread(this, pilotSocket());
		thread->start();
		// tickle is disabled due to crashs during sync
		// -> PADP TX "unexpected package"
//		startTickle();
	}

	return true;
}

bool NotepadConduit::event(QEvent *e)
{
	FUNCTIONSETUP;

	if(e->type() == QEvent::User) {
#ifdef DEBUG
		DEBUGCONDUIT << fname << ": Notepad thread done." << endl;
#endif
//		stopTickle();
		delayDone();
		if(thread->getFailed())
			logError(i18n("1 notepad could not be saved", "%n notepads could not be saved", thread->getFailed()));
		logMessage(i18n("1 notepad saved", "%n notepads saved", thread->getSaved()));
		delete thread;
		return true;
	}
	else
		return ConduitAction::event(e);
}

//-----------------------------------------------------------------------------
// NotepadActionThread
//-----------------------------------------------------------------------------

NotepadActionThread::NotepadActionThread(QObject *parent, int pilotSocket) :
	fParent(parent), fPilotSocket(pilotSocket), notSaved(0), saved(0)
{
	FUNCTIONSETUP;
}

/*virtual*/ void NotepadActionThread::run()
{
	FUNCTIONSETUP;

	PilotSerialDatabase *db = new PilotSerialDatabase(fPilotSocket, "npadDB");

	int n = db->recordCount();
	QValueList<recordid_t> vl = db->idList();
	QValueList<recordid_t>::iterator it;
	struct NotePad a;
	for ( it = vl.begin(); it != vl.end(); ++it ) {
		PilotRecord *pr = db->readRecordById(*it);
		if(pr) {
			unpack_NotePad(&a, (unsigned char*)pr->getData(), pr->getLen());
			saveImage(&a);
		}
	}
	QApplication::postEvent(fParent, new QEvent(QEvent::User));
}

int NotepadActionThread::unpackNotePad(struct NotePad *a, unsigned char *buffer, int len)
{
	FUNCTIONSETUP;

	unsigned char *start = buffer;

	a->createDate.sec = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.min = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.hour = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.day = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.month = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.year = (unsigned short int) get_short(buffer);
	buffer += 2;

	a->createDate.s = (unsigned short int) get_short(buffer);
	buffer += 2;

	a->changeDate.sec = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.min = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.hour = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.day = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.month = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.year = (unsigned short int) get_short(buffer);
	buffer += 2;

	a->changeDate.s = (unsigned short int) get_short(buffer);
	buffer += 2;

	a->flags = (unsigned short int) get_short(buffer);
	buffer += 2;

	if( a->flags & NOTEPAD_FLAG_ALARM ) {
			a->alarmDate.sec = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.min = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.hour = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.day = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.month = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.year = (unsigned short int) get_short(buffer);
			buffer += 2;

			a->alarmDate.s = (unsigned short int) get_short(buffer);
			buffer += 2;
		}

		if( a->flags & NOTEPAD_FLAG_NAME ) {
			a->name = strdup((char *) buffer);

			buffer += strlen( a->name ) + 1;

			if( (strlen( a->name ) + 1)%2 == 1)
				++buffer;

		}
		else {
			a->name = NULL;
		}

	if( a->flags & NOTEPAD_FLAG_BODY ) {
			a->body.bodyLen = get_long( buffer );
			buffer += 4;

			a->body.width = get_long( buffer );
			buffer += 4;

			a->body.height = get_long( buffer );
			buffer += 4;

			a->body.l1 = get_long( buffer );
			buffer += 4;

			a->body.dataType = get_long( buffer );
			buffer += 4;

			a->body.dataLen = get_long( buffer );
			buffer += 4;

			a->data = (dataRec_t*)malloc( a->body.dataLen );

			if( a->data == NULL )
				return( 0 );

			memcpy( a->data, buffer, a->body.dataLen );
		}

	return ( buffer - start );	/* FIXME: return real length */
}

void NotepadActionThread::saveImage(struct NotePad *n)
{
	FUNCTIONSETUP;

	int i,j,k,datapoints = 0;
	QImage image(n->body.width+8, n->body.height, 8, 2);

	image.setColor(0, qRgb(0xaa, 0xc1 ,0x91) );
	image.setColor(1, qRgb(0x30, 0x36, 0x29) );

	int x = 0;
	int y = 0;
	int pos = 0;
	for(i=0; i<n->body.dataLen/2; ++i)
	{
		datapoints += n->data[i].repeat;
		for(j=0; j<n->data[i].repeat; ++j)
		{
			for(k=0; k<8; ++k)
			{
				y = pos / 160;
				x = pos % 160;

				if(n->data[i].data & 1<<(7-k))
					image.setPixel(x,y,1);
				else
		    		image.setPixel(x,y,0);
				++pos;
			}
		}
	}
	QString imgname = QString("%1/%2.png").arg(NotepadConduitSettings::outputDirectory()).arg(n->name);
	DEBUGCONDUIT << fname << ": Notepad " << imgname << endl;
	if(!image.save(imgname, "PNG", -1))
		++notSaved;
	else
		++saved;
}

<commit_msg>Don't do unconditional DEBUG<commit_after>/* KPilot
**
** Copyright (C) 2004 by Adriaan de Groot, Joern Ahrens
**
** The code for NotepadActionThread::unpackNotePad was taken from
** Angus Ainslies read-notepad.c, which is part of pilot-link.
** NotepadActionThread::saveImage is also based on read-notepad.c.
**
** This file is part of the Notepad conduit, a conduit for KPilot that
** stores the notepad drawings to files.
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation; either version 2.1 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
** MA 02111-1307, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org
*/

#include "options.h"
#include "pilotUser.h"
#include "pilotSerialDatabase.h"

#include "notepad-conduit.h"  // The Conduit action
#include "notepadconduit.h"   // The settings class

#include <pi-notepad.h>

#include <qthread.h>
#include <qapplication.h>
#include <qvaluelist.h>
#include <qimage.h>
#include <qdir.h>

extern "C"
{
long version_conduit_notepad = KPILOT_PLUGIN_API;
const char *id_conduit_notepad =
	"$Id$";
}

NotepadConduit::NotepadConduit(KPilotDeviceLink *d,	const char *n,
	const QStringList &args) :	ConduitAction(d, n, args)
{
	FUNCTIONSETUP;
#ifdef DEBUG
	DEBUGCONDUIT << id_conduit_notepad << endl;
#endif
	fConduitName=i18n("Notepad");
	thread = 0L;

	(void) id_conduit_notepad;
}

NotepadConduit::~NotepadConduit()
{
	FUNCTIONSETUP;
}

/* virtual */ bool NotepadConduit::exec()
{
	FUNCTIONSETUP;

#ifdef DEBUG
	DEBUGCONDUIT << fname << ": In exec() @" << (unsigned long) this << endl;
#endif

	QDir dir(NotepadConduitSettings::outputDirectory());
	if(!dir.exists() && !dir.mkdir(dir.path())) {
		emit logError(i18n("Unable to open %1").arg(dir.path()));
		delayDone();
		return false;
	}
	else {
		thread = new NotepadActionThread(this, pilotSocket());
		thread->start();
		// tickle is disabled due to crashs during sync
		// -> PADP TX "unexpected package"
//		startTickle();
	}

	return true;
}

bool NotepadConduit::event(QEvent *e)
{
	FUNCTIONSETUP;

	if(e->type() == QEvent::User) {
#ifdef DEBUG
		DEBUGCONDUIT << fname << ": Notepad thread done." << endl;
#endif
//		stopTickle();
		delayDone();
		if(thread->getFailed())
			logError(i18n("1 notepad could not be saved", "%n notepads could not be saved", thread->getFailed()));
		logMessage(i18n("1 notepad saved", "%n notepads saved", thread->getSaved()));
		delete thread;
		return true;
	}
	else
		return ConduitAction::event(e);
}

//-----------------------------------------------------------------------------
// NotepadActionThread
//-----------------------------------------------------------------------------

NotepadActionThread::NotepadActionThread(QObject *parent, int pilotSocket) :
	fParent(parent), fPilotSocket(pilotSocket), notSaved(0), saved(0)
{
	FUNCTIONSETUP;
}

/*virtual*/ void NotepadActionThread::run()
{
	FUNCTIONSETUP;

	PilotSerialDatabase *db = new PilotSerialDatabase(fPilotSocket, "npadDB");

	int n = db->recordCount();
	QValueList<recordid_t> vl = db->idList();
	QValueList<recordid_t>::iterator it;
	struct NotePad a;
	for ( it = vl.begin(); it != vl.end(); ++it ) {
		PilotRecord *pr = db->readRecordById(*it);
		if(pr) {
			unpack_NotePad(&a, (unsigned char*)pr->getData(), pr->getLen());
			saveImage(&a);
		}
	}
	QApplication::postEvent(fParent, new QEvent(QEvent::User));
}

int NotepadActionThread::unpackNotePad(struct NotePad *a, unsigned char *buffer, int len)
{
	FUNCTIONSETUP;

	unsigned char *start = buffer;

	a->createDate.sec = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.min = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.hour = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.day = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.month = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->createDate.year = (unsigned short int) get_short(buffer);
	buffer += 2;

	a->createDate.s = (unsigned short int) get_short(buffer);
	buffer += 2;

	a->changeDate.sec = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.min = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.hour = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.day = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.month = (unsigned short int) get_short(buffer);
	buffer += 2;
	a->changeDate.year = (unsigned short int) get_short(buffer);
	buffer += 2;

	a->changeDate.s = (unsigned short int) get_short(buffer);
	buffer += 2;

	a->flags = (unsigned short int) get_short(buffer);
	buffer += 2;

	if( a->flags & NOTEPAD_FLAG_ALARM ) {
			a->alarmDate.sec = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.min = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.hour = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.day = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.month = (unsigned short int) get_short(buffer);
			buffer += 2;
			a->alarmDate.year = (unsigned short int) get_short(buffer);
			buffer += 2;

			a->alarmDate.s = (unsigned short int) get_short(buffer);
			buffer += 2;
		}

		if( a->flags & NOTEPAD_FLAG_NAME ) {
			a->name = strdup((char *) buffer);

			buffer += strlen( a->name ) + 1;

			if( (strlen( a->name ) + 1)%2 == 1)
				++buffer;

		}
		else {
			a->name = NULL;
		}

	if( a->flags & NOTEPAD_FLAG_BODY ) {
			a->body.bodyLen = get_long( buffer );
			buffer += 4;

			a->body.width = get_long( buffer );
			buffer += 4;

			a->body.height = get_long( buffer );
			buffer += 4;

			a->body.l1 = get_long( buffer );
			buffer += 4;

			a->body.dataType = get_long( buffer );
			buffer += 4;

			a->body.dataLen = get_long( buffer );
			buffer += 4;

			a->data = (dataRec_t*)malloc( a->body.dataLen );

			if( a->data == NULL )
				return( 0 );

			memcpy( a->data, buffer, a->body.dataLen );
		}

	return ( buffer - start );	/* FIXME: return real length */
}

void NotepadActionThread::saveImage(struct NotePad *n)
{
	FUNCTIONSETUP;

	int i,j,k,datapoints = 0;
	QImage image(n->body.width+8, n->body.height, 8, 2);

	image.setColor(0, qRgb(0xaa, 0xc1 ,0x91) );
	image.setColor(1, qRgb(0x30, 0x36, 0x29) );

	int x = 0;
	int y = 0;
	int pos = 0;
	for(i=0; i<n->body.dataLen/2; ++i)
	{
		datapoints += n->data[i].repeat;
		for(j=0; j<n->data[i].repeat; ++j)
		{
			for(k=0; k<8; ++k)
			{
				y = pos / 160;
				x = pos % 160;

				if(n->data[i].data & 1<<(7-k))
					image.setPixel(x,y,1);
				else
		    		image.setPixel(x,y,0);
				++pos;
			}
		}
	}
	QString imgname = QString("%1/%2.png").arg(NotepadConduitSettings::outputDirectory()).arg(n->name);
	DEBUGCONDUIT << fname << ": Notepad " << imgname << endl;
	if(!image.save(imgname, "PNG", -1))
		++notSaved;
	else
		++saved;
}

<|endoftext|>


<commit_before>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/MIRIAM/CRDFWriter.cpp,v $
//   $Revision: 1.4 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2008/02/04 17:28:01 $
// End CVS Header

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2001 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include <sstream>

#include "copasi.h"

#include "CRDFWriter.h"
#include "CRDFGraph.h"
#include "CRDFNode.h"
#include "CRDFEdge.h"
#include "CRDFSubject.h"
#include "CRDFObject.h"
#include "CRDFLiteral.h"

#include "utilities/CCopasiMessage.h"

//static
std::string CRDFWriter::xmlFromGraph(const CRDFGraph * pGraph)
{
  CRDFWriter Writer;

  char * XML = Writer.CRDFWriter::write(pGraph);

  if (XML != NULL)
    return XML;

  return "";
}

CRDFWriter::CRDFWriter():
    CRaptorInit(),
    mpWriter(NULL),
    mpGraph(NULL)
{
  mpWriter = raptor_new_serializer("rdfxml-abbrev");

  // We do not want <?xml version="1.0" encoding="utf-8"?>
  raptor_serializer_set_feature(mpWriter, RAPTOR_FEATURE_WRITER_XML_DECLARATION, 0);
}

CRDFWriter::~CRDFWriter()
{
  if (mpWriter != NULL)
    raptor_free_serializer(mpWriter);
}

void CRDFWriter::initNamespaces(const CRDFGraph * pGraph)
{
  std::map< std::string, std::string >::const_iterator it =
    pGraph->getNameSpaceMap().begin();
  std::map< std::string, std::string >::const_iterator end =
    pGraph->getNameSpaceMap().end();

  raptor_uri* pURI = NULL;

  for (; it != end; ++it)
    {
      pURI = raptor_new_uri((const unsigned char *) it->second.c_str());
      raptor_serialize_set_namespace(mpWriter, pURI, (const unsigned char *) it->first.c_str());
      pRaptorFreeUri(pURI);
    }
}

char * CRDFWriter::write(const CRDFGraph * pGraph)
{
  bool success = true;

  char * XML;  /* destination for string */
  size_t Length;  /* length of constructed string */

  initNamespaces(pGraph);

  raptor_uri * pURI = raptor_new_uri((const unsigned char *) "");

  if (raptor_serialize_start_to_string(mpWriter, pURI, (void **) & XML, & Length))
    fatalError();

  // We need do add all subject nodes.
  // This means we need to iterate over all Resource and BlankID nodes
  std::map< std::string, CRDFNode * >::const_iterator itMap;
  std::map< std::string, CRDFNode * >::const_iterator endMap;

  itMap = pGraph->getBlankNodeMap().begin();
  endMap = pGraph->getBlankNodeMap().end();
  for (; itMap != endMap; ++itMap)
    if (itMap->second->isSubjectNode())
      success &= addSubjectNode(itMap->second);

  itMap = pGraph->getLocalResourceNodeMap().begin();
  endMap = pGraph->getLocalResourceNodeMap().end();
  for (; itMap != endMap; ++itMap)
    if (itMap->second->isSubjectNode())
      success &= addSubjectNode(itMap->second);

  // We might be describing a remote resource
  std::vector< CRDFNode *>::const_iterator itVector;
  std::vector< CRDFNode *>::const_iterator endVector;
  for (itVector = pGraph->getRemoteResourceNodes().begin(), endVector = pGraph->getRemoteResourceNodes().end();
       itVector != endVector; ++itVector)
    if ((*itVector)->isSubjectNode())
      success &= addSubjectNode((*itVector));

  if (raptor_serialize_end(mpWriter))
    fatalError();

  return XML;
}

bool CRDFWriter::addSubjectNode(const CRDFNode * pSubjectNode)
{
  bool success = true;

  raptor_uri * pSubjectURI = NULL;
  raptor_uri * pPredicateURI = NULL;
  raptor_uri * pObjectURI = NULL;
  raptor_uri * pLiteralDataTypeURI = NULL;

  raptor_statement Triplet;

  // Set the subject of the triplet
  const CRDFSubject & Subject = pSubjectNode->getSubject();
  switch (Subject.getType())
    {
    case CRDFSubject::RESOURCE:
      Triplet.subject_type = RAPTOR_IDENTIFIER_TYPE_RESOURCE;
      pSubjectURI = raptor_new_uri((const unsigned char *) Subject.getResource().c_str());
      Triplet.subject = pSubjectURI;
      break;

    case CRDFSubject::BLANK_NODE:
      Triplet.subject_type = RAPTOR_IDENTIFIER_TYPE_ANONYMOUS;
      Triplet.subject = Subject.getBlankNodeID().c_str();
      break;
    }

  CRDFNode::const_iterator it = pSubjectNode->getEdges().begin();
  CRDFNode::const_iterator end = pSubjectNode->getEdges().end();

  for (; it != end; ++it)
    {
      // Set the predicate of the triplet
      Triplet.predicate_type = RAPTOR_IDENTIFIER_TYPE_RESOURCE;
      pPredicateURI = raptor_new_uri((const unsigned char *) it->first.c_str());
      Triplet.predicate = pPredicateURI;

      // Set the object of the triplet
      const CRDFNode * pProperty = it->second;
      if (!pProperty->isObjectNode())
        {
          success = false;
          continue;
        }

      const CRDFObject & Object = pProperty->getObject();
      switch (Object.getType())
        {
        case CRDFObject::RESOURCE:
          Triplet.object_type = RAPTOR_IDENTIFIER_TYPE_RESOURCE;
          pObjectURI = raptor_new_uri((const unsigned char *) Object.getResource().c_str());
          Triplet.object = pObjectURI;
          break;

        case CRDFObject::BLANK_NODE:
          Triplet.object_type = RAPTOR_IDENTIFIER_TYPE_ANONYMOUS;
          Triplet.object = Object.getBlankNodeID().c_str();
          break;

        case CRDFObject::LITERAL:
          Triplet.object_type = RAPTOR_IDENTIFIER_TYPE_LITERAL;
          const CRDFLiteral & Literal = Object.getLiteral();

          switch (Literal.getType())
            {
            case CRDFLiteral::TYPED:
              pLiteralDataTypeURI = raptor_new_uri((const unsigned char *) Literal.getDataType().c_str());
              Triplet.object_literal_datatype = pLiteralDataTypeURI;
              Triplet.object_literal_language = NULL;
              break;

            case CRDFLiteral::PLAIN:
              Triplet.object_literal_datatype = NULL;
              if (Literal.getLanguage() != "")
                Triplet.object_literal_language = (const unsigned char *) Literal.getLanguage().c_str();
              else
                Triplet.object_literal_language = NULL;
              break;
            }

          Triplet.object = Literal.getLexicalData().c_str();
          break;
        }

      if (raptor_serialize_statement(mpWriter, &Triplet))
        success = false;

      pRaptorFreeUri(pPredicateURI);
      pRaptorFreeUri(pObjectURI);
      pRaptorFreeUri(pLiteralDataTypeURI);
    }

  pRaptorFreeUri(pSubjectURI);

  return success;
}
<commit_msg>The RDF writer now automatically removes any empty element.<commit_after>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/MIRIAM/CRDFWriter.cpp,v $
//   $Revision: 1.5 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2008/04/29 15:30:40 $
// End CVS Header

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2001 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include <sstream>

#include "copasi.h"

#include "CRDFWriter.h"
#include "CRDFGraph.h"
#include "CRDFNode.h"
#include "CRDFEdge.h"
#include "CRDFSubject.h"
#include "CRDFObject.h"
#include "CRDFLiteral.h"

#include "utilities/CCopasiMessage.h"

//static
std::string CRDFWriter::xmlFromGraph(const CRDFGraph * pGraph)
{
  CRDFWriter Writer;

  char * XML = Writer.CRDFWriter::write(pGraph);

  if (XML != NULL)
    return XML;

  return "";
}

CRDFWriter::CRDFWriter():
    CRaptorInit(),
    mpWriter(NULL),
    mpGraph(NULL)
{
  mpWriter = raptor_new_serializer("rdfxml-abbrev");

  // We do not want <?xml version="1.0" encoding="utf-8"?>
  raptor_serializer_set_feature(mpWriter, RAPTOR_FEATURE_WRITER_XML_DECLARATION, 0);
  // Remove any empty elements
  raptor_serializer_set_feature(mpWriter, RAPTOR_FEATURE_WRITER_AUTO_EMPTY, 1);
}

CRDFWriter::~CRDFWriter()
{
  if (mpWriter != NULL)
    raptor_free_serializer(mpWriter);
}

void CRDFWriter::initNamespaces(const CRDFGraph * pGraph)
{
  std::map< std::string, std::string >::const_iterator it =
    pGraph->getNameSpaceMap().begin();
  std::map< std::string, std::string >::const_iterator end =
    pGraph->getNameSpaceMap().end();

  raptor_uri* pURI = NULL;

  for (; it != end; ++it)
    {
      pURI = raptor_new_uri((const unsigned char *) it->second.c_str());
      raptor_serialize_set_namespace(mpWriter, pURI, (const unsigned char *) it->first.c_str());
      pRaptorFreeUri(pURI);
    }
}

char * CRDFWriter::write(const CRDFGraph * pGraph)
{
  bool success = true;

  char * XML;  /* destination for string */
  size_t Length;  /* length of constructed string */

  initNamespaces(pGraph);

  raptor_uri * pURI = raptor_new_uri((const unsigned char *) "");

  if (raptor_serialize_start_to_string(mpWriter, pURI, (void **) & XML, & Length))
    fatalError();

  // We need do add all subject nodes.
  // This means we need to iterate over all Resource and BlankID nodes
  std::map< std::string, CRDFNode * >::const_iterator itMap;
  std::map< std::string, CRDFNode * >::const_iterator endMap;

  itMap = pGraph->getBlankNodeMap().begin();
  endMap = pGraph->getBlankNodeMap().end();
  for (; itMap != endMap; ++itMap)
    if (itMap->second->isSubjectNode())
      success &= addSubjectNode(itMap->second);

  itMap = pGraph->getLocalResourceNodeMap().begin();
  endMap = pGraph->getLocalResourceNodeMap().end();
  for (; itMap != endMap; ++itMap)
    if (itMap->second->isSubjectNode())
      success &= addSubjectNode(itMap->second);

  // We might be describing a remote resource
  std::vector< CRDFNode *>::const_iterator itVector;
  std::vector< CRDFNode *>::const_iterator endVector;
  for (itVector = pGraph->getRemoteResourceNodes().begin(), endVector = pGraph->getRemoteResourceNodes().end();
       itVector != endVector; ++itVector)
    if ((*itVector)->isSubjectNode())
      success &= addSubjectNode((*itVector));

  if (raptor_serialize_end(mpWriter))
    fatalError();

  return XML;
}

bool CRDFWriter::addSubjectNode(const CRDFNode * pSubjectNode)
{
  bool success = true;

  raptor_uri * pSubjectURI = NULL;
  raptor_uri * pPredicateURI = NULL;
  raptor_uri * pObjectURI = NULL;
  raptor_uri * pLiteralDataTypeURI = NULL;

  raptor_statement Triplet;

  // Set the subject of the triplet
  const CRDFSubject & Subject = pSubjectNode->getSubject();
  switch (Subject.getType())
    {
    case CRDFSubject::RESOURCE:
      Triplet.subject_type = RAPTOR_IDENTIFIER_TYPE_RESOURCE;
      pSubjectURI = raptor_new_uri((const unsigned char *) Subject.getResource().c_str());
      Triplet.subject = pSubjectURI;
      break;

    case CRDFSubject::BLANK_NODE:
      Triplet.subject_type = RAPTOR_IDENTIFIER_TYPE_ANONYMOUS;
      Triplet.subject = Subject.getBlankNodeID().c_str();
      break;
    }

  CRDFNode::const_iterator it = pSubjectNode->getEdges().begin();
  CRDFNode::const_iterator end = pSubjectNode->getEdges().end();

  for (; it != end; ++it)
    {
      // Set the predicate of the triplet
      Triplet.predicate_type = RAPTOR_IDENTIFIER_TYPE_RESOURCE;
      pPredicateURI = raptor_new_uri((const unsigned char *) it->first.c_str());
      Triplet.predicate = pPredicateURI;

      // Set the object of the triplet
      const CRDFNode * pProperty = it->second;
      if (!pProperty->isObjectNode())
        {
          success = false;
          continue;
        }

      const CRDFObject & Object = pProperty->getObject();
      switch (Object.getType())
        {
        case CRDFObject::RESOURCE:
          Triplet.object_type = RAPTOR_IDENTIFIER_TYPE_RESOURCE;
          pObjectURI = raptor_new_uri((const unsigned char *) Object.getResource().c_str());
          Triplet.object = pObjectURI;
          break;

        case CRDFObject::BLANK_NODE:
          Triplet.object_type = RAPTOR_IDENTIFIER_TYPE_ANONYMOUS;
          Triplet.object = Object.getBlankNodeID().c_str();
          break;

        case CRDFObject::LITERAL:
          Triplet.object_type = RAPTOR_IDENTIFIER_TYPE_LITERAL;
          const CRDFLiteral & Literal = Object.getLiteral();

          switch (Literal.getType())
            {
            case CRDFLiteral::TYPED:
              pLiteralDataTypeURI = raptor_new_uri((const unsigned char *) Literal.getDataType().c_str());
              Triplet.object_literal_datatype = pLiteralDataTypeURI;
              Triplet.object_literal_language = NULL;
              break;

            case CRDFLiteral::PLAIN:
              Triplet.object_literal_datatype = NULL;
              if (Literal.getLanguage() != "")
                Triplet.object_literal_language = (const unsigned char *) Literal.getLanguage().c_str();
              else
                Triplet.object_literal_language = NULL;
              break;
            }

          Triplet.object = Literal.getLexicalData().c_str();
          break;
        }

      if (raptor_serialize_statement(mpWriter, &Triplet))
        success = false;

      pRaptorFreeUri(pPredicateURI);
      pRaptorFreeUri(pObjectURI);
      pRaptorFreeUri(pLiteralDataTypeURI);
    }

  pRaptorFreeUri(pSubjectURI);

  return success;
}
<|endoftext|>


<commit_before>#include "cppunit/TestRegistry.h"
#include "cppunit/TextTestResult.h"
#include "cppunit/TestSuite.h"
#include "cppunit/Test.h"

#include "BoardGame.h"
#include "Chess.h"

#include "BoardGameTest.h"
#include "ChessTest.h"

#include <vector>
#include <iostream>

int
main(int argc, char** argv)
{
  CppUnit::TextTestResult res;
  CppUnit::TestSuite suite;

  BoardGameTest<BoardGame>* bgt = new BoardGameTest<BoardGame>("BoardGameTest<BoardGame>");
  ChessTest<Chess>* ct = new ChessTest<Chess>("ChessTest<Chess>");

  bgt->registerTests(&suite);
  ct->registerTests(&suite);

  std::vector<CppUnit::Test*> tests =
      CppUnit::TestRegistry::getRegistry().getAllTests();

  for(std::vector<CppUnit::Test*>::iterator it=tests.begin();
      it!=tests.end(); ++it) {

    (*it)->run(&res);

  }
  std::cout << res << endl;

  delete ct;
  delete bgt;
  return 0;
}
<commit_msg>One more std:: added.<commit_after>#include "cppunit/TestRegistry.h"
#include "cppunit/TextTestResult.h"
#include "cppunit/TestSuite.h"
#include "cppunit/Test.h"

#include "BoardGame.h"
#include "Chess.h"

#include "BoardGameTest.h"
#include "ChessTest.h"

#include <vector>
#include <iostream>

int
main(int argc, char** argv)
{
  CppUnit::TextTestResult res;
  CppUnit::TestSuite suite;

  BoardGameTest<BoardGame>* bgt = new BoardGameTest<BoardGame>("BoardGameTest<BoardGame>");
  ChessTest<Chess>* ct = new ChessTest<Chess>("ChessTest<Chess>");

  bgt->registerTests(&suite);
  ct->registerTests(&suite);

  std::vector<CppUnit::Test*> tests =
      CppUnit::TestRegistry::getRegistry().getAllTests();

  for(std::vector<CppUnit::Test*>::iterator it=tests.begin();
      it!=tests.end(); ++it) {

    (*it)->run(&res);

  }
  std::cout << res << std::endl;

  delete ct;
  delete bgt;
  return 0;
}
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct CopyPass : public Pass {
	CopyPass() : Pass("copy", "copy modules in the design") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    copy old_name new_name\n");
		log("\n");
		log("Copy the specified module. Note that selection patterns are not supported\n");
		log("by this command.\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		if (args.size() != 3)
			log_cmd_error("Invalid number of arguments!\n");

		std::string src_name = RTLIL::escape_id(args[1]);
		std::string trg_name = RTLIL::escape_id(args[2]);

		if (design->modules_.count(src_name) == 0)
			log_cmd_error("Can't find source module %s.\n", src_name.c_str());

		if (design->modules_.count(trg_name) != 0)
			log_cmd_error("Target module name %s already exists.\n", trg_name.c_str());

		RTLIL::Module *new_mod = design->module(src_name)->clone();
		new_mod->name = trg_name;
		design->add(new_mod);
	}
} CopyPass;

PRIVATE_NAMESPACE_END
<commit_msg>Clean up private member usage in `passes/cmds/copy.cc`.<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct CopyPass : public Pass {
	CopyPass() : Pass("copy", "copy modules in the design") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    copy old_name new_name\n");
		log("\n");
		log("Copy the specified module. Note that selection patterns are not supported\n");
		log("by this command.\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		if (args.size() != 3)
			log_cmd_error("Invalid number of arguments!\n");

		std::string src_name = RTLIL::escape_id(args[1]);
		std::string trg_name = RTLIL::escape_id(args[2]);

		if (design->module(src_name) == nullptr)
			log_cmd_error("Can't find source module %s.\n", src_name.c_str());

		if (design->module(trg_name) != nullptr)
			log_cmd_error("Target module name %s already exists.\n", trg_name.c_str());

		RTLIL::Module *new_mod = design->module(src_name)->clone();
		new_mod->name = trg_name;
		design->add(new_mod);
	}
} CopyPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>//===-- FunctionLoweringInfo.cpp ------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This implements routines for translating functions from LLVM IR into
// Machine IR.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "function-lowering-info"
#include "FunctionLoweringInfo.h"
#include "llvm/CallingConv.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetIntrinsicInfo.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;

/// ComputeLinearIndex - Given an LLVM IR aggregate type and a sequence
/// of insertvalue or extractvalue indices that identify a member, return
/// the linearized index of the start of the member.
///
unsigned llvm::ComputeLinearIndex(const TargetLowering &TLI, const Type *Ty,
                                  const unsigned *Indices,
                                  const unsigned *IndicesEnd,
                                  unsigned CurIndex) {
  // Base case: We're done.
  if (Indices && Indices == IndicesEnd)
    return CurIndex;

  // Given a struct type, recursively traverse the elements.
  if (const StructType *STy = dyn_cast<StructType>(Ty)) {
    for (StructType::element_iterator EB = STy->element_begin(),
                                      EI = EB,
                                      EE = STy->element_end();
        EI != EE; ++EI) {
      if (Indices && *Indices == unsigned(EI - EB))
        return ComputeLinearIndex(TLI, *EI, Indices+1, IndicesEnd, CurIndex);
      CurIndex = ComputeLinearIndex(TLI, *EI, 0, 0, CurIndex);
    }
    return CurIndex;
  }
  // Given an array type, recursively traverse the elements.
  else if (const ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
    const Type *EltTy = ATy->getElementType();
    for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
      if (Indices && *Indices == i)
        return ComputeLinearIndex(TLI, EltTy, Indices+1, IndicesEnd, CurIndex);
      CurIndex = ComputeLinearIndex(TLI, EltTy, 0, 0, CurIndex);
    }
    return CurIndex;
  }
  // We haven't found the type we're looking for, so keep searching.
  return CurIndex + 1;
}

/// ComputeValueVTs - Given an LLVM IR type, compute a sequence of
/// EVTs that represent all the individual underlying
/// non-aggregate types that comprise it.
///
/// If Offsets is non-null, it points to a vector to be filled in
/// with the in-memory offsets of each of the individual values.
///
void llvm::ComputeValueVTs(const TargetLowering &TLI, const Type *Ty,
                           SmallVectorImpl<EVT> &ValueVTs,
                           SmallVectorImpl<uint64_t> *Offsets,
                           uint64_t StartingOffset) {
  // Given a struct type, recursively traverse the elements.
  if (const StructType *STy = dyn_cast<StructType>(Ty)) {
    const StructLayout *SL = TLI.getTargetData()->getStructLayout(STy);
    for (StructType::element_iterator EB = STy->element_begin(),
                                      EI = EB,
                                      EE = STy->element_end();
         EI != EE; ++EI)
      ComputeValueVTs(TLI, *EI, ValueVTs, Offsets,
                      StartingOffset + SL->getElementOffset(EI - EB));
    return;
  }
  // Given an array type, recursively traverse the elements.
  if (const ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
    const Type *EltTy = ATy->getElementType();
    uint64_t EltSize = TLI.getTargetData()->getTypeAllocSize(EltTy);
    for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i)
      ComputeValueVTs(TLI, EltTy, ValueVTs, Offsets,
                      StartingOffset + i * EltSize);
    return;
  }
  // Interpret void as zero return values.
  if (Ty->isVoidTy())
    return;
  // Base case: we can get an EVT for this LLVM IR type.
  ValueVTs.push_back(TLI.getValueType(Ty));
  if (Offsets)
    Offsets->push_back(StartingOffset);
}

/// isUsedOutsideOfDefiningBlock - Return true if this instruction is used by
/// PHI nodes or outside of the basic block that defines it, or used by a
/// switch or atomic instruction, which may expand to multiple basic blocks.
static bool isUsedOutsideOfDefiningBlock(Instruction *I) {
  if (isa<PHINode>(I)) return true;
  BasicBlock *BB = I->getParent();
  for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); UI != E; ++UI)
    if (cast<Instruction>(*UI)->getParent() != BB || isa<PHINode>(*UI))
      return true;
  return false;
}

/// isOnlyUsedInEntryBlock - If the specified argument is only used in the
/// entry block, return true.  This includes arguments used by switches, since
/// the switch may expand into multiple basic blocks.
static bool isOnlyUsedInEntryBlock(Argument *A, bool EnableFastISel) {
  // With FastISel active, we may be splitting blocks, so force creation
  // of virtual registers for all non-dead arguments.
  // Don't force virtual registers for byval arguments though, because
  // fast-isel can't handle those in all cases.
  if (EnableFastISel && !A->hasByValAttr())
    return A->use_empty();

  BasicBlock *Entry = A->getParent()->begin();
  for (Value::use_iterator UI = A->use_begin(), E = A->use_end(); UI != E; ++UI)
    if (cast<Instruction>(*UI)->getParent() != Entry || isa<SwitchInst>(*UI))
      return false;  // Use not in entry block.
  return true;
}

FunctionLoweringInfo::FunctionLoweringInfo(TargetLowering &tli)
  : TLI(tli) {
}

void FunctionLoweringInfo::set(Function &fn, MachineFunction &mf,
                               bool EnableFastISel) {
  Fn = &fn;
  MF = &mf;
  RegInfo = &MF->getRegInfo();

  // Create a vreg for each argument register that is not dead and is used
  // outside of the entry block for the function.
  for (Function::arg_iterator AI = Fn->arg_begin(), E = Fn->arg_end();
       AI != E; ++AI)
    if (!isOnlyUsedInEntryBlock(AI, EnableFastISel))
      InitializeRegForValue(AI);

  // Initialize the mapping of values to registers.  This is only set up for
  // instruction values that are used outside of the block that defines
  // them.
  Function::iterator BB = Fn->begin(), EB = Fn->end();
  for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
    if (AllocaInst *AI = dyn_cast<AllocaInst>(I))
      if (ConstantInt *CUI = dyn_cast<ConstantInt>(AI->getArraySize())) {
        const Type *Ty = AI->getAllocatedType();
        uint64_t TySize = TLI.getTargetData()->getTypeAllocSize(Ty);
        unsigned Align =
          std::max((unsigned)TLI.getTargetData()->getPrefTypeAlignment(Ty),
                   AI->getAlignment());

        TySize *= CUI->getZExtValue();   // Get total allocated size.
        if (TySize == 0) TySize = 1; // Don't create zero-sized stack objects.
        StaticAllocaMap[AI] =
          MF->getFrameInfo()->CreateStackObject(TySize, Align, false);
      }

  for (; BB != EB; ++BB)
    for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
      if (!I->use_empty() && isUsedOutsideOfDefiningBlock(I))
        if (!isa<AllocaInst>(I) ||
            !StaticAllocaMap.count(cast<AllocaInst>(I)))
          InitializeRegForValue(I);

  // Create an initial MachineBasicBlock for each LLVM BasicBlock in F.  This
  // also creates the initial PHI MachineInstrs, though none of the input
  // operands are populated.
  for (BB = Fn->begin(), EB = Fn->end(); BB != EB; ++BB) {
    MachineBasicBlock *MBB = mf.CreateMachineBasicBlock(BB);
    MBBMap[BB] = MBB;
    MF->push_back(MBB);

    // Transfer the address-taken flag. This is necessary because there could
    // be multiple MachineBasicBlocks corresponding to one BasicBlock, and only
    // the first one should be marked.
    if (BB->hasAddressTaken())
      MBB->setHasAddressTaken();

    // Create Machine PHI nodes for LLVM PHI nodes, lowering them as
    // appropriate.
    PHINode *PN;
    DebugLoc DL;
    for (BasicBlock::iterator
           I = BB->begin(), E = BB->end(); I != E; ++I) {

      PN = dyn_cast<PHINode>(I);
      if (!PN || PN->use_empty()) continue;

      unsigned PHIReg = ValueMap[PN];
      assert(PHIReg && "PHI node does not have an assigned virtual register!");

      SmallVector<EVT, 4> ValueVTs;
      ComputeValueVTs(TLI, PN->getType(), ValueVTs);
      for (unsigned vti = 0, vte = ValueVTs.size(); vti != vte; ++vti) {
        EVT VT = ValueVTs[vti];
        unsigned NumRegisters = TLI.getNumRegisters(Fn->getContext(), VT);
        const TargetInstrInfo *TII = MF->getTarget().getInstrInfo();
        for (unsigned i = 0; i != NumRegisters; ++i)
          BuildMI(MBB, DL, TII->get(TargetOpcode::PHI), PHIReg + i);
        PHIReg += NumRegisters;
      }
    }
  }
}

/// clear - Clear out all the function-specific state. This returns this
/// FunctionLoweringInfo to an empty state, ready to be used for a
/// different function.
void FunctionLoweringInfo::clear() {
  MBBMap.clear();
  ValueMap.clear();
  StaticAllocaMap.clear();
#ifndef NDEBUG
  CatchInfoLost.clear();
  CatchInfoFound.clear();
#endif
  LiveOutRegInfo.clear();
}

unsigned FunctionLoweringInfo::MakeReg(EVT VT) {
  return RegInfo->createVirtualRegister(TLI.getRegClassFor(VT));
}

/// CreateRegForValue - Allocate the appropriate number of virtual registers of
/// the correctly promoted or expanded types.  Assign these registers
/// consecutive vreg numbers and return the first assigned number.
///
/// In the case that the given value has struct or array type, this function
/// will assign registers for each member or element.
///
unsigned FunctionLoweringInfo::CreateRegForValue(const Value *V) {
  SmallVector<EVT, 4> ValueVTs;
  ComputeValueVTs(TLI, V->getType(), ValueVTs);

  unsigned FirstReg = 0;
  for (unsigned Value = 0, e = ValueVTs.size(); Value != e; ++Value) {
    EVT ValueVT = ValueVTs[Value];
    EVT RegisterVT = TLI.getRegisterType(V->getContext(), ValueVT);

    unsigned NumRegs = TLI.getNumRegisters(V->getContext(), ValueVT);
    for (unsigned i = 0; i != NumRegs; ++i) {
      unsigned R = MakeReg(RegisterVT);
      if (!FirstReg) FirstReg = R;
    }
  }
  return FirstReg;
}

/// ExtractTypeInfo - Returns the type info, possibly bitcast, encoded in V.
GlobalVariable *llvm::ExtractTypeInfo(Value *V) {
  V = V->stripPointerCasts();
  GlobalVariable *GV = dyn_cast<GlobalVariable>(V);
  assert ((GV || isa<ConstantPointerNull>(V)) &&
          "TypeInfo must be a global variable or NULL");
  return GV;
}

/// AddCatchInfo - Extract the personality and type infos from an eh.selector
/// call, and add them to the specified machine basic block.
void llvm::AddCatchInfo(CallInst &I, MachineModuleInfo *MMI,
                        MachineBasicBlock *MBB) {
  // Inform the MachineModuleInfo of the personality for this landing pad.
  ConstantExpr *CE = cast<ConstantExpr>(I.getOperand(2));
  assert(CE->getOpcode() == Instruction::BitCast &&
         isa<Function>(CE->getOperand(0)) &&
         "Personality should be a function");
  MMI->addPersonality(MBB, cast<Function>(CE->getOperand(0)));

  // Gather all the type infos for this landing pad and pass them along to
  // MachineModuleInfo.
  std::vector<GlobalVariable *> TyInfo;
  unsigned N = I.getNumOperands();

  for (unsigned i = N - 1; i > 2; --i) {
    if (ConstantInt *CI = dyn_cast<ConstantInt>(I.getOperand(i))) {
      unsigned FilterLength = CI->getZExtValue();
      unsigned FirstCatch = i + FilterLength + !FilterLength;
      assert (FirstCatch <= N && "Invalid filter length");

      if (FirstCatch < N) {
        TyInfo.reserve(N - FirstCatch);
        for (unsigned j = FirstCatch; j < N; ++j)
          TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
        MMI->addCatchTypeInfo(MBB, TyInfo);
        TyInfo.clear();
      }

      if (!FilterLength) {
        // Cleanup.
        MMI->addCleanup(MBB);
      } else {
        // Filter.
        TyInfo.reserve(FilterLength - 1);
        for (unsigned j = i + 1; j < FirstCatch; ++j)
          TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
        MMI->addFilterTypeInfo(MBB, TyInfo);
        TyInfo.clear();
      }

      N = i;
    }
  }

  if (N > 3) {
    TyInfo.reserve(N - 3);
    for (unsigned j = 3; j < N; ++j)
      TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
    MMI->addCatchTypeInfo(MBB, TyInfo);
  }
}

void llvm::CopyCatchInfo(BasicBlock *SrcBB, BasicBlock *DestBB,
                         MachineModuleInfo *MMI, FunctionLoweringInfo &FLI) {
  for (BasicBlock::iterator I = SrcBB->begin(), E = --SrcBB->end(); I != E; ++I)
    if (EHSelectorInst *EHSel = dyn_cast<EHSelectorInst>(I)) {
      // Apply the catch info to DestBB.
      AddCatchInfo(*EHSel, MMI, FLI.MBBMap[DestBB]);
#ifndef NDEBUG
      if (!FLI.MBBMap[SrcBB]->isLandingPad())
        FLI.CatchInfoFound.insert(EHSel);
#endif
    }
}
<commit_msg>Forgot the part where we handle the ".llvm.eh.catch.all.value".<commit_after>//===-- FunctionLoweringInfo.cpp ------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This implements routines for translating functions from LLVM IR into
// Machine IR.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "function-lowering-info"
#include "FunctionLoweringInfo.h"
#include "llvm/CallingConv.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetIntrinsicInfo.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;

/// ComputeLinearIndex - Given an LLVM IR aggregate type and a sequence
/// of insertvalue or extractvalue indices that identify a member, return
/// the linearized index of the start of the member.
///
unsigned llvm::ComputeLinearIndex(const TargetLowering &TLI, const Type *Ty,
                                  const unsigned *Indices,
                                  const unsigned *IndicesEnd,
                                  unsigned CurIndex) {
  // Base case: We're done.
  if (Indices && Indices == IndicesEnd)
    return CurIndex;

  // Given a struct type, recursively traverse the elements.
  if (const StructType *STy = dyn_cast<StructType>(Ty)) {
    for (StructType::element_iterator EB = STy->element_begin(),
                                      EI = EB,
                                      EE = STy->element_end();
        EI != EE; ++EI) {
      if (Indices && *Indices == unsigned(EI - EB))
        return ComputeLinearIndex(TLI, *EI, Indices+1, IndicesEnd, CurIndex);
      CurIndex = ComputeLinearIndex(TLI, *EI, 0, 0, CurIndex);
    }
    return CurIndex;
  }
  // Given an array type, recursively traverse the elements.
  else if (const ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
    const Type *EltTy = ATy->getElementType();
    for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
      if (Indices && *Indices == i)
        return ComputeLinearIndex(TLI, EltTy, Indices+1, IndicesEnd, CurIndex);
      CurIndex = ComputeLinearIndex(TLI, EltTy, 0, 0, CurIndex);
    }
    return CurIndex;
  }
  // We haven't found the type we're looking for, so keep searching.
  return CurIndex + 1;
}

/// ComputeValueVTs - Given an LLVM IR type, compute a sequence of
/// EVTs that represent all the individual underlying
/// non-aggregate types that comprise it.
///
/// If Offsets is non-null, it points to a vector to be filled in
/// with the in-memory offsets of each of the individual values.
///
void llvm::ComputeValueVTs(const TargetLowering &TLI, const Type *Ty,
                           SmallVectorImpl<EVT> &ValueVTs,
                           SmallVectorImpl<uint64_t> *Offsets,
                           uint64_t StartingOffset) {
  // Given a struct type, recursively traverse the elements.
  if (const StructType *STy = dyn_cast<StructType>(Ty)) {
    const StructLayout *SL = TLI.getTargetData()->getStructLayout(STy);
    for (StructType::element_iterator EB = STy->element_begin(),
                                      EI = EB,
                                      EE = STy->element_end();
         EI != EE; ++EI)
      ComputeValueVTs(TLI, *EI, ValueVTs, Offsets,
                      StartingOffset + SL->getElementOffset(EI - EB));
    return;
  }
  // Given an array type, recursively traverse the elements.
  if (const ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
    const Type *EltTy = ATy->getElementType();
    uint64_t EltSize = TLI.getTargetData()->getTypeAllocSize(EltTy);
    for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i)
      ComputeValueVTs(TLI, EltTy, ValueVTs, Offsets,
                      StartingOffset + i * EltSize);
    return;
  }
  // Interpret void as zero return values.
  if (Ty->isVoidTy())
    return;
  // Base case: we can get an EVT for this LLVM IR type.
  ValueVTs.push_back(TLI.getValueType(Ty));
  if (Offsets)
    Offsets->push_back(StartingOffset);
}

/// isUsedOutsideOfDefiningBlock - Return true if this instruction is used by
/// PHI nodes or outside of the basic block that defines it, or used by a
/// switch or atomic instruction, which may expand to multiple basic blocks.
static bool isUsedOutsideOfDefiningBlock(Instruction *I) {
  if (isa<PHINode>(I)) return true;
  BasicBlock *BB = I->getParent();
  for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); UI != E; ++UI)
    if (cast<Instruction>(*UI)->getParent() != BB || isa<PHINode>(*UI))
      return true;
  return false;
}

/// isOnlyUsedInEntryBlock - If the specified argument is only used in the
/// entry block, return true.  This includes arguments used by switches, since
/// the switch may expand into multiple basic blocks.
static bool isOnlyUsedInEntryBlock(Argument *A, bool EnableFastISel) {
  // With FastISel active, we may be splitting blocks, so force creation
  // of virtual registers for all non-dead arguments.
  // Don't force virtual registers for byval arguments though, because
  // fast-isel can't handle those in all cases.
  if (EnableFastISel && !A->hasByValAttr())
    return A->use_empty();

  BasicBlock *Entry = A->getParent()->begin();
  for (Value::use_iterator UI = A->use_begin(), E = A->use_end(); UI != E; ++UI)
    if (cast<Instruction>(*UI)->getParent() != Entry || isa<SwitchInst>(*UI))
      return false;  // Use not in entry block.
  return true;
}

FunctionLoweringInfo::FunctionLoweringInfo(TargetLowering &tli)
  : TLI(tli) {
}

void FunctionLoweringInfo::set(Function &fn, MachineFunction &mf,
                               bool EnableFastISel) {
  Fn = &fn;
  MF = &mf;
  RegInfo = &MF->getRegInfo();

  // Create a vreg for each argument register that is not dead and is used
  // outside of the entry block for the function.
  for (Function::arg_iterator AI = Fn->arg_begin(), E = Fn->arg_end();
       AI != E; ++AI)
    if (!isOnlyUsedInEntryBlock(AI, EnableFastISel))
      InitializeRegForValue(AI);

  // Initialize the mapping of values to registers.  This is only set up for
  // instruction values that are used outside of the block that defines
  // them.
  Function::iterator BB = Fn->begin(), EB = Fn->end();
  for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
    if (AllocaInst *AI = dyn_cast<AllocaInst>(I))
      if (ConstantInt *CUI = dyn_cast<ConstantInt>(AI->getArraySize())) {
        const Type *Ty = AI->getAllocatedType();
        uint64_t TySize = TLI.getTargetData()->getTypeAllocSize(Ty);
        unsigned Align =
          std::max((unsigned)TLI.getTargetData()->getPrefTypeAlignment(Ty),
                   AI->getAlignment());

        TySize *= CUI->getZExtValue();   // Get total allocated size.
        if (TySize == 0) TySize = 1; // Don't create zero-sized stack objects.
        StaticAllocaMap[AI] =
          MF->getFrameInfo()->CreateStackObject(TySize, Align, false);
      }

  for (; BB != EB; ++BB)
    for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
      if (!I->use_empty() && isUsedOutsideOfDefiningBlock(I))
        if (!isa<AllocaInst>(I) ||
            !StaticAllocaMap.count(cast<AllocaInst>(I)))
          InitializeRegForValue(I);

  // Create an initial MachineBasicBlock for each LLVM BasicBlock in F.  This
  // also creates the initial PHI MachineInstrs, though none of the input
  // operands are populated.
  for (BB = Fn->begin(), EB = Fn->end(); BB != EB; ++BB) {
    MachineBasicBlock *MBB = mf.CreateMachineBasicBlock(BB);
    MBBMap[BB] = MBB;
    MF->push_back(MBB);

    // Transfer the address-taken flag. This is necessary because there could
    // be multiple MachineBasicBlocks corresponding to one BasicBlock, and only
    // the first one should be marked.
    if (BB->hasAddressTaken())
      MBB->setHasAddressTaken();

    // Create Machine PHI nodes for LLVM PHI nodes, lowering them as
    // appropriate.
    PHINode *PN;
    DebugLoc DL;
    for (BasicBlock::iterator
           I = BB->begin(), E = BB->end(); I != E; ++I) {

      PN = dyn_cast<PHINode>(I);
      if (!PN || PN->use_empty()) continue;

      unsigned PHIReg = ValueMap[PN];
      assert(PHIReg && "PHI node does not have an assigned virtual register!");

      SmallVector<EVT, 4> ValueVTs;
      ComputeValueVTs(TLI, PN->getType(), ValueVTs);
      for (unsigned vti = 0, vte = ValueVTs.size(); vti != vte; ++vti) {
        EVT VT = ValueVTs[vti];
        unsigned NumRegisters = TLI.getNumRegisters(Fn->getContext(), VT);
        const TargetInstrInfo *TII = MF->getTarget().getInstrInfo();
        for (unsigned i = 0; i != NumRegisters; ++i)
          BuildMI(MBB, DL, TII->get(TargetOpcode::PHI), PHIReg + i);
        PHIReg += NumRegisters;
      }
    }
  }
}

/// clear - Clear out all the function-specific state. This returns this
/// FunctionLoweringInfo to an empty state, ready to be used for a
/// different function.
void FunctionLoweringInfo::clear() {
  MBBMap.clear();
  ValueMap.clear();
  StaticAllocaMap.clear();
#ifndef NDEBUG
  CatchInfoLost.clear();
  CatchInfoFound.clear();
#endif
  LiveOutRegInfo.clear();
}

unsigned FunctionLoweringInfo::MakeReg(EVT VT) {
  return RegInfo->createVirtualRegister(TLI.getRegClassFor(VT));
}

/// CreateRegForValue - Allocate the appropriate number of virtual registers of
/// the correctly promoted or expanded types.  Assign these registers
/// consecutive vreg numbers and return the first assigned number.
///
/// In the case that the given value has struct or array type, this function
/// will assign registers for each member or element.
///
unsigned FunctionLoweringInfo::CreateRegForValue(const Value *V) {
  SmallVector<EVT, 4> ValueVTs;
  ComputeValueVTs(TLI, V->getType(), ValueVTs);

  unsigned FirstReg = 0;
  for (unsigned Value = 0, e = ValueVTs.size(); Value != e; ++Value) {
    EVT ValueVT = ValueVTs[Value];
    EVT RegisterVT = TLI.getRegisterType(V->getContext(), ValueVT);

    unsigned NumRegs = TLI.getNumRegisters(V->getContext(), ValueVT);
    for (unsigned i = 0; i != NumRegs; ++i) {
      unsigned R = MakeReg(RegisterVT);
      if (!FirstReg) FirstReg = R;
    }
  }
  return FirstReg;
}

/// ExtractTypeInfo - Returns the type info, possibly bitcast, encoded in V.
GlobalVariable *llvm::ExtractTypeInfo(Value *V) {
  V = V->stripPointerCasts();
  GlobalVariable *GV = dyn_cast<GlobalVariable>(V);

  if (GV && GV->getName() == ".llvm.eh.catch.all.value") {
    assert(GV->hasInitializer() &&
           "The EH catch-all value must have an initializer");
    Value *Init = GV->getInitializer();
    GV = dyn_cast<GlobalVariable>(Init);
    if (!GV) V = cast<ConstantPointerNull>(Init);
  }

  assert((GV || isa<ConstantPointerNull>(V)) &&
         "TypeInfo must be a global variable or NULL");
  return GV;
}

/// AddCatchInfo - Extract the personality and type infos from an eh.selector
/// call, and add them to the specified machine basic block.
void llvm::AddCatchInfo(CallInst &I, MachineModuleInfo *MMI,
                        MachineBasicBlock *MBB) {
  // Inform the MachineModuleInfo of the personality for this landing pad.
  ConstantExpr *CE = cast<ConstantExpr>(I.getOperand(2));
  assert(CE->getOpcode() == Instruction::BitCast &&
         isa<Function>(CE->getOperand(0)) &&
         "Personality should be a function");
  MMI->addPersonality(MBB, cast<Function>(CE->getOperand(0)));

  // Gather all the type infos for this landing pad and pass them along to
  // MachineModuleInfo.
  std::vector<GlobalVariable *> TyInfo;
  unsigned N = I.getNumOperands();

  for (unsigned i = N - 1; i > 2; --i) {
    if (ConstantInt *CI = dyn_cast<ConstantInt>(I.getOperand(i))) {
      unsigned FilterLength = CI->getZExtValue();
      unsigned FirstCatch = i + FilterLength + !FilterLength;
      assert (FirstCatch <= N && "Invalid filter length");

      if (FirstCatch < N) {
        TyInfo.reserve(N - FirstCatch);
        for (unsigned j = FirstCatch; j < N; ++j)
          TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
        MMI->addCatchTypeInfo(MBB, TyInfo);
        TyInfo.clear();
      }

      if (!FilterLength) {
        // Cleanup.
        MMI->addCleanup(MBB);
      } else {
        // Filter.
        TyInfo.reserve(FilterLength - 1);
        for (unsigned j = i + 1; j < FirstCatch; ++j)
          TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
        MMI->addFilterTypeInfo(MBB, TyInfo);
        TyInfo.clear();
      }

      N = i;
    }
  }

  if (N > 3) {
    TyInfo.reserve(N - 3);
    for (unsigned j = 3; j < N; ++j)
      TyInfo.push_back(ExtractTypeInfo(I.getOperand(j)));
    MMI->addCatchTypeInfo(MBB, TyInfo);
  }
}

void llvm::CopyCatchInfo(BasicBlock *SrcBB, BasicBlock *DestBB,
                         MachineModuleInfo *MMI, FunctionLoweringInfo &FLI) {
  for (BasicBlock::iterator I = SrcBB->begin(), E = --SrcBB->end(); I != E; ++I)
    if (EHSelectorInst *EHSel = dyn_cast<EHSelectorInst>(I)) {
      // Apply the catch info to DestBB.
      AddCatchInfo(*EHSel, MMI, FLI.MBBMap[DestBB]);
#ifndef NDEBUG
      if (!FLI.MBBMap[SrcBB]->isLandingPad())
        FLI.CatchInfoFound.insert(EHSel);
#endif
    }
}
<|endoftext|>


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

#include "config.h"

#include <string>

#include "Document.h"
#include "DOMWindow.h"
#include "Frame.h"
#include "InspectorController.h"
#include "Node.h"
#include "Page.h"
#include "PlatformString.h"
#include "SecurityOrigin.h"
#include "V8Binding.h"
#include "V8CustomBinding.h"
#include "V8Proxy.h"
#include "V8Utilities.h"
#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
#undef LOG

#include "base/string_util.h"
#include "base/values.h"
#include "webkit/api/public/WebScriptSource.h"
#include "webkit/glue/devtools/bound_object.h"
#include "webkit/glue/devtools/debugger_agent.h"
#include "webkit/glue/devtools/devtools_rpc_js.h"
#include "webkit/glue/devtools/dom_agent.h"
#include "webkit/glue/devtools/tools_agent.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webdevtoolsclient_delegate.h"
#include "webkit/glue/webdevtoolsclient_impl.h"
#include "webkit/glue/webframe.h"
#include "webkit/glue/webview_impl.h"

using namespace WebCore;
using WebKit::WebScriptSource;
using WebKit::WebString;

DEFINE_RPC_JS_BOUND_OBJ(DebuggerAgent, DEBUGGER_AGENT_STRUCT,
    DebuggerAgentDelegate, DEBUGGER_AGENT_DELEGATE_STRUCT)
DEFINE_RPC_JS_BOUND_OBJ(DomAgent, DOM_AGENT_STRUCT,
    DomAgentDelegate, DOM_AGENT_DELEGATE_STRUCT)
DEFINE_RPC_JS_BOUND_OBJ(ToolsAgent, TOOLS_AGENT_STRUCT,
    ToolsAgentDelegate, TOOLS_AGENT_DELEGATE_STRUCT)

class ToolsAgentNativeDelegateImpl : public ToolsAgentNativeDelegate {
 public:
  struct ResourceContentRequestData {
    String mime_type;
    RefPtr<Node> frame;
  };

  ToolsAgentNativeDelegateImpl(WebFrameImpl* frame) : frame_(frame) {}
  virtual ~ToolsAgentNativeDelegateImpl() {}

  // ToolsAgentNativeDelegate implementation.
  virtual void DidGetResourceContent(int request_id, const String& content) {
    if (!resource_content_requests_.contains(request_id)) {
      NOTREACHED();
      return;
    }
    ResourceContentRequestData request =
        resource_content_requests_.take(request_id);

    InspectorController* ic = frame_->frame()->page()->inspectorController();
    if (request.frame && request.frame->attached()) {
      ic->addSourceToFrame(request.mime_type, content, request.frame.get());
    }
  }

  bool WaitingForResponse(int resource_id, Node* frame) {
    if (resource_content_requests_.contains(resource_id)) {
      DCHECK(resource_content_requests_.get(resource_id).frame.get() == frame)
          << "Only one frame is expected to display given resource";
      return true;
    }
    return false;
  }

  void RequestSent(int resource_id, String mime_type, Node* frame) {
    ResourceContentRequestData data;
    data.mime_type = mime_type;
    data.frame = frame;
    DCHECK(!resource_content_requests_.contains(resource_id));
    resource_content_requests_.set(resource_id, data);
  }

 private:
  WebFrameImpl* frame_;
  HashMap<int, ResourceContentRequestData> resource_content_requests_;
  DISALLOW_COPY_AND_ASSIGN(ToolsAgentNativeDelegateImpl);
};

namespace {

class RemoteDebuggerCommandExecutor : public CppBoundClass {
 public:
  RemoteDebuggerCommandExecutor(
      WebDevToolsClientDelegate* delegate,
      WebFrame* frame,
      const std::wstring& classname)
      : delegate_(delegate) {
    BindToJavascript(frame, classname);
    BindMethod("DebuggerCommand",
                &RemoteDebuggerCommandExecutor::DebuggerCommand);
  }
  virtual ~RemoteDebuggerCommandExecutor() {}

  // The DebuggerCommand() function provided to Javascript.
  void DebuggerCommand(const CppArgumentList& args, CppVariant* result) {
    std::string command = args[0].ToString();
    result->SetNull();
    delegate_->SendDebuggerCommandToAgent(command);
  }

 private:
  WebDevToolsClientDelegate* delegate_;
  DISALLOW_COPY_AND_ASSIGN(RemoteDebuggerCommandExecutor);
};

} //  namespace

// static
WebDevToolsClient* WebDevToolsClient::Create(
    WebView* view,
    WebDevToolsClientDelegate* delegate) {
  return new WebDevToolsClientImpl(static_cast<WebViewImpl*>(view), delegate);
}

WebDevToolsClientImpl::WebDevToolsClientImpl(
    WebViewImpl* web_view_impl,
    WebDevToolsClientDelegate* delegate)
    : web_view_impl_(web_view_impl),
      delegate_(delegate),
      loaded_(false) {
  WebFrameImpl* frame = web_view_impl_->main_frame();

  // Debugger commands should be sent using special method.
  debugger_command_executor_obj_.set(new RemoteDebuggerCommandExecutor(
      delegate, frame, L"RemoteDebuggerCommandExecutor"));
  debugger_agent_obj_.set(new JsDebuggerAgentBoundObj(
      this, frame, L"RemoteDebuggerAgent"));
  dom_agent_obj_.set(new JsDomAgentBoundObj(this, frame, L"RemoteDomAgent"));
  tools_agent_obj_.set(
      new JsToolsAgentBoundObj(this, frame, L"RemoteToolsAgent"));

  v8::HandleScope scope;
  v8::Handle<v8::Context> frame_context = V8Proxy::context(frame->frame());
  dev_tools_host_.set(new BoundObject(frame_context, this, "DevToolsHost"));
  dev_tools_host_->AddProtoFunction(
      "reset",
      WebDevToolsClientImpl::JsReset);
  dev_tools_host_->AddProtoFunction(
      "addSourceToFrame",
      WebDevToolsClientImpl::JsAddSourceToFrame);
  dev_tools_host_->AddProtoFunction(
      "addResourceSourceToFrame",
      WebDevToolsClientImpl::JsAddResourceSourceToFrame);
  dev_tools_host_->AddProtoFunction(
      "loaded",
      WebDevToolsClientImpl::JsLoaded);
  dev_tools_host_->AddProtoFunction(
      "search",
      WebCore::V8Custom::v8InspectorControllerSearchCallback);
  dev_tools_host_->AddProtoFunction(
      "getPlatform",
      WebDevToolsClientImpl::JsGetPlatform);
  dev_tools_host_->AddProtoFunction(
      "activateWindow",
      WebDevToolsClientImpl::JsActivateWindow);
  dev_tools_host_->AddProtoFunction(
      "closeWindow",
      WebDevToolsClientImpl::JsCloseWindow);
  dev_tools_host_->AddProtoFunction(
      "dockWindow",
      WebDevToolsClientImpl::JsDockWindow);
  dev_tools_host_->AddProtoFunction(
      "undockWindow",
      WebDevToolsClientImpl::JsUndockWindow);
  dev_tools_host_->AddProtoFunction(
      "toggleInspectElementMode",
      WebDevToolsClientImpl::JsToggleInspectElementMode);
  dev_tools_host_->Build();
}

WebDevToolsClientImpl::~WebDevToolsClientImpl() {
}

void WebDevToolsClientImpl::DispatchMessageFromAgent(
      const std::string& class_name,
      const std::string& method_name,
      const std::string& raw_msg) {
  if (ToolsAgentNativeDelegateDispatch::Dispatch(
          tools_agent_native_delegate_impl_.get(),
          class_name,
          method_name,
          raw_msg)) {
    return;
  }

  std::string expr = StringPrintf(
      "devtools.dispatch('%s','%s',%s)",
      class_name.c_str(),
      method_name.c_str(),
      raw_msg.c_str());
  if (!loaded_) {
    pending_incoming_messages_.append(expr);
    return;
  }
  ExecuteScript(expr);
}

void WebDevToolsClientImpl::AddResourceSourceToFrame(int resource_id,
                                                     String mime_type,
                                                     Node* frame) {
  if (tools_agent_native_delegate_impl_->WaitingForResponse(resource_id,
                                                            frame)) {
    return;
  }
  tools_agent_obj_->GetResourceContent(resource_id, resource_id);
  tools_agent_native_delegate_impl_->RequestSent(resource_id, mime_type, frame);
}

void WebDevToolsClientImpl::ExecuteScript(const std::string& expr) {
  web_view_impl_->GetMainFrame()->ExecuteScript(
      WebScriptSource(WebString::fromUTF8(expr)));
}

void WebDevToolsClientImpl::SendRpcMessage(const std::string& class_name,
                                           const std::string& method_name,
                                           const std::string& raw_msg) {
  delegate_->SendMessageToAgent(class_name, method_name, raw_msg);
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsReset(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  WebFrameImpl* frame = client->web_view_impl_->main_frame();
  client->tools_agent_native_delegate_impl_.set(
      new ToolsAgentNativeDelegateImpl(frame));
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsAddSourceToFrame(
    const v8::Arguments& args) {
  if (args.Length() < 2) {
    return v8::Undefined();
  }

  v8::TryCatch exception_catcher;

  String mime_type = WebCore::toWebCoreStringWithNullCheck(args[0]);
  if (mime_type.isEmpty() || exception_catcher.HasCaught()) {
    return v8::Undefined();
  }
  String source_string = WebCore::toWebCoreStringWithNullCheck(args[1]);
  if (source_string.isEmpty() || exception_catcher.HasCaught()) {
    return v8::Undefined();
  }
  Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(args[2]);
  if (!node || !node->attached()) {
    return v8::Undefined();
  }

  Page* page = V8Proxy::retrieveFrameForEnteredContext()->page();
  InspectorController* inspectorController = page->inspectorController();
  return WebCore::v8Boolean(inspectorController->
      addSourceToFrame(mime_type, source_string, node));
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsAddResourceSourceToFrame(
    const v8::Arguments& args) {
  int resource_id = static_cast<int>(args[0]->NumberValue());
  String mime_type = WebCore::toWebCoreStringWithNullCheck(args[1]);
  if (mime_type.isEmpty()) {
    return v8::Undefined();
  }
  Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(args[2]);
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->AddResourceSourceToFrame(resource_id, mime_type, node);
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsLoaded(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->loaded_ = true;

  // Grant the devtools page the ability to have source view iframes.
  Page* page = V8Proxy::retrieveFrameForEnteredContext()->page();
  SecurityOrigin* origin = page->mainFrame()->domWindow()->securityOrigin();
  origin->grantUniversalAccess();

  for (Vector<std::string>::iterator it =
           client->pending_incoming_messages_.begin();
       it != client->pending_incoming_messages_.end();
       ++it) {
    client->ExecuteScript(*it);
  }
  client->pending_incoming_messages_.clear();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsGetPlatform(
    const v8::Arguments& args) {
#if defined OS_MACOSX
  return v8String("mac-leopard");
#elif defined OS_LINUX
  return v8String("linux");
#else
  return v8String("windows");
#endif
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsActivateWindow(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->delegate_->ActivateWindow();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsCloseWindow(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->delegate_->CloseWindow();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsDockWindow(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->delegate_->DockWindow();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsUndockWindow(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->delegate_->UndockWindow();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsToggleInspectElementMode(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  int enabled = static_cast<int>(args[0]->BooleanValue());
  client->delegate_->ToggleInspectElementMode(enabled);
  return v8::Undefined();
}
<commit_msg>Land Anton's change to cast from v8::Value to v8::Object before converting a wrapper to a native Node pointer in devtools.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"

#include <string>

#include "Document.h"
#include "DOMWindow.h"
#include "Frame.h"
#include "InspectorController.h"
#include "Node.h"
#include "Page.h"
#include "PlatformString.h"
#include "SecurityOrigin.h"
#include "V8Binding.h"
#include "V8CustomBinding.h"
#include "V8Proxy.h"
#include "V8Utilities.h"
#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
#undef LOG

#include "base/string_util.h"
#include "base/values.h"
#include "webkit/api/public/WebScriptSource.h"
#include "webkit/glue/devtools/bound_object.h"
#include "webkit/glue/devtools/debugger_agent.h"
#include "webkit/glue/devtools/devtools_rpc_js.h"
#include "webkit/glue/devtools/dom_agent.h"
#include "webkit/glue/devtools/tools_agent.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webdevtoolsclient_delegate.h"
#include "webkit/glue/webdevtoolsclient_impl.h"
#include "webkit/glue/webframe.h"
#include "webkit/glue/webview_impl.h"

using namespace WebCore;
using WebKit::WebScriptSource;
using WebKit::WebString;

DEFINE_RPC_JS_BOUND_OBJ(DebuggerAgent, DEBUGGER_AGENT_STRUCT,
    DebuggerAgentDelegate, DEBUGGER_AGENT_DELEGATE_STRUCT)
DEFINE_RPC_JS_BOUND_OBJ(DomAgent, DOM_AGENT_STRUCT,
    DomAgentDelegate, DOM_AGENT_DELEGATE_STRUCT)
DEFINE_RPC_JS_BOUND_OBJ(ToolsAgent, TOOLS_AGENT_STRUCT,
    ToolsAgentDelegate, TOOLS_AGENT_DELEGATE_STRUCT)

class ToolsAgentNativeDelegateImpl : public ToolsAgentNativeDelegate {
 public:
  struct ResourceContentRequestData {
    String mime_type;
    RefPtr<Node> frame;
  };

  ToolsAgentNativeDelegateImpl(WebFrameImpl* frame) : frame_(frame) {}
  virtual ~ToolsAgentNativeDelegateImpl() {}

  // ToolsAgentNativeDelegate implementation.
  virtual void DidGetResourceContent(int request_id, const String& content) {
    if (!resource_content_requests_.contains(request_id)) {
      NOTREACHED();
      return;
    }
    ResourceContentRequestData request =
        resource_content_requests_.take(request_id);

    InspectorController* ic = frame_->frame()->page()->inspectorController();
    if (request.frame && request.frame->attached()) {
      ic->addSourceToFrame(request.mime_type, content, request.frame.get());
    }
  }

  bool WaitingForResponse(int resource_id, Node* frame) {
    if (resource_content_requests_.contains(resource_id)) {
      DCHECK(resource_content_requests_.get(resource_id).frame.get() == frame)
          << "Only one frame is expected to display given resource";
      return true;
    }
    return false;
  }

  void RequestSent(int resource_id, String mime_type, Node* frame) {
    ResourceContentRequestData data;
    data.mime_type = mime_type;
    data.frame = frame;
    DCHECK(!resource_content_requests_.contains(resource_id));
    resource_content_requests_.set(resource_id, data);
  }

 private:
  WebFrameImpl* frame_;
  HashMap<int, ResourceContentRequestData> resource_content_requests_;
  DISALLOW_COPY_AND_ASSIGN(ToolsAgentNativeDelegateImpl);
};

namespace {

class RemoteDebuggerCommandExecutor : public CppBoundClass {
 public:
  RemoteDebuggerCommandExecutor(
      WebDevToolsClientDelegate* delegate,
      WebFrame* frame,
      const std::wstring& classname)
      : delegate_(delegate) {
    BindToJavascript(frame, classname);
    BindMethod("DebuggerCommand",
                &RemoteDebuggerCommandExecutor::DebuggerCommand);
  }
  virtual ~RemoteDebuggerCommandExecutor() {}

  // The DebuggerCommand() function provided to Javascript.
  void DebuggerCommand(const CppArgumentList& args, CppVariant* result) {
    std::string command = args[0].ToString();
    result->SetNull();
    delegate_->SendDebuggerCommandToAgent(command);
  }

 private:
  WebDevToolsClientDelegate* delegate_;
  DISALLOW_COPY_AND_ASSIGN(RemoteDebuggerCommandExecutor);
};

} //  namespace

// static
WebDevToolsClient* WebDevToolsClient::Create(
    WebView* view,
    WebDevToolsClientDelegate* delegate) {
  return new WebDevToolsClientImpl(static_cast<WebViewImpl*>(view), delegate);
}

WebDevToolsClientImpl::WebDevToolsClientImpl(
    WebViewImpl* web_view_impl,
    WebDevToolsClientDelegate* delegate)
    : web_view_impl_(web_view_impl),
      delegate_(delegate),
      loaded_(false) {
  WebFrameImpl* frame = web_view_impl_->main_frame();

  // Debugger commands should be sent using special method.
  debugger_command_executor_obj_.set(new RemoteDebuggerCommandExecutor(
      delegate, frame, L"RemoteDebuggerCommandExecutor"));
  debugger_agent_obj_.set(new JsDebuggerAgentBoundObj(
      this, frame, L"RemoteDebuggerAgent"));
  dom_agent_obj_.set(new JsDomAgentBoundObj(this, frame, L"RemoteDomAgent"));
  tools_agent_obj_.set(
      new JsToolsAgentBoundObj(this, frame, L"RemoteToolsAgent"));

  v8::HandleScope scope;
  v8::Handle<v8::Context> frame_context = V8Proxy::context(frame->frame());
  dev_tools_host_.set(new BoundObject(frame_context, this, "DevToolsHost"));
  dev_tools_host_->AddProtoFunction(
      "reset",
      WebDevToolsClientImpl::JsReset);
  dev_tools_host_->AddProtoFunction(
      "addSourceToFrame",
      WebDevToolsClientImpl::JsAddSourceToFrame);
  dev_tools_host_->AddProtoFunction(
      "addResourceSourceToFrame",
      WebDevToolsClientImpl::JsAddResourceSourceToFrame);
  dev_tools_host_->AddProtoFunction(
      "loaded",
      WebDevToolsClientImpl::JsLoaded);
  dev_tools_host_->AddProtoFunction(
      "search",
      WebCore::V8Custom::v8InspectorControllerSearchCallback);
  dev_tools_host_->AddProtoFunction(
      "getPlatform",
      WebDevToolsClientImpl::JsGetPlatform);
  dev_tools_host_->AddProtoFunction(
      "activateWindow",
      WebDevToolsClientImpl::JsActivateWindow);
  dev_tools_host_->AddProtoFunction(
      "closeWindow",
      WebDevToolsClientImpl::JsCloseWindow);
  dev_tools_host_->AddProtoFunction(
      "dockWindow",
      WebDevToolsClientImpl::JsDockWindow);
  dev_tools_host_->AddProtoFunction(
      "undockWindow",
      WebDevToolsClientImpl::JsUndockWindow);
  dev_tools_host_->AddProtoFunction(
      "toggleInspectElementMode",
      WebDevToolsClientImpl::JsToggleInspectElementMode);
  dev_tools_host_->Build();
}

WebDevToolsClientImpl::~WebDevToolsClientImpl() {
}

void WebDevToolsClientImpl::DispatchMessageFromAgent(
      const std::string& class_name,
      const std::string& method_name,
      const std::string& raw_msg) {
  if (ToolsAgentNativeDelegateDispatch::Dispatch(
          tools_agent_native_delegate_impl_.get(),
          class_name,
          method_name,
          raw_msg)) {
    return;
  }

  std::string expr = StringPrintf(
      "devtools.dispatch('%s','%s',%s)",
      class_name.c_str(),
      method_name.c_str(),
      raw_msg.c_str());
  if (!loaded_) {
    pending_incoming_messages_.append(expr);
    return;
  }
  ExecuteScript(expr);
}

void WebDevToolsClientImpl::AddResourceSourceToFrame(int resource_id,
                                                     String mime_type,
                                                     Node* frame) {
  if (tools_agent_native_delegate_impl_->WaitingForResponse(resource_id,
                                                            frame)) {
    return;
  }
  tools_agent_obj_->GetResourceContent(resource_id, resource_id);
  tools_agent_native_delegate_impl_->RequestSent(resource_id, mime_type, frame);
}

void WebDevToolsClientImpl::ExecuteScript(const std::string& expr) {
  web_view_impl_->GetMainFrame()->ExecuteScript(
      WebScriptSource(WebString::fromUTF8(expr)));
}

void WebDevToolsClientImpl::SendRpcMessage(const std::string& class_name,
                                           const std::string& method_name,
                                           const std::string& raw_msg) {
  delegate_->SendMessageToAgent(class_name, method_name, raw_msg);
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsReset(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  WebFrameImpl* frame = client->web_view_impl_->main_frame();
  client->tools_agent_native_delegate_impl_.set(
      new ToolsAgentNativeDelegateImpl(frame));
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsAddSourceToFrame(
    const v8::Arguments& args) {
  if (args.Length() < 2) {
    return v8::Undefined();
  }

  v8::TryCatch exception_catcher;

  String mime_type = WebCore::toWebCoreStringWithNullCheck(args[0]);
  if (mime_type.isEmpty() || exception_catcher.HasCaught()) {
    return v8::Undefined();
  }
  String source_string = WebCore::toWebCoreStringWithNullCheck(args[1]);
  if (source_string.isEmpty() || exception_catcher.HasCaught()) {
    return v8::Undefined();
  }
  v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(args[2]);
  Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(wrapper);
  if (!node || !node->attached()) {
    return v8::Undefined();
  }

  Page* page = V8Proxy::retrieveFrameForEnteredContext()->page();
  InspectorController* inspectorController = page->inspectorController();
  return WebCore::v8Boolean(inspectorController->
      addSourceToFrame(mime_type, source_string, node));
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsAddResourceSourceToFrame(
    const v8::Arguments& args) {
  int resource_id = static_cast<int>(args[0]->NumberValue());
  String mime_type = WebCore::toWebCoreStringWithNullCheck(args[1]);
  if (mime_type.isEmpty()) {
    return v8::Undefined();
  }
  v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(args[2]);
  Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(wrapper);
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->AddResourceSourceToFrame(resource_id, mime_type, node);
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsLoaded(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->loaded_ = true;

  // Grant the devtools page the ability to have source view iframes.
  Page* page = V8Proxy::retrieveFrameForEnteredContext()->page();
  SecurityOrigin* origin = page->mainFrame()->domWindow()->securityOrigin();
  origin->grantUniversalAccess();

  for (Vector<std::string>::iterator it =
           client->pending_incoming_messages_.begin();
       it != client->pending_incoming_messages_.end();
       ++it) {
    client->ExecuteScript(*it);
  }
  client->pending_incoming_messages_.clear();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsGetPlatform(
    const v8::Arguments& args) {
#if defined OS_MACOSX
  return v8String("mac-leopard");
#elif defined OS_LINUX
  return v8String("linux");
#else
  return v8String("windows");
#endif
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsActivateWindow(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->delegate_->ActivateWindow();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsCloseWindow(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->delegate_->CloseWindow();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsDockWindow(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->delegate_->DockWindow();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsUndockWindow(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  client->delegate_->UndockWindow();
  return v8::Undefined();
}

// static
v8::Handle<v8::Value> WebDevToolsClientImpl::JsToggleInspectElementMode(
    const v8::Arguments& args) {
  WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
      v8::External::Cast(*args.Data())->Value());
  int enabled = static_cast<int>(args[0]->BooleanValue());
  client->delegate_->ToggleInspectElementMode(enabled);
  return v8::Undefined();
}
<|endoftext|>