<commit_before>// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - 3D Module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/3D/Model.hpp>
#include <Nazara/3D/Config.hpp>
#include <memory>
#include <Nazara/3D/Debug.hpp>

NzModel::NzModel() :
m_animation(nullptr),
m_mesh(nullptr),
m_currentSequence(nullptr),
m_matCount(0),
m_skinCount(0)
{
}

NzModel::NzModel(const NzModel& model) :
m_materials(model.m_materials),
m_animation(model.m_animation),
m_mesh(model.m_mesh),
m_currentSequence(model.m_currentSequence),
m_matCount(model.m_matCount),
m_skinCount(model.m_skinCount)
{
	if (m_mesh)
	{
		if (m_animation)
			m_animation->AddResourceReference();

		m_mesh->AddResourceReference();

		// Nous n'avons des matériaux que si nous avons un mesh
		for (const NzMaterial* material : m_materials)
			material->AddResourceReference();
	}
}

NzModel::~NzModel()
{
	Reset();
}

const NzAnimation* NzModel::GetAnimation() const
{
	return m_animation;
}

const NzMaterial* NzModel::GetMaterial(unsigned int matIndex) const
{
	#if NAZARA_3D_SAFE
	if (matIndex >= m_matCount)
	{
		NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_matCount));
		return nullptr;
	}
	#endif

	return m_materials[matIndex];
}

const NzMaterial* NzModel::GetMaterial(unsigned int skinIndex, unsigned int matIndex) const
{
	#if NAZARA_3D_SAFE
	if (skinIndex >= m_skinCount)
	{
		NazaraError("Skin index out of range (" + NzString::Number(skinIndex) + " >= " + NzString::Number(m_skinCount));
		return nullptr;
	}

	if (matIndex >= m_matCount)
	{
		NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_matCount));
		return nullptr;
	}
	#endif

	return m_materials[matIndex];
}

unsigned int NzModel::GetMaterialCount() const
{
	return m_matCount;
}
unsigned int NzModel::GetSkinCount() const
{
	return m_skinCount;
}

const NzMesh* NzModel::GetMesh() const
{
	return m_mesh;
}

nzSceneNodeType NzModel::GetSceneNodeType() const
{
	return nzSceneNodeType_Model;
}

const NzSkeleton* NzModel::GetSkeleton() const
{
	return &m_skeleton;
}

bool NzModel::HasAnimation() const
{
	return m_animation != nullptr;
}

bool NzModel::LoadFromFile(const NzString& meshPath, const NzMeshParams& meshParameters, const NzModelParameters& modelParameters)
{
	///TODO: ResourceManager
	std::unique_ptr<NzMesh> mesh(new NzMesh);
	if (!mesh->LoadFromFile(meshPath, meshParameters))
	{
		NazaraError("Failed to load mesh");
		return false;
	}

	mesh->SetPersistent(false, false);
	SetMesh(mesh.release(), modelParameters);

	return true;
}

bool NzModel::LoadFromMemory(const void* data, std::size_t size, const NzMeshParams& meshParameters, const NzModelParameters& modelParameters)
{
	std::unique_ptr<NzMesh> mesh(new NzMesh);
	if (!mesh->LoadFromMemory(data, size, meshParameters))
	{
		NazaraError("Failed to load mesh");
		return false;
	}

	mesh->SetPersistent(false, false);
	SetMesh(mesh.release(), modelParameters);

	return true;
}

bool NzModel::LoadFromStream(NzInputStream& stream, const NzMeshParams& meshParameters, const NzModelParameters& modelParameters)
{
	std::unique_ptr<NzMesh> mesh(new NzMesh);
	if (!mesh->LoadFromStream(stream, meshParameters))
	{
		NazaraError("Failed to load mesh");
		return false;
	}

	mesh->SetPersistent(false, false);
	SetMesh(mesh.release(), modelParameters);

	return true;
}

void NzModel::Reset()
{
	m_matCount = 0;
	m_skinCount = 0;

	if (m_mesh)
	{
		m_mesh->RemoveResourceReference();
		m_mesh = nullptr;

		m_skeleton.Destroy();

		if (m_animation)
		{
			m_animation->RemoveResourceReference();
			m_animation = nullptr;
		}

		// Nous n'avons des matériaux que si nous avons un mesh
		for (const NzMaterial* material : m_materials)
			material->RemoveResourceReference();

		m_materials.clear();
	}
}

bool NzModel::SetAnimation(const NzAnimation* animation)
{
	#if NAZARA_3D_SAFE
	if (!m_mesh)
	{
		NazaraError("Model has no animation");
		return false;
	}

	if (animation)
	{
		if (!animation->IsValid())
		{
			NazaraError("Invalid animation");
			return false;
		}

		if (animation->GetType() != m_mesh->GetAnimationType())
		{
			NazaraError("Animation type must match mesh animation type");
			return false;
		}

		if (animation->GetType() == nzAnimationType_Skeletal && animation->GetJointCount() != m_mesh->GetJointCount())
		{
			NazaraError("Animation joint count must match mesh joint count");
			return false;
		}
	}
	#endif

	m_animation = animation;
	if (m_animation)
	{
		m_animation->AddResourceReference();
		SetSequence(0);
	}

	return true;
}

void NzModel::SetMaterial(unsigned int matIndex, const NzMaterial* material)
{
	#if NAZARA_3D_SAFE
	if (matIndex >= m_matCount)
	{
		NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_matCount));
		return;
	}
	#endif

	m_materials[matIndex]->RemoveResourceReference();

	if (material)
		m_materials[matIndex] = material;
	else
		m_materials[matIndex] = NzMaterial::GetDefault();

	m_materials[matIndex]->AddResourceReference();
}

void NzModel::SetMaterial(unsigned int skinIndex, unsigned int matIndex, const NzMaterial* material)
{
	#if NAZARA_3D_SAFE
	if (skinIndex >= m_skinCount)
	{
		NazaraError("Skin index out of range (" + NzString::Number(skinIndex) + " >= " + NzString::Number(m_skinCount));
		return;
	}

	if (matIndex >= m_matCount)
	{
		NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_matCount));
		return;
	}
	#endif

	unsigned int index = skinIndex*m_matCount + matIndex;

	m_materials[index]->RemoveResourceReference();

	if (material)
		m_materials[index] = material;
	else
		m_materials[index] = NzMaterial::GetDefault();

	m_materials[index]->AddResourceReference();
}

void NzModel::SetMesh(const NzMesh* mesh, const NzModelParameters& modelParameters)
{
	Reset();

	if (mesh)
	{
		m_mesh = mesh;
		m_mesh->AddResourceReference();

		if (m_mesh->GetAnimationType() == nzAnimationType_Skeletal)
			m_skeleton = *mesh->GetSkeleton(); // Copie du squelette template

		if (modelParameters.loadAnimation)
		{
			NzString animationPath = m_mesh->GetAnimation();
			if (!animationPath.IsEmpty())
			{
				std::unique_ptr<NzAnimation> animation(new NzAnimation);
				if (animation->LoadFromFile(animationPath, modelParameters.animationParams) && SetAnimation(animation.get()))
				{
					animation->SetPersistent(false);
					animation.release();
				}
				else
					NazaraWarning("Failed to load animation");
			}
		}

		m_interpolation = 0.f;
		m_matCount = mesh->GetMaterialCount();
		m_materials.resize(m_matCount, NzMaterial::GetDefault());
		if (modelParameters.loadMaterials)
		{
			for (unsigned int i = 0; i < m_matCount; ++i)
			{
				NzString mat = mesh->GetMaterial(i);
				if (!mat.IsEmpty())
				{
					std::unique_ptr<NzMaterial> material(new NzMaterial);
					if (material->LoadFromFile(mat, modelParameters.materialParams))
					{
						material->SetPersistent(false, false); // Pas de vérification des références car nous n'y avons pas encore accroché de référence
						m_materials[i] = material.release();
					}
					else
						NazaraWarning("Failed to load material #" + NzString::Number(i));
				}
			}
		}

		for (const NzMaterial* material : m_materials)
			material->AddResourceReference();
	}
}

void NzModel::SetSkinCount(unsigned int skinCount)
{
	#if NAZARA_3D_SAFE
	if (skinCount == 0)
	{
		NazaraError("Skin count must be over 0");
		return;
	}
	#endif

	m_materials.resize(m_matCount*skinCount, NzMaterial::GetDefault());
	m_skinCount = skinCount;
}

bool NzModel::SetSequence(const NzString& sequenceName)
{
	#if NAZARA_3D_SAFE
	if (!m_animation)
	{
		NazaraError("Model has no animation");
		return false;
	}
	#endif

	m_currentSequence = m_animation->GetSequence(sequenceName);
	if (m_currentSequence)
	{
		m_nextFrame = m_currentSequence->firstFrame;
		return true;
	}
	else
	{
		NazaraError("Sequence not found");
		return false;
	}
}

void NzModel::SetSequence(unsigned int sequenceIndex)
{
	#if NAZARA_3D_SAFE
	if (!m_animation)
	{
		NazaraError("Model has no animation");
		return;
	}
	#endif

	m_currentSequence = m_animation->GetSequence(sequenceIndex);
	m_nextFrame = m_currentSequence->firstFrame;
}

void NzModel::Update(float elapsedTime)
{
	#if NAZARA_3D_SAFE
	if (!m_animation)
	{
		NazaraError("Model has no animation");
		return;
	}
	#endif

	m_interpolation += m_currentSequence->frameRate * elapsedTime;
	while (m_interpolation > 1.f)
	{
		m_interpolation -= 1.f;

		m_currentFrame = m_nextFrame;
		if (++m_nextFrame >= m_currentSequence->firstFrame+m_currentSequence->frameCount)
			m_nextFrame = m_currentSequence->firstFrame;
	}

	m_mesh->Animate(m_animation, m_currentFrame, m_nextFrame, m_interpolation);
}
<commit_msg>Fixed interpolation while looping a sequence<commit_after>// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - 3D Module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/3D/Model.hpp>
#include <Nazara/3D/Config.hpp>
#include <memory>
#include <Nazara/3D/Debug.hpp>

NzModel::NzModel() :
m_animation(nullptr),
m_mesh(nullptr),
m_currentSequence(nullptr),
m_matCount(0),
m_skinCount(0)
{
}

NzModel::NzModel(const NzModel& model) :
m_materials(model.m_materials),
m_animation(model.m_animation),
m_mesh(model.m_mesh),
m_currentSequence(model.m_currentSequence),
m_matCount(model.m_matCount),
m_skinCount(model.m_skinCount)
{
	if (m_mesh)
	{
		if (m_animation)
			m_animation->AddResourceReference();

		m_mesh->AddResourceReference();

		// Nous n'avons des matériaux que si nous avons un mesh
		for (const NzMaterial* material : m_materials)
			material->AddResourceReference();
	}
}

NzModel::~NzModel()
{
	Reset();
}

const NzAnimation* NzModel::GetAnimation() const
{
	return m_animation;
}

const NzMaterial* NzModel::GetMaterial(unsigned int matIndex) const
{
	#if NAZARA_3D_SAFE
	if (matIndex >= m_matCount)
	{
		NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_matCount));
		return nullptr;
	}
	#endif

	return m_materials[matIndex];
}

const NzMaterial* NzModel::GetMaterial(unsigned int skinIndex, unsigned int matIndex) const
{
	#if NAZARA_3D_SAFE
	if (skinIndex >= m_skinCount)
	{
		NazaraError("Skin index out of range (" + NzString::Number(skinIndex) + " >= " + NzString::Number(m_skinCount));
		return nullptr;
	}

	if (matIndex >= m_matCount)
	{
		NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_matCount));
		return nullptr;
	}
	#endif

	return m_materials[matIndex];
}

unsigned int NzModel::GetMaterialCount() const
{
	return m_matCount;
}

unsigned int NzModel::GetSkinCount() const
{
	return m_skinCount;
}

const NzMesh* NzModel::GetMesh() const
{
	return m_mesh;
}

nzSceneNodeType NzModel::GetSceneNodeType() const
{
	return nzSceneNodeType_Model;
}

const NzSkeleton* NzModel::GetSkeleton() const
{
	return &m_skeleton;
}

bool NzModel::HasAnimation() const
{
	return m_animation != nullptr;
}

bool NzModel::LoadFromFile(const NzString& meshPath, const NzMeshParams& meshParameters, const NzModelParameters& modelParameters)
{
	///TODO: ResourceManager
	std::unique_ptr<NzMesh> mesh(new NzMesh);
	if (!mesh->LoadFromFile(meshPath, meshParameters))
	{
		NazaraError("Failed to load mesh");
		return false;
	}

	mesh->SetPersistent(false, false);
	SetMesh(mesh.release(), modelParameters);

	return true;
}

bool NzModel::LoadFromMemory(const void* data, std::size_t size, const NzMeshParams& meshParameters, const NzModelParameters& modelParameters)
{
	std::unique_ptr<NzMesh> mesh(new NzMesh);
	if (!mesh->LoadFromMemory(data, size, meshParameters))
	{
		NazaraError("Failed to load mesh");
		return false;
	}

	mesh->SetPersistent(false, false);
	SetMesh(mesh.release(), modelParameters);

	return true;
}

bool NzModel::LoadFromStream(NzInputStream& stream, const NzMeshParams& meshParameters, const NzModelParameters& modelParameters)
{
	std::unique_ptr<NzMesh> mesh(new NzMesh);
	if (!mesh->LoadFromStream(stream, meshParameters))
	{
		NazaraError("Failed to load mesh");
		return false;
	}

	mesh->SetPersistent(false, false);
	SetMesh(mesh.release(), modelParameters);

	return true;
}

void NzModel::Reset()
{
	m_matCount = 0;
	m_skinCount = 0;

	if (m_mesh)
	{
		m_mesh->RemoveResourceReference();
		m_mesh = nullptr;

		m_skeleton.Destroy();

		if (m_animation)
		{
			m_animation->RemoveResourceReference();
			m_animation = nullptr;
		}

		// Nous n'avons des matériaux que si nous avons un mesh
		for (const NzMaterial* material : m_materials)
			material->RemoveResourceReference();

		m_materials.clear();
	}
}

bool NzModel::SetAnimation(const NzAnimation* animation)
{
	#if NAZARA_3D_SAFE
	if (!m_mesh)
	{
		NazaraError("Model has no animation");
		return false;
	}

	if (animation)
	{
		if (!animation->IsValid())
		{
			NazaraError("Invalid animation");
			return false;
		}

		if (animation->GetType() != m_mesh->GetAnimationType())
		{
			NazaraError("Animation type must match mesh animation type");
			return false;
		}

		if (animation->GetType() == nzAnimationType_Skeletal && animation->GetJointCount() != m_mesh->GetJointCount())
		{
			NazaraError("Animation joint count must match mesh joint count");
			return false;
		}
	}
	#endif

	m_animation = animation;
	if (m_animation)
	{
		m_animation->AddResourceReference();
		m_currentFrame = 0;
		m_interpolation = 0.f;

		SetSequence(0);
	}

	return true;
}

void NzModel::SetMaterial(unsigned int matIndex, const NzMaterial* material)
{
	#if NAZARA_3D_SAFE
	if (matIndex >= m_matCount)
	{
		NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_matCount));
		return;
	}
	#endif

	m_materials[matIndex]->RemoveResourceReference();

	if (material)
		m_materials[matIndex] = material;
	else
		m_materials[matIndex] = NzMaterial::GetDefault();

	m_materials[matIndex]->AddResourceReference();
}

void NzModel::SetMaterial(unsigned int skinIndex, unsigned int matIndex, const NzMaterial* material)
{
	#if NAZARA_3D_SAFE
	if (skinIndex >= m_skinCount)
	{
		NazaraError("Skin index out of range (" + NzString::Number(skinIndex) + " >= " + NzString::Number(m_skinCount));
		return;
	}

	if (matIndex >= m_matCount)
	{
		NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_matCount));
		return;
	}
	#endif

	unsigned int index = skinIndex*m_matCount + matIndex;

	m_materials[index]->RemoveResourceReference();

	if (material)
		m_materials[index] = material;
	else
		m_materials[index] = NzMaterial::GetDefault();

	m_materials[index]->AddResourceReference();
}

void NzModel::SetMesh(const NzMesh* mesh, const NzModelParameters& modelParameters)
{
	Reset();

	if (mesh)
	{
		m_mesh = mesh;
		m_mesh->AddResourceReference();

		if (m_mesh->GetAnimationType() == nzAnimationType_Skeletal)
			m_skeleton = *mesh->GetSkeleton(); // Copie du squelette template

		if (modelParameters.loadAnimation)
		{
			NzString animationPath = m_mesh->GetAnimation();
			if (!animationPath.IsEmpty())
			{
				std::unique_ptr<NzAnimation> animation(new NzAnimation);
				if (animation->LoadFromFile(animationPath, modelParameters.animationParams) && SetAnimation(animation.get()))
				{
					animation->SetPersistent(false);
					animation.release();
				}
				else
					NazaraWarning("Failed to load animation");
			}
		}

		m_matCount = mesh->GetMaterialCount();
		m_materials.resize(m_matCount, NzMaterial::GetDefault());
		if (modelParameters.loadMaterials)
		{
			for (unsigned int i = 0; i < m_matCount; ++i)
			{
				NzString mat = mesh->GetMaterial(i);
				if (!mat.IsEmpty())
				{
					std::unique_ptr<NzMaterial> material(new NzMaterial);
					if (material->LoadFromFile(mat, modelParameters.materialParams))
					{
						material->SetPersistent(false, false); // Pas de vérification des références car nous n'y avons pas encore accroché de référence
						m_materials[i] = material.release();
					}
					else
						NazaraWarning("Failed to load material #" + NzString::Number(i));
				}
			}
		}

		for (const NzMaterial* material : m_materials)
			material->AddResourceReference();
	}
}

void NzModel::SetSkinCount(unsigned int skinCount)
{
	#if NAZARA_3D_SAFE
	if (skinCount == 0)
	{
		NazaraError("Skin count must be over 0");
		return;
	}
	#endif

	m_materials.resize(m_matCount*skinCount, NzMaterial::GetDefault());
	m_skinCount = skinCount;
}

bool NzModel::SetSequence(const NzString& sequenceName)
{
	#if NAZARA_3D_SAFE
	if (!m_animation)
	{
		NazaraError("Model has no animation");
		return false;
	}
	#endif

	m_currentSequence = m_animation->GetSequence(sequenceName);
	if (m_currentSequence)
	{
		m_nextFrame = m_currentSequence->firstFrame;
		return true;
	}
	else
	{
		NazaraError("Sequence not found");
		return false;
	}
}

void NzModel::SetSequence(unsigned int sequenceIndex)
{
	#if NAZARA_3D_SAFE
	if (!m_animation)
	{
		NazaraError("Model has no animation");
		return;
	}
	#endif

	m_currentSequence = m_animation->GetSequence(sequenceIndex);
	m_nextFrame = m_currentSequence->firstFrame;
}

void NzModel::Update(float elapsedTime)
{
	#if NAZARA_3D_SAFE
	if (!m_animation)
	{
		NazaraError("Model has no animation");
		return;
	}
	#endif

	m_interpolation += m_currentSequence->frameRate * elapsedTime;
	while (m_interpolation > 1.f)
	{
		m_interpolation -= 1.f;

		unsigned lastFrame = m_currentSequence->firstFrame + m_currentSequence->frameCount - 1;
		if (m_nextFrame+1 > lastFrame)
		{
			m_currentFrame = m_currentSequence->firstFrame;
			m_nextFrame = m_currentFrame+1;
		}
		else
		{
			m_currentFrame = m_nextFrame;
			m_nextFrame++;
		}
	}

	m_mesh->Animate(m_animation, m_currentFrame, m_nextFrame, m_interpolation);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "PictureRenderer.h"
#include "SamplePipeControllers.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkImageEncoder.h"
#include "SkGPipe.h"
#include "SkPicture.h"
#include "SkString.h"
#include "SkTDArray.h"
#include "SkTypes.h"
#include "picture_utils.h"

#if SK_SUPPORT_GPU
#include "SkGpuDevice.h"
#endif

namespace sk_tools {

enum {
    kDefaultTileWidth = 256,
    kDefaultTileHeight = 256
};

void PictureRenderer::init(SkPicture* pict) {
    SkASSERT(NULL == fPicture);
    SkASSERT(NULL == fCanvas.get());
    if (fPicture != NULL || NULL != fCanvas.get()) {
        return;
    }

    SkASSERT(pict != NULL);
    if (NULL == pict) {
        return;
    }

    fPicture = pict;
    fCanvas.reset(this->setupCanvas());
}

SkCanvas* PictureRenderer::setupCanvas() {
    return this->setupCanvas(fPicture->width(), fPicture->height());
}

SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
    switch(fDeviceType) {
        case kBitmap_DeviceType: {
            SkBitmap bitmap;
            sk_tools::setup_bitmap(&bitmap, width, height);
            return SkNEW_ARGS(SkCanvas, (bitmap));
            break;
        }
#if SK_SUPPORT_GPU
        case kGPU_DeviceType: {
            SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice,
                                                    (fGrContext, SkBitmap::kARGB_8888_Config,
                                                    width, height)));
            return SkNEW_ARGS(SkCanvas, (device.get()));
            break;
        }
#endif
        default:
            SkASSERT(0);
    }

    return NULL;
}

void PictureRenderer::end() {
    this->resetState();
    fPicture = NULL;
    fCanvas.reset(NULL);
}

void PictureRenderer::resetState() {
#if SK_SUPPORT_GPU
    if (this->isUsingGpuDevice()) {
        SkGLContext* glContext = fGrContextFactory.getGLContext(
            GrContextFactory::kNative_GLContextType);
        SK_GL(*glContext, Finish());
    }
#endif
}

void PictureRenderer::finishDraw() {
    SkASSERT(fCanvas.get() != NULL);
    if (NULL == fCanvas.get()) {
        return;
    }

    fCanvas->flush();

#if SK_SUPPORT_GPU
    if (this->isUsingGpuDevice()) {
        SkGLContext* glContext = fGrContextFactory.getGLContext(
            GrContextFactory::kNative_GLContextType);

        SkASSERT(glContext != NULL);
        if (NULL == glContext) {
            return;
        }

        SK_GL(*glContext, Finish());
    }
#endif
}

bool PictureRenderer::write(const SkString& path) const {
    SkASSERT(fCanvas.get() != NULL);
    SkASSERT(fPicture != NULL);
    if (NULL == fCanvas.get() || NULL == fPicture) {
        return false;
    }

    SkBitmap bitmap;
    sk_tools::setup_bitmap(&bitmap, fPicture->width(), fPicture->height());

    fCanvas->readPixels(&bitmap, 0, 0);
    sk_tools::force_all_opaque(bitmap);

    return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
}

void PipePictureRenderer::render() {
    SkASSERT(fCanvas.get() != NULL);
    SkASSERT(fPicture != NULL);
    if (NULL == fCanvas.get() || NULL == fPicture) {
        return;
    }

    PipeController pipeController(fCanvas.get());
    SkGPipeWriter writer;
    SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
    pipeCanvas->drawPicture(*fPicture);
    writer.endRecording();
    this->finishDraw();
}

void SimplePictureRenderer::render() {
    SkASSERT(fCanvas.get() != NULL);
    SkASSERT(fPicture != NULL);
    if (NULL == fCanvas.get() || NULL == fPicture) {
        return;
    }

    fCanvas->drawPicture(*fPicture);
    this->finishDraw();
}

TiledPictureRenderer::TiledPictureRenderer()
    : fTileWidth(kDefaultTileWidth)
    , fTileHeight(kDefaultTileHeight) {}

void TiledPictureRenderer::init(SkPicture* pict) {
    SkASSERT(pict != NULL);
    SkASSERT(0 == fTiles.count());
    if (NULL == pict || fTiles.count() != 0) {
        return;
    }

    this->INHERITED::init(pict);

    if (fTileWidthPercentage > 0) {
        fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100));
    }
    if (fTileHeightPercentage > 0) {
        fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100));
    }

    this->setupTiles();
}

void TiledPictureRenderer::render() {
    SkASSERT(fCanvas.get() != NULL);
    SkASSERT(fPicture != NULL);
    if (NULL == fCanvas.get() || NULL == fPicture) {
        return;
    }

    this->drawTiles();
    this->copyTilesToCanvas();
    this->finishDraw();
}

void TiledPictureRenderer::end() {
    this->deleteTiles();
    this->INHERITED::end();
}

TiledPictureRenderer::~TiledPictureRenderer() {
    this->deleteTiles();
}

void TiledPictureRenderer::clipTile(SkCanvas* tile) {
    SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
                                 SkIntToScalar(fPicture->height()));
    tile->clipRect(clip);
}

void TiledPictureRenderer::addTile(int tile_x_start, int tile_y_start) {
    SkCanvas* tile = this->setupCanvas(fTileWidth, fTileHeight);

    tile->translate(SkIntToScalar(-tile_x_start), SkIntToScalar(-tile_y_start));
    this->clipTile(tile);

    fTiles.push(tile);
}

void TiledPictureRenderer::setupTiles() {
    for (int tile_y_start = 0; tile_y_start < fPicture->height();
         tile_y_start += fTileHeight) {
        for (int tile_x_start = 0; tile_x_start < fPicture->width();
             tile_x_start += fTileWidth) {
            this->addTile(tile_x_start, tile_y_start);
        }
    }
}

void TiledPictureRenderer::deleteTiles() {
    for (int i = 0; i < fTiles.count(); ++i) {
        SkDELETE(fTiles[i]);
    }

    fTiles.reset();
}

void TiledPictureRenderer::drawTiles() {
    for (int i = 0; i < fTiles.count(); ++i) {
        fTiles[i]->drawPicture(*(fPicture));
    }
}

void TiledPictureRenderer::finishDraw() {
    for (int i = 0; i < fTiles.count(); ++i) {
        fTiles[i]->flush();
    }

#if SK_SUPPORT_GPU
    if (this->isUsingGpuDevice()) {
        SkGLContext* glContext = fGrContextFactory.getGLContext(
            GrContextFactory::kNative_GLContextType);

        SkASSERT(glContext != NULL);
        if (NULL == glContext) {
            return;
        }

        SK_GL(*glContext, Finish());
    }
#endif
}

void TiledPictureRenderer::copyTilesToCanvas() {
    int tile_index = 0;
    for (int tile_y_start = 0; tile_y_start < fPicture->height();
         tile_y_start += fTileHeight) {
        for (int tile_x_start = 0; tile_x_start < fPicture->width();
             tile_x_start += fTileWidth) {
            SkASSERT(tile_index < fTiles.count());
            SkBitmap source = fTiles[tile_index]->getDevice()->accessBitmap(false);
            fCanvas->drawBitmap(source,
                                SkIntToScalar(tile_x_start),
                                SkIntToScalar(tile_y_start));
            ++tile_index;
        }
    }
}

}
<commit_msg>Changed how tiles are copied to the master canvas.<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "PictureRenderer.h"
#include "SamplePipeControllers.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkImageEncoder.h"
#include "SkGPipe.h"
#include "SkMatrix.h"
#include "SkPicture.h"
#include "SkScalar.h"
#include "SkString.h"
#include "SkTDArray.h"
#include "SkTypes.h"
#include "picture_utils.h"

#if SK_SUPPORT_GPU
#include "SkGpuDevice.h"
#endif

namespace sk_tools {

enum {
    kDefaultTileWidth = 256,
    kDefaultTileHeight = 256
};

void PictureRenderer::init(SkPicture* pict) {
    SkASSERT(NULL == fPicture);
    SkASSERT(NULL == fCanvas.get());
    if (fPicture != NULL || NULL != fCanvas.get()) {
        return;
    }

    SkASSERT(pict != NULL);
    if (NULL == pict) {
        return;
    }

    fPicture = pict;
    fCanvas.reset(this->setupCanvas());
}

SkCanvas* PictureRenderer::setupCanvas() {
    return this->setupCanvas(fPicture->width(), fPicture->height());
}

SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
    switch(fDeviceType) {
        case kBitmap_DeviceType: {
            SkBitmap bitmap;
            sk_tools::setup_bitmap(&bitmap, width, height);
            return SkNEW_ARGS(SkCanvas, (bitmap));
            break;
        }
#if SK_SUPPORT_GPU
        case kGPU_DeviceType: {
            SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice,
                                                    (fGrContext, SkBitmap::kARGB_8888_Config,
                                                    width, height)));
            return SkNEW_ARGS(SkCanvas, (device.get()));
            break;
        }
#endif
        default:
            SkASSERT(0);
    }

    return NULL;
}

void PictureRenderer::end() {
    this->resetState();
    fPicture = NULL;
    fCanvas.reset(NULL);
}

void PictureRenderer::resetState() {
#if SK_SUPPORT_GPU
    if (this->isUsingGpuDevice()) {
        SkGLContext* glContext = fGrContextFactory.getGLContext(
            GrContextFactory::kNative_GLContextType);
        SK_GL(*glContext, Finish());
    }
#endif
}

void PictureRenderer::finishDraw() {
    SkASSERT(fCanvas.get() != NULL);
    if (NULL == fCanvas.get()) {
        return;
    }

    fCanvas->flush();

#if SK_SUPPORT_GPU
    if (this->isUsingGpuDevice()) {
        SkGLContext* glContext = fGrContextFactory.getGLContext(
            GrContextFactory::kNative_GLContextType);

        SkASSERT(glContext != NULL);
        if (NULL == glContext) {
            return;
        }

        SK_GL(*glContext, Finish());
    }
#endif
}

bool PictureRenderer::write(const SkString& path) const {
    SkASSERT(fCanvas.get() != NULL);
    SkASSERT(fPicture != NULL);
    if (NULL == fCanvas.get() || NULL == fPicture) {
        return false;
    }

    SkBitmap bitmap;
    sk_tools::setup_bitmap(&bitmap, fPicture->width(), fPicture->height());

    fCanvas->readPixels(&bitmap, 0, 0);
    sk_tools::force_all_opaque(bitmap);

    return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
}

void PipePictureRenderer::render() {
    SkASSERT(fCanvas.get() != NULL);
    SkASSERT(fPicture != NULL);
    if (NULL == fCanvas.get() || NULL == fPicture) {
        return;
    }

    PipeController pipeController(fCanvas.get());
    SkGPipeWriter writer;
    SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
    pipeCanvas->drawPicture(*fPicture);
    writer.endRecording();
    this->finishDraw();
}

void SimplePictureRenderer::render() {
    SkASSERT(fCanvas.get() != NULL);
    SkASSERT(fPicture != NULL);
    if (NULL == fCanvas.get() || NULL == fPicture) {
        return;
    }

    fCanvas->drawPicture(*fPicture);
    this->finishDraw();
}

TiledPictureRenderer::TiledPictureRenderer()
    : fTileWidth(kDefaultTileWidth)
    , fTileHeight(kDefaultTileHeight) {}

void TiledPictureRenderer::init(SkPicture* pict) {
    SkASSERT(pict != NULL);
    SkASSERT(0 == fTiles.count());
    if (NULL == pict || fTiles.count() != 0) {
        return;
    }

    this->INHERITED::init(pict);

    if (fTileWidthPercentage > 0) {
        fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100));
    }
    if (fTileHeightPercentage > 0) {
        fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100));
    }

    this->setupTiles();
}

void TiledPictureRenderer::render() {
    SkASSERT(fCanvas.get() != NULL);
    SkASSERT(fPicture != NULL);
    if (NULL == fCanvas.get() || NULL == fPicture) {
        return;
    }

    this->drawTiles();
    this->copyTilesToCanvas();
    this->finishDraw();
}

void TiledPictureRenderer::end() {
    this->deleteTiles();
    this->INHERITED::end();
}

TiledPictureRenderer::~TiledPictureRenderer() {
    this->deleteTiles();
}

void TiledPictureRenderer::clipTile(SkCanvas* tile) {
    SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
                                 SkIntToScalar(fPicture->height()));
    tile->clipRect(clip);
}

void TiledPictureRenderer::addTile(int tile_x_start, int tile_y_start) {
    SkCanvas* tile = this->setupCanvas(fTileWidth, fTileHeight);

    tile->translate(SkIntToScalar(-tile_x_start), SkIntToScalar(-tile_y_start));
    this->clipTile(tile);

    fTiles.push(tile);
}

void TiledPictureRenderer::setupTiles() {
    for (int tile_y_start = 0; tile_y_start < fPicture->height();
         tile_y_start += fTileHeight) {
        for (int tile_x_start = 0; tile_x_start < fPicture->width();
             tile_x_start += fTileWidth) {
            this->addTile(tile_x_start, tile_y_start);
        }
    }
}

void TiledPictureRenderer::deleteTiles() {
    for (int i = 0; i < fTiles.count(); ++i) {
        SkDELETE(fTiles[i]);
    }

    fTiles.reset();
}

void TiledPictureRenderer::drawTiles() {
    for (int i = 0; i < fTiles.count(); ++i) {
        fTiles[i]->drawPicture(*(fPicture));
    }
}

void TiledPictureRenderer::finishDraw() {
    for (int i = 0; i < fTiles.count(); ++i) {
        fTiles[i]->flush();
    }

#if SK_SUPPORT_GPU
    if (this->isUsingGpuDevice()) {
        SkGLContext* glContext = fGrContextFactory.getGLContext(
            GrContextFactory::kNative_GLContextType);

        SkASSERT(glContext != NULL);
        if (NULL == glContext) {
            return;
        }

        SK_GL(*glContext, Finish());
    }
#endif
}

void TiledPictureRenderer::copyTilesToCanvas() {
    for (int i = 0; i < fTiles.count(); ++i) {
        // Since SkPicture performs a save and restore when being drawn to a
        // canvas, we can be confident that the transform matrix of the canvas
        // is what we set when creating the tiles.
        SkMatrix matrix = fTiles[i]->getTotalMatrix();
        SkScalar tile_x_start = matrix.getTranslateX();
        SkScalar tile_y_start = matrix.getTranslateY();

        SkBitmap source = fTiles[i]->getDevice()->accessBitmap(false);

        fCanvas->drawBitmap(source, -tile_x_start, -tile_y_start);
    }
}

}
<|endoftext|>


<commit_before><commit_msg>Any reason to use IsHeadlessModeRequested here?<commit_after><|endoftext|>


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

#include "performance.h"

#include <QtTest/QtTest>
#include <QDebug>
#include <QFile>
#include <QTime>

void tst_SymbianPluginPerfomance::initTestCase()
{
    QString absolutePath("C:/logs/qtphonebook/performancelog.htm");
	mFile = new QFile(absolutePath);

    if (mFile->open(QIODevice::Text | QIODevice::WriteOnly))
        mDebug = new QDebug(mFile);

    log() << "------------- Start symbian backend performance test ---------------
";
    mCntMng = new QContactManager("symbian");

    if (mCntMng == NULL) {
        log() << "No results. QContactManager was not created
";
        QSKIP("Contact manager was not created", SkipAll);
    }
}

void tst_SymbianPluginPerfomance::cleanupTestCase()
{
    log() << "------------- End symbian backend performance test ---------------
";
    delete mCntMng;
    delete mDebug;
    mFile->close();
    delete mFile;
}

void tst_SymbianPluginPerfomance::simpleContactsTestCase()
{
    QTime t;
    t.start();

    // Create N contacts
    for(int i=0; i<NO_OF_CONTACTS; i++) {
        QChar c(i);
        QString first("Alice");
        QContact alice;

        // Contact details
        QContactName aliceName;
        aliceName.setFirst(first.append(c));
        alice.saveDetail(&aliceName);

        // Save the contact
        if (mCntMng->saveContact(&alice))
            mContactList.append(alice.id());
    }
    log() << "Created " << mContactList.count() << " simple contacts in "
        << t.elapsed() / 1000 << "s" << t.elapsed() % 1000 << "ms
";

    // Remove N contacts
    t.restart();
    for(int i=0; i<mContactList.count(); i++)
        mCntMng->removeContact(mContactList[i]);

    log() << "Removed " << mContactList.count() << " simple contacts in "
        << t.elapsed() / 1000 << "s" << t.elapsed() % 1000 << "ms
";

    mContactList.clear();
}

void tst_SymbianPluginPerfomance::complexContactsTestCase()
{
    QTime t;
    t.start();

    // Create N contacts
    for(int i=0; i<NO_OF_CONTACTS; i++) {
        QContact alice;

        // Contact details
        QChar c(i);
        QString first("Alice");
        QString last("Jones");

        QContactName aliceName;
        aliceName.setFirst(first.append(c));
        aliceName.setLast(last.append(c));
        alice.saveDetail(&aliceName);

        QString label("Ally Jones");
        QContactDisplayLabel aliceDisplay;
        aliceDisplay.setLabel(label.append(c));
        alice.saveDetail(&aliceDisplay);

        QContactPhoneNumber number;
        number.setContexts("Home");
        number.setSubTypes("Mobile");
        number.setNumber("12345678");
        alice.saveDetail(&number);
        alice.setPreferredDetail("DialAction", number);

        QContactPhoneNumber number2;
        number2.setContexts("Work");
        number2.setSubTypes("Landline");
        number2.setNumber("555-4444");
        alice.saveDetail(&number2);

        QContactAddress add;
        add.setStreet("Leeds West Yorkshire");
        add.setPostcode("10087");
        add.setRegion("New York");
        add.setCountry("United States");
        alice.saveDetail(&add);

        QContactGender gender;
        gender.setGender("Female");
        alice.saveDetail(&gender);

        QContactBirthday bday;
        bday.setDate(QDate(25,10,1978));
        alice.saveDetail(&bday);

        QContactOnlineAccount acc;
        acc.setAccountUri("sips:alice.jones@nokia.com");
        alice.saveDetail(&acc);

        QContactEmailAddress email;
        email.setEmailAddress("mailto:alice.jones@nokia.com");
        alice.saveDetail(&email);

        QContactOrganisation org;
        org.setDepartment("Services");
        org.setTitle("Assistant Manager");
        org.setLocation("Nokia Cyber Park");
        alice.saveDetail(&email);

        // Save the contact
        if (mCntMng->saveContact(&alice))
            mContactList.append(alice.id());

    }
    log() << "Created " << mContactList.count() << " complex contacts in "
        << t.elapsed() / 1000 << "s" << t.elapsed() % 1000 << "ms
";

    // Remove N contacts
    t.restart();
    for(int i=0; i<mContactList.count(); i++)
        mCntMng->removeContact(mContactList[i]);

    log() << "Removed " << mContactList.count() << " complex contacts in "
        << t.elapsed() / 1000 << "s" << t.elapsed() % 1000 << "ms
";

    mContactList.clear();
}

QDebug tst_SymbianPluginPerfomance::log()
{
    if (mDebug != NULL) {
        return *mDebug;
    } else {
       return qDebug();
    }
}

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

#include "performance.h"

#include <QtTest/QtTest>
#include <QDebug>
#include <QFile>
#include <QTime>

void tst_SymbianPluginPerfomance::initTestCase()
{
    QString absolutePath("C:/logs/qtphonebook/performancelog.htm");
	mFile = new QFile(absolutePath);

    if (mFile->open(QIODevice::Text | QIODevice::WriteOnly))
        mDebug = new QDebug(mFile);

    log() << "------------- Start symbian backend performance test ---------------
";
    mCntMng = new QContactManager("symbian");

    if (mCntMng == NULL) {
        log() << "No results. QContactManager was not created
";
        QSKIP("Contact manager was not created", SkipAll);
    }
}

void tst_SymbianPluginPerfomance::cleanupTestCase()
{
    log() << "------------- End symbian backend performance test ---------------
";
    delete mCntMng;
    delete mDebug;
    mFile->close();
    delete mFile;
}

void tst_SymbianPluginPerfomance::simpleContactsTestCase()
{
    QTime t;
    t.start();

    // Create N contacts
    for(int i=0; i<NO_OF_CONTACTS; i++) {
        QString c = QString::number(i);
        QString first("Alice");
        QContact alice;

        // Contact details
        QContactName aliceName;
        aliceName.setFirst(first.append(c));
        alice.saveDetail(&aliceName);

        // Save the contact
        if (mCntMng->saveContact(&alice))
            mContactList.append(alice.id());
    }
    log() << "Created " << mContactList.count() << " simple contacts in "
        << t.elapsed() / 1000 << "s" << t.elapsed() % 1000 << "ms
";

    // Remove N contacts
    t.restart();
    for(int i=0; i<mContactList.count(); i++)
        mCntMng->removeContact(mContactList[i]);

    log() << "Removed " << mContactList.count() << " simple contacts in "
        << t.elapsed() / 1000 << "s" << t.elapsed() % 1000 << "ms
";

    mContactList.clear();
}

void tst_SymbianPluginPerfomance::complexContactsTestCase()
{
    QTime t;
    t.start();

    // Create N contacts
    for(int i=0; i<NO_OF_CONTACTS; i++) {
        QContact alice;

        // Contact details
        QString c = QString::number(i);
        QString first("Alice");
        QString last("Jones");

        QContactName aliceName;
        aliceName.setFirst(first.append(c));
        aliceName.setLast(last.append(c));
        alice.saveDetail(&aliceName);

        QString label("Ally Jones");
        QContactDisplayLabel aliceDisplay;
        aliceDisplay.setLabel(label.append(c));
        alice.saveDetail(&aliceDisplay);

        QContactPhoneNumber number;
        number.setContexts("Home");
        number.setSubTypes("Mobile");
        number.setNumber("12345678");
        alice.saveDetail(&number);
        alice.setPreferredDetail("DialAction", number);

        QContactPhoneNumber number2;
        number2.setContexts("Work");
        number2.setSubTypes("Landline");
        number2.setNumber("555-4444");
        alice.saveDetail(&number2);

        QContactAddress add;
        add.setStreet("Leeds West Yorkshire");
        add.setPostcode("10087");
        add.setRegion("New York");
        add.setCountry("United States");
        alice.saveDetail(&add);

        QContactGender gender;
        gender.setGender("Female");
        alice.saveDetail(&gender);

        QContactBirthday bday;
        bday.setDate(QDate(25,10,1978));
        alice.saveDetail(&bday);

        QContactOnlineAccount acc;
        acc.setAccountUri("sips:alice.jones@nokia.com");
        alice.saveDetail(&acc);

        QContactEmailAddress email;
        email.setEmailAddress("mailto:alice.jones@nokia.com");
        alice.saveDetail(&email);

        QContactOrganization org;
        org.setDepartment("Services");
        org.setTitle("Assistant Manager");
        org.setLocation("Nokia Cyber Park");
        alice.saveDetail(&email);

        // Save the contact
        if (mCntMng->saveContact(&alice))
            mContactList.append(alice.id());

    }
    log() << "Created " << mContactList.count() << " complex contacts in "
        << t.elapsed() / 1000 << "s" << t.elapsed() % 1000 << "ms
";

    // Remove N contacts
    t.restart();
    for(int i=0; i<mContactList.count(); i++)
        mCntMng->removeContact(mContactList[i]);

    log() << "Removed " << mContactList.count() << " complex contacts in "
        << t.elapsed() / 1000 << "s" << t.elapsed() % 1000 << "ms
";

    mContactList.clear();
}

QDebug tst_SymbianPluginPerfomance::log()
{
    if (mDebug != NULL) {
        return *mDebug;
    } else {
       return qDebug();
    }
}

QTEST_MAIN(tst_SymbianPluginPerfomance);
<|endoftext|>


<commit_before>//===--- SILBasicBlock.cpp - Basic blocks for high-level SIL code ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the high-level BasicBlocks used for Swift SIL code.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/STLExtras.h"
#include "swift/SIL/ApplySite.h"
#include "swift/SIL/DebugUtils.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/Strings.h"
using namespace swift;

//===----------------------------------------------------------------------===//
// SILBasicBlock Implementation
//===----------------------------------------------------------------------===//

SILBasicBlock::SILBasicBlock(SILFunction *parent, SILBasicBlock *relativeToBB,
                             bool after)
    : Parent(parent), PredList(nullptr) {
  if (!relativeToBB) {
    parent->getBlocks().push_back(this);
  } else if (after) {
    parent->getBlocks().insertAfter(relativeToBB->getIterator(), this);
  } else {
    parent->getBlocks().insert(relativeToBB->getIterator(), this);
  }
}
SILBasicBlock::~SILBasicBlock() {
  // Invalidate all of the basic block arguments.
  for (auto *Arg : ArgumentList) {
    getModule().notifyDeleteHandlers(Arg);
  }

  dropAllReferences();

  SILModule *M = nullptr;
  if (getParent())
    M = &getParent()->getModule();

  for (auto I = begin(), E = end(); I != E;) {
    auto Inst = &*I;
    ++I;
    if (M) {
      // Notify the delete handlers that the instructions in this block are
      // being deleted.
      M->notifyDeleteHandlers(Inst);
    }
    erase(Inst);
  }

  // iplist's destructor is going to destroy the InstList.
  InstList.clearAndLeakNodesUnsafely();
}

int SILBasicBlock::getDebugID() const {
  if (!getParent())
    return -1;
  int idx = 0;
  for (const SILBasicBlock &B : *getParent()) {
    if (&B == this)
      return idx;
    idx++;
  }
  llvm_unreachable("block not in function's block list");
}

SILModule &SILBasicBlock::getModule() const {
  return getParent()->getModule();
}

void SILBasicBlock::insert(iterator InsertPt, SILInstruction *I) {
  InstList.insert(InsertPt, I);
}

void SILBasicBlock::push_back(SILInstruction *I) {
  InstList.push_back(I);
}

void SILBasicBlock::push_front(SILInstruction *I) {
  InstList.push_front(I);
}

void SILBasicBlock::remove(SILInstruction *I) {
  InstList.remove(I);
}

void SILBasicBlock::eraseInstructions() {
 for (auto It = begin(); It != end();) {
    auto *Inst = &*It++;
    Inst->replaceAllUsesOfAllResultsWithUndef();
    Inst->eraseFromParent();
  }
}

/// Returns the iterator following the erased instruction.
SILBasicBlock::iterator SILBasicBlock::erase(SILInstruction *I) {
  // Notify the delete handlers that this instruction is going away.
  getModule().notifyDeleteHandlers(&*I);
  auto *F = getParent();
  auto nextIter = InstList.erase(I);
  F->getModule().deallocateInst(I);
  return nextIter;
}

/// This method unlinks 'self' from the containing SILFunction and deletes it.
void SILBasicBlock::eraseFromParent() {
  getParent()->getBlocks().erase(this);
}

void SILBasicBlock::cloneArgumentList(SILBasicBlock *Other) {
  assert(Other->isEntry() == isEntry() &&
         "Expected to both blocks to be entries or not");
  if (isEntry()) {
    assert(args_empty() && "Expected to have no arguments");
    for (auto *FuncArg : Other->getSILFunctionArguments()) {
      createFunctionArgument(FuncArg->getType(),
                             FuncArg->getDecl());
    }
    return;
  }

  for (auto *PHIArg : Other->getSILPhiArguments()) {
    createPhiArgument(PHIArg->getType(), PHIArg->getOwnershipKind(),
                      PHIArg->getDecl());
  }
}

void SILBasicBlock::moveArgumentList(SILBasicBlock *from) {
  ArgumentList = std::move(from->ArgumentList);
  for (SILArgument *arg : getArguments()) {
    arg->parentBlock = this;
  }
}

SILFunctionArgument *
SILBasicBlock::createFunctionArgument(SILType Ty, const ValueDecl *D,
                                      bool disableEntryBlockVerification) {
  assert((disableEntryBlockVerification || isEntry()) &&
         "Function Arguments can only be in the entry block");
  const SILFunction *Parent = getParent();
  auto OwnershipKind = ValueOwnershipKind(
      *Parent, Ty,
      Parent->getConventions().getSILArgumentConvention(getNumArguments()));
  return new (getModule()) SILFunctionArgument(this, Ty, OwnershipKind, D);
}

SILFunctionArgument *SILBasicBlock::insertFunctionArgument(arg_iterator Iter,
                                                           SILType Ty,
                                                           ValueOwnershipKind OwnershipKind,
                                                           const ValueDecl *D) {
  assert(isEntry() && "Function Arguments can only be in the entry block");
  return new (getModule()) SILFunctionArgument(this, Iter, Ty, OwnershipKind, D);
}

SILFunctionArgument *SILBasicBlock::replaceFunctionArgument(
    unsigned i, SILType Ty, ValueOwnershipKind Kind, const ValueDecl *D) {
  assert(isEntry() && "Function Arguments can only be in the entry block");

  SILFunction *F = getParent();
  SILModule &M = F->getModule();
  if (Ty.isTrivial(*F))
    Kind = ValueOwnershipKind::None;

  assert(ArgumentList[i]->use_empty() && "Expected no uses of the old arg!");

  // Notify the delete handlers that this argument is being deleted.
  M.notifyDeleteHandlers(ArgumentList[i]);

  SILFunctionArgument *NewArg = new (M) SILFunctionArgument(Ty, Kind, D);
  NewArg->setParent(this);

  // TODO: When we switch to malloc/free allocation we'll be leaking memory
  // here.
  ArgumentList[i] = NewArg;

  return NewArg;
}

/// Replace the ith BB argument with a new one with type Ty (and optional
/// ValueDecl D).
SILPhiArgument *SILBasicBlock::replacePhiArgument(unsigned i, SILType Ty,
                                                  ValueOwnershipKind Kind,
                                                  const ValueDecl *D) {
  assert(!isEntry() && "PHI Arguments can not be in the entry block");
  SILFunction *F = getParent();
  SILModule &M = F->getModule();
  if (Ty.isTrivial(*F))
    Kind = ValueOwnershipKind::None;

  assert(ArgumentList[i]->use_empty() && "Expected no uses of the old BB arg!");

  // Notify the delete handlers that this argument is being deleted.
  M.notifyDeleteHandlers(ArgumentList[i]);

  SILPhiArgument *NewArg = new (M) SILPhiArgument(Ty, Kind, D);
  NewArg->setParent(this);

  // TODO: When we switch to malloc/free allocation we'll be leaking memory
  // here.
  ArgumentList[i] = NewArg;

  return NewArg;
}

SILPhiArgument *SILBasicBlock::replacePhiArgumentAndReplaceAllUses(
    unsigned i, SILType ty, ValueOwnershipKind kind, const ValueDecl *d) {
  // Put in an undef placeholder before we do the replacement since
  // replacePhiArgument() expects the replaced argument to not have
  // any uses.
  SmallVector<Operand *, 16> operands;
  SILValue undef = SILUndef::get(ty, *getParent());
  for (auto *use : getArgument(i)->getUses()) {
    use->set(undef);
    operands.push_back(use);
  }

  // Perform the replacement.
  auto *newArg = replacePhiArgument(i, ty, kind, d);

  // Wire back up the uses.
  while (!operands.empty()) {
    operands.pop_back_val()->set(newArg);
  }

  return newArg;
}

SILPhiArgument *SILBasicBlock::createPhiArgument(SILType Ty,
                                                 ValueOwnershipKind Kind,
                                                 const ValueDecl *D) {
  assert(!isEntry() && "PHI Arguments can not be in the entry block");
  if (Ty.isTrivial(*getParent()))
    Kind = ValueOwnershipKind::None;
  return new (getModule()) SILPhiArgument(this, Ty, Kind, D);
}

SILPhiArgument *SILBasicBlock::insertPhiArgument(arg_iterator Iter, SILType Ty,
                                                 ValueOwnershipKind Kind,
                                                 const ValueDecl *D) {
  assert(!isEntry() && "PHI Arguments can not be in the entry block");
  if (Ty.isTrivial(*getParent()))
    Kind = ValueOwnershipKind::None;
  return new (getModule()) SILPhiArgument(this, Iter, Ty, Kind, D);
}

void SILBasicBlock::eraseArgument(int Index) {
  assert(getArgument(Index)->use_empty() &&
         "Erasing block argument that has uses!");
  // Notify the delete handlers that this BB argument is going away.
  getModule().notifyDeleteHandlers(getArgument(Index));
  ArgumentList.erase(ArgumentList.begin() + Index);
}

/// Splits a basic block into two at the specified instruction.
///
/// Note that all the instructions BEFORE the specified iterator
/// stay as part of the original basic block. The old basic block is left
/// without a terminator.
SILBasicBlock *SILBasicBlock::split(iterator I) {
  SILBasicBlock *New =
    new (Parent->getModule()) SILBasicBlock(Parent, this, /*after*/true);
  // Move all of the specified instructions from the original basic block into
  // the new basic block.
  New->InstList.splice(New->end(), InstList, I, end());
  return New;
}

/// Move the basic block to after the specified basic block in the IR.
void SILBasicBlock::moveAfter(SILBasicBlock *After) {
  assert(getParent() && getParent() == After->getParent() &&
         "Blocks must be in the same function");
  auto InsertPt = std::next(SILFunction::iterator(After));
  auto &BlkList = getParent()->getBlocks();
  BlkList.splice(InsertPt, BlkList, this);
}

void SILBasicBlock::moveTo(SILBasicBlock::iterator To, SILInstruction *I) {
  assert(I->getParent() != this && "Must move from different basic block");
  InstList.splice(To, I->getParent()->InstList, I);
  ScopeCloner ScopeCloner(*Parent);
  I->setDebugScope(ScopeCloner.getOrCreateClonedScope(I->getDebugScope()));
}

void
llvm::ilist_traits<swift::SILBasicBlock>::
transferNodesFromList(llvm::ilist_traits<SILBasicBlock> &SrcTraits,
                      block_iterator First, block_iterator Last) {
  assert(&Parent->getModule() == &SrcTraits.Parent->getModule() &&
         "Module mismatch!");

  // If we are asked to splice into the same function, don't update parent
  // pointers.
  if (Parent == SrcTraits.Parent)
    return;

  ScopeCloner ScopeCloner(*Parent);

  // If splicing blocks not in the same function, update the parent pointers.
  for (; First != Last; ++First) {
    First->Parent = Parent;
    for (auto &II : *First)
      II.setDebugScope(ScopeCloner.getOrCreateClonedScope(II.getDebugScope()));
  }
}

/// ScopeCloner expects NewFn to be a clone of the original
/// function, with all debug scopes and locations still pointing to
/// the original function.
ScopeCloner::ScopeCloner(SILFunction &NewFn) : NewFn(NewFn) {
  // Some clients of SILCloner copy over the original function's
  // debug scope. Create a new one here.
  // FIXME: Audit all call sites and make them create the function
  // debug scope.
  auto *SILFn = NewFn.getDebugScope()->Parent.get<SILFunction *>();
  if (SILFn != &NewFn) {
    SILFn->setInlined();
    NewFn.setDebugScope(getOrCreateClonedScope(NewFn.getDebugScope()));
  }
}

const SILDebugScope *
ScopeCloner::getOrCreateClonedScope(const SILDebugScope *OrigScope) {
  if (!OrigScope)
    return nullptr;

  auto it = ClonedScopeCache.find(OrigScope);
  if (it != ClonedScopeCache.end())
    return it->second;

  auto ClonedScope = new (NewFn.getModule()) SILDebugScope(*OrigScope);
  if (OrigScope->InlinedCallSite) {
    // For inlined functions, we need to rewrite the inlined call site.
    ClonedScope->InlinedCallSite =
        getOrCreateClonedScope(OrigScope->InlinedCallSite);
  } else {
    if (auto *ParentScope = OrigScope->Parent.dyn_cast<const SILDebugScope *>())
      ClonedScope->Parent = getOrCreateClonedScope(ParentScope);
    else
      ClonedScope->Parent = &NewFn;
  }
  // Create an inline scope for the cloned instruction.
  assert(ClonedScopeCache.find(OrigScope) == ClonedScopeCache.end());
  ClonedScopeCache.insert({OrigScope, ClonedScope});
  return ClonedScope;
}

bool SILBasicBlock::isEntry() const {
  return this == &*getParent()->begin();
}

/// Declared out of line so we can have a declaration of SILArgument.
#define ARGUMENT(NAME, PARENT)                                                 \
  NAME##ArrayRef SILBasicBlock::get##NAME##s() const {                         \
    return NAME##ArrayRef(getArguments(),                                      \
                          [](SILArgument *arg) { return cast<NAME>(arg); });   \
  }
#include "swift/SIL/SILNodes.def"

/// Returns true if this block ends in an unreachable or an apply of a
/// no-return apply or builtin.
bool SILBasicBlock::isNoReturn() const {
  if (isa<UnreachableInst>(getTerminator()))
    return true;

  auto Iter = prev_or_begin(getTerminator()->getIterator(), begin());
  FullApplySite FAS = FullApplySite::isa(const_cast<SILInstruction *>(&*Iter));
  if (FAS && FAS.isCalleeNoReturn()) {
    return true;
  }

  if (auto *BI = dyn_cast<BuiltinInst>(&*Iter)) {
    return BI->getModule().isNoReturnBuiltinOrIntrinsic(BI->getName());
  }

  return false;
}

bool SILBasicBlock::isTrampoline() const {
  auto *Branch = dyn_cast<BranchInst>(getTerminator());
  if (!Branch)
    return false;
  return begin() == Branch->getIterator();
}

bool SILBasicBlock::isLegalToHoistInto() const {
  return true;
}

const SILDebugScope *SILBasicBlock::getScopeOfFirstNonMetaInstruction() {
  for (auto &Inst : *this)
    if (Inst.isMetaInstruction())
      return Inst.getDebugScope();
  return begin()->getDebugScope();
}
<commit_msg>SIL: fix a use-list iteration problem in replacePhiArgumentAndReplaceAllUses()<commit_after>//===--- SILBasicBlock.cpp - Basic blocks for high-level SIL code ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the high-level BasicBlocks used for Swift SIL code.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/STLExtras.h"
#include "swift/SIL/ApplySite.h"
#include "swift/SIL/DebugUtils.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/Strings.h"
using namespace swift;

//===----------------------------------------------------------------------===//
// SILBasicBlock Implementation
//===----------------------------------------------------------------------===//

SILBasicBlock::SILBasicBlock(SILFunction *parent, SILBasicBlock *relativeToBB,
                             bool after)
    : Parent(parent), PredList(nullptr) {
  if (!relativeToBB) {
    parent->getBlocks().push_back(this);
  } else if (after) {
    parent->getBlocks().insertAfter(relativeToBB->getIterator(), this);
  } else {
    parent->getBlocks().insert(relativeToBB->getIterator(), this);
  }
}
SILBasicBlock::~SILBasicBlock() {
  // Invalidate all of the basic block arguments.
  for (auto *Arg : ArgumentList) {
    getModule().notifyDeleteHandlers(Arg);
  }

  dropAllReferences();

  SILModule *M = nullptr;
  if (getParent())
    M = &getParent()->getModule();

  for (auto I = begin(), E = end(); I != E;) {
    auto Inst = &*I;
    ++I;
    if (M) {
      // Notify the delete handlers that the instructions in this block are
      // being deleted.
      M->notifyDeleteHandlers(Inst);
    }
    erase(Inst);
  }

  // iplist's destructor is going to destroy the InstList.
  InstList.clearAndLeakNodesUnsafely();
}

int SILBasicBlock::getDebugID() const {
  if (!getParent())
    return -1;
  int idx = 0;
  for (const SILBasicBlock &B : *getParent()) {
    if (&B == this)
      return idx;
    idx++;
  }
  llvm_unreachable("block not in function's block list");
}

SILModule &SILBasicBlock::getModule() const {
  return getParent()->getModule();
}

void SILBasicBlock::insert(iterator InsertPt, SILInstruction *I) {
  InstList.insert(InsertPt, I);
}

void SILBasicBlock::push_back(SILInstruction *I) {
  InstList.push_back(I);
}

void SILBasicBlock::push_front(SILInstruction *I) {
  InstList.push_front(I);
}

void SILBasicBlock::remove(SILInstruction *I) {
  InstList.remove(I);
}

void SILBasicBlock::eraseInstructions() {
 for (auto It = begin(); It != end();) {
    auto *Inst = &*It++;
    Inst->replaceAllUsesOfAllResultsWithUndef();
    Inst->eraseFromParent();
  }
}

/// Returns the iterator following the erased instruction.
SILBasicBlock::iterator SILBasicBlock::erase(SILInstruction *I) {
  // Notify the delete handlers that this instruction is going away.
  getModule().notifyDeleteHandlers(&*I);
  auto *F = getParent();
  auto nextIter = InstList.erase(I);
  F->getModule().deallocateInst(I);
  return nextIter;
}

/// This method unlinks 'self' from the containing SILFunction and deletes it.
void SILBasicBlock::eraseFromParent() {
  getParent()->getBlocks().erase(this);
}

void SILBasicBlock::cloneArgumentList(SILBasicBlock *Other) {
  assert(Other->isEntry() == isEntry() &&
         "Expected to both blocks to be entries or not");
  if (isEntry()) {
    assert(args_empty() && "Expected to have no arguments");
    for (auto *FuncArg : Other->getSILFunctionArguments()) {
      createFunctionArgument(FuncArg->getType(),
                             FuncArg->getDecl());
    }
    return;
  }

  for (auto *PHIArg : Other->getSILPhiArguments()) {
    createPhiArgument(PHIArg->getType(), PHIArg->getOwnershipKind(),
                      PHIArg->getDecl());
  }
}

void SILBasicBlock::moveArgumentList(SILBasicBlock *from) {
  ArgumentList = std::move(from->ArgumentList);
  for (SILArgument *arg : getArguments()) {
    arg->parentBlock = this;
  }
}

SILFunctionArgument *
SILBasicBlock::createFunctionArgument(SILType Ty, const ValueDecl *D,
                                      bool disableEntryBlockVerification) {
  assert((disableEntryBlockVerification || isEntry()) &&
         "Function Arguments can only be in the entry block");
  const SILFunction *Parent = getParent();
  auto OwnershipKind = ValueOwnershipKind(
      *Parent, Ty,
      Parent->getConventions().getSILArgumentConvention(getNumArguments()));
  return new (getModule()) SILFunctionArgument(this, Ty, OwnershipKind, D);
}

SILFunctionArgument *SILBasicBlock::insertFunctionArgument(arg_iterator Iter,
                                                           SILType Ty,
                                                           ValueOwnershipKind OwnershipKind,
                                                           const ValueDecl *D) {
  assert(isEntry() && "Function Arguments can only be in the entry block");
  return new (getModule()) SILFunctionArgument(this, Iter, Ty, OwnershipKind, D);
}

SILFunctionArgument *SILBasicBlock::replaceFunctionArgument(
    unsigned i, SILType Ty, ValueOwnershipKind Kind, const ValueDecl *D) {
  assert(isEntry() && "Function Arguments can only be in the entry block");

  SILFunction *F = getParent();
  SILModule &M = F->getModule();
  if (Ty.isTrivial(*F))
    Kind = ValueOwnershipKind::None;

  assert(ArgumentList[i]->use_empty() && "Expected no uses of the old arg!");

  // Notify the delete handlers that this argument is being deleted.
  M.notifyDeleteHandlers(ArgumentList[i]);

  SILFunctionArgument *NewArg = new (M) SILFunctionArgument(Ty, Kind, D);
  NewArg->setParent(this);

  // TODO: When we switch to malloc/free allocation we'll be leaking memory
  // here.
  ArgumentList[i] = NewArg;

  return NewArg;
}

/// Replace the ith BB argument with a new one with type Ty (and optional
/// ValueDecl D).
SILPhiArgument *SILBasicBlock::replacePhiArgument(unsigned i, SILType Ty,
                                                  ValueOwnershipKind Kind,
                                                  const ValueDecl *D) {
  assert(!isEntry() && "PHI Arguments can not be in the entry block");
  SILFunction *F = getParent();
  SILModule &M = F->getModule();
  if (Ty.isTrivial(*F))
    Kind = ValueOwnershipKind::None;

  assert(ArgumentList[i]->use_empty() && "Expected no uses of the old BB arg!");

  // Notify the delete handlers that this argument is being deleted.
  M.notifyDeleteHandlers(ArgumentList[i]);

  SILPhiArgument *NewArg = new (M) SILPhiArgument(Ty, Kind, D);
  NewArg->setParent(this);

  // TODO: When we switch to malloc/free allocation we'll be leaking memory
  // here.
  ArgumentList[i] = NewArg;

  return NewArg;
}

SILPhiArgument *SILBasicBlock::replacePhiArgumentAndReplaceAllUses(
    unsigned i, SILType ty, ValueOwnershipKind kind, const ValueDecl *d) {
  // Put in an undef placeholder before we do the replacement since
  // replacePhiArgument() expects the replaced argument to not have
  // any uses.
  SmallVector<Operand *, 16> operands;
  SILValue undef = SILUndef::get(ty, *getParent());
  SILArgument *arg = getArgument(i);
  while (!arg->use_empty()) {
    Operand *use = *arg->use_begin();
    use->set(undef);
    operands.push_back(use);
  }

  // Perform the replacement.
  auto *newArg = replacePhiArgument(i, ty, kind, d);

  // Wire back up the uses.
  while (!operands.empty()) {
    operands.pop_back_val()->set(newArg);
  }

  return newArg;
}

SILPhiArgument *SILBasicBlock::createPhiArgument(SILType Ty,
                                                 ValueOwnershipKind Kind,
                                                 const ValueDecl *D) {
  assert(!isEntry() && "PHI Arguments can not be in the entry block");
  if (Ty.isTrivial(*getParent()))
    Kind = ValueOwnershipKind::None;
  return new (getModule()) SILPhiArgument(this, Ty, Kind, D);
}

SILPhiArgument *SILBasicBlock::insertPhiArgument(arg_iterator Iter, SILType Ty,
                                                 ValueOwnershipKind Kind,
                                                 const ValueDecl *D) {
  assert(!isEntry() && "PHI Arguments can not be in the entry block");
  if (Ty.isTrivial(*getParent()))
    Kind = ValueOwnershipKind::None;
  return new (getModule()) SILPhiArgument(this, Iter, Ty, Kind, D);
}

void SILBasicBlock::eraseArgument(int Index) {
  assert(getArgument(Index)->use_empty() &&
         "Erasing block argument that has uses!");
  // Notify the delete handlers that this BB argument is going away.
  getModule().notifyDeleteHandlers(getArgument(Index));
  ArgumentList.erase(ArgumentList.begin() + Index);
}

/// Splits a basic block into two at the specified instruction.
///
/// Note that all the instructions BEFORE the specified iterator
/// stay as part of the original basic block. The old basic block is left
/// without a terminator.
SILBasicBlock *SILBasicBlock::split(iterator I) {
  SILBasicBlock *New =
    new (Parent->getModule()) SILBasicBlock(Parent, this, /*after*/true);
  // Move all of the specified instructions from the original basic block into
  // the new basic block.
  New->InstList.splice(New->end(), InstList, I, end());
  return New;
}

/// Move the basic block to after the specified basic block in the IR.
void SILBasicBlock::moveAfter(SILBasicBlock *After) {
  assert(getParent() && getParent() == After->getParent() &&
         "Blocks must be in the same function");
  auto InsertPt = std::next(SILFunction::iterator(After));
  auto &BlkList = getParent()->getBlocks();
  BlkList.splice(InsertPt, BlkList, this);
}

void SILBasicBlock::moveTo(SILBasicBlock::iterator To, SILInstruction *I) {
  assert(I->getParent() != this && "Must move from different basic block");
  InstList.splice(To, I->getParent()->InstList, I);
  ScopeCloner ScopeCloner(*Parent);
  I->setDebugScope(ScopeCloner.getOrCreateClonedScope(I->getDebugScope()));
}

void
llvm::ilist_traits<swift::SILBasicBlock>::
transferNodesFromList(llvm::ilist_traits<SILBasicBlock> &SrcTraits,
                      block_iterator First, block_iterator Last) {
  assert(&Parent->getModule() == &SrcTraits.Parent->getModule() &&
         "Module mismatch!");

  // If we are asked to splice into the same function, don't update parent
  // pointers.
  if (Parent == SrcTraits.Parent)
    return;

  ScopeCloner ScopeCloner(*Parent);

  // If splicing blocks not in the same function, update the parent pointers.
  for (; First != Last; ++First) {
    First->Parent = Parent;
    for (auto &II : *First)
      II.setDebugScope(ScopeCloner.getOrCreateClonedScope(II.getDebugScope()));
  }
}

/// ScopeCloner expects NewFn to be a clone of the original
/// function, with all debug scopes and locations still pointing to
/// the original function.
ScopeCloner::ScopeCloner(SILFunction &NewFn) : NewFn(NewFn) {
  // Some clients of SILCloner copy over the original function's
  // debug scope. Create a new one here.
  // FIXME: Audit all call sites and make them create the function
  // debug scope.
  auto *SILFn = NewFn.getDebugScope()->Parent.get<SILFunction *>();
  if (SILFn != &NewFn) {
    SILFn->setInlined();
    NewFn.setDebugScope(getOrCreateClonedScope(NewFn.getDebugScope()));
  }
}

const SILDebugScope *
ScopeCloner::getOrCreateClonedScope(const SILDebugScope *OrigScope) {
  if (!OrigScope)
    return nullptr;

  auto it = ClonedScopeCache.find(OrigScope);
  if (it != ClonedScopeCache.end())
    return it->second;

  auto ClonedScope = new (NewFn.getModule()) SILDebugScope(*OrigScope);
  if (OrigScope->InlinedCallSite) {
    // For inlined functions, we need to rewrite the inlined call site.
    ClonedScope->InlinedCallSite =
        getOrCreateClonedScope(OrigScope->InlinedCallSite);
  } else {
    if (auto *ParentScope = OrigScope->Parent.dyn_cast<const SILDebugScope *>())
      ClonedScope->Parent = getOrCreateClonedScope(ParentScope);
    else
      ClonedScope->Parent = &NewFn;
  }
  // Create an inline scope for the cloned instruction.
  assert(ClonedScopeCache.find(OrigScope) == ClonedScopeCache.end());
  ClonedScopeCache.insert({OrigScope, ClonedScope});
  return ClonedScope;
}

bool SILBasicBlock::isEntry() const {
  return this == &*getParent()->begin();
}

/// Declared out of line so we can have a declaration of SILArgument.
#define ARGUMENT(NAME, PARENT)                                                 \
  NAME##ArrayRef SILBasicBlock::get##NAME##s() const {                         \
    return NAME##ArrayRef(getArguments(),                                      \
                          [](SILArgument *arg) { return cast<NAME>(arg); });   \
  }
#include "swift/SIL/SILNodes.def"

/// Returns true if this block ends in an unreachable or an apply of a
/// no-return apply or builtin.
bool SILBasicBlock::isNoReturn() const {
  if (isa<UnreachableInst>(getTerminator()))
    return true;

  auto Iter = prev_or_begin(getTerminator()->getIterator(), begin());
  FullApplySite FAS = FullApplySite::isa(const_cast<SILInstruction *>(&*Iter));
  if (FAS && FAS.isCalleeNoReturn()) {
    return true;
  }

  if (auto *BI = dyn_cast<BuiltinInst>(&*Iter)) {
    return BI->getModule().isNoReturnBuiltinOrIntrinsic(BI->getName());
  }

  return false;
}

bool SILBasicBlock::isTrampoline() const {
  auto *Branch = dyn_cast<BranchInst>(getTerminator());
  if (!Branch)
    return false;
  return begin() == Branch->getIterator();
}

bool SILBasicBlock::isLegalToHoistInto() const {
  return true;
}

const SILDebugScope *SILBasicBlock::getScopeOfFirstNonMetaInstruction() {
  for (auto &Inst : *this)
    if (Inst.isMetaInstruction())
      return Inst.getDebugScope();
  return begin()->getDebugScope();
}
<|endoftext|>


<commit_before>
// Event.cpp

// Implements the cEvent object representing an OS-specific synchronization primitive that can be waited-for
// Implemented as an Event on Win and as a 1-semaphore on *nix

#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "Event.h"

cEvent::cEvent(void)
{
#ifdef _WIN32
	m_Event = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (m_Event == NULL)
	{
		LOGERROR("cEvent: cannot create event, GLE = %d. Aborting server.", GetLastError());
		abort();
	}
#else  // *nix
	m_bIsNamed = false;
	m_Event = new sem_t;
	if (sem_init(m_Event, 0, 0))
	{
		// This path is used by MacOS, because it doesn't support unnamed semaphores.
		delete m_Event;
		m_bIsNamed = true;

		AString EventName;
		Printf(EventName, "cEvent%p", this);
		m_Event = sem_open(EventName.c_str(), O_CREAT, 777, 0 );
		if (m_Event == SEM_FAILED)
		{
			LOGERROR("cEvent: Cannot create event, errno = %i. Aborting server.", errno);
			abort();
		}
		// Unlink the semaphore immediately - it will continue to function but will not pollute the namespace
		// We don't store the name, so can't call this in the destructor
		if (sem_unlink(EventName.c_str()) != 0)
		{
			LOGWARN("ERROR: Could not unlink cEvent. (%i)", errno);
		}
	}
#endif  // *nix
}

cEvent::~cEvent()
{
#ifdef _WIN32
	CloseHandle(m_Event);
#else
	if (m_bIsNamed)
	{
		if (sem_close(m_Event) != 0)
		{
			LOGERROR("ERROR: Could not close cEvent. (%i)", errno);
		}
	}
	else
	{
		sem_destroy(m_Event);
		delete m_Event;
	}
#endif
}

void cEvent::Wait(void)
{
	#ifdef _WIN32
		DWORD res = WaitForSingleObject(m_Event, INFINITE);
		if (res != WAIT_OBJECT_0)
		{
			LOGWARN("cEvent: waiting for the event failed: %d, GLE = %d. Continuing, but server may be unstable.", res, GetLastError());
		}
	#else
		int res = sem_wait(m_Event);
		if (res != 0 )
		{
			LOGWARN("cEvent: waiting for the event failed: %i, errno = %i. Continuing, but server may be unstable.", res, errno);
		}
	#endif
}

void cEvent::Set(void)
{
	#ifdef _WIN32
		if (!SetEvent(m_Event))
		{
			LOGWARN("cEvent: Could not set cEvent: GLE = %d", GetLastError());
		}
	#else
		int res = sem_post(m_Event);
		if (res != 0)
		{
			LOGWARN("cEvent: Could not set cEvent: %i, errno = %d", res, errno);
		}
	#endif
}

<commit_msg>Switched cEvent to use strerror_r for error messages<commit_after>
// Event.cpp

// Implements the cEvent object representing an OS-specific synchronization primitive that can be waited-for
// Implemented as an Event on Win and as a 1-semaphore on *nix

#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "Event.h"
#if not defined(_WIN32)
#include <string.h>
#endif

cEvent::cEvent(void)
{
#ifdef _WIN32
	m_Event = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (m_Event == NULL)
	{
		LOGERROR("cEvent: cannot create event, GLE = %d. Aborting server.", GetLastError());
		abort();
	}
#else  // *nix
	m_bIsNamed = false;
	m_Event = new sem_t;
	if (sem_init(m_Event, 0, 0))
	{
		// This path is used by MacOS, because it doesn't support unnamed semaphores.
		delete m_Event;
		m_bIsNamed = true;

		AString EventName;
		Printf(EventName, "cEvent%p", this);
		m_Event = sem_open(EventName.c_str(), O_CREAT, 777, 0 );
		if (m_Event == SEM_FAILED)
		{
			char buffer[1024];
			strerror_r(errno,buffer,1024);
			LOGERROR("cEvent: Cannot create event, err = %s. Aborting server.", buffer);
			abort();
		}
		// Unlink the semaphore immediately - it will continue to function but will not pollute the namespace
		// We don't store the name, so can't call this in the destructor
		if (sem_unlink(EventName.c_str()) != 0)
		{
			char buffer[1024];
			strerror_r(errno,buffer,1024);
			LOGWARN("ERROR: Could not unlink cEvent. (%s)", buffer);
		}
	}
#endif  // *nix
}

cEvent::~cEvent()
{
#ifdef _WIN32
	CloseHandle(m_Event);
#else
	if (m_bIsNamed)
	{
		if (sem_close(m_Event) != 0)
		{
			char buffer[1024];
			strerror_r(errno,buffer,1024);
			LOGERROR("ERROR: Could not close cEvent. (%s)", buffer);
		}
	}
	else
	{
		sem_destroy(m_Event);
		delete m_Event;
	}
#endif
}

void cEvent::Wait(void)
{
	#ifdef _WIN32
		DWORD res = WaitForSingleObject(m_Event, INFINITE);
		if (res != WAIT_OBJECT_0)
		{
			LOGWARN("cEvent: waiting for the event failed: %d, GLE = %d. Continuing, but server may be unstable.", res, GetLastError());
		}
	#else
		int res = sem_wait(m_Event);
		if (res != 0 )
		{
			char buffer[1024];
			strerror_r(errno,buffer,1024);
			LOGWARN("cEvent: waiting for the event failed: %i, err = %s. Continuing, but server may be unstable.", res, buffer);
		}
	#endif
}

void cEvent::Set(void)
{
	#ifdef _WIN32
		if (!SetEvent(m_Event))
		{
			LOGWARN("cEvent: Could not set cEvent: GLE = %d", GetLastError());
		}
	#else
		int res = sem_post(m_Event);
		if (res != 0)
		{
			char buffer[1024];
			strerror_r(errno,buffer,1024);
			LOGWARN("cEvent: Could not set cEvent: %i, err = %s", res, buffer);
		}
	#endif
}

<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include <cling/Interpreter/Interpreter.h>
#include <cling/Interpreter/Value.h>
#include <iostream>
#include <string>
#include <sstream>

///\brief Pass a value from the compiled program into cling, let cling modify it
///  and return the modified value into the compiled program.
int setAndUpdate(int arg, cling::Interpreter& interp) {
   int ret = arg; // The value that will be modified
                  // Update the value of ret by passing it to the interpreter.
   std::ostringstream sstr;
   sstr << "int& ref = *(int*)" << &ret << ';';
   sstr << "ref = ref * ref;";
   interp.process(sstr.str());
   return ret;
}

///\brief A ridiculously complicated way of converting an int to a string.
std::unique_ptr<std::string> stringify(int value, cling::Interpreter& interp) {

   // Declare the function to cling:
   static const std::string codeFunc = R"CODE(
#include <string>
std::string* createAString(const char* str) {
   return new std::string(str);
})CODE";
   interp.declare(codeFunc);

   // Call the function with "runtime" values:
   std::ostringstream sstr;
   sstr << "createAString(\"" << value << "\");";
   cling::Value res; // Will hold the result of the expression evaluation.
   interp.process(sstr.str(), &res);

   // Grab the return value of `createAString()`:
   std::string* resStr = reinterpret_cast<std::string*>(res.getPtr());
   return std::unique_ptr<std::string>(resStr);
}

int main(int argc, const char* const* argv) {
    // Create the Interpreter. LLVMDIR is provided as -D during compilation.
    cling::Interpreter interp(argc, argv, LLVMDIR);

    std::cout << setAndUpdate(17, interp) << '\n';
    std::cout << *stringify(42, interp) << '\n';

    return 0;
}
<commit_msg>Use static_cast; nicer print-out.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include <cling/Interpreter/Interpreter.h>
#include <cling/Interpreter/Value.h>
#include <iostream>
#include <string>
#include <sstream>

///\brief Pass a value from the compiled program into cling, let cling modify it
///  and return the modified value into the compiled program.
int setAndUpdate(int arg, cling::Interpreter& interp) {
   int ret = arg; // The value that will be modified
                  // Update the value of ret by passing it to the interpreter.
   std::ostringstream sstr;
   sstr << "int& ref = *(int*)" << &ret << ';';
   sstr << "ref = ref * ref;";
   interp.process(sstr.str());
   return ret;
}

///\brief A ridiculously complicated way of converting an int to a string.
std::unique_ptr<std::string> stringify(int value, cling::Interpreter& interp) {

   // Declare the function to cling:
   static const std::string codeFunc = R"CODE(
#include <string>
std::string* createAString(const char* str) {
   return new std::string(str);
})CODE";
   interp.declare(codeFunc);

   // Call the function with "runtime" values:
   std::ostringstream sstr;
   sstr << "createAString(\"" << value << "\");";
   cling::Value res; // Will hold the result of the expression evaluation.
   interp.process(sstr.str(), &res);

   // Grab the return value of `createAString()`:
   std::string* resStr = static_cast<std::string*>(res.getPtr());
   return std::unique_ptr<std::string>(resStr);
}

int main(int argc, const char* const* argv) {
    // Create the Interpreter. LLVMDIR is provided as -D during compilation.
    cling::Interpreter interp(argc, argv, LLVMDIR);

    std::cout << "The square of 17 is " << setAndUpdate(17, interp) << '\n';
    std::cout << "Printing a string of 42: " << *stringify(42, interp) << '\n';

    return 0;
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2015, Deutsches Forschungszentrum für Künstliche Intelligenz GmbH.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

// Do NOT add anything to this file
// This header from boost takes ages to compile, so we make sure it is compiled
// only once (here)

#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif
#define BOOST_TEST_NO_MAIN
#define BOOST_TEST_MODULE test module name
#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>
#include <iostream>
#include "PathSingleton.hpp"

// entry point:
int main(int argc, char* argv[], char* envp[])
{
  PathSingleton::binaryFolderPath = boost::filesystem::system_complete(argv[0]);
  PathSingleton::binaryFolderPath = PathSingleton::binaryFolderPath.parent_path();
  return boost::unit_test::unit_test_main( &init_unit_test, argc, argv );
}

<commit_msg>destroy class loader at the end of test suits<commit_after>//
// Copyright (c) 2015, Deutsches Forschungszentrum für Künstliche Intelligenz GmbH.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

// Do NOT add anything to this file
// This header from boost takes ages to compile, so we make sure it is compiled
// only once (here)

#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif
#define BOOST_TEST_NO_MAIN
#define BOOST_TEST_MODULE test module name
#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>
#include <iostream>
#include "PathSingleton.hpp"
#include <envire_core/plugin/ClassLoader.hpp>

// entry point:
int main(int argc, char* argv[], char* envp[])
{
  PathSingleton::binaryFolderPath = boost::filesystem::system_complete(argv[0]);
  PathSingleton::binaryFolderPath = PathSingleton::binaryFolderPath.parent_path();
  int result = boost::unit_test::unit_test_main( &init_unit_test, argc, argv );

  envire::core::ClassLoader::destroyInstance();
  return result;
}

<|endoftext|>